diff --git a/Sources/Auth/Internal/SessionStorage.swift b/Sources/Auth/Internal/SessionStorage.swift index 7e724b7a..28f240d2 100644 --- a/Sources/Auth/Internal/SessionStorage.swift +++ b/Sources/Auth/Internal/SessionStorage.swift @@ -19,7 +19,9 @@ struct StoredSession: Codable { init(session: Session, expirationDate: Date? = nil) { self.session = session - self.expirationDate = expirationDate ?? Date().addingTimeInterval(session.expiresIn) + self.expirationDate = expirationDate + ?? session.expiresAt.map(Date.init(timeIntervalSince1970:)) + ?? Date().addingTimeInterval(session.expiresIn) } } diff --git a/Sources/Auth/Types.swift b/Sources/Auth/Types.swift index f7f97331..df84b080 100644 --- a/Sources/Auth/Types.swift +++ b/Sources/Auth/Types.swift @@ -220,6 +220,44 @@ public struct UserIdentity: Codable, Hashable, Identifiable, Sendable { self.lastSignInAt = lastSignInAt self.updatedAt = updatedAt } + + private enum CodingKeys: CodingKey { + case id + case identityId + case userId + case identityData + case provider + case createdAt + case lastSignInAt + case updatedAt + } + + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + id = try container.decode(String.self, forKey: .id) + identityId = try container.decodeIfPresent(UUID.self, forKey: .identityId) + ?? UUID(uuidString: "00000000-0000-0000-0000-000000000000")! + userId = try container.decode(UUID.self, forKey: .userId) + identityData = try container.decodeIfPresent([String: AnyJSON].self, forKey: .identityData) + provider = try container.decode(String.self, forKey: .provider) + createdAt = try container.decode(Date.self, forKey: .createdAt) + lastSignInAt = try container.decode(Date.self, forKey: .lastSignInAt) + updatedAt = try container.decode(Date.self, forKey: .updatedAt) + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(id, forKey: .id) + try container.encode(identityId, forKey: .identityId) + try container.encode(userId, forKey: .userId) + try container.encodeIfPresent(identityData, forKey: .identityData) + try container.encode(provider, forKey: .provider) + try container.encode(createdAt, forKey: .createdAt) + try container.encode(lastSignInAt, forKey: .lastSignInAt) + try container.encode(updatedAt, forKey: .updatedAt) + } } public enum Provider: String, Identifiable, Codable, CaseIterable, Sendable { diff --git a/Tests/AuthTests/AuthClientTests.swift b/Tests/AuthTests/AuthClientTests.swift index 5c447261..90bcadf3 100644 --- a/Tests/AuthTests/AuthClientTests.swift +++ b/Tests/AuthTests/AuthClientTests.swift @@ -31,6 +31,7 @@ final class AuthClientTests: XCTestCase { override func setUp() { super.setUp() + Current = .mock eventEmitter = .mock sessionManager = .mock diff --git a/Tests/AuthTests/MockHelpers.swift b/Tests/AuthTests/MockHelpers.swift index 561341d4..2f8b1229 100644 --- a/Tests/AuthTests/MockHelpers.swift +++ b/Tests/AuthTests/MockHelpers.swift @@ -9,6 +9,6 @@ func json(named name: String) -> Data { extension Decodable { init(fromMockNamed name: String) { - self = try! AuthClient.Configuration.jsonDecoder.decode(Self.self, from: json(named: name)) + self = try! Current.configuration.decoder.decode(Self.self, from: json(named: name)) } } diff --git a/Tests/AuthTests/Resources/stored-session_2_4_0.json b/Tests/AuthTests/Resources/stored-session_2_4_0.json new file mode 100644 index 00000000..f2f310ab --- /dev/null +++ b/Tests/AuthTests/Resources/stored-session_2_4_0.json @@ -0,0 +1,40 @@ +{ + "expiration_date": "2022-03-30T10:33:41.018575157Z", + "session": { + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjQ4NjQwMDIxLCJzdWIiOiJmMzNkM2VjOS1hMmVlLTQ3YzQtODBlMS01YmQ5MTlmM2Q4YjgiLCJlbWFpbCI6Imd1aWxoZXJtZTJAZ3Jkcy5kZXYiLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQifQ.4lMvmz2pJkWu1hMsBgXP98Fwz4rbvFYl4VA9joRv6kY", + "token_type": "bearer", + "expires_in": 3600, + "refresh_token": "GGduTeu95GraIXQ56jppkw", + "user": { + "id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "aud": "authenticated", + "role": "authenticated", + "email": "guilherme@binaryscraping.co", + "email_confirmed_at": "2022-03-30T10:33:41.018575157Z", + "phone": "", + "last_sign_in_at": "2022-03-30T10:33:41.021531328Z", + "app_metadata": { + "provider": "email", + "providers": [ + "email" + ] + }, + "user_metadata": {}, + "identities": [ + { + "id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "user_id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "identity_data": { + "sub": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8" + }, + "provider": "email", + "last_sign_in_at": "2022-03-30T10:33:41.015557063Z", + "created_at": "2022-03-30T10:33:41.015612Z", + "updated_at": "2022-03-30T10:33:41.015616Z" + } + ], + "created_at": "2022-03-30T10:33:41.005433Z", + "updated_at": "2022-03-30T10:33:41.022688Z" + } + } +} diff --git a/Tests/AuthTests/Resources/stored-session_2_5_0.json b/Tests/AuthTests/Resources/stored-session_2_5_0.json new file mode 100644 index 00000000..0b557f34 --- /dev/null +++ b/Tests/AuthTests/Resources/stored-session_2_5_0.json @@ -0,0 +1,41 @@ +{ + "expiration_date": "2022-03-30T10:33:41.018575157Z", + "session": { + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNjQ4NjQwMDIxLCJzdWIiOiJmMzNkM2VjOS1hMmVlLTQ3YzQtODBlMS01YmQ5MTlmM2Q4YjgiLCJlbWFpbCI6Imd1aWxoZXJtZTJAZ3Jkcy5kZXYiLCJwaG9uZSI6IiIsImFwcF9tZXRhZGF0YSI6eyJwcm92aWRlciI6ImVtYWlsIiwicHJvdmlkZXJzIjpbImVtYWlsIl19LCJ1c2VyX21ldGFkYXRhIjp7fSwicm9sZSI6ImF1dGhlbnRpY2F0ZWQifQ.4lMvmz2pJkWu1hMsBgXP98Fwz4rbvFYl4VA9joRv6kY", + "token_type": "bearer", + "expires_in": 3600, + "refresh_token": "GGduTeu95GraIXQ56jppkw", + "user": { + "id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "aud": "authenticated", + "role": "authenticated", + "email": "guilherme@binaryscraping.co", + "email_confirmed_at": "2022-03-30T10:33:41.018575157Z", + "phone": "", + "last_sign_in_at": "2022-03-30T10:33:41.021531328Z", + "app_metadata": { + "provider": "email", + "providers": [ + "email" + ] + }, + "user_metadata": {}, + "identities": [ + { + "id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "user_id": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8", + "identity_id": "859f402d-b3de-4105-a1b9-932836d9193b", + "identity_data": { + "sub": "f33d3ec9-a2ee-47c4-80e1-5bd919f3d8b8" + }, + "provider": "email", + "last_sign_in_at": "2022-03-30T10:33:41.015557063Z", + "created_at": "2022-03-30T10:33:41.015612Z", + "updated_at": "2022-03-30T10:33:41.015616Z" + } + ], + "created_at": "2022-03-30T10:33:41.005433Z", + "updated_at": "2022-03-30T10:33:41.022688Z" + } + } +} diff --git a/Tests/AuthTests/StoredSessionTests.swift b/Tests/AuthTests/StoredSessionTests.swift new file mode 100644 index 00000000..c589bc56 --- /dev/null +++ b/Tests/AuthTests/StoredSessionTests.swift @@ -0,0 +1,19 @@ +@testable import Auth +import SnapshotTesting +import XCTest + +final class StoredSessionTests: XCTestCase { + func testDecode2_4_0() throws { + XCTAssertNoThrow(try AuthClient.Configuration.jsonDecoder.decode( + StoredSession.self, + from: json(named: "stored-session_2_4_0") + )) + } + + func testDecode2_5_0() throws { + XCTAssertNoThrow(try AuthClient.Configuration.jsonDecoder.decode( + StoredSession.self, + from: json(named: "stored-session_2_5_0") + )) + } +}