1+ // Copyright 2025 Google LLC
2+ //
3+ // Licensed under the Apache License, Version 2.0 (the "License");
4+ // you may not use this file except in compliance with the License.
5+ // You may obtain a copy of the License at
6+ //
7+ // http://www.apache.org/licenses/LICENSE-2.0
8+ //
9+ // Unless required by applicable law or agreed to in writing, software
10+ // distributed under the License is distributed on an "AS IS" BASIS,
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ // See the License for the specific language governing permissions and
13+ // limitations under the License.
14+ @preconcurrency import FirebaseAuth
15+ import SwiftUI
16+
17+ public enum SecondFactorType {
18+ case sms
19+ case totp
20+ }
21+
22+ public struct TOTPEnrollmentInfo {
23+ public let sharedSecretKey : String
24+ public let qrCodeURL : URL ?
25+ public let accountName : String ?
26+ public let issuer : String ?
27+ public let verificationStatus : VerificationStatus
28+
29+ public enum VerificationStatus {
30+ case pending
31+ case verified
32+ case failed
33+ }
34+
35+ public init ( sharedSecretKey: String ,
36+ qrCodeURL: URL ? = nil ,
37+ accountName: String ? = nil ,
38+ issuer: String ? = nil ,
39+ verificationStatus: VerificationStatus = . pending) {
40+ self . sharedSecretKey = sharedSecretKey
41+ self . qrCodeURL = qrCodeURL
42+ self . accountName = accountName
43+ self . issuer = issuer
44+ self . verificationStatus = verificationStatus
45+ }
46+ }
47+
48+ public struct EnrollmentSession {
49+ public let id : String
50+ public let type : SecondFactorType
51+ public let session : MultiFactorSession
52+ public let totpInfo : TOTPEnrollmentInfo ?
53+ public let phoneNumber : String ?
54+ public let verificationId : String ?
55+ public let status : EnrollmentStatus
56+ public let createdAt : Date
57+ public let expiresAt : Date
58+
59+ // Internal handle to finish TOTP
60+ internal let _totpSecret : AnyObject ?
61+
62+ public enum EnrollmentStatus {
63+ case initiated
64+ case verificationSent
65+ case verificationPending
66+ case completed
67+ case failed
68+ case expired
69+ }
70+
71+ public init ( id: String = UUID ( ) . uuidString,
72+ type: SecondFactorType ,
73+ session: MultiFactorSession ,
74+ totpInfo: TOTPEnrollmentInfo ? = nil ,
75+ phoneNumber: String ? = nil ,
76+ verificationId: String ? = nil ,
77+ status: EnrollmentStatus = . initiated,
78+ createdAt: Date = Date ( ) ,
79+ expiresAt: Date = Date ( ) . addingTimeInterval ( 600 ) , // 10 minutes default
80+ _totpSecret: AnyObject ? = nil ) {
81+ self . id = id
82+ self . type = type
83+ self . session = session
84+ self . totpInfo = totpInfo
85+ self . phoneNumber = phoneNumber
86+ self . verificationId = verificationId
87+ self . status = status
88+ self . createdAt = createdAt
89+ self . expiresAt = expiresAt
90+ self . _totpSecret = _totpSecret
91+ }
92+
93+ public var isExpired : Bool {
94+ return Date ( ) > expiresAt
95+ }
96+
97+ public var canProceed : Bool {
98+ return !isExpired &&
99+ ( status == . initiated || status == . verificationSent || status == . verificationPending)
100+ }
101+ }
102+
103+ public enum MFAHint {
104+ case phone( displayName: String ? , uid: String , phoneNumber: String ? )
105+ case totp( displayName: String ? , uid: String )
106+ }
107+
108+ public struct MFARequired {
109+ public let hints : [ MFAHint ]
110+
111+ public init ( hints: [ MFAHint ] ) {
112+ self . hints = hints
113+ }
114+ }
0 commit comments