Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  QRCodeParser.swift   Sprache: JAVA

 

import CocoaLumberjackSwift
import Foundation
import ThreemaEssentials
import ThreemaMacros

final class QRCodeParser {

    // MARK: - Public Methods

    func parse(_ code: String?) -> QRCodeParserResult? {
        let result: QRCodeParserResult? =
            (try? parseIdentity(code, log: false)) ??
            (try? parseIdentityLink(code, log: false)) ??
            (try? parseMultiDeviceLink(code, log: false)) ??
            (try? parseWebSession(code, log: false))

        if let result {
            DDLogVerbose("Detected a \(result) QR code.")
        }
        else {
            DDLogVerbose("QR Code not recognized.")
        }

        return result
    }

    func parseIdentity(_ code: String?, log: Bool = true) throws -> QRCodeParserResult {
        let identityPrefix = "3mid"
        let code = code ?? ""
        let components = code.components(separatedBy: ":")

        guard components.count == 2 else {
            try fail(
                "Invalid Identity QR code. Expected 2 components separated by `:`.",
                code: code,
                context: "Identity",
                log: log
            )
        }

        guard components.first == identityPrefix else {
            try fail(
                "Invalid Identity QR code. Expected first component `\(identityPrefix)`.",
                code: code,
                context: "Identity",
                log: log
            )
        }

        let values = components.last?.components(separatedBy: ",") ?? []

        guard values.count >= 2 else {
            try fail(
                "Invalid Identity QR code. Expected at least 2 values in second component.",
                code: code,
                context: "Identity",
                log: log
            )
        }

        let identityID = values[0]

        guard identityID.count == ThreemaIdentity.length else {
            try fail(
                "Invalid Identity QR code. Identity string must have length \(ThreemaIdentity.length).",
                code: code,
                context: "Identity",
                log: log
            )
        }

        let threemaIdentity = ThreemaIdentity(identityID)

        let publicKeyHexEncoded = values[1] as NSString

        guard
            let publicKeyData = publicKeyHexEncoded.decodeHex(),
            publicKeyData.count == kNaClCryptoPubKeySize
        else {
            try fail(
                "Invalid Identity QR code. Public key must be hex encoded with length \(kNaClCryptoPubKeySize).",
                code: code,
                context: "Identity",
                log: log
            )
        }

        var expirationDate: Date?

        if values.count >= 3 {
            guard let timeInterval = Double(values[2]) else {
                try fail(
                    "Invalid Identity QR code. Expiration date must be a double.",
                    code: code,
                    context: "Identity",
                    log: log
                )
            }
            expirationDate = Date(timeIntervalSince1970: timeInterval)
        }

        return .identityContact(identity: threemaIdentity, publicKey: publicKeyData, expirationDate: expirationDate)
    }

    func parseMultiDeviceLink(_ code: String?, log: Bool = true) throws -> QRCodeParserResult {
        guard
            let url = URL(string: code ?? ""),
            let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
            components.scheme == "threema",
            components.host == "device-group",
            components.path == "/join",
            let fragment = components.fragment
        else {
            try fail(
                "Invalid Multi-device Link QR code. Unexpected format.",
                code: code,
                context: "Multi-device Link",
                log: log
            )
        }
        return .multiDeviceLink(urlSafeBase64: fragment)
    }

    func parseWebSession(_ code: String?, log: Bool = true) throws -> QRCodeParserResult {
        guard
            let encoded = code,
            let data = Data(base64Encoded: encoded)
        else {
            try fail("Invalid Web Session QR code. Must be valid base64.", code: code, context: "Web Session", log: log)
        }

        do {
            let session = try makeSession(from: data, log: log)
            let authToken = try makeAuthToken(from: data, log: log)
            return .webSession(session: session, authToken: authToken)
        }
        catch {
            try fail(
                "Invalid Web Session QR code. Session or auth token data invalid.",
                code: code,
                context: "Web Session",
                log: log
            )
        }
    }

    func parseIdentityLink(_ code: String?, log: Bool = true) throws -> QRCodeParserResult {
        guard
            let url = URL(string: code ?? ""),
            let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
            components.scheme == "https",
            components.host == "threema.id",
            components.path.dropFirst().uppercased().count == kIdentityLen
        else {
            try fail(
                "Invalid Identity Link QR code. Unexpected format.",
                code: code,
                context: "Identity Link",
                log: log
            )
        }
        return .identityLink(url: url)
    }

    // MARK: - Helpers

    private func makeSession(from data: Data, log: Bool) throws -> [String: Any] {
        struct Bitfield: OptionSet {
            let rawValue: Int
            static let selfHosted = Bitfield(rawValue: 1 << 0)
            static let permanent = Bitfield(rawValue: 1 << 1)
        }

        let a = try unpackData(from: data, log: log)
        guard
            let field0 = a[0] as? Int,
            let field1 = a[1] as? Int,
            let field98 = a[98] as? Int,
            let field99 = a[99] as? NSString
        else {
            try fail("Invalid Session QR code. Missing required fields.", context: "Session", log: log)
        }

        let allOptions = Bitfield(rawValue: field1)

        var initiatorPermanentPublicKeyArray = [UInt8]()
        for index in 2...33 {
            guard let field = a[index] as? Int else {
                try fail("Invalid Session QR code. Invalid initiator public key data.", context: "Session", log: log)
            }
            initiatorPermanentPublicKeyArray.append(UInt8(field))
        }

        var serverPermanentPublicKeyArray = [UInt8]()
        for index in 66...97 {
            guard let field = a[index] as? Int else {
                try fail("Invalid Session QR code. Invalid server public key data.", context: "Session", log: log)
            }
            serverPermanentPublicKeyArray.append(UInt8(field))
        }

        var session = [String: Any]()
        session.updateValue(field0, forKey: "webClientVersion")
        session.updateValue(allOptions.contains(.permanent), forKey: "permanent")
        session.updateValue(allOptions.contains(.selfHosted), forKey: "selfHosted")
        session.updateValue(Data(initiatorPermanentPublicKeyArray), forKey: "initiatorPermanentPublicKey")
        session.updateValue(Data(serverPermanentPublicKeyArray), forKey: "serverPermanentPublicKey")
        session.updateValue(field98, forKey: "saltyRTCPort")
        session.updateValue(field99, forKey: "saltyRTCHost")
        return session
    }

    private func makeAuthToken(from data: Data, log: Bool) throws -> Data {
        let a = try unpackData(from: data, log: log)
        var authTokenArray = [UInt8]()
        for index in 34...65 {
            guard let value = a[index] as? Int else {
                try fail("Invalid Auth Token QR code. Invalid data.", context: "Auth Token", log: log)
            }
            authTokenArray.append(UInt8(value))
        }
        return Data(authTokenArray)
    }

    private func unpackData(from data: Data, log: Bool) throws -> [Unpackable] {
        do {
            let format = String(format: ">HB32B32B32BH%is", (data.count) - 101)
            let a = try unpack(format, data)
            return a
        }
        catch {
            try fail("Invalid QR code data. \(error.localizedDescription)", context: "Unpack", log: log)
        }
    }

    private func fail(_ message: String, code: String? = nil, context: String, log: Bool) throws -> Never {
        if log {
            if let code {
                DDLogVerbose("\(context) parse error: \(code). \(message)")
            }
            else {
                DDLogVerbose("\(context) parse error. \(message)")
            }
        }
        throw QRCodeParserError.invalidFormat(message)
    }
}

Messung
CHZG
849410092

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104852
#Domains=417171