24 Commits

Author SHA1 Message Date
Garfield
2014e03190 fix(oauth): include state in /oauth/connect-claude-ai flow
Claude.ai's MCP auth callback requires a state parameter. Generate a random
state in /oauth/connect-claude-ai and preserve it through the consent form
and login redirect so it is echoed back to claude.ai.
2026-06-12 15:09:19 -04:00
Garfield
f084be6bc6 fix(oauth): register Anthropic Claude.ai redirect_uri for browser MCP flow
Add https://claude.ai/api/mcp/auth_callback to the pre-registered OAuth
client redirect_uris so the new /oauth/connect-claude-ai route works.
ensureOAuthAppRegistered uses ON DUPLICATE KEY UPDATE so the DB row is
updated on the next server startup.
2026-06-12 15:04:46 -04:00
Garfield
6604ab5d2b feat(connect): dedicated Claude.ai / ChatGPT browser connect picker
- Replace single 'Connect to Claude / ChatGPT' button with a modal picker
  offering Claude.ai web, Claude Desktop, Codex CLI, and ChatGPT/GPT Actions.
- Add /oauth/connect-claude-ai backend route that redirects to Anthropic's
  official https://claude.ai/api/mcp/auth_callback OAuth callback.
- Update MCP callback result page with browser-specific instructions for
  Claude.ai web, Claude Desktop, ChatGPT/GPT Actions, and Codex CLI.
- Deploy new app and hermes images to K8s.
2026-06-12 14:55:36 -04:00
Garfield
45cf9cafe6 fix(clients): fall back to env credentials when customer has no per-account creds 2026-06-12 13:14:08 -04:00
Garfield
de6d6ae9de fix(redis): add reconnect strategy to prevent closed client errors 2026-06-12 13:08:36 -04:00
Garfield
663107bfbc deploy: hermes-mcp reviewer enum + squaremcp-site legal update 2026-06-12 12:13:56 -04:00
Garfield
d1ff459b46 chore(k8s): deploy Facebook/Instagram creds from vault (token currently 500) 2026-06-12 09:45:51 -04:00
Garfield
bc58befd5e feat(ui): v1 launch — consumer hero, onboarding flow, Obsidian app card 2026-06-12 06:39:07 -04:00
Garfield
f74f90a2f0 fix(webhook): preserve raw body for Meta webhook HMAC validation
The global express.json() middleware at line 77 was parsing the body
into a JS object before the route-level express.raw() could capture
the raw Buffer. When WHATSAPP_APP_SECRET is set and a signature is
present, crypto.createHmac().update(req.body) received an Object
instead of Buffer, throwing TypeError and crashing the process.

Fix: register app.use('/webhook/whatsapp', express.raw({ type: '*/*' }))
before app.use(express.json()) so the raw body is preserved for HMAC.

Post-deploy verification: all 7 webhook tests pass, pod 0 restarts.

Related: SquareMCP/2026-06-10-twilio-whatsapp-webhook-deployment.md
2026-06-10 22:37:00 -04:00
Garfield
7ddb6d48b4 fix(email): route sqcp SMTP through Azure ACS relay
Replaces direct Poste.io SMTP (mail.squaremcp.com:30587, port 25 blocked)
with Azure Communication Services relay (smtp.azurecomm.net:587).
All sqcp_* accounts share a single ACS credential; FROM addresses unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 14:22:21 -04:00
Garfield
da4058483a fix(auth): switch to K8s Redis, add claude.ai/chatgpt CORS origins
- REDIS_URL → K8s ClusterIP with auth (fixes silent hang on host Redis)
- Socket timeouts (connectTimeout 3s, socketTimeout 5s) on Redis client
- Add claude.ai, chatgpt.com, chat.openai.com to CORS allowlist
- Update hermes-mcp image SHA (includes above changes)
- Add squaremcp-broker-demo.mp4 to site Dockerfile; bump site image SHA

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 05:39:48 -04:00
Garfield
34983c44e2 security: fix reset token leak, add rate limiting, body limits, webhook HMAC, JWT_SECRET
- CRITICAL: forgot-password no longer returns token in response; sends email via info@squaremcp.com instead
- Rate limit: login 10/15min, forgot-password 5/hr, chat 30/hr (Redis, per IP)
- express.json() capped at 100kb
- WhatsApp webhook HMAC verification (activates when WHATSAPP_APP_SECRET is set)
- JWT_SECRET now explicitly set in K8s (was falling back to CREDENTIAL_ENCRYPTION_KEY)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 20:14:08 -04:00
Garfield
423dc89c94 perf(oauth): Redis-cache getTokenCustomer to eliminate uncached DB hit on every ChatGPT API call
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 20:02:02 -04:00
Garfield
4746c4ee1c fix(whatsapp): fall back to default Twilio account when customer has no WhatsApp creds
Customers who haven't connected WhatsApp in the dashboard now
automatically use the SquareMCP default number (+19547385805 via Twilio)
instead of throwing 'WhatsApp not connected'. Routing flag usingDefault
replaces the !customer check so OAuth sessions get the same Twilio path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:46:21 -04:00
Garfield
c270f8f74b fix(oauth): allow wildcard ChatGPT callback URI pattern
ChatGPT regenerates its GPT ID (and callback URL) every time the GPT
is saved, making exact redirect_uri matching impossible. Added support
for the registered URI pattern https://chat.openai.com/aip/*/oauth/callback
which matches any valid ChatGPT GPT callback via regex.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 00:15:46 -04:00
Garfield
c6504ec60f feat: /openapi-chatgpt.json — 29-op spec for ChatGPT Custom GPT limit
Drops obsidian (5 ops) and whatsapp/templates list (1 op) to stay
under ChatGPT's 30-operation cap. Served at /openapi-chatgpt.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:39:02 -04:00
Garfield
b67146dfc8 feat(whatsapp): Twilio send path for default account + API v21
The SquareMCP number (+19547385805) is registered under Twilio's BSP,
so direct Meta API sends were blocked with #200 permission errors.
Default account now routes through Twilio's REST API; customer-owned
accounts still use Meta's Cloud API directly.

- twilioSend(): POST to api.twilio.com with Basic auth
- resolveTemplateText(): fetches template body from Meta, substitutes
  {{1}}/{{}} parameters, so templates render correctly via Twilio
- Bumped WHATSAPP_API_VERSION to v21.0
- Added TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, TWILIO_WHATSAPP_NUMBER,
  WHATSAPP_DEFAULT_BUSINESS_ACCOUNT_ID to K8s deployment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 21:34:42 -04:00
Garfield
dcc1c39754 chore: add WhatsApp credentials for SquareMCP number +19547385805
WHATSAPP_DEFAULT_PHONE_NUMBER_ID, WHATSAPP_DEFAULT_ACCESS_TOKEN,
and WA_VERIFY_TOKEN (hermes-wa-2026) added to K8s deployment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 13:15:24 -04:00
Garfield
d89df87a6c feat: Twilio voice webhook to reject calls on WhatsApp number
POST /webhook/twilio/voice returns TwiML that says the number doesn't
accept voice calls and hangs up — needed for Twilio number config.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 12:31:09 -04:00
Garfield
adebe29ca0 feat: Slack alerts for chat widget escalations + support@ email polling
- notifications/slack.ts: added sendChatEscalationAlert (fires when visitor
  asks about pricing, demo, help, or a human) and sendSupportEmailAlert
- email-poller.ts: polls support@squaremcp.com every 5 min via IMAP,
  deduplicates with Redis (support📧alerted_uids), fires Slack alert
  for each new unseen message
- index.ts: detectEscalation() scans last user message for trigger phrases;
  chat endpoint fires alert fire-and-forget after responding; startEmailPoller()
  called on server boot

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 21:47:43 -04:00
Garfield
d613119d55 chore: add SLACK_DEFAULT_BOT_TOKEN to K8s deployment
Enables Slack demo tools in the chat widget agent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 19:29:47 -04:00
Garfield
18b838c268 feat: ChatGPT Custom GPT support in chat bot + sqcp SMTP routing fix
- chat.ts: system prompt now includes step-by-step ChatGPT Custom GPT
  setup (openapi.json import + OAuth), Claude/Cursor/Windsurf config,
  and mortgage broker guidance — bot no longer incorrectly says ChatGPT
  is unsupported
- smtp.ts: all sqcp_* accounts now route to mail.squaremcp.com (SQCP_SMTP_HOST)
  instead of the fetcherpay server
- tools.ts: ACCOUNT_PARAM description now lists all 14 mailboxes including
  the 7 squaremcp.com accounts so Claude picks the right one without guessing
- package.json: postinstall hook runs imapflow patch script after npm install
- hermes-k8s.yaml: updated image digest to current production build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:53:42 -04:00
Garfield
1f8d97b6bd fix: serve chat-widget.js correctly in production
- Copy product/ into Docker image (was missing from final stage)
- Fix static file path: ../../product → ../product (wrong depth from dist/index.js)
- Add ANTHROPIC_API_KEY to K8s manifest (chat endpoint was returning 500)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 18:45:43 -04:00
Garfield
38e367ea58 feat(email): add all 7 squaremcp.com email accounts
- New accounts: sqcp_garfield, sqcp_info, sqcp_sales, sqcp_support,
  sqcp_founder, sqcp_contact, sqcp_admin
- All use same poste.io mail server as fetcherpay.com (IMAP 30993, SMTP 30587)
- Password: onelove for all accounts
- Updated: imap.ts, smtp.ts, tools.ts, manifest.ts, hermes-k8s.yaml
2026-05-15 11:34:56 -04:00