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>
37 lines
1.3 KiB
Swift
37 lines
1.3 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import ManaCore
|
|
|
|
@Suite("JWT")
|
|
struct JWTTests {
|
|
@Test("Liefert expiry aus gültigem JWT")
|
|
func extractsExpiry() throws {
|
|
// Header: {"alg":"HS256","typ":"JWT"}
|
|
// Payload: {"sub":"u1","exp":2000000000}
|
|
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1MSIsImV4cCI6MjAwMDAwMDAwMH0.signature"
|
|
let expiry = try #require(JWT.expiry(of: token))
|
|
#expect(expiry == Date(timeIntervalSince1970: 2_000_000_000))
|
|
}
|
|
|
|
@Test("Nil für nicht-JWT-Strings")
|
|
func nilForNonJWT() {
|
|
#expect(JWT.expiry(of: "nonsense") == nil)
|
|
#expect(JWT.expiry(of: "a.b") == nil)
|
|
#expect(JWT.expiry(of: "a.b.c.d") == nil)
|
|
}
|
|
|
|
@Test("Nil wenn exp-Claim fehlt")
|
|
func nilWhenExpMissing() {
|
|
// Payload: {"sub":"u1"}
|
|
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1MSJ9.signature"
|
|
#expect(JWT.expiry(of: token) == nil)
|
|
}
|
|
|
|
@Test("Toleriert Base64URL-Padding")
|
|
func toleratesBase64URLPadding() throws {
|
|
// Payload ohne Padding: {"exp":1700000000}
|
|
let token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE3MDAwMDAwMDB9.sig"
|
|
let expiry = try #require(JWT.expiry(of: token))
|
|
#expect(expiry == Date(timeIntervalSince1970: 1_700_000_000))
|
|
}
|
|
}
|