← back to Filemaker Mcp

lib/george-auth.js

41 lines

// Resolve the George (Gmail agent, :9850) basic-auth credential from the SAME
// canonical fleet source George itself reads, so a rotation there propagates
// here automatically instead of silently breaking this pipeline.
//
// History: before 2026-07-13 these callers hardcoded an empty password
// ('admin:'). On 2026-07-13 the fleet cred was rotated to a real 32-char pass
// AND George was hardened to fail-closed on empty/invalid creds. The empty
// password started returning 401, which made bin/shopify-sync.js throw
// 'George search failed: 401' at its first step — freezing the Shopify→FileMaker
// order sync at order #32600 (see data/sync.out.log FATAL loop). This resolver
// prevents a recurrence: it always tracks the live fleet cred.
//
// Priority: GEORGE_BASIC_AUTH env → fleet DW-MCP/.env → local filemaker-mcp/.env.
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

function fromEnvFile(path, key) {
  try {
    const m = readFileSync(path, 'utf8').match(new RegExp('^' + key + '=(.+)$', 'm'));
    return m ? m[1].trim() : '';
  } catch {
    return '';
  }
}

export function georgeCred() {
  const HOME = process.env.HOME || '';
  return (
    process.env.GEORGE_BASIC_AUTH ||
    fromEnvFile(join(HOME, 'Projects/Designer-Wallcoverings/DW-MCP/.env'), 'GEORGE_BASIC_AUTH') ||
    fromEnvFile(join(HOME, 'Projects/filemaker-mcp/.env'), 'GEORGE_BASIC_AUTH') ||
    'admin:' // legacy fallback — now rejected by George, so it 401s loudly rather than silently
  );
}

export function georgeAuthHeader() {
  return 'Basic ' + Buffer.from(georgeCred()).toString('base64');
}

export const GEORGE_URL = process.env.GEORGE_URL || 'http://127.0.0.1:9850';