PR #1 of the multi-device roadmap. Adds per-device X25519 keys registered on-chain so senders can fan out envelopes across all of a recipient's physical devices — fixes the single-device limitation where a second phone / desktop loses messages as soon as the first one reads them. Chain (blockchain/): - New event types LINK_DEVICE / UNLINK_DEVICE, signed by the identity's master Ed25519. - LinkDevicePayload {x25519_pub_key, device_name} + UnlinkDevicePayload {x25519_pub_key} on the wire. - State: prefixDevice + x25519_pub → DeviceRecord{owner, name, added_at, revoked_at?}; reverse index prefixDevicesByOwner for O(k) listing. Revoke is a soft-delete — the row stays as a visible tombstone so offline clients can detect their own revocation and wipe local state. - MaxDevicesPerOwner = 10 slot cap; MaxDeviceNameLen = 64. - Strict lowercase-hex validation on x25519_pub so clients can't desync on letter case. - Same-owner re-link is a rename/refresh (recreates reverse index too — needed after a revoke). - Chain.DevicesOf(master_pub) returns the active records; empty slice for legacy identities so senders can fall back to IdentityInfo.X25519Pub. HTTP (node/): - GET /api/devices/{master_pub_or_addr} — returns {master_pub, count, devices[]}. Revoked records filtered out. - /api/identity/{pub} gains `device_count` so senders can decide upfront whether to fan out or take the legacy path. Tests (blockchain/devices_test.go): - Happy paths (1, 3 devices), foreign-owner rejection, same-owner refresh after revoke, unlink removes from active set, foreign-signer unlink rejection, idempotent double-unlink, malformed pub/name rejection, MaxDevices cap + recovery after unlink frees a slot, empty list for unknown master. Also in this commit: - deploy/single/join.sh — convenience script operators have been iterating on in this session (joiner-node bring-up + firewall port patching + Caddy opt-out). - client-app/app.json — `usesCleartextTraffic: true` on Android so installed APKs can talk to http:// dev nodes without TLS. See docs/ROADMAP.md for PRs #2..#4 (client fan-out, pairing flow, desktop Electron shell).
72 lines
2.0 KiB
JSON
72 lines
2.0 KiB
JSON
{
|
|
"expo": {
|
|
"name": "DChain Messenger",
|
|
"slug": "dchain-messenger",
|
|
"version": "1.0.0",
|
|
"orientation": "portrait",
|
|
"userInterfaceStyle": "dark",
|
|
"backgroundColor": "#000000",
|
|
"ios": {
|
|
"supportsTablet": false,
|
|
"bundleIdentifier": "com.dchain.messenger",
|
|
"infoPlist": {
|
|
"NSMicrophoneUsageDescription": "Allow DChain to record voice messages and video.",
|
|
"NSCameraUsageDescription": "Allow DChain to record video messages and scan QR codes.",
|
|
"NSPhotoLibraryUsageDescription": "Allow DChain to attach photos and videos from your library.",
|
|
"ITSAppUsesNonExemptEncryption": false
|
|
}
|
|
},
|
|
"android": {
|
|
"package": "com.dchain.messenger",
|
|
"softwareKeyboardLayoutMode": "pan",
|
|
"usesCleartextTraffic": true,
|
|
"permissions": [
|
|
"android.permission.RECORD_AUDIO",
|
|
"android.permission.CAMERA",
|
|
"android.permission.READ_EXTERNAL_STORAGE",
|
|
"android.permission.WRITE_EXTERNAL_STORAGE",
|
|
"android.permission.MODIFY_AUDIO_SETTINGS"
|
|
]
|
|
},
|
|
"web": {
|
|
"bundler": "metro",
|
|
"output": "static"
|
|
},
|
|
"plugins": [
|
|
"expo-router",
|
|
"expo-secure-store",
|
|
[
|
|
"expo-camera",
|
|
{
|
|
"cameraPermission": "Allow DChain to record video messages and scan QR codes.",
|
|
"microphonePermission": "Allow DChain to record audio with video."
|
|
}
|
|
],
|
|
[
|
|
"expo-image-picker",
|
|
{
|
|
"photosPermission": "Allow DChain to attach photos and videos.",
|
|
"cameraPermission": "Allow DChain to take photos."
|
|
}
|
|
],
|
|
[
|
|
"expo-audio",
|
|
{
|
|
"microphonePermission": "Allow DChain to record voice messages."
|
|
}
|
|
],
|
|
"expo-video"
|
|
],
|
|
"experiments": {
|
|
"typedRoutes": false
|
|
},
|
|
"scheme": "dchain",
|
|
"extra": {
|
|
"router": {},
|
|
"eas": {
|
|
"projectId": "28d7743e-6745-460f-8ce5-c971c5c297b6"
|
|
}
|
|
}
|
|
}
|
|
}
|