fix: Use correct device auth payload format for signature
The signature payload was incorrect. Changed from: $nonce:$signedAt To gateway's expected v2 format: v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce This matches the buildDeviceAuthPayload() function in Clawdbot's gateway/device-auth.js module.
This commit is contained in:
parent
1f58f36470
commit
a1e94f559f
|
|
@ -20,7 +20,7 @@ import java.security.SecureRandom
|
|||
* The key format matches the Clawdbot gateway protocol:
|
||||
* - Public key: 32 bytes raw, base64url-encoded
|
||||
* - Signature: 64 bytes raw, base64url-encoded
|
||||
* - Payload: "$nonce:$signedAt" (matching gateway's expected format)
|
||||
* - Payload format (v2): "v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce"
|
||||
*/
|
||||
class DeviceIdentity(context: Context) {
|
||||
|
||||
|
|
@ -68,13 +68,43 @@ class DeviceIdentity(context: Context) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sign a challenge nonce for gateway authentication
|
||||
* Sign a challenge nonce for gateway authentication.
|
||||
*
|
||||
* Builds the payload in gateway's expected format:
|
||||
* v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce
|
||||
*
|
||||
* @param nonce Challenge nonce from gateway
|
||||
* @param clientId Client identifier (e.g., "clawdnode-android")
|
||||
* @param clientMode Client mode ("node")
|
||||
* @param role Role ("node")
|
||||
* @param scopes Comma-separated scopes (empty for nodes)
|
||||
* @param token Auth token (gateway token or device token)
|
||||
*/
|
||||
fun signChallenge(nonce: String): SignedChallenge {
|
||||
fun signChallenge(
|
||||
nonce: String,
|
||||
clientId: String,
|
||||
clientMode: String,
|
||||
role: String,
|
||||
scopes: String = "",
|
||||
token: String = ""
|
||||
): SignedChallenge {
|
||||
ensureKeyPair()
|
||||
|
||||
val signedAt = System.currentTimeMillis()
|
||||
val payload = "$nonce:$signedAt"
|
||||
|
||||
// Build payload in gateway's expected format:
|
||||
// v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce
|
||||
val payload = listOf(
|
||||
"v2",
|
||||
deviceId,
|
||||
clientId,
|
||||
clientMode,
|
||||
role,
|
||||
scopes,
|
||||
signedAt.toString(),
|
||||
token,
|
||||
nonce
|
||||
).joinToString("|")
|
||||
|
||||
Log.d(tag, "Signing payload: $payload")
|
||||
|
||||
|
|
|
|||
|
|
@ -226,7 +226,16 @@ class GatewayClient(
|
|||
|
||||
try {
|
||||
deviceId = deviceIdentity.deviceId
|
||||
signedChallenge = deviceIdentity.signChallenge(nonce)
|
||||
// Sign with full device auth payload:
|
||||
// v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce
|
||||
signedChallenge = deviceIdentity.signChallenge(
|
||||
nonce = nonce,
|
||||
clientId = Protocol.CLIENT_ID,
|
||||
clientMode = Protocol.MODE,
|
||||
role = Protocol.ROLE,
|
||||
scopes = "", // Nodes don't use scopes
|
||||
token = token
|
||||
)
|
||||
publicKey = deviceIdentity.publicKey
|
||||
log("Device identity ready: id=${deviceId.take(8)}...")
|
||||
log("DEBUG: ${signedChallenge.debugInfo}")
|
||||
|
|
|
|||
Loading…
Reference in New Issue