Skip to content

Commit 47882d9

Browse files
grdsdevleoMehlig
andcommitted
fix(auth): stored session backwards compatibility (#294)
* Adds (failing) test for stored session decoding * Provides default value to `identityId` * style: swift format --------- Co-authored-by: leoMehlig <[email protected]>
1 parent f167264 commit 47882d9

File tree

7 files changed

+143
-2
lines changed

7 files changed

+143
-2
lines changed

Sources/Auth/Internal/SessionStorage.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ struct StoredSession: Codable {
1919

2020
init(session: Session, expirationDate: Date? = nil) {
2121
self.session = session
22-
self.expirationDate = expirationDate ?? Date().addingTimeInterval(session.expiresIn)
22+
self.expirationDate = expirationDate
23+
?? session.expiresAt.map(Date.init(timeIntervalSince1970:))
24+
?? Date().addingTimeInterval(session.expiresIn)
2325
}
2426
}
2527

Sources/Auth/Types.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,44 @@ public struct UserIdentity: Codable, Hashable, Identifiable, Sendable {
220220
self.lastSignInAt = lastSignInAt
221221
self.updatedAt = updatedAt
222222
}
223+
224+
private enum CodingKeys: CodingKey {
225+
case id
226+
case identityId
227+
case userId
228+
case identityData
229+
case provider
230+
case createdAt
231+
case lastSignInAt
232+
case updatedAt
233+
}
234+
235+
public init(from decoder: any Decoder) throws {
236+
let container = try decoder.container(keyedBy: CodingKeys.self)
237+
238+
id = try container.decode(String.self, forKey: .id)
239+
identityId = try container.decodeIfPresent(UUID.self, forKey: .identityId)
240+
?? UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
241+
userId = try container.decode(UUID.self, forKey: .userId)
242+
identityData = try container.decodeIfPresent([String: AnyJSON].self, forKey: .identityData)
243+
provider = try container.decode(String.self, forKey: .provider)
244+
createdAt = try container.decode(Date.self, forKey: .createdAt)
245+
lastSignInAt = try container.decode(Date.self, forKey: .lastSignInAt)
246+
updatedAt = try container.decode(Date.self, forKey: .updatedAt)
247+
}
248+
249+
public func encode(to encoder: any Encoder) throws {
250+
var container = encoder.container(keyedBy: CodingKeys.self)
251+
252+
try container.encode(id, forKey: .id)
253+
try container.encode(identityId, forKey: .identityId)
254+
try container.encode(userId, forKey: .userId)
255+
try container.encodeIfPresent(identityData, forKey: .identityData)
256+
try container.encode(provider, forKey: .provider)
257+
try container.encode(createdAt, forKey: .createdAt)
258+
try container.encode(lastSignInAt, forKey: .lastSignInAt)
259+
try container.encode(updatedAt, forKey: .updatedAt)
260+
}
223261
}
224262

225263
public enum Provider: String, Identifiable, Codable, CaseIterable, Sendable {

Tests/AuthTests/AuthClientTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ final class AuthClientTests: XCTestCase {
3131

3232
override func setUp() {
3333
super.setUp()
34+
Current = .mock
3435

3536
eventEmitter = .mock
3637
sessionManager = .mock

Tests/AuthTests/MockHelpers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ func json(named name: String) -> Data {
99

1010
extension Decodable {
1111
init(fromMockNamed name: String) {
12-
self = try! AuthClient.Configuration.jsonDecoder.decode(Self.self, from: json(named: name))
12+
self = try! Current.configuration.decoder.decode(Self.self, from: json(named: name))
1313
}
1414
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"expiration_date": "2022-03-30T10:33:41.018575157Z",
3+
"session": {
4+
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjQ4NjQwMDIxLCJzdWIiOiJmMzNkM2VjOS1hMmVlLTQ3YzQtODBlMS01YmQ5MTlmM2Q4YjgiLCJlbWFpbCI6Imd1aWxoZXJtZTJAZ3Jkcy5kZXYiLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQifQ.4lMvmz2pJkWu1hMsBgXP98Fwz4rbvFYl4VA9joRv6kY",
5+
"token_type": "bearer",
6+
"expires_in": 3600,
7+
"refresh_token": "GGduTeu95GraIXQ56jppkw",
8+
"user": {
9+
"id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
10+
"aud": "authenticated",
11+
"role": "authenticated",
12+
"email": "[email protected]",
13+
"email_confirmed_at": "2022-03-30T10:33:41.018575157Z",
14+
"phone": "",
15+
"last_sign_in_at": "2022-03-30T10:33:41.021531328Z",
16+
"app_metadata": {
17+
"provider": "email",
18+
"providers": [
19+
"email"
20+
]
21+
},
22+
"user_metadata": {},
23+
"identities": [
24+
{
25+
"id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
26+
"user_id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
27+
"identity_data": {
28+
"sub": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8"
29+
},
30+
"provider": "email",
31+
"last_sign_in_at": "2022-03-30T10:33:41.015557063Z",
32+
"created_at": "2022-03-30T10:33:41.015612Z",
33+
"updated_at": "2022-03-30T10:33:41.015616Z"
34+
}
35+
],
36+
"created_at": "2022-03-30T10:33:41.005433Z",
37+
"updated_at": "2022-03-30T10:33:41.022688Z"
38+
}
39+
}
40+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"expiration_date": "2022-03-30T10:33:41.018575157Z",
3+
"session": {
4+
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjQ4NjQwMDIxLCJzdWIiOiJmMzNkM2VjOS1hMmVlLTQ3YzQtODBlMS01YmQ5MTlmM2Q4YjgiLCJlbWFpbCI6Imd1aWxoZXJtZTJAZ3Jkcy5kZXYiLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQifQ.4lMvmz2pJkWu1hMsBgXP98Fwz4rbvFYl4VA9joRv6kY",
5+
"token_type": "bearer",
6+
"expires_in": 3600,
7+
"refresh_token": "GGduTeu95GraIXQ56jppkw",
8+
"user": {
9+
"id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
10+
"aud": "authenticated",
11+
"role": "authenticated",
12+
"email": "[email protected]",
13+
"email_confirmed_at": "2022-03-30T10:33:41.018575157Z",
14+
"phone": "",
15+
"last_sign_in_at": "2022-03-30T10:33:41.021531328Z",
16+
"app_metadata": {
17+
"provider": "email",
18+
"providers": [
19+
"email"
20+
]
21+
},
22+
"user_metadata": {},
23+
"identities": [
24+
{
25+
"id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
26+
"user_id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8",
27+
"identity_id": "859f402d-b3de-4105-a1b9-932836d9193b",
28+
"identity_data": {
29+
"sub": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8"
30+
},
31+
"provider": "email",
32+
"last_sign_in_at": "2022-03-30T10:33:41.015557063Z",
33+
"created_at": "2022-03-30T10:33:41.015612Z",
34+
"updated_at": "2022-03-30T10:33:41.015616Z"
35+
}
36+
],
37+
"created_at": "2022-03-30T10:33:41.005433Z",
38+
"updated_at": "2022-03-30T10:33:41.022688Z"
39+
}
40+
}
41+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@testable import Auth
2+
import SnapshotTesting
3+
import XCTest
4+
5+
final class StoredSessionTests: XCTestCase {
6+
func testDecode2_4_0() throws {
7+
XCTAssertNoThrow(try AuthClient.Configuration.jsonDecoder.decode(
8+
StoredSession.self,
9+
from: json(named: "stored-session_2_4_0")
10+
))
11+
}
12+
13+
func testDecode2_5_0() throws {
14+
XCTAssertNoThrow(try AuthClient.Configuration.jsonDecoder.decode(
15+
StoredSession.self,
16+
from: json(named: "stored-session_2_5_0")
17+
))
18+
}
19+
}

0 commit comments

Comments
 (0)