teamclaude-cloud 1.5.5 → 1.5.7

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamclaude-cloud",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "description": "Multi-account Claude proxy with quota-based rotation + cloud token sync and auth-key control",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -9,7 +9,7 @@ import { createProxyServer } from './server.js';
9
9
  import { importCredentials, loginOAuth, fetchProfile, refreshAccessToken, isTokenExpiringSoon } from './oauth.js';
10
10
  import { cloudLogin, cloudValidateOwner, cloudRefreshSession, cloudPush, cloudPushUsage, cloudReportUsage, cloudPull, cloudRefreshToken, cloudReportToken, cloudKeyCreate, cloudKeyList, cloudKeyRevoke, cloudKeyMove, cloudGroupList, cloudGroupCreate, cloudGroupRename, cloudGroupDelete, cloudGroupSetAccounts, cloudAccountSetEnabled, buildUsageFromQuota, mergePulledAccounts, resolveCloud, DEFAULT_CLOUD, keySource, reconcileRemovedAccounts } from './cloud.js';
11
11
  import { TUI } from './tui.js';
12
- import { maskIf, maskEmail } from './mask.js';
12
+ import { maskIf, maskEmail, maskEmailsIn } from './mask.js';
13
13
 
14
14
  const args = process.argv.slice(2);
15
15
  const command = args[0];
@@ -989,7 +989,7 @@ async function accountsCommand() {
989
989
  const src = a.source ? `, ${a.source}` : '';
990
990
  console.log(` [${i + 1}] ${maskIf(a.name, config.maskMode)} (${status}${src})`);
991
991
  if (hasProfile && p.email && p.email !== a.name) console.log(` Email: ${maskIf(p.email, config.maskMode)}`);
992
- if (hasProfile && p.orgName) console.log(` Org: ${p.orgName}`);
992
+ if (hasProfile && p.orgName) console.log(` Org: ${maskEmailsIn(p.orgName, config.maskMode)}`);
993
993
  if (verbose && a.expiresAt) {
994
994
  const remaining = a.expiresAt - Date.now();
995
995
  if (remaining <= 0) {
package/src/mask.js CHANGED
@@ -29,3 +29,12 @@ export function maskEmail(value) {
29
29
  export function maskIf(value, on) {
30
30
  return on ? maskEmail(value) : value;
31
31
  }
32
+
33
+ // Mask every email SUBSTRING inside a free-form string (log lines, "X's Organization",
34
+ // generic table cells) — non-email text is left intact. Use this where an email is
35
+ // embedded in a larger string, not the whole value.
36
+ const EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
37
+ export function maskEmailsIn(value, on) {
38
+ if (!on || typeof value !== 'string') return value;
39
+ return value.replace(EMAIL_RE, (m) => maskEmail(m));
40
+ }
package/src/tui.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { importCredentials, fetchProfile } from './oauth.js';
2
- import { maskIf } from './mask.js';
2
+ import { maskIf, maskEmailsIn } from './mask.js';
3
3
 
4
4
  // ── ANSI helpers ─────────────────────────────────────────────
5
5
 
@@ -201,12 +201,25 @@ export class TUI {
201
201
  }
202
202
 
203
203
  _addLog(msg) {
204
- msg = msg.replace(/^\[TeamClaude\]\s*/, '');
205
- this.log.unshift({ t: timestamp(), msg });
204
+ // Store RAW; masking is applied at RENDER time (_maskLog) so a mid-session mask
205
+ // toggle re-masks already-buffered lines too (Codex HIGH: buffered logs stayed raw).
206
+ this.log.unshift({ t: timestamp(), msg: msg.replace(/^\[TeamClaude\]\s*/, '') });
206
207
  if (this.log.length > 200) this.log.length = 200;
207
208
  if (this.running) this.render();
208
209
  }
209
210
 
211
+ // Mask every email in a log line when mask mode is on — applied at RENDER time. Uses
212
+ // an email REGEX (not the current account list) so it also masks a just-deleted
213
+ // account's name and can't partially expose one email that is a substring of another
214
+ // (Codex HIGH ×3). Covers TUI-generated lines AND redirected server/account-manager
215
+ // console output, so ordinary request/activity logging can't bypass mask mode.
216
+ _maskLog(s) {
217
+ return maskEmailsIn(s, this.config?.maskMode === true);
218
+ }
219
+
220
+ // Mask a single account name for direct render (active-requests line, etc.).
221
+ _mn(name) { return maskIf(name, this.config?.maskMode === true); }
222
+
210
223
  // ── input handling ─────────────────────────────────
211
224
 
212
225
  _onData(d) {
@@ -736,7 +749,7 @@ export class TUI {
736
749
  for (const [, r] of this.active) {
737
750
  const el = ((now - r.started) / 1000).toFixed(1);
738
751
  const sp = cyan(SPINNER[this.frame]);
739
- const a = r.account ? ` → ${r.account}` : '';
752
+ const a = r.account ? ` → ${this._mn(r.account)}` : '';
740
753
  lines.push(` ${sp} ${gray(r.t)} ${r.method} ${r.path}${a} ${dim(`(${el}s...)`)}`);
741
754
  }
742
755
 
@@ -744,7 +757,7 @@ export class TUI {
744
757
  const footerH = 2;
745
758
  const space = Math.max(0, H - lines.length - footerH);
746
759
  for (let i = 0; i < space && i < this.log.length; i++) {
747
- lines.push(` ${gray(this.log[i].t)} ${this.log[i].msg}`);
760
+ lines.push(` ${gray(this.log[i].t)} ${this._maskLog(this.log[i].msg)}`);
748
761
  }
749
762
 
750
763
  // Pad to fill