mana-swift-event-sync/Sources/ManaEventSync/Core/JWTSubject.swift
Till JS 3be550a154 feat: ManaEventSync E-4.0–E-4.2 — geteilte native Event-Sync-Lib
Extrahiert die zuvor zweimal von Hand gebaute Plumbing aus pageta-native
+ nutriphi-native in ein Paket ManaEventSync (Counterpart zu @mana/event-sync):

- Core: EventEnvelope (+clientId/payloadHash), JSONValue, ULID, JWTSubject, EventSyncError
- EventStorage (SwiftData): parametrierbar (Store/App-Group/additionalModels/In-Memory),
  Outbox, Claim-Reattribute, Anonymous-Retention-Prune
- Transport: SyncHTTPClient (+X-Schema-Hash/422), optionaler SyncWSClient
- Crypto: CryptoProvider/NoOp/MasterKey (AES-GCM enc:1:), VaultClient — opt-in
- EventSyncEngine: besitzt die Identität (makeEnvelope anon/echt), emit offline,
  signIn(realUserId) re-taggt idempotent + drained, Retention 10k/90d

18 Tests grün. Plan: mana/docs/playbooks/MANA_SWIFT_EVENT_SYNC.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 12:39:59 +02:00

27 lines
1.1 KiB
Swift

import Foundation
/// Liest den `sub`-Claim aus einem JWT (Base64URL-Decode des Payloads).
///
/// Bewusst hier statt in `ManaCore` dupliziert, solange `JWT.sub(of:)`
/// dort nicht öffentlich ist — vermeidet eine Cross-Repo-Änderung.
public enum JWTSubject {
public static func subject(of token: String) -> String? {
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],
let sub = dict["sub"] as? String
else { return nil }
return sub
}
private static func base64URLDecode(_ value: String) -> Data? {
var base64 = value
.replacingOccurrences(of: "-", with: "+")
.replacingOccurrences(of: "_", with: "/")
let padding = (4 - base64.count % 4) % 4
base64.append(String(repeating: "=", count: padding))
return Data(base64Encoded: base64)
}
}