Add device access token authentication
This commit is contained in:
@@ -345,12 +345,7 @@ final class MacLibraryViewModel {
|
||||
appVersion: environment.appVersion
|
||||
)
|
||||
let response = try await makeAPIClient(for: environment).registerDevice(payload)
|
||||
|
||||
try await keychainService.save(response.deviceId, forKey: Self.deviceIdKey)
|
||||
try await keychainService.save(response.bootstrapToken, forKey: Self.bootstrapTokenKey)
|
||||
|
||||
registeredDeviceId = response.deviceId
|
||||
deviceRegistrationStatus = "Registered successfully at \(response.serverTime)."
|
||||
try await persistRegisteredDevice(response)
|
||||
} catch {
|
||||
deviceRegistrationStatus = "Registration failed: \(error.localizedDescription)"
|
||||
}
|
||||
@@ -365,7 +360,7 @@ final class MacLibraryViewModel {
|
||||
|
||||
do {
|
||||
let environment = try currentEnvironment()
|
||||
let deviceId = try await currentDeviceId()
|
||||
let deviceId = try await currentOrRegisterDeviceId(for: environment)
|
||||
let response = try await makeAPIClient(for: environment).sendHeartbeat(
|
||||
DeviceHeartbeatPayload(
|
||||
deviceId: deviceId,
|
||||
@@ -421,7 +416,7 @@ final class MacLibraryViewModel {
|
||||
|
||||
do {
|
||||
let environment = try currentEnvironment()
|
||||
let deviceId = try await currentDeviceId()
|
||||
let deviceId = try await currentOrRegisterDeviceId(for: environment)
|
||||
let fileURL = URL(fileURLWithPath: initialTrack.localFilePath)
|
||||
|
||||
try await withStoredFolderAccess {
|
||||
@@ -589,13 +584,18 @@ final class MacLibraryViewModel {
|
||||
private func restoreDeviceIdentity() async {
|
||||
do {
|
||||
let deviceId = try await keychainService.loadValue(forKey: Self.deviceIdKey)
|
||||
let deviceAccessToken = try await keychainService.loadValue(
|
||||
forKey: Self.deviceAccessTokenKey
|
||||
)
|
||||
let bootstrapToken = try await keychainService.loadValue(forKey: Self.bootstrapTokenKey)
|
||||
|
||||
registeredDeviceId = deviceId
|
||||
|
||||
if let deviceId {
|
||||
if let bootstrapToken, !bootstrapToken.isEmpty {
|
||||
if let deviceAccessToken, !deviceAccessToken.isEmpty {
|
||||
deviceRegistrationStatus = "Registered locally."
|
||||
} else if let bootstrapToken, !bootstrapToken.isEmpty {
|
||||
deviceRegistrationStatus = "Device ID restored (\(deviceId)). Re-register to get a device access token."
|
||||
} else {
|
||||
deviceRegistrationStatus = "Device ID restored (\(deviceId)). Bootstrap token is missing."
|
||||
}
|
||||
@@ -621,23 +621,62 @@ final class MacLibraryViewModel {
|
||||
)
|
||||
}
|
||||
|
||||
private func currentDeviceId() async throws -> String {
|
||||
private func currentOrRegisterDeviceId(
|
||||
for environment: ServerEnvironment
|
||||
) async throws -> String {
|
||||
if let registeredDeviceId, !registeredDeviceId.isEmpty {
|
||||
return registeredDeviceId
|
||||
if let savedDeviceAccessToken = try await keychainService.loadValue(
|
||||
forKey: Self.deviceAccessTokenKey
|
||||
), !savedDeviceAccessToken.isEmpty {
|
||||
return registeredDeviceId
|
||||
}
|
||||
}
|
||||
|
||||
if let savedDeviceId = try await keychainService.loadValue(forKey: Self.deviceIdKey),
|
||||
let savedDeviceAccessToken = try await keychainService.loadValue(
|
||||
forKey: Self.deviceAccessTokenKey
|
||||
),
|
||||
!savedDeviceAccessToken.isEmpty,
|
||||
!savedDeviceId.isEmpty
|
||||
{
|
||||
registeredDeviceId = savedDeviceId
|
||||
return savedDeviceId
|
||||
}
|
||||
|
||||
throw BackendConnectionError.missingDeviceIdentity
|
||||
let payload = DeviceRegistrationPayload(
|
||||
platform: .macos,
|
||||
deviceName: Self.currentDeviceName,
|
||||
appVersion: environment.appVersion
|
||||
)
|
||||
let response = try await makeAPIClient(for: environment).registerDevice(payload)
|
||||
try await persistRegisteredDevice(response)
|
||||
return response.deviceId
|
||||
}
|
||||
|
||||
private func makeAPIClient(for environment: ServerEnvironment) -> URLSessionVelodyAPIClient {
|
||||
URLSessionVelodyAPIClient(environment: environment)
|
||||
URLSessionVelodyAPIClient(
|
||||
environment: environment,
|
||||
deviceAccessTokenProvider: { [self] in
|
||||
try await self.keychainService.loadValue(forKey: Self.deviceAccessTokenKey)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private func persistRegisteredDevice(
|
||||
_ response: DeviceRegistrationResponse
|
||||
) async throws {
|
||||
try await keychainService.save(response.deviceId, forKey: Self.deviceIdKey)
|
||||
try await keychainService.save(
|
||||
response.deviceAccessToken,
|
||||
forKey: Self.deviceAccessTokenKey
|
||||
)
|
||||
try await keychainService.save(
|
||||
response.bootstrapToken,
|
||||
forKey: Self.bootstrapTokenKey
|
||||
)
|
||||
|
||||
registeredDeviceId = response.deviceId
|
||||
deviceRegistrationStatus = "Registered successfully at \(response.serverTime)."
|
||||
}
|
||||
|
||||
private func currentTrack(for trackID: String) -> LibraryTrack? {
|
||||
@@ -847,6 +886,7 @@ final class MacLibraryViewModel {
|
||||
|
||||
private static let serverURLDefaultsKey = "velody.server-environment.base-url"
|
||||
private static let deviceIdKey = "velody.device-id"
|
||||
private static let deviceAccessTokenKey = "velody.device-access-token"
|
||||
private static let bootstrapTokenKey = "velody.bootstrap-token"
|
||||
private static let playbackSessionDefaultsKey = "velody.playback.session"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user