CodeVerifier.kt
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.wear.phone.interactions.authentication
import android.os.Build
import androidx.annotation.RequiresApi
import java.nio.charset.StandardCharsets
import java.security.SecureRandom
import java.util.Base64
/**
* Authorisation code verifier.
*
* * Related specifications:
* Proof Key for Code Exchange by OAuth Public Clients (RFC 7636).
* https://tools.ietf.org/html/rfc7636
*/
@RequiresApi(Build.VERSION_CODES.O)
public class CodeVerifier {
private companion object {
/**
* The minimum byte length of a code verifier.
*/
private const val MIN_LENGTH_BYTE = 32
/**
* The maximum character length of a code verifier.
*/
private const val MAX_LENGTH_BYTE = 96
/**
* The minimum character length of a code verifier with base64url-encoded.
*/
private const val MIN_LENGTH_BASE64URL = 43
/**
* The maximum character length of a code verifier with base64url-encoded.
*/
private const val MAX_LENGTH_BASE64URL = 128
/**
* The secure random generator.
*/
private val SECURE_RANDOM: SecureRandom = SecureRandom()
}
/**
* The verifier value.
*/
private var value: String? = null
@JvmOverloads
public constructor(
/**
* It is RECOMMENDED that the output of a suitable random number generator be used to create a
* 32-octet sequence. The octet sequence is then base64url-encoded to produce a 43-octet URL
* safe string to use as the code verifier.
*/
byteLength: Int = 32
) {
/**
* Generates a new code verifier with a cryptographic random value of the specified byte
* length, Base64URL-encoded
*/
require((byteLength >= MIN_LENGTH_BYTE) and (byteLength <= MAX_LENGTH_BYTE)) {
"code verifier for PKCE must has a minimum length of $MIN_LENGTH_BASE64URL characters" +
" and a maximum length of $MAX_LENGTH_BASE64URL characters, please generate " +
"the code verifier with byte length between $MIN_LENGTH_BYTE and $MAX_LENGTH_BYTE"
}
val randomBytes = ByteArray(byteLength)
SECURE_RANDOM.nextBytes(randomBytes)
value = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}
public constructor(value: String) {
this.value = value
}
public fun getValue(): String {
return value!!
}
internal fun getValueBytes(): ByteArray {
return value!!.toByteArray(StandardCharsets.UTF_8)
}
override fun equals(other: Any?): Boolean {
if (other is CodeVerifier) {
return other.getValue() == value
}
return false
}
override fun hashCode(): Int {
return getValueBytes().contentHashCode()
}
}