12 Commits

Author SHA1 Message Date
9df12ac8c5 Fix login being permanently impossible without a pre-existing saved key
api_key_hash is a one-way hash, so /api/login could never hand back a
previously-issued key — the frontend's fallback of reusing whatever key
happened to already be in localStorage meant login only worked on the
exact browser that originally signed up, and was completely broken on
any new device, incognito window, or after clearing storage, even with
the correct password.

/api/login now issues a fresh 'Dashboard Login' named key on every
successful login, replacing only that one key each time (no duplicate
accumulation) and never touching the user's other named keys (e.g. an
already-connected Claude Desktop/Codex client) or the legacy key.

Also fixes a bug this exposed: list_api_keys' legacy-key backfill only
ran when a user had zero rows in api_keys at all, so if login created a
'Dashboard Login' row first, the original signup key would never get
backfilled and would silently vanish from the Tokens page (while still
remaining fully valid for authentication). Backfill now checks
specifically whether the legacy key's hash is already represented,
independent of what other named keys exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 03:02:57 +05:30
7384a6c05a Strip trailing slashes from PUBLIC_URL, CORS_ORIGINS, FRONTEND_BASE_URL
A trailing slash on CORS_ORIGINS never matches a browser's Origin header
(which never includes a path), silently breaking CORS with no error
message beyond the browser's generic "No Access-Control-Allow-Origin
header" — exactly what happened in production after switching domains.
A trailing slash on PUBLIC_URL/FRONTEND_BASE_URL similarly produced
double-slash URLs in API responses and reset-password links. All three
are now normalized at config-load time so a .env typo can't cause this
again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 02:54:15 +05:30
23a14a9710 Rebrand to GetOdooMCP
Renames all user-facing branding to match the new getodoomcp.com domain:
default MCP server name (shown to MCP clients during the initialize
handshake), password-reset email subject/from-address. Internal Python
package name (mt_odoo_mcp) deliberately left unchanged — renaming it would
require updating every import plus the deployed systemd/pm2 invocation,
for zero user-visible benefit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 02:48:53 +05:30
721cde8e9f Update .env.example to the new getodoomcp.com domains
Documents the current production domains (api.getodoomcp.com backend,
getodoomcp.com frontend) and warns against trailing slashes on
PUBLIC_URL/CORS_ORIGINS/FRONTEND_BASE_URL, which caused a CORS + double-
slash 404 bug on the frontend.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 02:35:28 +05:30
b56435e258 Add per-key Odoo connection scoping, fix named keys never authenticating
API keys can now be locked to a single Odoo connection at creation time.
A scoped key's tool calls silently default to that connection when none
is specified, and are rejected outright if the caller explicitly requests
a different one. Unscoped keys (including the legacy key) keep working
across all connections as before. New instance_name column on api_keys,
added via a runtime migration so it applies safely to already-deployed
databases, not just fresh installs.

Also fixes a significant pre-existing bug found while testing this:
get_user_by_api_key (used for both REST and MCP auth) only ever checked
the legacy single-key column — it never checked the api_keys table at
all, meaning every named key created via POST /api/keys was completely
unusable for actual authentication. You could create/list/revoke them,
but never log in with one. Named keys now authenticate correctly
everywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 02:28:18 +05:30
0439811613 Sync legacy api_keys row when the single legacy key is regenerated
regenerate_api_key() only updated users.api_key_hash/prefix, leaving the
backfilled 'Default (legacy)' row in api_keys stale after rotation — not a
security issue (the old hash was still correctly rejected) but the Tokens
page would show a wrong/orphaned prefix for a key that no longer works.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-02 00:31:14 +05:30
05babc6d99 Add password reset, revocable API keys, usage analytics, and admin panel
Adds forgot/reset password flow with dev-mode email logging, multiple
named/revocable API keys per user (replacing the single legacy key model
while keeping it working), per-tool-call usage analytics recorded from the
MCP call_tool handler, and a separate admin API (auth/queries/routes) for
managing all users and viewing system-wide analytics — authenticated via a
hardcoded operator identity, fully isolated from regular user auth.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 17:05:01 +05:30
198b5f1b90 Migrate MCP transport to Streamable HTTP, add session sweeper, CORS, public URL config
Replaces the old SseServerTransport (broken against current MCP clients —
405s on POST, session-id redirects, no protocol negotiation) with
StreamableHTTPServerTransport. Adds an idle-session sweeper to prevent
abandoned client connections from leaking memory indefinitely, CORS
middleware for browser-based frontend access, and PUBLIC_URL/CORS_ORIGINS
settings so signup responses show the correct connection URL instead of a
placeholder.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-01 13:43:34 +05:30
fc6d7c8ca6 Replace passlib with bcrypt directly — fixes bcrypt 5.0 compatibility 2026-06-29 10:06:21 +05:30
3eb9f83853 Fix missing email-validator dep and bad config import 2026-06-29 09:25:17 +05:30
ff8b8995c1 Fix bad import in auth/service.py 2026-06-29 09:20:20 +05:30
b2ca96066b fixed known bugs_new 2026-06-29 09:10:05 +05:30