123 lines
3.6 KiB
Markdown
123 lines
3.6 KiB
Markdown
# ClawdNode Android Debugging Session - 2025-01-28
|
|
|
|
## Problem
|
|
ClawdNode Android app fails to connect to Clawdbot gateway - shows "failed to connect".
|
|
|
|
## Root Cause #1 (Fixed Earlier)
|
|
**Cryptographic algorithm mismatch**: Gateway uses Ed25519 signatures, Android app was using ECDSA P-256. Fixed by switching to Bouncy Castle Ed25519.
|
|
|
|
## Root Cause #2 (Fixed 2025-01-28)
|
|
**Signature payload format was WRONG!**
|
|
|
|
Android was signing:
|
|
```
|
|
$nonce:$signedAt
|
|
```
|
|
|
|
Gateway actually expects (from `gateway/device-auth.js`):
|
|
```
|
|
v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce
|
|
```
|
|
|
|
Example: `v2|abc123def|clawdbot-android|node|node||1706470000000|gateway-token|challenge-nonce`
|
|
|
|
## Solution Implemented (Commit a1e94f5)
|
|
|
|
### DeviceIdentity.kt
|
|
Updated `signChallenge()` to accept all required parameters and build correct payload:
|
|
```kotlin
|
|
fun signChallenge(
|
|
nonce: String,
|
|
clientId: String,
|
|
clientMode: String,
|
|
role: String,
|
|
scopes: String = "",
|
|
token: String = ""
|
|
): SignedChallenge {
|
|
val signedAt = System.currentTimeMillis()
|
|
val payload = listOf(
|
|
"v2", deviceId, clientId, clientMode, role, scopes,
|
|
signedAt.toString(), token, nonce
|
|
).joinToString("|")
|
|
// ... sign payload with Ed25519
|
|
}
|
|
```
|
|
|
|
### GatewayClient.kt
|
|
Updated `handleConnectChallenge()` to pass all parameters:
|
|
```kotlin
|
|
signedChallenge = deviceIdentity.signChallenge(
|
|
nonce = nonce,
|
|
clientId = Protocol.CLIENT_ID, // "clawdbot-android"
|
|
clientMode = Protocol.MODE, // "node"
|
|
role = Protocol.ROLE, // "node"
|
|
scopes = "",
|
|
token = token // gateway token
|
|
)
|
|
```
|
|
|
|
## Gateway Protocol Details (from source code analysis)
|
|
|
|
### WebSocket Handshake Flow
|
|
1. Client connects to `ws://gateway:18789/ws`
|
|
2. Gateway sends: `{"type": "event", "event": "connect.challenge", "payload": {"nonce": "...", "ts": ...}}`
|
|
3. Client sends connect request with signed device info
|
|
4. Gateway verifies signature, responds with `hello-ok`
|
|
|
|
### Device Auth Payload (v2)
|
|
Built by `buildDeviceAuthPayload()` in `gateway/device-auth.js`:
|
|
```
|
|
v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce
|
|
```
|
|
|
|
### Key Functions
|
|
```javascript
|
|
// Building payload (gateway/device-auth.js)
|
|
buildDeviceAuthPayload(params) {
|
|
const base = [
|
|
"v2", params.deviceId, params.clientId, params.clientMode,
|
|
params.role, params.scopes.join(","), String(params.signedAtMs),
|
|
params.token ?? "", params.nonce ?? ""
|
|
];
|
|
return base.join("|");
|
|
}
|
|
|
|
// Signing (infra/device-identity.js)
|
|
signDevicePayload(privateKeyPem, payload) {
|
|
return crypto.sign(null, Buffer.from(payload, "utf8"), key).toString("base64url");
|
|
}
|
|
```
|
|
|
|
### Device Identity Format
|
|
- **Public key**: 32 bytes raw, base64url encoded
|
|
- **Device ID**: SHA-256 hash of raw public key bytes, hex encoded
|
|
- **Signature**: Ed25519 signature of UTF-8 payload bytes, base64url encoded
|
|
|
|
## Android Implementation Notes
|
|
- Using Bouncy Castle Ed25519 (Android Keystore only supports Ed25519 on API 33+)
|
|
- Keys stored in EncryptedSharedPreferences (AES-256)
|
|
- 32-byte seed for private key, generates public key
|
|
|
|
## Next Steps to Test
|
|
1. On Mac Mini: `cd ~/dev/clawdnode-android && git pull origin main`
|
|
2. Android Studio: Sync & rebuild
|
|
3. On phone: Clear ClawdNode app data (regenerates keys)
|
|
4. Test connection
|
|
|
|
## Git Repo
|
|
`git@zurich.inou.com:clawdnode-android.git`
|
|
|
|
## Network Details
|
|
- Gateway: ws://100.123.216.65:18789/ws (Tailscale WebSocket)
|
|
- Phone Tailscale IP: 100.102.141.81
|
|
- Gateway host: james
|
|
|
|
## Debugging Commands
|
|
```bash
|
|
# Watch gateway logs (check for signature verification errors)
|
|
journalctl -u clawdbot -f | grep -i "device\|signature\|connect"
|
|
|
|
# Or if running via pm2/direct:
|
|
tail -f ~/.clawdbot/logs/*.log
|
|
```
|