fix(apps): sign gateway device auth with v3 payload
This commit is contained in:
parent
473a27470f
commit
490cb5174d
@ -372,7 +372,7 @@ class GatewaySession(
|
||||
|
||||
val signedAtMs = System.currentTimeMillis()
|
||||
val payload =
|
||||
buildDeviceAuthPayload(
|
||||
buildDeviceAuthPayloadV3(
|
||||
deviceId = identity.deviceId,
|
||||
clientId = client.id,
|
||||
clientMode = client.mode,
|
||||
@ -381,6 +381,8 @@ class GatewaySession(
|
||||
signedAtMs = signedAtMs,
|
||||
token = if (authToken.isNotEmpty()) authToken else null,
|
||||
nonce = connectNonce,
|
||||
platform = client.platform,
|
||||
deviceFamily = client.deviceFamily,
|
||||
)
|
||||
val signature = identityStore.signPayload(payload, identity)
|
||||
val publicKey = identityStore.publicKeyBase64Url(identity)
|
||||
@ -582,7 +584,7 @@ class GatewaySession(
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildDeviceAuthPayload(
|
||||
private fun buildDeviceAuthPayloadV3(
|
||||
deviceId: String,
|
||||
clientId: String,
|
||||
clientMode: String,
|
||||
@ -591,12 +593,16 @@ class GatewaySession(
|
||||
signedAtMs: Long,
|
||||
token: String?,
|
||||
nonce: String,
|
||||
platform: String?,
|
||||
deviceFamily: String?,
|
||||
): String {
|
||||
val scopeString = scopes.joinToString(",")
|
||||
val authToken = token.orEmpty()
|
||||
val platformNorm = normalizeDeviceMetadataField(platform)
|
||||
val deviceFamilyNorm = normalizeDeviceMetadataField(deviceFamily)
|
||||
val parts =
|
||||
mutableListOf(
|
||||
"v2",
|
||||
"v3",
|
||||
deviceId,
|
||||
clientId,
|
||||
clientMode,
|
||||
@ -605,10 +611,15 @@ class GatewaySession(
|
||||
signedAtMs.toString(),
|
||||
authToken,
|
||||
nonce,
|
||||
platformNorm,
|
||||
deviceFamilyNorm,
|
||||
)
|
||||
return parts.joinToString("|")
|
||||
}
|
||||
|
||||
private fun normalizeDeviceMetadataField(value: String?): String =
|
||||
value?.trim()?.lowercase(Locale.ROOT).orEmpty()
|
||||
|
||||
private fun normalizeCanvasHostUrl(
|
||||
raw: String?,
|
||||
endpoint: GatewayEndpoint,
|
||||
|
||||
@ -280,19 +280,17 @@ actor GatewayWizardClient {
|
||||
let connectNonce = try await self.waitForConnectChallenge()
|
||||
let identity = DeviceIdentityStore.loadOrCreate()
|
||||
let signedAtMs = Int(Date().timeIntervalSince1970 * 1000)
|
||||
let scopesValue = scopes.joined(separator: ",")
|
||||
let payloadParts = [
|
||||
"v2",
|
||||
identity.deviceId,
|
||||
clientId,
|
||||
clientMode,
|
||||
role,
|
||||
scopesValue,
|
||||
String(signedAtMs),
|
||||
self.token ?? "",
|
||||
connectNonce,
|
||||
]
|
||||
let payload = payloadParts.joined(separator: "|")
|
||||
let payload = buildDeviceAuthPayloadV3(
|
||||
deviceId: identity.deviceId,
|
||||
clientId: clientId,
|
||||
clientMode: clientMode,
|
||||
role: role,
|
||||
scopes: scopes,
|
||||
signedAtMs: signedAtMs,
|
||||
token: self.token,
|
||||
nonce: connectNonce,
|
||||
platform: platform,
|
||||
deviceFamily: "Mac")
|
||||
if let signature = DeviceIdentityStore.signPayload(payload, identity: identity),
|
||||
let publicKey = DeviceIdentityStore.publicKeyBase64Url(identity)
|
||||
{
|
||||
@ -329,6 +327,44 @@ actor GatewayWizardClient {
|
||||
}
|
||||
}
|
||||
|
||||
private func buildDeviceAuthPayloadV3(
|
||||
deviceId: String,
|
||||
clientId: String,
|
||||
clientMode: String,
|
||||
role: String,
|
||||
scopes: [String],
|
||||
signedAtMs: Int,
|
||||
token: String?,
|
||||
nonce: String,
|
||||
platform: String?,
|
||||
deviceFamily: String?) -> String
|
||||
{
|
||||
let scopeString = scopes.joined(separator: ",")
|
||||
let authToken = token ?? ""
|
||||
let normalizedPlatform = normalizeMetadataField(platform)
|
||||
let normalizedDeviceFamily = normalizeMetadataField(deviceFamily)
|
||||
return [
|
||||
"v3",
|
||||
deviceId,
|
||||
clientId,
|
||||
clientMode,
|
||||
role,
|
||||
scopeString,
|
||||
String(signedAtMs),
|
||||
authToken,
|
||||
nonce,
|
||||
normalizedPlatform,
|
||||
normalizedDeviceFamily,
|
||||
].joined(separator: "|")
|
||||
}
|
||||
|
||||
private func normalizeMetadataField(_ value: String?) -> String {
|
||||
guard let value else { return "" }
|
||||
return value
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.lowercased(with: Locale(identifier: "en_US_POSIX"))
|
||||
}
|
||||
|
||||
private func waitForConnectChallenge() async throws -> String {
|
||||
guard let task = self.task else { throw ConnectChallengeError.timeout }
|
||||
return try await AsyncTimeout.withTimeout(
|
||||
|
||||
@ -398,20 +398,18 @@ public actor GatewayChannelActor {
|
||||
}
|
||||
let signedAtMs = Int(Date().timeIntervalSince1970 * 1000)
|
||||
let connectNonce = try await self.waitForConnectChallenge()
|
||||
let scopesValue = scopes.joined(separator: ",")
|
||||
let payloadParts = [
|
||||
"v2",
|
||||
identity?.deviceId ?? "",
|
||||
clientId,
|
||||
clientMode,
|
||||
role,
|
||||
scopesValue,
|
||||
String(signedAtMs),
|
||||
authToken ?? "",
|
||||
connectNonce,
|
||||
]
|
||||
let payload = payloadParts.joined(separator: "|")
|
||||
if includeDeviceIdentity, let identity {
|
||||
let payload = buildDeviceAuthPayloadV3(
|
||||
deviceId: identity.deviceId,
|
||||
clientId: clientId,
|
||||
clientMode: clientMode,
|
||||
role: role,
|
||||
scopes: scopes,
|
||||
signedAtMs: signedAtMs,
|
||||
token: authToken,
|
||||
nonce: connectNonce,
|
||||
platform: platform,
|
||||
deviceFamily: InstanceIdentity.deviceFamily)
|
||||
if let signature = DeviceIdentityStore.signPayload(payload, identity: identity),
|
||||
let publicKey = DeviceIdentityStore.publicKeyBase64Url(identity) {
|
||||
let device: [String: ProtoAnyCodable] = [
|
||||
@ -445,6 +443,44 @@ public actor GatewayChannelActor {
|
||||
}
|
||||
}
|
||||
|
||||
private func buildDeviceAuthPayloadV3(
|
||||
deviceId: String,
|
||||
clientId: String,
|
||||
clientMode: String,
|
||||
role: String,
|
||||
scopes: [String],
|
||||
signedAtMs: Int,
|
||||
token: String?,
|
||||
nonce: String,
|
||||
platform: String?,
|
||||
deviceFamily: String?) -> String
|
||||
{
|
||||
let scopeString = scopes.joined(separator: ",")
|
||||
let authToken = token ?? ""
|
||||
let normalizedPlatform = normalizeMetadataField(platform)
|
||||
let normalizedDeviceFamily = normalizeMetadataField(deviceFamily)
|
||||
return [
|
||||
"v3",
|
||||
deviceId,
|
||||
clientId,
|
||||
clientMode,
|
||||
role,
|
||||
scopeString,
|
||||
String(signedAtMs),
|
||||
authToken,
|
||||
nonce,
|
||||
normalizedPlatform,
|
||||
normalizedDeviceFamily,
|
||||
].joined(separator: "|")
|
||||
}
|
||||
|
||||
private func normalizeMetadataField(_ value: String?) -> String {
|
||||
guard let value else { return "" }
|
||||
return value
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
.lowercased(with: Locale(identifier: "en_US_POSIX"))
|
||||
}
|
||||
|
||||
private func handleConnectResponse(
|
||||
_ res: ResponseFrame,
|
||||
identity: DeviceIdentity?,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user