@bondsmith/bondsmithd 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +22 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1006,7 +1006,7 @@ import { sign } from "crypto";
1006
1006
  import WebSocket from "ws";
1007
1007
 
1008
1008
  // src/version.ts
1009
- var DAEMON_VERSION = true ? "0.1.9" : "dev";
1009
+ var DAEMON_VERSION = true ? "0.1.10" : "dev";
1010
1010
  var VERSION_FLAGS = ["--version", "-v"];
1011
1011
  function versionLine() {
1012
1012
  return `bondsmithd ${DAEMON_VERSION} (protocol ${PROTOCOL_VERSION})`;
@@ -1357,6 +1357,14 @@ function createOutputPacer(options) {
1357
1357
  };
1358
1358
  }
1359
1359
 
1360
+ // src/ws/sanitize-insert-text.ts
1361
+ var DISALLOWED_CHARACTERS = /[\x00-\x08\x0b-\x1f\x7f-\x9f‪-‮⁦-⁩]/g;
1362
+ function sanitizeInsertText(text) {
1363
+ const withLineFeeds = text.replace(/\r\n?/g, "\n");
1364
+ const sanitized = withLineFeeds.replace(DISALLOWED_CHARACTERS, "");
1365
+ return { text: sanitized, strippedCount: withLineFeeds.length - sanitized.length };
1366
+ }
1367
+
1360
1368
  // src/ws/router.ts
1361
1369
  var SIGNABLE_ACTION_SET = new Set(SIGNABLE_ACTIONS);
1362
1370
  function isSignableAction(type) {
@@ -1640,10 +1648,14 @@ async function dispatch(conn, message, {
1640
1648
  case "session.insertText": {
1641
1649
  const session = getSessionOrError(sessionManager, conn, message.sessionId);
1642
1650
  if (!session) return;
1651
+ const { text, strippedCount } = sanitizeInsertText(message.text);
1652
+ if (strippedCount > 0) {
1653
+ console.warn(`bondsmithd: stripped ${strippedCount} control characters from inserted text`);
1654
+ }
1643
1655
  try {
1644
1656
  await sendKeysLiteral(
1645
1657
  session.tmuxSessionName,
1646
- `${BRACKETED_PASTE_START}${message.text}${BRACKETED_PASTE_END}`
1658
+ `${BRACKETED_PASTE_START}${text}${BRACKETED_PASTE_END}`
1647
1659
  );
1648
1660
  } catch (err) {
1649
1661
  conn.send(error(errorMessageOf(err, "failed to insert text")));
@@ -1863,6 +1875,10 @@ var ConnectionAuthState = class {
1863
1875
  isRevoked() {
1864
1876
  return this.revoked;
1865
1877
  }
1878
+ /** Unsolicited daemon broadcasts (session.created/updated) go only to connections that completed the handshake and still hold authority. */
1879
+ canReceiveBroadcasts() {
1880
+ return this.authenticated !== null && !this.revoked;
1881
+ }
1866
1882
  /** The controller/account this connection authenticated as, or null before a successful handshake. Used by verify-command.ts to reject an envelope signed by a DIFFERENT controller than the one that authenticated this connection. */
1867
1883
  getAuthenticatedIdentity() {
1868
1884
  return this.authenticated;
@@ -2040,7 +2056,7 @@ function startRelayClient(deps) {
2040
2056
  let reconnectTimer;
2041
2057
  function broadcast(message) {
2042
2058
  for (const entry of sessions.values()) {
2043
- entry.conn.send(message);
2059
+ if (entry.connectionAuth.canReceiveBroadcasts()) entry.conn.send(message);
2044
2060
  }
2045
2061
  }
2046
2062
  const routerDeps = { ...deps, broadcast };
@@ -3714,7 +3730,9 @@ function createDaemonWebSocketServer(httpServer, config, daemonFingerprint, pend
3714
3730
  function broadcast(message) {
3715
3731
  const payload = JSON.stringify(message);
3716
3732
  for (const client of wss.clients) {
3717
- if (client.readyState === client.OPEN) client.send(payload);
3733
+ if (client.readyState === client.OPEN && connectionAuthBySocket.get(client)?.canReceiveBroadcasts()) {
3734
+ client.send(payload);
3735
+ }
3718
3736
  }
3719
3737
  }
3720
3738
  sessionManager.onSessionUpdated((session) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bondsmith/bondsmithd",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "private": false,
5
5
  "description": "Local daemon for Bondsmith agent sessions — runs on the user's own machine, pairs with a Bondsmith account, and exposes tmux-backed terminal sessions to the Bondsmith web app over a signed WebSocket protocol.",
6
6
  "homepage": "https://bondsmith.dev",