this repo has no description
1import JOSESwift 2 3class JoseUtil: NSObject { 4 private static func headerStringToHeader(_ headerString: String) -> JWSHeader? { 5 guard let headerData = headerString.data(using: .utf8) else { 6 return nil 7 } 8 return JWSHeader(headerData) 9 } 10 11 private static func payloadStringToPayload(_ payloadString: String) -> Payload? { 12 guard let payloadData = payloadString.data(using: .utf8) else { 13 return nil 14 } 15 return Payload(payloadData) 16 } 17 18 static func createJwt(header: String, payload: String, jwk: SecKey) throws -> String { 19 guard let header = headerStringToHeader(header) else { 20 throw ExpoAtprotoAuthError.invalidHeader("could not parse header string") 21 } 22 23 guard let payload = payloadStringToPayload(payload) else { 24 throw ExpoAtprotoAuthError.invalidPayload("could not parse payload string") 25 } 26 27 let signer = Signer(signingAlgorithm: .ES256, key: jwk) 28 29 guard let signer = signer else { 30 throw ExpoAtprotoAuthError.nullSigner 31 } 32 33 let jws = try JWS(header: header, payload: payload, signer: signer) 34 35 return jws.compactSerializedString 36 } 37 38 static func verifyJwt(token: String, jwk: SecKey, options: VerifyOptions) throws -> VerifyResponse { 39 guard let jws = try? JWS(compactSerialization: token), 40 let verifier = Verifier(verifyingAlgorithm: .ES256, key: jwk), 41 let validation = try? jws.validate(using: verifier) 42 else { 43 throw ExpoAtprotoAuthError.invalidJwk 44 } 45 46 let header = validation.header 47 let payload = String(data: validation.payload.data(), encoding: .utf8) 48 guard let payload = payload else { 49 throw ExpoAtprotoAuthError.invalidPayload("unable to parse payload") 50 } 51 52 var protectedHeader: [String: Any] = [:] 53 protectedHeader["alg"] = "ES256" 54 if header.jku != nil { 55 protectedHeader["jku"] = header.jku?.absoluteString 56 } 57 if header.kid != nil { 58 protectedHeader["kid"] = header.kid 59 } 60 if header.typ != nil { 61 protectedHeader["typ"] = header.typ 62 } 63 if header.cty != nil { 64 protectedHeader["cty"] = header.cty 65 } 66 if header.crit != nil { 67 protectedHeader["crit"] = header.crit 68 } 69 70 if let typ = options.typ { 71 if header.typ != typ { 72 throw ExpoAtprotoAuthError.invalidPayload("typ mismatch") 73 } 74 } 75 76 let claims = try JSONSerialization.jsonObject(with: validation.payload.data(), options: []) as? [String: Any] 77 78 if let requiredClaims = options.requiredClaims { 79 try requiredClaims.forEach { c in 80 if claims?[c] == nil { 81 throw ExpoAtprotoAuthError.invalidPayload("required claim \(c) missing") 82 } 83 } 84 } 85 86 if let audience = options.audience { 87 if claims?["aud"] as? String != audience { 88 throw ExpoAtprotoAuthError.invalidPayload("audience mismatch") 89 } 90 } 91 92 if let subject = options.subject { 93 if claims?["sub"] as? String != subject { 94 throw ExpoAtprotoAuthError.invalidPayload("subject mismatch") 95 } 96 } 97 98 if let checkTolerance = options.clockTolerance { 99 let now = Date() 100 let expiryDate: Date 101 if let expiryString = claims?["exp"] as? String { 102 let formatter = ISO8601DateFormatter() 103 expiryDate = formatter.date(from: expiryString)! 104 } else { 105 throw ExpoAtprotoAuthError.invalidPayload("expiry missing") 106 } 107 if expiryDate < now - checkTolerance { 108 throw ExpoAtprotoAuthError.invalidPayload("token expired") 109 } 110 } 111 112 if let maxTokenAge = options.maxTokenAge { 113 let now = Date() 114 if let expiryString = claims?["exp"] as? String { 115 let formatter = ISO8601DateFormatter() 116 let expiryDate = formatter.date(from: expiryString)! 117 if expiryDate < now - maxTokenAge { 118 throw ExpoAtprotoAuthError.invalidPayload("token expired") 119 } 120 } else { 121 throw ExpoAtprotoAuthError.invalidPayload("expiry missing") 122 } 123 } 124 125 if let issuer = options.issuer { 126 if claims?["iss"] as? String != issuer { 127 throw ExpoAtprotoAuthError.invalidPayload("issuer mismatch") 128 } 129 } 130 131 let res = VerifyResponse() 132 res.payload = payload 133 res.protectedHeader = protectedHeader 134 135 return res 136 } 137}