Skip to content

Commit

Permalink
simplify kt
Browse files Browse the repository at this point in the history
  • Loading branch information
haileyok committed Apr 15, 2024
1 parent 7ed21e4 commit f464875
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 256 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class CryptoUtil {
return random
}

fun generateKeyPair(): Any {
fun generateKeyPair(): Map<String, String> {
val keyIdString = UUID.randomUUID().toString()

val keyPairGen = KeyPairGenerator.getInstance("EC")
Expand All @@ -44,27 +44,9 @@ class CryptoUtil {
.algorithm(Algorithm.parse("ES256"))
.build()


return JWKPair(
JWK(
alg = privateJwk.algorithm.toString(),
kty = privateJwk.keyType.toString(),
crv = privateJwk.curve.toString(),
x = privateJwk.x.toString(),
y = privateJwk.y.toString(),
d = privateJwk.d.toString(),
use = privateJwk.keyUse.toString(),
kid = privateJwk.keyID
),
JWK(
alg = publicJwk.algorithm.toString(),
kty = publicJwk.keyType.toString(),
crv = publicJwk.curve.toString(),
x = publicJwk.x.toString(),
y = publicJwk.y.toString(),
use = publicJwk.keyUse.toString(),
kid = publicJwk.keyID
)
return mapOf(
"privateKey" to privateJwk.toJSONString(),
"publicKey" to publicJwk.toJSONString()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ class ExpoBlueskyOAuthClientModule : Module() {
return@Function CryptoUtil().getRandomValues(byteLength)
}

AsyncFunction("generateJwk") { algorithim: String ->
AsyncFunction("generateJwk") { algorithim: String? ->
if (algorithim != "ES256") {
throw Exception("Unsupported algorithm")
}
return@AsyncFunction CryptoUtil().generateKeyPair()
}

AsyncFunction("createJwt") { header: JWTHeader, payload: JWTPayload, jwk: JWK ->
AsyncFunction("createJwt") { header: String, payload: String, jwk: String ->
return@AsyncFunction JWTUtil().createJwt(header, payload, jwk)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,7 @@ package expo.modules.blueskyoauthclient
import expo.modules.kotlin.records.Record
import expo.modules.kotlin.records.Field

class JWK(
@Field var alg: String = "",
@Field var kty: String = "",
@Field var crv: String? = null,
@Field var x: String? = null,
@Field var y: String? = null,
@Field var e: String? = null,
@Field var n: String? = null,
@Field var d: String? = null,
@Field var use: String? = null,
@Field var kid: String? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (alg.isNotEmpty()) parts.add("\"alg\": \"$alg\"")
if (kty.isNotEmpty()) parts.add("\"kty\": \"$kty\"")
if (crv != null) parts.add("\"crv\": \"$crv\"")
if (x != null) parts.add("\"x\": \"$x\"")
if (y != null) parts.add("\"y\": \"$y\"")
if (e != null) parts.add("\"e\": \"$e\"")
if (n != null) parts.add("\"n\": \"$n\"")
if (d != null) parts.add("\"d\": \"$d\"")
if (use != null) parts.add("\"use\": \"$use\"")
if (kid != null) parts.add("\"kid\": \"$kid\"")
return "{ ${parts.joinToString()} }"
}
}

class JWKPair(@Field val privateKey: JWK, @Field val publicKey: JWK) : Record
class JWKPair(
@Field val privateKey: String,
@Field val publicKey: String
) : Record
Original file line number Diff line number Diff line change
Expand Up @@ -3,173 +3,7 @@ package expo.modules.blueskyoauthclient
import expo.modules.kotlin.records.Record
import expo.modules.kotlin.records.Field

class JWTHeader(
@Field var alg: String = "",
@Field var jku: String? = null,
@Field var jwk: JWK? = null,
@Field var kid: String? = null,
@Field var typ: String? = null,
@Field var cty: String? = null,
@Field var crit: String? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (alg.isNotEmpty()) parts.add("\"alg\": \"$alg\"")
if (jku != null) parts.add("\"jku\": \"$jku\"")
if (jwk != null) parts.add("\"jwk\": ${jwk?.toJson()}")
if (kid != null) parts.add("\"kid\": \"$kid\"")
if (typ != null) parts.add("\"typ\": \"$typ\"")
if (cty != null) parts.add("\"cty\": \"$cty\"")
if (crit != null) parts.add("\"crit\": \"$crit\"")
return "{ ${parts.joinToString()} }"
}
}

class JWTPayload(
@Field var iss: String? = null,
@Field var aud: String? = null,
@Field var sub: String? = null,
@Field var exp: Int? = null,
@Field var nbr: Int? = null,
@Field var iat: Int? = null,
@Field var jti: String? = null,
@Field var htm: String? = null,
@Field var htu: String? = null,
@Field var ath: String? = null,
@Field var acr: String? = null,
@Field var azp: String? = null,
@Field var amr: String? = null,
@Field var cnf: JWTPayloadCNF? = null,
@Field var client_id: String? = null,
@Field var scope: String? = null,
@Field var nonce: String? = null,
@Field var at_hash: String? = null,
@Field var c_hash: String? = null,
@Field var s_hash: String? = null,
@Field var auth_time: Int? = null,
@Field var name: String? = null,
@Field var family_name: String? = null,
@Field var given_name: String? = null,
@Field var middle_name: String? = null,
@Field var nickname: String? = null,
@Field var preferred_username: String? = null,
@Field var gender: String? = null,
@Field var picture: String? = null,
@Field var profile: String? = null,
@Field var birthdate: String? = null,
@Field var zoneinfo: String? = null,
@Field var updated_at: Int? = null,
@Field var email: String? = null,
@Field var email_verified: Boolean? = null,
@Field var phone_number: String? = null,
@Field var phone_number_verified: Boolean? = null,
@Field var address: JWTPayloadAddress? = null,
@Field var authorization_details: JWTPayloadAuthorizationDetails? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (iss != null) parts.add("\"iss\": \"$iss\"")
if (aud != null) parts.add("\"aud\": \"$aud\"")
if (sub != null) parts.add("\"sub\": \"$sub\"")
if (exp != null) parts.add("\"exp\": $exp")
if (nbr != null) parts.add("\"nbr\": $nbr")
if (iat != null) parts.add("\"iat\": $iat")
if (jti != null) parts.add("\"jti\": \"$jti\"")
if (htm != null) parts.add("\"htm\": \"$htm\"")
if (htu != null) parts.add("\"htu\": \"$htu\"")
if (ath != null) parts.add("\"ath\": \"$ath\"")
if (acr != null) parts.add("\"acr\": \"$acr\"")
if (azp != null) parts.add("\"azp\": \"$azp\"")
if (amr != null) parts.add("\"amr\": \"$amr\"")
if (cnf != null) parts.add("\"cnf\": ${cnf?.toJson()}")
if (client_id != null) parts.add("\"client_id\": \"$client_id\"")
if (scope != null) parts.add("\"scope\": \"$scope\"")
if (nonce != null) parts.add("\"nonce\": \"$nonce\"")
if (at_hash != null) parts.add("\"at_hash\": \"$at_hash\"")
if (c_hash != null) parts.add("\"c_hash\": \"$c_hash\"")
if (s_hash != null) parts.add("\"s_hash\": \"$s_hash\"")
if (auth_time != null) parts.add("\"auth_time\": $auth_time")
if (name != null) parts.add("\"name\": \"$name\"")
if (family_name != null) parts.add("\"family_name\": \"$family_name\"")
if (given_name != null) parts.add("\"given_name\": \"$given_name\"")
if (middle_name != null) parts.add("\"middle_name\": \"$middle_name\"")
if (nickname != null) parts.add("\"nickname\": \"$nickname\"")
if (preferred_username != null) parts.add("\"preferred_username\": \"$preferred_username\"")
if (gender != null) parts.add("\"gender\": \"$gender\"")
if (picture != null) parts.add("\"picture\": \"$picture\"")
if (profile != null) parts.add("\"profile\": \"$profile\"")
if (birthdate != null) parts.add("\"birthdate\": \"$birthdate\"")
if (zoneinfo != null) parts.add("\"zoneinfo\": \"$zoneinfo\"")
if (updated_at != null) parts.add("\"updated_at\": $updated_at")
if (email != null) parts.add("\"email\": \"$email\"")
if (email_verified != null) parts.add("\"email_verified\": $email_verified")
if (phone_number != null) parts.add("\"phone_number\": \"$phone_number\"")
if (phone_number_verified != null) parts.add("\"phone_number_verified\": $phone_number_verified")
if (address != null) parts.add("\"address\": ${address?.toJson()}")
if (authorization_details != null) parts.add("\"authorization_details\": ${authorization_details?.toJson()}")
return "{ ${parts.joinToString()} }"
}
}

class JWTPayloadCNF(
@Field var jwk: JWK? = null,
@Field var jwe: String? = null,
@Field var jku: String? = null,
@Field var jkt: String? = null,
@Field var osc: String? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (jwk != null) parts.add("\"jwk\": ${jwk?.toJson()}")
if (jwe != null) parts.add("\"jwe\": \"$jwe\"")
if (jku != null) parts.add("\"jku\": \"$jku\"")
if (jkt != null) parts.add("\"jkt\": \"$jkt\"")
if (osc != null) parts.add("\"osc\": \"$osc\"")
return "{ ${parts.joinToString()} }"
}
}

class JWTPayloadAddress(
@Field var formatted: String? = null,
@Field var street_address: String? = null,
@Field var locality: String? = null,
@Field var region: String? = null,
@Field var postal_code: String? = null,
@Field var country: String? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (formatted != null) parts.add("\"formatted\": \"$formatted\"")
if (street_address != null) parts.add("\"street_address\": \"$street_address\"")
if (locality != null) parts.add("\"locality\": \"$locality\"")
if (region != null) parts.add("\"region\": \"$region\"")
if (postal_code != null) parts.add("\"postal_code\": \"$postal_code\"")
if (country != null) parts.add("\"country\": \"$country\"")
return "{ ${parts.joinToString()} }"
}
}

class JWTPayloadAuthorizationDetails(
@Field var type: String? = null,
@Field var locations: Array<String>? = null,
@Field var actions: Array<String>? = null,
@Field var datatypes: Array<String>? = null,
@Field var identifier: String? = null,
@Field var privileges: Array<String>? = null
) : Record {
fun toJson(): String {
val parts = mutableListOf<String>()
if (type != null) parts.add("\"type\": \"$type\"")
if (locations != null) parts.add("\"locations\": [${locations?.joinToString()}]")
if (actions != null) parts.add("\"actions\": [${actions?.joinToString()}]")
if (datatypes != null) parts.add("\"datatypes\": [${datatypes?.joinToString()}]")
if (identifier != null) parts.add("\"identifier\": \"$identifier\"")
if (privileges != null) parts.add("\"privileges\": [${privileges?.joinToString()}]")
return "{ ${parts.joinToString()} }"
}
}

class JWTVerifyResponse(
@Field var protectedHeader: JWTHeader = JWTHeader(),
@Field var payload: String = "",
@Field var protectedHeader: String,
@Field var payload: String,
) : Record
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.jwt.SignedJWT

class JWTUtil {
fun createJwt(header: JWTHeader, payload: JWTPayload, jwk: JWK): String {
val parsedKey = ECKey.parse(jwk.toJson())
val parsedHeader = JWSHeader.parse(header.toJson())
val parsedPayload = JWTClaimsSet.parse(payload.toJson())
fun createJwt(header: String, payload: String, jwk: String): String {
val parsedKey = ECKey.parse(jwk)
val parsedHeader = JWSHeader.parse(header)
val parsedPayload = JWTClaimsSet.parse(payload)

val signer = ECDSASigner(parsedKey)
val jwt = SignedJWT(parsedHeader, parsedPayload)
Expand All @@ -20,9 +20,9 @@ class JWTUtil {
return jwt.serialize()
}

fun verifyJwt(token: String, jwk: JWK): JWTVerifyResponse {
fun verifyJwt(token: String, jwk: String): Map<String, String> {
try {
val parsedKey = ECKey.parse(jwk.toJson())
val parsedKey = ECKey.parse(jwk)
val jwt = SignedJWT.parse(token)
val verifier = ECDSAVerifier(parsedKey)

Expand All @@ -32,36 +32,10 @@ class JWTUtil {

val header = jwt.header
val payload = jwt.payload
val ecKey = header.jwk?.toECKey()
val serializedJwk = if (ecKey != null) {
JWK(
alg = ecKey.algorithm.toString(),
kty = ecKey.keyType.toString(),
crv = ecKey.curve.toString(),
x = ecKey.x.toString(),
y = ecKey.y.toString(),
d = ecKey.d.toString(),
use = ecKey.keyUse.toString(),
kid = ecKey.keyID
)
} else {
null
}

val serializedHeader = JWTHeader(
alg = header.algorithm.toString(),
jku = header.jwkurl?.toString(),
jwk = serializedJwk,
kid = header.keyID,
typ = header.type?.toString(),
cty = header.contentType,
crit = header.criticalParams?.joinToString()
)
val serializedPayload = payload.toString()

return JWTVerifyResponse(
protectedHeader = serializedHeader,
payload = serializedPayload,
return mapOf(
"payload" to payload.toString(),
"protectedHeader" to header.toString()
)
} catch(e: Exception) {
throw e
Expand Down

0 comments on commit f464875

Please sign in to comment.