Files
Morgan Pretty eddffae6a1 Refactored a number of processes to no longer require database access
• Refactored the MessageSender to no longer require database access
• Refactored the attachment upload process to no longer require database access
• Updated the OpenGroupAPI to no longer require database access
• Added back logic to send the `endCall` message when receiving a call while on another call
• Added `community` to `AuthenticationMethod` to help standardise the code behaviour
• Updated the `toProto` functions to no longer required a `Database` instance
• Updated a bunch of functions to be @MainActor (so we can ditch thread swapping code)
2025-06-03 08:51:05 +10:00

128 lines
3.9 KiB
Swift

// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import GRDB
public enum Authentication {}
public protocol AuthenticationMethod: SignatureGenerator {
var info: Authentication.Info { get }
}
public extension AuthenticationMethod {
var swarmPublicKey: String {
get throws {
switch info {
case .standard(let sessionId, _), .groupAdmin(let sessionId, _), .groupMember(let sessionId, _):
return sessionId.hexString
case .community: throw CryptoError.invalidAuthentication
}
}
}
}
// MARK: - SignatureGenerator
public protocol SignatureGenerator {
func generateSignature(
with verificationBytes: [UInt8],
using dependencies: Dependencies
) throws -> Authentication.Signature
}
// MARK: - Signature Verification
public extension Authentication {
static func verify(
signature: Authentication.Signature,
publicKey: [UInt8],
verificationBytes: [UInt8],
using dependencies: Dependencies
) -> Bool {
switch signature {
case .standard(let signature):
return dependencies[singleton: .crypto].verify(
.signature(message: verificationBytes, publicKey: publicKey, signature: signature)
)
// Currently we never sign anything with a subaccount which requires verification
case .subaccount: return false
}
}
}
// MARK: - Authentication.Info
public extension Authentication {
enum Info: Equatable {
/// Used when interacting as the current user
case standard(sessionId: SessionId, ed25519PublicKey: [UInt8])
/// Used when interacting as a group admin
case groupAdmin(groupSessionId: SessionId, ed25519SecretKey: [UInt8])
/// Used when interacting as a group member
case groupMember(groupSessionId: SessionId, authData: Data)
/// Used when interacting with a community
case community(
server: String,
publicKey: String,
hasCapabilities: Bool,
supportsBlinding: Bool,
forceBlinded: Bool
)
}
}
// MARK: - Authentication.Signature
public extension Authentication {
enum Signature: Equatable, CustomStringConvertible {
/// Used for signing standard requests
case standard(signature: [UInt8])
/// Used for signing standard requests
case subaccount(subaccount: [UInt8], subaccountSig: [UInt8], signature: [UInt8])
// MARK: - CustomStringConvertible
public var description: String {
switch self {
case .standard(let signature):
return """
standard(
signature: \(signature.toHexString())
)
"""
case .subaccount(let subaccount, let subaccountSig, let signature):
return """
subaccount(
subaccount: \(subaccount.toHexString()),
subaccountSig: \(subaccountSig.toHexString()),
signature: \(signature.toHexString())
)
"""
}
}
}
}
public extension Optional where Wrapped == Authentication.Signature {
var nullIfEmpty: Authentication.Signature? {
switch self {
case .none: return nil
case .standard(let signature):
guard !signature.isEmpty else { return nil }
return self
case .subaccount(let subaccount, let subaccountSig, let signature):
guard !subaccount.isEmpty, !subaccountSig.isEmpty, !signature.isEmpty else { return nil }
return self
}
}
}