Files
luma/Sources/LumaCore/AuthFailure.swift
Ole André Vadla Ravnås 39aa24f773 Use unified error formatting for user messages
WelcomeModel, CollaborationSession, and AuthFailure all hand-rolled
String(describing:) variants to dodge NSError bridging or the enum-case
form. With Frida.Error now formatting itself, these collapse to plain
localizedDescription / String(describing:).
2026-05-11 10:56:53 +02:00

45 lines
1.9 KiB
Swift

import Foundation
import Frida
/// Wire-format sibling of `luma-server`'s `AuthFailure`. The portal's
/// authentication delegate packs this JSON envelope into the thrown error
/// message so clients can tell an auth rejection (domain == "auth") apart
/// from a transient upstream issue (domain == "github").
public struct AuthFailure: Sendable, Decodable, Swift.Error {
public let domain: String
public let code: String
public let message: String
public init(domain: String, code: String, message: String) {
self.domain = domain
self.code = code
self.message = message
}
public var isAuthRejection: Bool { domain == "auth" }
/// Marker the server prefixes its base64-encoded JSON envelope with.
/// Must match `LumaServer.AuthFailure.marker`.
private static let marker = "luma-auth:"
private static let base64Alphabet: Set<Character> = {
var set = Set<Character>("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
return set
}()
public static func fromError(_ error: any Swift.Error) -> AuthFailure? {
// The portal's auth delegate tags its JSON envelope with a
// `luma-auth:<base64>` sentinel. Any wrapping layers (Frida's
// client-side transport re-stringifies the error one or more
// times on its way up) can't corrupt the base64 alphabet, so we
// just scan for the marker and decode the payload up to the
// first non-base64 byte.
let text = String(describing: error)
guard let markerRange = text.range(of: marker) else { return nil }
let tail = text[markerRange.upperBound...]
let base64End = tail.firstIndex { !base64Alphabet.contains($0) } ?? tail.endIndex
let encoded = String(tail[..<base64End])
guard let data = Data(base64Encoded: encoded) else { return nil }
return try? JSONDecoder().decode(AuthFailure.self, from: data)
}
}