@clawchatsai/connector 0.0.54 β†’ 0.0.56

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.
@@ -13,6 +13,7 @@ export interface PluginConfig {
13
13
  userId: string;
14
14
  serverUrl: string;
15
15
  apiKey: string;
16
+ gatewayId?: string;
16
17
  gatewayToken?: string;
17
18
  devicePrivateKey?: string;
18
19
  schemaVersion: number;
package/dist/index.js CHANGED
@@ -213,7 +213,16 @@ async function startClawChats(ctx, api, mediaStash) {
213
213
  }
214
214
  });
215
215
  // 5. Connect to signaling server
216
- signaling = new SignalingClient(config.serverUrl, config.userId, config.apiKey);
216
+ const _hostname = (() => { try {
217
+ return require('os').hostname();
218
+ }
219
+ catch {
220
+ return undefined;
221
+ } })();
222
+ signaling = new SignalingClient(config.serverUrl, config.userId, config.apiKey, {
223
+ gatewayId: config.gatewayId,
224
+ hostname: _hostname,
225
+ });
217
226
  signaling.on('connected', () => {
218
227
  ctx.logger.info('Connected to signaling server');
219
228
  });
@@ -755,6 +764,7 @@ async function handleSetup(token) {
755
764
  userId: msg.userId,
756
765
  serverUrl: tokenData.serverUrl,
757
766
  apiKey,
767
+ gatewayId: msg.gatewayId,
758
768
  gatewayToken,
759
769
  schemaVersion: 1,
760
770
  installedAt: new Date().toISOString(),
@@ -803,29 +813,38 @@ async function handleSetup(token) {
803
813
  });
804
814
  });
805
815
  }
806
- async function enrollTotp(config) {
816
+ async function enrollTotp(config, existingSecret) {
807
817
  const readline = await import('node:readline');
808
818
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
809
819
  const ask = (q) => new Promise(r => rl.question(q, r));
810
820
  try {
811
- // Generate TOTP secret
812
- const totpSecret = generateTotpSecret();
813
- const email = config.google?.authorizedEmail || config.userId;
814
- const otpauthUri = buildOtpauthUri(totpSecret, email);
815
- // Format secret with spaces for readability
816
- const formatted = totpSecret.match(/.{1,4}/g)?.join(' ') || totpSecret;
817
- console.log('');
818
- console.log(' πŸ” Setting up two-factor authentication');
819
- console.log('');
820
- console.log(' Open this link to scan the QR code with your authenticator app:');
821
- console.log(` ${config.serverUrl.replace('wss://', 'https://').replace(/\/ws\/?$/, '')}/totp-setup#${totpSecret}`);
822
- console.log('');
823
- console.log(` Or enter this code manually: ${formatted}`);
824
- console.log('');
825
- console.log(" Don't have an authenticator app?");
826
- console.log(' Google Authenticator: https://apps.apple.com/app/google-authenticator/id388497605');
827
- console.log(' https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2');
828
- console.log('');
821
+ let totpSecret;
822
+ if (existingSecret) {
823
+ // Reusing secret from another gateway β€” strip spaces, uppercase
824
+ totpSecret = existingSecret.replace(/\s+/g, '').toUpperCase();
825
+ console.log('');
826
+ console.log(' πŸ” Verifying existing TOTP secret…');
827
+ console.log('');
828
+ }
829
+ else {
830
+ // Generate a brand new TOTP secret
831
+ totpSecret = generateTotpSecret();
832
+ const email = config.google?.authorizedEmail || config.userId;
833
+ void buildOtpauthUri(totpSecret, email); // keep import used
834
+ const formatted = totpSecret.match(/.{1,4}/g)?.join(' ') || totpSecret;
835
+ console.log('');
836
+ console.log(' πŸ” Setting up two-factor authentication');
837
+ console.log('');
838
+ console.log(' Open this link to scan the QR code with your authenticator app:');
839
+ console.log(` ${config.serverUrl.replace('wss://', 'https://').replace(/\/ws\/?$/, '')}/totp-setup#${totpSecret}`);
840
+ console.log('');
841
+ console.log(` Or enter this code manually: ${formatted}`);
842
+ console.log('');
843
+ console.log(" Don't have an authenticator app?");
844
+ console.log(' Google Authenticator: https://apps.apple.com/app/google-authenticator/id388497605');
845
+ console.log(' https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2');
846
+ console.log('');
847
+ }
829
848
  // Verification loop
830
849
  let verified = false;
831
850
  for (let attempt = 0; attempt < 5; attempt++) {
@@ -876,6 +895,27 @@ async function enrollTotp(config) {
876
895
  return false;
877
896
  }
878
897
  }
898
+ async function handleShowTotp() {
899
+ const config = loadConfig();
900
+ if (!config) {
901
+ console.error('ClawChats not configured. Run: openclaw clawchats setup <token>');
902
+ return;
903
+ }
904
+ if (!config.totp?.secret) {
905
+ console.error('No TOTP secret found. Run: openclaw clawchats reauth to set one up first.');
906
+ return;
907
+ }
908
+ console.log('');
909
+ console.log('Your TOTP secret (account-level, keep this safe):');
910
+ console.log('');
911
+ console.log(` ${config.totp.secret}`);
912
+ console.log('');
913
+ console.log('To reuse this on a new gateway:');
914
+ console.log(' 1. Generate a setup token at login.clawchats.ai/dashboard');
915
+ console.log(' 2. On the new machine: openclaw clawchats setup <token>');
916
+ console.log(' 3. When prompted for a TOTP secret, paste the value above');
917
+ console.log('');
918
+ }
879
919
  async function handleReauth() {
880
920
  const config = loadConfig();
881
921
  if (!config) {
@@ -886,7 +926,16 @@ async function handleReauth() {
886
926
  console.log('');
887
927
  console.log(' ⚠️ This will invalidate all existing sessions.');
888
928
  console.log(' All connected browsers will need to re-authenticate.');
889
- const success = await enrollTotp(config);
929
+ console.log('');
930
+ const readline = await import('node:readline');
931
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
932
+ const ask = (q) => new Promise(r => rl.question(q, r));
933
+ let existingSecret;
934
+ const reuseAnswer = await ask(' Reuse TOTP from another gateway? Paste secret (or press Enter to generate new): ');
935
+ rl.close();
936
+ if (reuseAnswer.trim())
937
+ existingSecret = reuseAnswer.trim();
938
+ const success = await enrollTotp(config, existingSecret);
890
939
  if (success) {
891
940
  console.log(' All previous sessions have been invalidated.');
892
941
  console.log(' Restart the gateway for changes to take effect: systemctl --user restart openclaw-gateway');
@@ -1063,6 +1112,9 @@ const plugin = {
1063
1112
  cmd.command('reauth')
1064
1113
  .description('Reset two-factor authentication (new TOTP secret + invalidate sessions)')
1065
1114
  .action(() => handleReauth());
1115
+ cmd.command('show-totp')
1116
+ .description('Show your TOTP secret (use when adding ClawChats to a second gateway)')
1117
+ .action(() => handleShowTotp());
1066
1118
  cmd.command('reset')
1067
1119
  .description('Disconnect and remove all ClawChats data')
1068
1120
  .action(() => handleReset());
@@ -17,6 +17,8 @@ export declare class SignalingClient extends EventEmitter {
17
17
  private readonly serverUrl;
18
18
  private readonly userId;
19
19
  private readonly apiKey;
20
+ private readonly gatewayId?;
21
+ private readonly hostname?;
20
22
  private ws;
21
23
  /** True only after gateway-auth-ok has been received. */
22
24
  private _connected;
@@ -31,7 +33,10 @@ export declare class SignalingClient extends EventEmitter {
31
33
  private reconnectTimer;
32
34
  /** Timer handle for ping-timeout watchdog. */
33
35
  private pingWatchdog;
34
- constructor(serverUrl: string, userId: string, apiKey: string);
36
+ constructor(serverUrl: string, userId: string, apiKey: string, opts?: {
37
+ gatewayId?: string;
38
+ hostname?: string;
39
+ });
35
40
  /** Returns true when gateway-auth-ok has been received on the current socket. */
36
41
  get isConnected(): boolean;
37
42
  /**
@@ -33,6 +33,8 @@ export class SignalingClient extends EventEmitter {
33
33
  serverUrl;
34
34
  userId;
35
35
  apiKey;
36
+ gatewayId;
37
+ hostname;
36
38
  ws = null;
37
39
  /** True only after gateway-auth-ok has been received. */
38
40
  _connected = false;
@@ -47,11 +49,13 @@ export class SignalingClient extends EventEmitter {
47
49
  reconnectTimer = null;
48
50
  /** Timer handle for ping-timeout watchdog. */
49
51
  pingWatchdog = null;
50
- constructor(serverUrl, userId, apiKey) {
52
+ constructor(serverUrl, userId, apiKey, opts) {
51
53
  super();
52
54
  this.serverUrl = serverUrl;
53
55
  this.userId = userId;
54
56
  this.apiKey = apiKey;
57
+ this.gatewayId = opts?.gatewayId;
58
+ this.hostname = opts?.hostname;
55
59
  }
56
60
  // -------------------------------------------------------------------------
57
61
  // Public API
@@ -132,6 +136,8 @@ export class SignalingClient extends EventEmitter {
132
136
  userId: this.userId,
133
137
  apiKey: this.apiKey,
134
138
  pluginVersion: PLUGIN_VERSION,
139
+ ...(this.gatewayId ? { gatewayId: this.gatewayId } : {}),
140
+ ...(this.hostname ? { hostname: this.hostname } : {}),
135
141
  });
136
142
  // Resolve the connect() promise: the socket is open and auth is in flight
137
143
  settle();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawchatsai/connector",
3
- "version": "0.0.54",
3
+ "version": "0.0.56",
4
4
  "type": "module",
5
5
  "description": "ClawChats OpenClaw plugin β€” P2P tunnel + local API bridge",
6
6
  "main": "dist/index.js",