claude-cac 1.5.0-beta.1 → 1.5.0-beta.2

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/cac +75 -69
  2. package/package.json +1 -1
package/cac CHANGED
@@ -11,7 +11,7 @@ VERSIONS_DIR="$CAC_DIR/versions"
11
11
  # ── utils: colors, read/write, UUID, proxy parsing ───────────────────────
12
12
 
13
13
  # shellcheck disable=SC2034 # used in build-concatenated cac script
14
- CAC_VERSION="1.5.0-beta.1"
14
+ CAC_VERSION="1.5.0-beta.2"
15
15
 
16
16
  _read() { [[ -f "$1" ]] && tr -d '[:space:]' < "$1" || echo "${2:-}"; }
17
17
  _die() { printf '%b\n' "$(_red "error:") $*" >&2; exit 1; }
@@ -2351,22 +2351,74 @@ cmd_check() {
2351
2351
  fi
2352
2352
  fi
2353
2353
 
2354
- # ── fingerprint hook runtime verification ──
2354
+ # ── identity spoofing (consolidated) ──
2355
+ local os; os=$(_detect_os)
2356
+ local _id_ok=0 _id_total=0 _id_issues=()
2357
+
2358
+ # fingerprint hook
2359
+ local _fp_ok=false
2355
2360
  if [[ -f "$CAC_DIR/fingerprint-hook.js" ]] && [[ -f "$env_dir/hostname" ]]; then
2356
2361
  local expected_hn; expected_hn=$(_read "$env_dir/hostname")
2357
2362
  local actual_hn
2358
2363
  actual_hn=$(NODE_OPTIONS="--require $CAC_DIR/fingerprint-hook.js" CAC_HOSTNAME="$expected_hn" \
2359
2364
  node -e "process.stdout.write(require('os').hostname())" 2>/dev/null || true)
2365
+ (( _id_total++ )) || true
2360
2366
  if [[ "$actual_hn" == "$expected_hn" ]]; then
2361
- echo " $(_green "✓") fingerprint spoofed ($(_dim "$expected_hn"))"
2367
+ _fp_ok=true; (( _id_ok++ )) || true
2362
2368
  else
2363
- echo " $(_red "✗") fingerprint NOT spoofed (got: $actual_hn)"
2364
- problems+=("fingerprint hook not working")
2369
+ _id_issues+=("fingerprint hook not working")
2370
+ fi
2371
+ fi
2372
+ # git email
2373
+ (( _id_total++ )) || true
2374
+ if [[ -f "$env_dir/git_email" ]]; then
2375
+ (( _id_ok++ )) || true
2376
+ else
2377
+ _id_issues+=("git email not spoofed")
2378
+ fi
2379
+ # repo hash
2380
+ (( _id_total++ )) || true
2381
+ if [[ -f "$env_dir/fake_git_remote" ]]; then
2382
+ (( _id_ok++ )) || true
2383
+ else
2384
+ _id_issues+=("repo hash not spoofed")
2385
+ fi
2386
+ # user_id consistency
2387
+ local _uid_ok=true
2388
+ local _env_uid; _env_uid=$(_read "$env_dir/user_id" "")
2389
+ if [[ -n "$_env_uid" ]]; then
2390
+ local _config_dir="${CLAUDE_CONFIG_DIR:-$ENVS_DIR/$current/.claude}"
2391
+ local _cj="$_config_dir/.claude.json"
2392
+ [[ -f "$_cj" ]] || _cj="$HOME/.claude.json"
2393
+ if [[ -f "$_cj" ]]; then
2394
+ local _actual_uid
2395
+ _actual_uid=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('userID',''))" "$_cj" 2>/dev/null || true)
2396
+ (( _id_total++ )) || true
2397
+ if [[ -n "$_actual_uid" ]] && [[ "$_actual_uid" != "$_env_uid" ]]; then
2398
+ _uid_ok=false
2399
+ _id_issues+=("user_id mismatch")
2400
+ else
2401
+ (( _id_ok++ )) || true
2402
+ fi
2365
2403
  fi
2366
2404
  fi
2405
+ # billing header
2406
+ (( _id_total++ )) || true
2407
+ [[ "$wrapper_content" == *"CLAUDE_CODE_ATTRIBUTION_HEADER"* ]] && { (( _id_ok++ )) || true; } || _id_issues+=("billing header exposed")
2408
+
2409
+ # display consolidated identity line
2410
+ local _id_extra=""
2411
+ [[ -f "$env_dir/persona" ]] && _id_extra=" + $(_read "$env_dir/persona")"
2412
+ if [[ "$_id_ok" -eq "$_id_total" ]]; then
2413
+ echo " $(_green "✓") identity ${_id_ok}/${_id_total} spoofed${_id_extra}"
2414
+ else
2415
+ echo " $(_red "✗") identity ${_id_ok}/${_id_total} spoofed${_id_extra}"
2416
+ for _ii in "${_id_issues[@]}"; do
2417
+ problems+=("$_ii")
2418
+ done
2419
+ fi
2367
2420
 
2368
2421
  # ── IPv6 leak detection ──
2369
- local os; os=$(_detect_os)
2370
2422
  local ipv6_leak=false
2371
2423
  if [[ "$os" == "macos" ]]; then
2372
2424
  local ipv6_addrs
@@ -2378,80 +2430,28 @@ cmd_check() {
2378
2430
  [[ "$ipv6_addrs" -gt 0 ]] && ipv6_leak=true
2379
2431
  fi
2380
2432
  if [[ "$ipv6_leak" == "true" ]]; then
2381
- echo " $(_yellow "⚠") IPv6 global address detected (potential leak)"
2433
+ echo " $(_yellow "⚠") IPv6 global address detected (potential leak)"
2382
2434
  else
2383
- echo " $(_green "✓") IPv6 no global address"
2435
+ echo " $(_green "✓") IPv6 no global address"
2384
2436
  fi
2385
2437
 
2386
- # ── residual telemetry files ──
2438
+ # ── warnings (only shown when relevant) ──
2387
2439
  if [[ -d "$HOME/.claude/telemetry" ]]; then
2388
2440
  local tel_files
2389
2441
  tel_files=$(find "$HOME/.claude/telemetry" -type f 2>/dev/null | wc -l | tr -d ' ')
2390
2442
  if [[ "$tel_files" -gt 0 ]]; then
2391
- echo " $(_yellow "⚠") residual $tel_files telemetry files in ~/.claude/telemetry/"
2392
- echo " $(_dim "hint: rm -rf ~/.claude/telemetry/")"
2443
+ echo " $(_yellow "⚠") residual $tel_files telemetry files in ~/.claude/telemetry/"
2393
2444
  fi
2394
2445
  fi
2395
-
2396
- # ── concurrent sessions ──
2397
2446
  local _claude_count
2398
2447
  _claude_count=$(pgrep -x "claude" 2>/dev/null | wc -l | tr -d '[:space:]') || _claude_count=0
2399
2448
  local _max_sessions; _max_sessions=$(_cac_setting max_sessions 10)
2400
2449
  if [[ "$_claude_count" -gt "$_max_sessions" ]]; then
2401
- echo " $(_yellow "⚠") sessions $_claude_count running (threshold: $_max_sessions)"
2402
- fi
2403
-
2404
- # ── metadata.user_id consistency ──
2405
- local _env_uid; _env_uid=$(_read "$env_dir/user_id" "")
2406
- if [[ -n "$_env_uid" ]]; then
2407
- local _config_dir="${CLAUDE_CONFIG_DIR:-$ENVS_DIR/$current/.claude}"
2408
- local _cj="$_config_dir/.claude.json"
2409
- [[ -f "$_cj" ]] || _cj="$HOME/.claude.json"
2410
- if [[ -f "$_cj" ]]; then
2411
- local _actual_uid
2412
- _actual_uid=$(python3 -c "import json,sys; print(json.load(open(sys.argv[1])).get('userID',''))" "$_cj" 2>/dev/null || true)
2413
- if [[ -n "$_actual_uid" ]] && [[ "$_actual_uid" != "$_env_uid" ]]; then
2414
- echo " $(_yellow "⚠") user_id mismatch — Claude may have overwritten it"
2415
- echo " $(_dim "env: ${_env_uid:0:16}... json: ${_actual_uid:0:16}...")"
2416
- problems+=("user_id mismatch between env file and .claude.json")
2417
- else
2418
- echo " $(_green "✓") user_id consistent"
2419
- fi
2420
- fi
2421
- fi
2422
-
2423
- # ── git email spoofing ──
2424
- if [[ -f "$env_dir/git_email" ]]; then
2425
- echo " $(_green "✓") git email spoofed ($(_dim "$(_read "$env_dir/git_email")"))"
2426
- else
2427
- echo " $(_yellow "⚠") git email not spoofed (real email exposed)"
2428
- fi
2429
-
2430
- # ── repository fingerprint (rh) ──
2431
- if [[ -f "$env_dir/fake_git_remote" ]]; then
2432
- echo " $(_green "✓") repo hash spoofed"
2433
- else
2434
- echo " $(_yellow "⚠") repo hash not spoofed (rh links activity across accounts)"
2450
+ echo " $(_yellow "⚠") sessions $_claude_count running (threshold: $_max_sessions)"
2435
2451
  fi
2436
-
2437
- # ── billing header ──
2438
- if [[ "$wrapper_content" == *"CLAUDE_CODE_ATTRIBUTION_HEADER"* ]]; then
2439
- echo " $(_green "✓") billing header disabled"
2440
- fi
2441
-
2442
- # ── Keychain residual (macOS) ──
2443
2452
  if [[ "$os" == "macos" ]]; then
2444
- local _kc_found=false
2445
- security find-generic-password -s "claude-code-credentials" >/dev/null 2>&1 && _kc_found=true
2446
- if [[ "$_kc_found" == "true" ]]; then
2447
- echo " $(_yellow "⚠") keychain Trusted Device Token found in macOS Keychain"
2448
- echo " $(_dim "hint: security delete-generic-password -s 'claude-code-credentials'")"
2449
- fi
2450
- fi
2451
-
2452
- # ── persona ──
2453
- if [[ -f "$env_dir/persona" ]]; then
2454
- echo " $(_green "✓") persona $(_dim "$(_read "$env_dir/persona")")"
2453
+ security find-generic-password -s "claude-code-credentials" >/dev/null 2>&1 && \
2454
+ echo " $(_yellow "") keychain Trusted Device Token residual"
2455
2455
  fi
2456
2456
 
2457
2457
  # ── network check (slow — streaming output) ──
@@ -2551,13 +2551,19 @@ cmd_check() {
2551
2551
 
2552
2552
  # ── verbose mode ──
2553
2553
  if [[ "$verbose" == "true" ]]; then
2554
+ echo " $(_bold "Identity")"
2555
+ echo " $([[ "$_fp_ok" == "true" ]] && _green "✓" || _red "✗") hostname $(_read "$env_dir/hostname" "—")"
2556
+ echo " $([[ -f "$env_dir/git_email" ]] && _green "✓" || _yellow "⚠") git email $(_read "$env_dir/git_email" "—")"
2557
+ echo " $([[ -f "$env_dir/fake_git_remote" ]] && _green "✓" || _yellow "⚠") repo hash $(_read "$env_dir/fake_git_remote" "—")"
2558
+ echo " $([[ "$_uid_ok" == "true" ]] && _green "✓" || _yellow "⚠") user_id $(_read "$env_dir/user_id" "—" | cut -c1-16)..."
2559
+ echo " $([[ "$wrapper_content" == *"CLAUDE_CODE_ATTRIBUTION_HEADER"* ]] && _green "✓" || _yellow "⚠") billing $([[ "$wrapper_content" == *"CLAUDE_CODE_ATTRIBUTION_HEADER"* ]] && echo "disabled" || echo "exposed")"
2560
+ [[ -f "$env_dir/persona" ]] && echo " $(_green "✓") persona $(_read "$env_dir/persona")"
2561
+ echo
2554
2562
  echo " $(_bold "Details")"
2555
2563
  echo " $(_dim "UUID") $(_read "$env_dir/uuid")"
2556
2564
  echo " $(_dim "stable_id") $(_read "$env_dir/stable_id")"
2557
- echo " $(_dim "user_id") $(_read "$env_dir/user_id" "—")"
2558
- echo " $(_dim "git_email") $(_read "$env_dir/git_email" "—")"
2559
- echo " $(_dim "rh_remote") $(_read "$env_dir/fake_git_remote" "—")"
2560
- echo " $(_dim "persona") $(_read "$env_dir/persona" "—")"
2565
+ echo " $(_dim "MAC") $(_read "$env_dir/mac_address" "—")"
2566
+ echo " $(_dim "machine_id") $(_read "$env_dir/machine_id" "—")"
2561
2567
  echo " $(_dim "TZ") $(_read "$env_dir/tz" "—")"
2562
2568
  echo " $(_dim "LANG") $(_read "$env_dir/lang" "—")"
2563
2569
  echo " $(_dim "env") ${env_dir/#$HOME/~}/.claude/"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-cac",
3
- "version": "1.5.0-beta.1",
3
+ "version": "1.5.0-beta.2",
4
4
  "description": "Isolate, protect, and manage your Claude Code — versions, environments, identity, and proxy.",
5
5
  "bin": {
6
6
  "cac": "cac"