6 Commits

4 changed files with 77 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
{ {
"originHash" : "33e7d52ad13cf774717778548edb365d33ff62d766d0049165bc8970f19a23ef", "originHash" : "967609fc5437e21be07c4206e2daefc73c3c7522601e64540f0dd5f115b19a6d",
"pins" : [ "pins" : [
{ {
"identity" : "lcecryptokitbinary", "identity" : "lcecryptokitbinary",
@@ -7,7 +7,7 @@
"location" : "https://60c260c85d3a2fe840411b0ff98f521b5eca3c56@git.loverde.com.br/Loverde-Company-LTDA/LCECryptoKitBinary.git", "location" : "https://60c260c85d3a2fe840411b0ff98f521b5eca3c56@git.loverde.com.br/Loverde-Company-LTDA/LCECryptoKitBinary.git",
"state" : { "state" : {
"revision" : "2c5c47cebef40a8adc5557d071a35be405c05e30", "revision" : "2c5c47cebef40a8adc5557d071a35be405c05e30",
"version" : "1.0.2" "version" : "1.0.3"
} }
} }
], ],

View File

@@ -11,7 +11,7 @@ let cryptoPackageURL = isLocalDevelopment
let packageDependencies: [Package.Dependency] = enableCryptoBinary let packageDependencies: [Package.Dependency] = enableCryptoBinary
? [ ? [
.package(url: cryptoPackageURL, exact: "1.0.2") .package(url: cryptoPackageURL, exact: "1.0.3")
] ]
: [] : []

View File

@@ -58,6 +58,28 @@ public final class LCECryptoKitManager {
public func decodeOTPWithKey(_ otpHash: String) -> Bool { public func decodeOTPWithKey(_ otpHash: String) -> Bool {
LCECryptoKit.decodeSeed(otpKey: otpHash, hashKey: self.hashKey) LCECryptoKit.decodeSeed(otpKey: otpHash, hashKey: self.hashKey)
} }
// MARK: - Salted/Iterated/Peppered Login (atomenta-cryptokit-pepper-refactor-sdd.md)
public static func generateSalt() -> String {
LCECryptoKit.generateSalt()
}
public static func computeClientHash(email: String, password: String, salt: String) -> String {
LCECryptoKit.computeClientHash(email: email, password: password, salt: salt)
}
public static func computeLoginBearerToken(userId: String, clientHash: String) -> String? {
LCECryptoKit.computeLoginBearerToken(userId: userId, clientHash: clientHash)
}
public static func otpEncode(_ plainText: String) -> String? {
LCECryptoKit.otpEncode(plainText)
}
public static func otpDecode(_ otpEncoded: String) -> String? {
LCECryptoKit.otpDecode(otpEncoded)
}
} }
#else #else
@@ -92,5 +114,27 @@ public final class LCECryptoKitManager {
public func decodeOTPWithKey(_ otpHash: String) -> Bool { public func decodeOTPWithKey(_ otpHash: String) -> Bool {
false false
} }
// MARK: - Salted/Iterated/Peppered Login (atomenta-cryptokit-pepper-refactor-sdd.md)
public static func generateSalt() -> String {
""
}
public static func computeClientHash(email: String, password: String, salt: String) -> String {
""
}
public static func computeLoginBearerToken(userId: String, clientHash: String) -> String? {
nil
}
public static func otpEncode(_ plainText: String) -> String? {
nil
}
public static func otpDecode(_ otpEncoded: String) -> String? {
nil
}
} }
#endif #endif

View File

@@ -26,10 +26,8 @@ import Foundation
import Security import Security
#endif #endif
#if canImport(UIKit) #if canImport(UIKit)
#if canImport(UIKit)
import UIKit import UIKit
#endif #endif
#endif
/// A generic `Result` enumeration to represent either a success `Value` or a failure `Error`. /// A generic `Result` enumeration to represent either a success `Value` or a failure `Error`.
public enum Result<Value, Error: Swift.Error> { public enum Result<Value, Error: Swift.Error> {
@@ -47,6 +45,8 @@ public enum httpMethod: String {
case get = "GET" case get = "GET"
/// The PUT method. /// The PUT method.
case put = "PUT" case put = "PUT"
/// The PATCH method.
case patch = "PATCH"
/// The DELETE method. /// The DELETE method.
case delete = "DELETE" case delete = "DELETE"
} }
@@ -90,7 +90,7 @@ public struct API {
/// - Parameters: /// - Parameters:
/// - url: The URL string for the request. /// - url: The URL string for the request.
/// - params: Optional parameters for the request. Can be `[String: Any]` for JSON/form-data, or `Data` for raw body. /// - params: Optional parameters for the request. Can be `[String: Any]` for JSON/form-data, or `Data` for raw body.
/// - method: The HTTP method to use for the request (`.get`, `.post`, `.put`, `.delete`). /// - method: The HTTP method to use for the request (`.get`, `.post`, `.put`, `.delete`,`.patch` ).
/// - headers: Optional custom HTTP headers to be added to the request. These override default headers if there are conflicts. /// - headers: Optional custom HTTP headers to be added to the request. These override default headers if there are conflicts.
/// - jsonEncoding: A boolean indicating whether parameters should be JSON encoded. Defaults to `true`. /// - jsonEncoding: A boolean indicating whether parameters should be JSON encoded. Defaults to `true`.
/// - debug: A boolean indicating whether to print debug logs for the request and response. Defaults to `true`. /// - debug: A boolean indicating whether to print debug logs for the request and response. Defaults to `true`.
@@ -110,8 +110,8 @@ public struct API {
persistConnection: Bool = false) async throws -> T { persistConnection: Bool = false) async throws -> T {
if let urlReq = URL(string: url.replaceURL(params as? [String: Any] ?? [:] )) { if let urlReq = URL(string: url.replaceURL(params as? [String: Any] ?? [:] )) {
var request = URLRequest(url: urlReq, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30) var request = URLRequest(url: urlReq, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: timeoutInterval)
if method == .post || method == .put || method == .delete { if method == .post || method == .put || method == .delete || method == .patch {
if let params = params as? [String: Any], if let params = params as? [String: Any],
let pathFile = params["file"] as? String, let pathFile = params["file"] as? String,
let fileURL = URL(string: pathFile) { let fileURL = URL(string: pathFile) {
@@ -194,7 +194,18 @@ public struct API {
API.requestLOG(method: method, request: request) API.requestLOG(method: method, request: request)
} }
let session = URLSession( // Only spin up a dedicated session (with its own @MainActor
// delegate hop for every TLS/auth challenge) when client
// certificate auth is actually configured. Creating one of
// these per request unconditionally and never invalidating
// it could stall the async challenge callback waiting on an
// already-busy MainActor, hanging the request indefinitely with
// no timeout or error ever surfacing. The common case (no
// client cert) uses the shared session, which has none of this
// risk and is what URLSession is designed to be reused as.
let usesCertSession = API.certData != nil
let session: URLSession = usesCertSession
? URLSession(
configuration: .default, configuration: .default,
delegate: URLSessionDelegateHandler( delegate: URLSessionDelegateHandler(
certData: API.certData, certData: API.certData,
@@ -202,6 +213,12 @@ public struct API {
), ),
delegateQueue: nil delegateQueue: nil
) )
: URLSession.shared
defer {
if usesCertSession {
session.finishTasksAndInvalidate()
}
}
do { do {
let (data, response) = try await session.data(for: request) let (data, response) = try await session.data(for: request)