ManaCore + ManaTokens als Swift-Package für alle nativen mana-e.V.-Apps. Phase α aus mana/docs/MANA_SWIFT.md durch. ManaCore: - AuthClient gegen mana-auth (Login, Refresh, Status-Maschine) - AuthenticatedTransport (URLSession + 401-Retry) - ManaAppConfig-Protocol für App-injizierbare Konfig - KeychainStore mit optionaler Shared-Access-Group - JWT-Parser für lokale Expiry-Prüfung - AuthError, CoreLog (interne OSLog-Logger) ManaTokens: - 12 Vereins-Tokens als dynamic Light/Dark Colors - 5 Brand-Literale (mana-yellow, spectrum-orange, ...) - Spacing, Radius, Typography aus mana/docs/THEMING.md Tests: 12 Unit-Tests grün via swift test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
25 lines
1.1 KiB
Swift
25 lines
1.1 KiB
Swift
import Foundation
|
|
|
|
/// JWT-Parsing-Helfer. **Verifiziert keine Signatur** — der Server bleibt
|
|
/// die Wahrheitsinstanz. Hier nur lokale Expiry-Prüfung für proaktiven
|
|
/// Refresh.
|
|
public enum JWT {
|
|
/// Liest `exp`-Claim aus einem JWT, falls vorhanden.
|
|
public static func expiry(of token: String) -> Date? {
|
|
let parts = token.split(separator: ".")
|
|
guard parts.count == 3 else { return nil }
|
|
guard let payloadData = base64URLDecode(String(parts[1])) else { return nil }
|
|
guard let dict = try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any] else { return nil }
|
|
guard let exp = dict["exp"] as? TimeInterval else { return nil }
|
|
return Date(timeIntervalSince1970: exp)
|
|
}
|
|
|
|
private static func base64URLDecode(_ value: String) -> Data? {
|
|
var base64 = value
|
|
.replacingOccurrences(of: "-", with: "+")
|
|
.replacingOccurrences(of: "_", with: "/")
|
|
let paddingNeeded = (4 - base64.count % 4) % 4
|
|
base64.append(String(repeating: "=", count: paddingNeeded))
|
|
return Data(base64Encoded: base64)
|
|
}
|
|
}
|