@bsv/authsocket-client
Version:
Mutually Authenticated Web Sockets Client
105 lines • 3.84 kB
JavaScript
import { io as realIo } from 'socket.io-client';
import { Peer, Utils } from '@bsv/sdk';
import { SocketClientTransport } from './SocketClientTransport.js';
/**
* Internal class that wraps a Socket.IO client connection with BRC-103 mutual authentication,
* enabling secure and identity-aware communication with a server.
*/
class AuthSocketClientImpl {
ioSocket;
peer;
connected = false;
id = '';
serverIdentityKey;
eventCallbacks = new Map();
/**
* Creates an instance of AuthSocketClient.
*
* @param ioSocket - The underlying Socket.IO client socket instance.
* @param peer - The BRC-103 Peer instance responsible for managing authenticated
* communication, including message signing and verification.
*/
constructor(ioSocket, peer) {
this.ioSocket = ioSocket;
this.peer = peer;
// Listen for 'connect' and 'disconnect' from underlying Socket.IO
this.ioSocket.on('connect', () => {
this.connected = true;
this.id = this.ioSocket.id || '';
// Re-dispatch to dev if they've called "socket.on('connect', ...)"
this.fireEventCallbacks('connect');
});
this.ioSocket.on('disconnect', (reason) => {
this.connected = false;
// Re-dispatch
this.fireEventCallbacks('disconnect', reason);
});
// Also listen for BRC-103 "general" messages
// We'll rely on peer.listenForGeneralMessages
this.peer.listenForGeneralMessages((senderKey, payload) => {
this.serverIdentityKey = senderKey;
const { eventName, data } = this.decodeEventPayload(payload);
this.fireEventCallbacks(eventName, data);
});
}
on(eventName, callback) {
let arr = this.eventCallbacks.get(eventName);
if (!arr) {
arr = [];
this.eventCallbacks.set(eventName, arr);
}
arr.push(callback);
return this;
}
emit(eventName, data) {
// We sign a BRC-103 "general" message and send to the server
// via peer.toPeer
const encoded = this.encodeEventPayload(eventName, data);
this.peer.toPeer(encoded, this.serverIdentityKey).catch(err => {
console.error(`BRC103IoClientSocket emit error for event "${eventName}":`, err);
});
return this;
}
disconnect() {
this.serverIdentityKey = undefined;
this.ioSocket.disconnect();
}
fireEventCallbacks(eventName, data) {
const cbs = this.eventCallbacks.get(eventName);
if (!cbs)
return;
for (const cb of cbs) {
cb(data);
}
}
encodeEventPayload(eventName, data) {
const obj = { eventName, data };
return Utils.toArray(JSON.stringify(obj), 'utf8');
}
decodeEventPayload(payload) {
try {
const str = Utils.toUTF8(payload);
return JSON.parse(str);
}
catch {
return { eventName: '_unknown', data: undefined };
}
}
}
/**
* Factory function for creating a new AuthSocketClientImpl instance.
*
* @param url - The server URL
* @param opts - Contains wallet, requested certificates, and other optional settings
*/
export function AuthSocketClient(url, opts) {
// 1) Create real socket.io-client connection
const socket = realIo(url, opts.managerOptions);
// 2) Create a BRC-103 transport for the new socket
const transport = new SocketClientTransport(socket);
// 3) Create a Peer
const peer = new Peer(opts.wallet, transport, opts.requestedCertificates, opts.sessionManager);
// 4) Return our new AuthSocketClientImpl
return new AuthSocketClientImpl(socket, peer);
}
//# sourceMappingURL=AuthSocketClient.js.map