69 lines
1.5 KiB
Swift
69 lines
1.5 KiB
Swift
import FluentKit
|
|||
|
|
import Foundation
|
||
|
|
|
||
|
|
/// A FluentKit model of a single `passkeys` row: a WebAuthn credential registered to an account.
|
||
|
|
final class PasskeyRecord: Model, @unchecked Sendable {
|
||
|
|
|
||
|
|
// MARK: Properties
|
||
|
|
|
||
|
|
static let schema = "passkeys"
|
||
|
|
|
||
|
|
@ID(key: .id)
|
||
|
|
var id: UUID?
|
||
|
|
|
||
|
|
@Parent(key: "user_id")
|
||
|
|
var user: UserRecord
|
||
|
|
|
||
|
|
/// The credential's identifier, base64url-encoded without padding.
|
||
|
|
@Field(key: "credential_id")
|
||
|
|
var credentialID: String
|
||
|
|
|
||
|
|
/// The credential's public key, COSE-encoded, as base64.
|
||
|
|
@Field(key: "public_key")
|
||
|
|
var publicKey: String
|
||
|
|
|
||
|
|
@Field(key: "sign_count")
|
||
|
|
var signCount: Int
|
||
|
|
|
||
|
|
@Field(key: "created_at")
|
||
|
|
var createdAt: Date
|
||
|
|
|
||
|
|
// MARK: Initializers
|
||
|
|
|
||
|
|
init() {}
|
||
|
|
|
||
|
|
init(
|
||
|
|
userID: UUID,
|
||
|
|
credentialID: String,
|
||
|
|
publicKey: [UInt8],
|
||
|
|
signCount: UInt32,
|
||
|
|
at date: Date
|
||
|
|
) {
|
||
|
|
self.$user.id = userID
|
||
|
|
self.credentialID = credentialID
|
||
|
|
self.publicKey = Data(publicKey).base64EncodedString()
|
||
|
|
self.signCount = Int(signCount)
|
||
|
|
self.createdAt = date
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
// MARK: - Extensions
|
||
|
|
|
||
|
|
extension PasskeyRecord {
|
||
|
|
|
||
|
|
// MARK: Computed
|
||
|
|
|
||
|
|
/// The `Sendable` snapshot of the saved record; its user must be eager-loaded.
|
||
|
|
var snapshot: Passkey {
|
||
|
|
get throws {
|
||
|
|
.init(
|
||
|
|
credentialID: credentialID,
|
||
|
|
publicKey: Array(Data(base64Encoded: publicKey) ?? .init()),
|
||
|
|
signCount: UInt32(clamping: signCount),
|
||
|
|
user: try user.snapshot
|
||
|
|
)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|