Skip to content

Commit

Permalink
feat: Add subscript accessor to get/set localizable JWT claims
Browse files Browse the repository at this point in the history
!feat: Remove global locale settings
chore: Fix concurrency warnings in Swift 5.10
chore: Operator for safeEqual function
chore: Remove DocC github workflow
  • Loading branch information
amosavian committed Apr 12, 2024
1 parent 244327c commit 11c3f72
Show file tree
Hide file tree
Showing 20 changed files with 214 additions and 180 deletions.
58 changes: 0 additions & 58 deletions .github/workflows/docc.yml

This file was deleted.

13 changes: 7 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,9 @@ let package = Package(
dependencies: [
.package(url: "https://github.com/Flight-School/AnyCodable", .upToNextMajor(from: "0.6.7")),
.package(url: "https://github.com/apple/swift-asn1.git", .upToNextMajor(from: "1.1.0")),
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMajor(from: "3.2.0")),
.package(url: "https://github.com/apple/swift-crypto.git", .upToNextMajor(from: "3.3.0")),
.package(url: "https://github.com/apple/swift-certificates", .upToNextMajor(from: "1.2.0")),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.8.0")),
// Plugins
.package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.53.1"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"),
.package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMajor(from: "1.8.2")),
],
targets: [
.target(
Expand All @@ -44,13 +41,17 @@ let package = Package(
.product(name: "Crypto", package: "swift-crypto", condition: .when(platforms: .nonDarwin)),
.product(name: "_CryptoExtras", package: "swift-crypto", condition: .when(platforms: .nonDarwin)),
.product(name: "CryptoSwift", package: "CryptoSwift", condition: .when(platforms: .nonDarwin)),
],
resources: [
.process("PrivacyInfo.xcprivacy"),
]
),
.testTarget(
name: "JWSETKitTests",
dependencies: ["JWSETKit"]
),
]
],
swiftLanguageVersions: [.v5]
)

for target in package.targets {
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ For detailed usage and API documentation, check [the documentation][docs].
[platforms-badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Famosavian%2FJWSETKit%2Fbadge%3Ftype%3Dplatforms

[RFC7159]: https://www.rfc-editor.org/rfc/rfc7159
[docs]: https://amosavian.github.io/JWSETKit/documentation/jwsetkit/
[docs]: https://swiftpackageindex.com/amosavian/JWSETKit/0.16.0/documentation/jwsetkit
[jwt-kit]: https://github.com/vapor/jwt-kit
[JOSESwift]: https://github.com/airsidemobile/JOSESwift
[JWTDecode]: https://github.com/auth0/JWTDecode.swift
Expand Down
9 changes: 1 addition & 8 deletions Sources/JWSETKit/Base/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@

import Foundation

/// General settings and configurations.
enum JSONWebKit {
/// Localization used for key lookups and translating errors.
@ReadWriteLocked
public static var locale: Locale = .autoupdatingCurrent
}

/// Error type thrown by JWSETKit framework.
public protocol JSONWebError: LocalizedError {
/// Localized error description in given locale's language.
Expand All @@ -22,7 +15,7 @@ public protocol JSONWebError: LocalizedError {

extension JSONWebError {
public var errorDescription: String? {
localizedError(for: JSONWebKit.locale)
localizedError(for: .current)
}
}

Expand Down
7 changes: 3 additions & 4 deletions Sources/JWSETKit/Cryptography/Algorithms/Algorithms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,11 @@ public struct JSONWebKeyCurve: StringRepresentable {
}

extension JSONWebKeyCurve {
@ReadWriteLocked
private static var keySizes: [Self: Int] = [
private static let keySizes: ReadWriteLockedValue<[Self: Int]> = .init([
.p256: 32, .ed25519: 32, .x25519: 32,
.p384: 48,
.p521: 66,
]
])

/// Key size in bytes.
public var coordinateSize: Int? {
Expand All @@ -168,7 +167,7 @@ extension JSONWebKeyCurve {
/// - curve: Curve name.
/// - keySize: Uncompressed key size in bytes.
public static func register(_ curve: Self, keySize: Int) async {
keySizes[curve] = keySize
keySizes.wrappedValue[curve] = keySize
}
}

Expand Down
10 changes: 4 additions & 6 deletions Sources/JWSETKit/Cryptography/Algorithms/Compression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,11 @@ public struct JSONWebCompressionAlgorithm: StringRepresentable {

extension JSONWebCompressionAlgorithm {
#if canImport(Compression)
@ReadWriteLocked
private static var compressors: [Self: any JSONWebCompressor.Type] = [
private static let compressors: ReadWriteLockedValue<[Self: any JSONWebCompressor.Type]> = .init([
.deflate: AppleCompressor<DeflateCompressionCodec>.self,
]
])
#else
@ReadWriteLocked
private static var compressors: [Self: any JSONWebCompressor.Type] = [:]
private static let compressors: ReadWriteLockedValue<[Self: any JSONWebCompressor.Type]> = .init([:])
#endif

/// Returns provided compressor for this algorithm.
Expand All @@ -70,7 +68,7 @@ extension JSONWebCompressionAlgorithm {
/// - algorithm: Compression algorithm.
/// - compressor: Compressor instance.
public static func register<C>(_ algorithm: Self, compressor: C.Type) where C: JSONWebCompressor {
compressors[algorithm] = compressor
compressors.wrappedValue[algorithm] = compressor
}
}

Expand Down
14 changes: 6 additions & 8 deletions Sources/JWSETKit/Cryptography/Algorithms/ContentEncryption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,16 @@ public struct JSONWebContentEncryptionAlgorithm: JSONWebAlgorithm {
}

extension JSONWebContentEncryptionAlgorithm {
@ReadWriteLocked
private static var keyRegistryClasses: [Self: any JSONWebSealingKey.Type] = [
private static let keyRegistryClasses: ReadWriteLockedValue<[Self: any JSONWebSealingKey.Type]> = .init([
.aesEncryptionGCM128: JSONWebKeyAESGCM.self,
.aesEncryptionGCM192: JSONWebKeyAESGCM.self,
.aesEncryptionGCM256: JSONWebKeyAESGCM.self,
.aesEncryptionCBC128SHA256: JSONWebKeyAESCBCHMAC.self,
.aesEncryptionCBC192SHA384: JSONWebKeyAESCBCHMAC.self,
.aesEncryptionCBC256SHA512: JSONWebKeyAESCBCHMAC.self,
]
])

@ReadWriteLocked
private static var keyLengths: [Self: SymmetricKeySize] = [
private static let keyLengths: ReadWriteLockedValue<[Self: SymmetricKeySize]> = .init([
.aesEncryptionGCM128: .bits128,
.aesEncryptionGCM192: .bits192,
.aesEncryptionGCM256: .bits256,
Expand All @@ -43,7 +41,7 @@ extension JSONWebContentEncryptionAlgorithm {
.aesEncryptionCBC128SHA256: .bits128 * 2,
.aesEncryptionCBC192SHA384: .bits192 * 2,
.aesEncryptionCBC256SHA512: .bits256 * 2,
]
])

/// Key type, either RSA, Elliptic curve, Symmetric, etc.
public var keyType: JSONWebKeyType? {
Expand Down Expand Up @@ -76,8 +74,8 @@ extension JSONWebContentEncryptionAlgorithm {
keyClass: KT.Type,
keyLength: SymmetricKeySize
) where KT: JSONWebSealingKey {
keyRegistryClasses[algorithm] = keyClass
keyLengths[algorithm] = keyLength
keyRegistryClasses.wrappedValue[algorithm] = keyClass
keyLengths.wrappedValue[algorithm] = keyLength
}
}

Expand Down
42 changes: 18 additions & 24 deletions Sources/JWSETKit/Cryptography/Algorithms/KeyEncryption.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ extension JSONWebKeyEncryptionAlgorithm {
_ cek: inout Data
) throws -> Void

@ReadWriteLocked
private static var keyRegistryClasses: [Self: (public: any JSONWebEncryptingKey.Type, private: any JSONWebDecryptingKey.Type)] = [
private static let keyRegistryClasses: ReadWriteLockedValue < [Self: (public: any JSONWebEncryptingKey.Type, private: any JSONWebDecryptingKey.Type)]> = .init([
.direct: (JSONWebDirectKey.self, JSONWebDirectKey.self),
.aesKeyWrap128: (JSONWebKeyAESKW.self, JSONWebKeyAESKW.self),
.aesKeyWrap192: (JSONWebKeyAESKW.self, JSONWebKeyAESKW.self),
Expand All @@ -57,10 +56,9 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: (JSONWebKeyAESKW.self, JSONWebKeyAESKW.self),
.ecdhEphemeralStaticAESKeyWrap192: (JSONWebKeyAESKW.self, JSONWebKeyAESKW.self),
.ecdhEphemeralStaticAESKeyWrap256: (JSONWebKeyAESKW.self, JSONWebKeyAESKW.self),
]
])

@ReadWriteLocked
private static var keyTypes: [Self: JSONWebKeyType] = [
private static let keyTypes: ReadWriteLockedValue<[Self: JSONWebKeyType]> = .init([
.direct: .symmetric,
.aesKeyWrap128: .symmetric,
.aesKeyWrap192: .symmetric,
Expand All @@ -80,10 +78,9 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: .symmetric,
.ecdhEphemeralStaticAESKeyWrap192: .symmetric,
.ecdhEphemeralStaticAESKeyWrap256: .symmetric,
]
])

@ReadWriteLocked
private static var keyLengths: [Self: Int] = [
private static let keyLengths: ReadWriteLockedValue<[Self: Int]> = .init([
.aesKeyWrap128: SymmetricKeySize.bits128.bitCount,
.aesKeyWrap192: SymmetricKeySize.bits192.bitCount,
.aesKeyWrap256: SymmetricKeySize.bits256.bitCount,
Expand All @@ -101,10 +98,9 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: SymmetricKeySize.bits128.bitCount,
.ecdhEphemeralStaticAESKeyWrap192: SymmetricKeySize.bits192.bitCount,
.ecdhEphemeralStaticAESKeyWrap256: SymmetricKeySize.bits256.bitCount,
]
])

@ReadWriteLocked
private static var hashFunctions: [Self: any HashFunction.Type] = [
private static let hashFunctions: ReadWriteLockedValue<[Self: any HashFunction.Type]> = .init([
.aesKeyWrap128: SHA256.self,
.aesKeyWrap192: SHA384.self,
.aesKeyWrap256: SHA512.self,
Expand All @@ -118,10 +114,9 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: SHA256.self,
.ecdhEphemeralStaticAESKeyWrap192: SHA256.self,
.ecdhEphemeralStaticAESKeyWrap256: SHA256.self,
]
])

@ReadWriteLocked
private static var encryptedKeyHandlers: [Self: EncryptedKeyHandler] = [
private static let encryptedKeyHandlers: ReadWriteLockedValue<[Self: EncryptedKeyHandler]> = .init([
.aesGCM128KeyWrap: aesGCMKeyWrapEncryptedKey,
.aesGCM192KeyWrap: aesGCMKeyWrapEncryptedKey,
.aesGCM256KeyWrap: aesGCMKeyWrapEncryptedKey,
Expand All @@ -132,10 +127,9 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: ecdhEsEncryptedKey,
.ecdhEphemeralStaticAESKeyWrap192: ecdhEsEncryptedKey,
.ecdhEphemeralStaticAESKeyWrap256: ecdhEsEncryptedKey,
]
])

@ReadWriteLocked
private static var decryptionMutators: [Self: DecryptionMutatorHandler] = [
private static let decryptionMutators: ReadWriteLockedValue<[Self: DecryptionMutatorHandler]> = .init([
.direct: directDecryptionMutator,
.aesGCM128KeyWrap: aesgcmDecryptionMutator,
.aesGCM192KeyWrap: aesgcmDecryptionMutator,
Expand All @@ -147,7 +141,7 @@ extension JSONWebKeyEncryptionAlgorithm {
.ecdhEphemeralStaticAESKeyWrap128: ecdhEsDecryptionMutator,
.ecdhEphemeralStaticAESKeyWrap192: ecdhEsDecryptionMutator,
.ecdhEphemeralStaticAESKeyWrap256: ecdhEsDecryptionMutator,
]
])

/// Key type, either RSA, Elliptic curve, Symmetric, etc.
public var keyType: JSONWebKeyType? {
Expand Down Expand Up @@ -205,12 +199,12 @@ extension JSONWebKeyEncryptionAlgorithm {
encryptedKeyHandler: EncryptedKeyHandler?,
decryptionMutating: DecryptionMutatorHandler?
) where Public: JSONWebEncryptingKey, Private: JSONWebDecryptingKey {
keyRegistryClasses[algorithm] = (publicKeyClass, privateKeyClass)
keyTypes[algorithm] = type
keyLengths[algorithm] = keyLengthInBits
hashFunctions[algorithm] = hashFunction
encryptedKeyHandlers[algorithm] = encryptedKeyHandler
decryptionMutators[algorithm] = decryptionMutating
keyRegistryClasses.wrappedValue[algorithm] = (publicKeyClass, privateKeyClass)
keyTypes.wrappedValue[algorithm] = type
keyLengths.wrappedValue[algorithm] = keyLengthInBits
hashFunctions.wrappedValue[algorithm] = hashFunction
encryptedKeyHandlers.wrappedValue[algorithm] = encryptedKeyHandler
decryptionMutators.wrappedValue[algorithm] = decryptionMutating
}

/// Generates new random key with minimum key length.
Expand Down
28 changes: 12 additions & 16 deletions Sources/JWSETKit/Cryptography/Algorithms/Signature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ public struct JSONWebSignatureAlgorithm: JSONWebAlgorithm {
}

extension JSONWebSignatureAlgorithm {
@ReadWriteLocked
private static var keyRegistryClasses: [Self: (public: any JSONWebValidatingKey.Type, private: any JSONWebSigningKey.Type)] = [
private static let keyRegistryClasses: ReadWriteLockedValue < [Self: (public: any JSONWebValidatingKey.Type, private: any JSONWebSigningKey.Type)]> = .init([
.none: (JSONWebDirectKey.self, JSONWebDirectKey.self),
.hmacSHA256: (JSONWebKeyHMAC<SHA256>.self, JSONWebKeyHMAC<SHA256>.self),
.hmacSHA384: (JSONWebKeyHMAC<SHA384>.self, JSONWebKeyHMAC<SHA384>.self),
Expand All @@ -38,10 +37,9 @@ extension JSONWebSignatureAlgorithm {
.rsaSignaturePKCS1v15SHA256: (JSONWebRSAPublicKey.self, JSONWebRSAPrivateKey.self),
.rsaSignaturePKCS1v15SHA384: (JSONWebRSAPublicKey.self, JSONWebRSAPrivateKey.self),
.rsaSignaturePKCS1v15SHA512: (JSONWebRSAPublicKey.self, JSONWebRSAPrivateKey.self),
]
])

@ReadWriteLocked
private static var keyTypes: [Self: JSONWebKeyType] = [
private static let keyTypes: ReadWriteLockedValue<[Self: JSONWebKeyType]> = .init([
.none: .symmetric,
.hmacSHA256: .symmetric,
.hmacSHA384: .symmetric,
Expand All @@ -56,16 +54,14 @@ extension JSONWebSignatureAlgorithm {
.rsaSignaturePKCS1v15SHA256: .rsa,
.rsaSignaturePKCS1v15SHA384: .rsa,
.rsaSignaturePKCS1v15SHA512: .rsa,
]
])

@ReadWriteLocked
private static var curves: [Self: JSONWebKeyCurve] = [
private static let curves: ReadWriteLockedValue<[Self: JSONWebKeyCurve]> = .init([
.ecdsaSignatureP256SHA256: .p256, .ecdsaSignatureP384SHA384: .p384,
.ecdsaSignatureP521SHA512: .p521, .eddsaSignature: .ed25519,
]
])

@ReadWriteLocked
private static var hashFunctions: [Self: any HashFunction.Type] = [
private static let hashFunctions: ReadWriteLockedValue<[Self: any HashFunction.Type]> = .init([
.hmacSHA256: SHA256.self,
.hmacSHA384: SHA384.self,
.hmacSHA512: SHA512.self,
Expand All @@ -79,7 +75,7 @@ extension JSONWebSignatureAlgorithm {
.rsaSignaturePKCS1v15SHA256: SHA256.self,
.rsaSignaturePKCS1v15SHA384: SHA384.self,
.rsaSignaturePKCS1v15SHA512: SHA512.self,
]
])

public var keyType: JSONWebKeyType? {
Self.keyTypes[self]
Expand Down Expand Up @@ -120,10 +116,10 @@ extension JSONWebSignatureAlgorithm {
publicKeyClass: Public.Type,
privateKeyClass: Private.Type
) where Public: JSONWebValidatingKey, Private: JSONWebSigningKey {
keyRegistryClasses[algorithm] = (publicKeyClass, privateKeyClass)
keyTypes[algorithm] = type
curves[algorithm] = curve
hashFunctions[algorithm] = hashFunction
keyRegistryClasses.wrappedValue[algorithm] = (publicKeyClass, privateKeyClass)
keyTypes.wrappedValue[algorithm] = type
curves.wrappedValue[algorithm] = curve
hashFunctions.wrappedValue[algorithm] = hashFunction
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/JWSETKit/Cryptography/Compression/Apple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension JSONWebCompressionAlgorithm {
}

/// Compressor contain compress and decompress implementation using `Compression` framework.
public struct AppleCompressor<Codec>: JSONWebCompressor where Codec: CompressionCodec {
public struct AppleCompressor<Codec>: JSONWebCompressor, Sendable where Codec: CompressionCodec {
public static func compress<D>(_ data: D) throws -> Data where D: DataProtocol {
var compressedData = Data()
let filter = try OutputFilter(.compress, using: Codec.algorithm.appleAlgorithm) {
Expand Down

0 comments on commit 11c3f72

Please sign in to comment.