Chat updates
This commit is contained in:
@@ -9954,13 +9954,6 @@ async function main() {
|
|||||||
const swarm = new Hyperswarm(swarmOpts)
|
const swarm = new Hyperswarm(swarmOpts)
|
||||||
bareOsRegisterCorestoreSuspendResumeHooks(store, swarm)
|
bareOsRegisterCorestoreSuspendResumeHooks(store, swarm)
|
||||||
const disk = new SwarmDisk()
|
const disk = new SwarmDisk()
|
||||||
if (
|
|
||||||
swarm.keyPair &&
|
|
||||||
swarm.keyPair.publicKey &&
|
|
||||||
swarm.keyPair.publicKey.byteLength === 32
|
|
||||||
) {
|
|
||||||
disk.localSwarmPublicKey = b4a.from(swarm.keyPair.publicKey)
|
|
||||||
}
|
|
||||||
if (bareOsChatMuxEnabled(hostEnvMain)) {
|
if (bareOsChatMuxEnabled(hostEnvMain)) {
|
||||||
disk.bareOsChatService = createBareOsChatService({
|
disk.bareOsChatService = createBareOsChatService({
|
||||||
env: /** @type {Record<string, string | undefined>} */ (
|
env: /** @type {Record<string, string | undefined>} */ (
|
||||||
|
|||||||
@@ -238,16 +238,13 @@ export function createBareOsChatService(opts = {}) {
|
|||||||
try {
|
try {
|
||||||
const id16 = randomBytes(16)
|
const id16 = randomBytes(16)
|
||||||
let pk = b4a.alloc(32)
|
let pk = b4a.alloc(32)
|
||||||
if (
|
if (socket?.publicKey && socket.publicKey.byteLength === 32) {
|
||||||
disk.localSwarmPublicKey &&
|
|
||||||
disk.localSwarmPublicKey.byteLength === 32
|
|
||||||
) {
|
|
||||||
pk = disk.localSwarmPublicKey
|
|
||||||
} else if (
|
|
||||||
socket?.publicKey &&
|
|
||||||
socket.publicKey.byteLength === 32
|
|
||||||
) {
|
|
||||||
pk = b4a.from(socket.publicKey)
|
pk = b4a.from(socket.publicKey)
|
||||||
|
} else if (
|
||||||
|
disk.localNoiseWirePk &&
|
||||||
|
disk.localNoiseWirePk.byteLength === 32
|
||||||
|
) {
|
||||||
|
pk = disk.localNoiseWirePk
|
||||||
}
|
}
|
||||||
chan.messages[2].send({
|
chan.messages[2].send({
|
||||||
roomId: 'general',
|
roomId: 'general',
|
||||||
@@ -294,19 +291,9 @@ export function createBareOsChatService(opts = {}) {
|
|||||||
*/
|
*/
|
||||||
broadcastLocal(disk, text, meta = {}) {
|
broadcastLocal(disk, text, meta = {}) {
|
||||||
const evtId = randomBytes(16)
|
const evtId = randomBytes(16)
|
||||||
let pk = meta.senderPk
|
let pk =
|
||||||
if (!pk || pk.byteLength !== 32) {
|
meta.senderPk && meta.senderPk.byteLength === 32 ? meta.senderPk : null
|
||||||
pk = null
|
if (!pk) {
|
||||||
}
|
|
||||||
if (!pk || pk.byteLength !== 32) {
|
|
||||||
if (
|
|
||||||
disk.localSwarmPublicKey &&
|
|
||||||
disk.localSwarmPublicKey.byteLength === 32
|
|
||||||
) {
|
|
||||||
pk = disk.localSwarmPublicKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!pk || pk.byteLength !== 32) {
|
|
||||||
for (const p of disk.peers) {
|
for (const p of disk.peers) {
|
||||||
const sk = p.socket?.publicKey
|
const sk = p.socket?.publicKey
|
||||||
if (sk && sk.byteLength === 32) {
|
if (sk && sk.byteLength === 32) {
|
||||||
@@ -315,6 +302,9 @@ export function createBareOsChatService(opts = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!pk && disk.localNoiseWirePk && disk.localNoiseWirePk.byteLength === 32) {
|
||||||
|
pk = disk.localNoiseWirePk
|
||||||
|
}
|
||||||
if (!pk || pk.byteLength !== 32) {
|
if (!pk || pk.byteLength !== 32) {
|
||||||
pk = b4a.alloc(32)
|
pk = b4a.alloc(32)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,8 +172,11 @@ export class SwarmDisk {
|
|||||||
this.seedHttpDhtProxyRoutes = null
|
this.seedHttpDhtProxyRoutes = null
|
||||||
/** @type {string[]} MBR-derived drive key hex list (primary + failovers). */
|
/** @type {string[]} MBR-derived drive key hex list (primary + failovers). */
|
||||||
this.mbrKeysHex = []
|
this.mbrKeysHex = []
|
||||||
/** Host Hyperswarm/DHT public key (32 bytes); set by booter `main` for chat wire `senderPk`. */
|
/**
|
||||||
this.localSwarmPublicKey = /** @type {Uint8Array | null} */ (null)
|
* Local Noise wire static key (32 bytes), last seen from `Hyperswarm` socket `publicKey`.
|
||||||
|
* Peers validate chat `senderPk` against `socket.remotePublicKey`, which matches **this** — not `swarm.keyPair.publicKey`.
|
||||||
|
*/
|
||||||
|
this.localNoiseWirePk = /** @type {Uint8Array | null} */ (null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -479,6 +482,14 @@ export class SwarmDisk {
|
|||||||
this.bareOsChatService.pairOnMux(this, mux, socket, peer)
|
this.bareOsChatService.pairOnMux(this, mux, socket, peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Sync local Noise static key once the secret stream exposes `publicKey` (may follow handshake). */
|
||||||
|
const cacheLocalNoiseWirePk = () => {
|
||||||
|
if (socket.publicKey && socket.publicKey.byteLength === 32) {
|
||||||
|
disk.localNoiseWirePk = b4a.from(socket.publicKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheLocalNoiseWirePk()
|
||||||
|
|
||||||
this.peers.add(peer)
|
this.peers.add(peer)
|
||||||
|
|
||||||
const collabNd =
|
const collabNd =
|
||||||
@@ -508,7 +519,10 @@ export class SwarmDisk {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.on('handshake', setPeerId)
|
socket.on('handshake', () => {
|
||||||
|
setPeerId()
|
||||||
|
cacheLocalNoiseWirePk()
|
||||||
|
})
|
||||||
if (!setPeerId()) {
|
if (!setPeerId()) {
|
||||||
let attempts = 0
|
let attempts = 0
|
||||||
const tryAgain = () => {
|
const tryAgain = () => {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"start": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
"start": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
||||||
"dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
"dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && bare index.js",
|
||||||
"pear:dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && pear run --dev .",
|
"pear:dev": "node ../../scripts/ensure-pear-node-modules.mjs packages/bare-os-booter && pear run --dev .",
|
||||||
"test": "../../node_modules/.bin/brittle-bare test.identity.js && node --require ./scripts/bare-node-test-shim.cjs ../../node_modules/.bin/brittle-node test.js test.bare-os-chat-service.js test.bare-holesail.js test.bare-holesail-managed.js test.bare-openssh-pty.js test.bare-openssh-sftp.js test.hrpc-allowlist.js test.socket-scm-rights.js",
|
"test": "../../node_modules/.bin/brittle-bare test.identity.js && node --require ./scripts/bare-node-test-shim.cjs ../../node_modules/.bin/brittle-node test.js test.bare-os-chat-service.js test.bare-os-chat-wire.js test.bare-holesail.js test.bare-holesail-managed.js test.bare-openssh-pty.js test.bare-openssh-sftp.js test.hrpc-allowlist.js test.socket-scm-rights.js",
|
||||||
"test:bare": "../../node_modules/.bin/brittle-bare test.identity.js test.bare-smoke.js"
|
"test:bare": "../../node_modules/.bin/brittle-bare test.identity.js test.bare-smoke.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* Proves chat `senderPk` must be the **Noise** `socket.publicKey` (32 B), not
|
||||||
|
* `swarm.keyPair.publicKey` — the peer's `remotePublicKey` matches the other
|
||||||
|
* side's `publicKey` on the same connection, not the DHT key pair.
|
||||||
|
*/
|
||||||
|
import Hyperswarm from 'hyperswarm'
|
||||||
|
import b4a from 'b4a'
|
||||||
|
import { topicKey } from 'bare-os-protocol/constants.js'
|
||||||
|
|
||||||
|
const topic = topicKey()
|
||||||
|
const a = new Hyperswarm()
|
||||||
|
const b = new Hyperswarm()
|
||||||
|
|
||||||
|
const aKey = a.keyPair.publicKey
|
||||||
|
const bKey = b.keyPair.publicKey
|
||||||
|
let aSock = null
|
||||||
|
let bSock = null
|
||||||
|
|
||||||
|
a.on('connection', (s) => {
|
||||||
|
aSock = s
|
||||||
|
check()
|
||||||
|
})
|
||||||
|
b.on('connection', (s) => {
|
||||||
|
bSock = s
|
||||||
|
check()
|
||||||
|
})
|
||||||
|
|
||||||
|
function check() {
|
||||||
|
if (!aSock || !bSock) return
|
||||||
|
const remoteB = b4a.equals(aSock.remotePublicKey, bKey)
|
||||||
|
const remoteA = b4a.equals(bSock.remotePublicKey, aKey)
|
||||||
|
console.log(
|
||||||
|
'DHT keyPair.pub === peer remotePk ?',
|
||||||
|
' A.remote vs B.dht:',
|
||||||
|
remoteB,
|
||||||
|
' B.remote vs A.dht:',
|
||||||
|
remoteA
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
'Noise wire identity (correct for chat senderPk):'
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
' B.remotePk === A.socket.publicKey',
|
||||||
|
b4a.equals(bSock.remotePublicKey, aSock.publicKey)
|
||||||
|
)
|
||||||
|
console.log(
|
||||||
|
' A.remotePk === B.socket.publicKey',
|
||||||
|
b4a.equals(aSock.remotePublicKey, bSock.publicKey)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.join(topic)
|
||||||
|
await new Promise((r) => setTimeout(r, 400))
|
||||||
|
a.join(topic)
|
||||||
|
|
||||||
|
await new Promise((r) => setTimeout(r, 12000))
|
||||||
|
|
||||||
|
if (!aSock || !bSock) {
|
||||||
|
console.error('FAIL: missing connection within timeout (NAT/firewall?)')
|
||||||
|
process.exitCode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
await a.destroy()
|
||||||
|
await b.destroy()
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import test from 'brittle'
|
||||||
|
import b4a from 'b4a'
|
||||||
|
import { createBareOsChatService } from './lib/bare-os-chat-service.js'
|
||||||
|
|
||||||
|
test('broadcastLocal senderPk equals Noise socket.publicKey', async (t) => {
|
||||||
|
const wirePk = b4a.alloc(32)
|
||||||
|
wirePk[7] = 42
|
||||||
|
|
||||||
|
/** @type {{ sent?: Uint8Array }} */
|
||||||
|
const cap = {}
|
||||||
|
const disk = {
|
||||||
|
localNoiseWirePk: wirePk,
|
||||||
|
peers: new Set([
|
||||||
|
{
|
||||||
|
socket: { publicKey: wirePk },
|
||||||
|
chatChan: {
|
||||||
|
messages: [, , , , { send(evt) {
|
||||||
|
cap.sent = /** @type {Uint8Array} */ (evt.senderPk)
|
||||||
|
} }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
protomuxChatChannelRxTotal: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const svc = createBareOsChatService({ env: {} })
|
||||||
|
svc.broadcastLocal(disk, 'hello', { displayName: 'x' })
|
||||||
|
|
||||||
|
t.ok(cap.sent && b4a.equals(cap.sent, wirePk), 'multiplex frame carries Noise static pk')
|
||||||
|
|
||||||
|
const hist = svc.history()
|
||||||
|
const last = hist[hist.length - 1]
|
||||||
|
t.ok(last && b4a.equals(/** @type {Uint8Array} */ (last.senderPk), wirePk))
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user