better implementation
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import CryptoKit
|
||||
import JOSESwift
|
||||
import ExpoModulesCore
|
||||
|
||||
class CryptoUtil {
|
||||
// The equivalent of crypto.subtle.digest() with JS on web
|
||||
@@ -13,8 +14,8 @@ class CryptoUtil {
|
||||
return Data(bytes)
|
||||
}
|
||||
|
||||
public static func generateKeyPair(kid: String?) throws -> (publicJWK: JWK, privateJWK: JWK)? {
|
||||
let keyIdString = kid ?? UUID().uuidString
|
||||
public static func generateKeyPair() throws -> JWKPair? {
|
||||
let keyIdString = UUID().uuidString
|
||||
|
||||
let privateKey = P256.Signing.PrivateKey()
|
||||
let publicKey = privateKey.publicKey
|
||||
@@ -23,10 +24,27 @@ class CryptoUtil {
|
||||
let y = publicKey.x963Representation[33...].base64URLEncodedString()
|
||||
let d = privateKey.rawRepresentation.base64URLEncodedString()
|
||||
|
||||
let publicJWK = JWK(kty: "EC", use: "sig", crv: "P-256", kid: keyIdString, x: x, y: y, alg: "ES256")
|
||||
let privateJWK = JWK(kty: "EC", use: "sig", crv: "P-256", kid: keyIdString, x: x, y: y, d: d, alg: "ES256")
|
||||
let publicJWK = JWK(
|
||||
alg: "ES256".toField(),
|
||||
kty: "EC".toField(),
|
||||
crv: "P-256".toNullableField(),
|
||||
x: x.toNullableField(),
|
||||
y: y.toNullableField(),
|
||||
use: "sig".toNullableField(),
|
||||
kid: keyIdString.toNullableField()
|
||||
)
|
||||
let privateJWK = JWK(
|
||||
alg: "ES256".toField(),
|
||||
kty: "EC".toField(),
|
||||
crv: "P-256".toNullableField(),
|
||||
x: x.toNullableField(),
|
||||
y: y.toNullableField(),
|
||||
d: d.toNullableField(),
|
||||
use: "sig".toNullableField(),
|
||||
kid: keyIdString.toNullableField()
|
||||
)
|
||||
|
||||
return (publicJWK, privateJWK)
|
||||
return JWKPair(privateKey: privateJWK.toField(), publicKey: publicJWK.toField())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,3 +53,12 @@ extension Data {
|
||||
return self.base64EncodedString().replacingOccurrences(of: "+", with: "-").replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "=", with: "")
|
||||
}
|
||||
}
|
||||
|
||||
extension String {
|
||||
func toField() -> Field<String> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
func toNullableField() -> Field<String?> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,22 +14,24 @@ public class ExpoBlueskyOAuthClientModule: Module {
|
||||
return CryptoUtil.getRandomValues(byteLength: byteLength)
|
||||
}
|
||||
|
||||
AsyncFunction ("generateKeyPair") { (kid: String?, promise: Promise) in
|
||||
let keypair = try? CryptoUtil.generateKeyPair(kid: kid)
|
||||
AsyncFunction ("generateJwk") { (algo: String?, promise: Promise) in
|
||||
if algo != "ES256" {
|
||||
promise.reject("GenerateKeyError", "Algorithim not supported.")
|
||||
return
|
||||
}
|
||||
|
||||
let keypair = try? CryptoUtil.generateKeyPair()
|
||||
|
||||
guard let keypair = keypair else {
|
||||
guard keypair != nil else {
|
||||
promise.reject("GenerateKeyError", "Error generating JWK.")
|
||||
return
|
||||
}
|
||||
|
||||
promise.resolve([
|
||||
"publicKey": keypair.publicJWK.toJson(),
|
||||
"privateKey": keypair.privateJWK.toJson()
|
||||
])
|
||||
promise.resolve(keypair)
|
||||
}
|
||||
|
||||
AsyncFunction("createJwt") { (jwk: String, header: String, payload: String, promise: Promise) in
|
||||
guard let jwt = JWTUtil.createJwt(jwk, header: header, payload: payload) else {
|
||||
AsyncFunction("createJwt") { (header: JWTHeader, payload: JWTPayload, jwk: JWK, promise: Promise) in
|
||||
guard let jwt = JWTUtil.createJwt(header: header, payload: payload, jwk: jwk) else {
|
||||
promise.reject("JWTError", "Error creating JWT.")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import ExpoModulesCore
|
||||
import JOSESwift
|
||||
|
||||
struct JWK : Record {
|
||||
@Field
|
||||
@@ -25,6 +26,17 @@ struct JWK : Record {
|
||||
func toField() -> Field<JWK> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
|
||||
func toSecKey() throws -> SecKey? {
|
||||
let jsonData = try JSONSerialization.data(withJSONObject: self.toDictionary())
|
||||
guard let jwk = try? JSONDecoder().decode(ECPrivateKey.self, from: jsonData),
|
||||
let key = try? jwk.converted(to: SecKey.self)
|
||||
else {
|
||||
print("Error creating SecKey.")
|
||||
return nil
|
||||
}
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
struct JWKPair : Record {
|
||||
|
||||
+29
-2
@@ -1,4 +1,5 @@
|
||||
import ExpoModulesCore
|
||||
import JOSESwift
|
||||
|
||||
struct JWTHeader : Record {
|
||||
@Field
|
||||
@@ -6,8 +7,6 @@ struct JWTHeader : Record {
|
||||
@Field
|
||||
var jku: String?
|
||||
@Field
|
||||
var jwk: JWK
|
||||
@Field
|
||||
var kid: String?
|
||||
@Field
|
||||
var x5u: String?
|
||||
@@ -21,6 +20,14 @@ struct JWTHeader : Record {
|
||||
var cty: String?
|
||||
@Field
|
||||
var crit: String?
|
||||
|
||||
func toField() -> Field<JWTHeader> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
|
||||
func toJWSHeader() throws -> JWSHeader? {
|
||||
return JWSHeader(try JSONSerialization.data(withJSONObject: self.toDictionary()))
|
||||
}
|
||||
}
|
||||
|
||||
struct JWTPayload : Record {
|
||||
@@ -106,6 +113,14 @@ struct JWTPayload : Record {
|
||||
var address: JWTPayloadAddress?
|
||||
@Field
|
||||
var authorization_details: JWTPayloadAuthorizationDetails?
|
||||
|
||||
func toField() -> Field<JWTPayload> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
|
||||
func toPayload() throws -> Payload {
|
||||
return Payload(try JSONSerialization.data(withJSONObject: self.toDictionary()))
|
||||
}
|
||||
}
|
||||
|
||||
struct JWTPayloadCNF : Record {
|
||||
@@ -121,6 +136,10 @@ struct JWTPayloadCNF : Record {
|
||||
var jkt: String?
|
||||
@Field
|
||||
var osc: String?
|
||||
|
||||
func toField() -> Field<JWTPayloadCNF> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
}
|
||||
|
||||
struct JWTPayloadAddress : Record {
|
||||
@@ -136,6 +155,10 @@ struct JWTPayloadAddress : Record {
|
||||
var postal_code: String?
|
||||
@Field
|
||||
var country: String?
|
||||
|
||||
func toField() -> Field<JWTPayloadAddress> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
}
|
||||
|
||||
struct JWTPayloadAuthorizationDetails : Record {
|
||||
@@ -151,4 +174,8 @@ struct JWTPayloadAuthorizationDetails : Record {
|
||||
var identifier: String?
|
||||
@Field
|
||||
var privileges: [String]?
|
||||
|
||||
func toField() -> Field<JWTPayloadAuthorizationDetails> {
|
||||
return Field(wrappedValue: self)
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,6 @@
|
||||
import JOSESwift
|
||||
|
||||
class JWTUtil {
|
||||
static func jsonToPrivateKey(_ jwkString: String) throws -> SecKey? {
|
||||
guard let jsonData = jwkString.data(using: .utf8),
|
||||
let jwk = try? JSONDecoder().decode(ECPrivateKey.self, from: jsonData),
|
||||
let key = try? jwk.converted(to: SecKey.self)
|
||||
else {
|
||||
let jsonData = jwkString.data(using: .utf8)!
|
||||
let jwk = try! JSONDecoder().decode(ECPrivateKey.self, from: jsonData)
|
||||
// let key = try! jwk.converted(to: SecKey.self)
|
||||
print("Error creating JWK from JWK string \(jwkString).")
|
||||
return nil
|
||||
}
|
||||
|
||||
return key
|
||||
}
|
||||
|
||||
static func jsonToPublicKey(_ jwkString: String) throws -> SecKey? {
|
||||
guard let jsonData = jwkString.data(using: .utf8),
|
||||
let jwk = try? JSONDecoder().decode(ECPublicKey.self, from: jsonData),
|
||||
@@ -46,12 +31,12 @@ class JWTUtil {
|
||||
return JWSHeader(headerData)
|
||||
}
|
||||
|
||||
public static func createJwt(_ jwkString: String, header headerString: String, payload payloadString: String) -> String? {
|
||||
guard let key = try? jsonToPrivateKey(jwkString),
|
||||
let payload = payloadStringToPayload(payloadString),
|
||||
let header = headerStringToPayload(headerString)
|
||||
else
|
||||
{
|
||||
public static func createJwt(header: JWTHeader, payload: JWTPayload, jwk: JWK) -> String? {
|
||||
guard let header = try? header.toJWSHeader(),
|
||||
let payload = try? payload.toPayload(),
|
||||
let key = try? jwk.toSecKey()
|
||||
else {
|
||||
print("didn't have one")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user