@@ -17,6 +17,14 @@ public final class FaceLivenessSession: LivenessService {
17
17
let baseURL : URL
18
18
var serverEventListeners : [ LivenessEventKind . Server : ( FaceLivenessSession . SessionConfiguration ) -> Void ] = [ : ]
19
19
var onComplete : ( ServerDisconnection ) -> Void = { _ in }
20
+ var serverDate : Date ?
21
+ var savedURLForReconnect : URL ?
22
+ var connectingState : ConnectingState = . normal
23
+
24
+ enum ConnectingState {
25
+ case normal
26
+ case reconnect
27
+ }
20
28
21
29
private let livenessServiceDispatchQueue = DispatchQueue (
22
30
label: " com.amazon.aws.amplify.liveness.service " ,
@@ -35,12 +43,16 @@ public final class FaceLivenessSession: LivenessService {
35
43
self . websocket = websocket
36
44
37
45
websocket. onMessageReceived { [ weak self] result in
38
- self ? . receive ( result: result) ?? false
46
+ self ? . receive ( result: result) ?? . stopAndInvalidateSession
39
47
}
40
48
41
49
websocket. onSocketClosed { [ weak self] closeCode in
42
50
self ? . onComplete ( . unexpectedClosure( closeCode) )
43
51
}
52
+
53
+ websocket. onServerDateReceived { [ weak self] serverDate in
54
+ self ? . serverDate = serverDate
55
+ }
44
56
}
45
57
46
58
public var onServiceException : ( FaceLivenessSessionError ) -> Void = { _ in }
@@ -75,6 +87,7 @@ public final class FaceLivenessSession: LivenessService {
75
87
guard let url = components? . url
76
88
else { throw FaceLivenessSessionError . invalidURL }
77
89
90
+ savedURLForReconnect = url
78
91
let signedConnectionURL = signer. sign ( url: url)
79
92
websocket. open ( url: signedConnectionURL)
80
93
}
@@ -93,17 +106,22 @@ public final class FaceLivenessSession: LivenessService {
93
106
]
94
107
)
95
108
96
- let eventDate = eventDate ( )
109
+ let dateForSigning : Date
110
+ if let serverDate = serverDate {
111
+ dateForSigning = serverDate
112
+ } else {
113
+ dateForSigning = eventDate ( )
114
+ }
97
115
98
116
let signedPayload = self . signer. signWithPreviousSignature (
99
117
payload: encodedPayload,
100
- dateHeader: ( key: " :date " , value: eventDate )
118
+ dateHeader: ( key: " :date " , value: dateForSigning )
101
119
)
102
120
103
121
let encodedEvent = self . eventStreamEncoder. encode (
104
122
payload: encodedPayload,
105
123
headers: [
106
- " :date " : . timestamp( eventDate ) ,
124
+ " :date " : . timestamp( dateForSigning ) ,
107
125
" :chunk-signature " : . data( signedPayload)
108
126
]
109
127
)
@@ -115,7 +133,7 @@ public final class FaceLivenessSession: LivenessService {
115
133
}
116
134
}
117
135
118
- private func fallbackDecoding( _ message: EventStream . Message ) -> Bool {
136
+ private func fallbackDecoding( _ message: EventStream . Message ) -> WebSocketSession . WebSocketMessageResult {
119
137
// We only care about two events above.
120
138
// Just in case the header value changes (it shouldn't)
121
139
// We'll try to decode each of these events
@@ -124,12 +142,12 @@ public final class FaceLivenessSession: LivenessService {
124
142
self . serverEventListeners [ . challenge] ? ( sessionConfiguration)
125
143
} else if ( try ? JSONDecoder ( ) . decode ( DisconnectEvent . self, from: message. payload) ) != nil {
126
144
onComplete ( . disconnectionEvent)
127
- return false
145
+ return . stopAndInvalidateSession
128
146
}
129
- return true
147
+ return . continueToReceive
130
148
}
131
149
132
- private func receive( result: Result < URLSessionWebSocketTask . Message , Error > ) -> Bool {
150
+ private func receive( result: Result < URLSessionWebSocketTask . Message , Error > ) -> WebSocketSession . WebSocketMessageResult {
133
151
switch result {
134
152
case . success( . data( let data) ) :
135
153
do {
@@ -145,28 +163,41 @@ public final class FaceLivenessSession: LivenessService {
145
163
)
146
164
let sessionConfiguration = sessionConfiguration ( from: payload)
147
165
serverEventListeners [ . challenge] ? ( sessionConfiguration)
148
- return true
166
+ return . continueToReceive
149
167
case . disconnect:
150
168
// :event-type DisconnectionEvent
151
169
onComplete ( . disconnectionEvent)
152
- return false
170
+ return . stopAndInvalidateSession
153
171
default :
154
- return true
172
+ return . continueToReceive
155
173
}
156
174
} else if let exceptionType = message. headers. first ( where: { $0. name == " :exception-type " } ) {
157
175
let exceptionEvent = LivenessEventKind . Exception ( rawValue: exceptionType. value)
158
- onServiceException ( . init( event: exceptionEvent) )
159
- return false
176
+ Amplify . log. verbose ( " \( #function) : Received exception: \( exceptionEvent) " )
177
+ guard exceptionEvent == . invalidSignature,
178
+ connectingState == . normal,
179
+ let savedURLForReconnect = savedURLForReconnect,
180
+ let serverDate = serverDate else {
181
+ onServiceException ( . init( event: exceptionEvent) )
182
+ return . stopAndInvalidateSession
183
+ }
184
+
185
+ connectingState = . reconnect
186
+ let signedConnectionURL = signer. sign (
187
+ url: savedURLForReconnect,
188
+ date: { serverDate }
189
+ )
190
+ return . invalidateSessionAndRetry( url: signedConnectionURL)
160
191
} else {
161
192
return fallbackDecoding ( message)
162
193
}
163
194
} catch {
164
- return false
195
+ return . stopAndInvalidateSession
165
196
}
166
197
case . success:
167
- return true
198
+ return . continueToReceive
168
199
case . failure:
169
- return false
200
+ return . stopAndInvalidateSession
170
201
}
171
202
}
172
203
}
0 commit comments