Member disclosure, three findings (fixes 1-3 of 5): 1. WEBHOOK_TOKEN was both the Open Collective webhook URL token and the X-Admin-Token for every /admin/* route, so anything that learned the webhook URL (OC admins, OC logs, this app's access logs) gained portal admin. The URL token is forced by OC's generic webhooks, which cannot set headers — the reuse is not. Introduce ADMIN_TOKEN, header-only. ADMIN_TOKEN_LEGACY=1 (default) still accepts WEBHOOK_TOKEN and logs a warning, so the admin panel and the scheduler keep working; set ADMIN_TOKEN everywhere, then flip it to 0 and rotate. sweep.sh and the digest script now send ADMIN_TOKEN. 2. The credit-pack path fell back to the webhook payload's own amount when OC could not resolve the order, so a forged POST naming its own totalAmount minted credits for any slug. The payload is now a hint only: an unresolvable order is refused, logged loudly, and emailed to the operator for manual reconciliation. Transient OC failures hold instead of granting blind. 3. Lapsing did not revoke access: both deactivation sites (lapse webhook, nightly sweep) discarded the key token deactivate_member() returns. Member keys carry no max_budget of their own, so they inherit the team's — zero the team budget on deactivation, which blocks every key under it. Key deletion is deliberately NOT used: provisioning reuses the stored sk- token on reactivation, and get_or_create_team does not update an existing team's budget, so the two renewal paths now re-sync the budget explicitly. Failures are loud (log + alert email); deactivation still completes.
32 lines
923 B
JSON
32 lines
923 B
JSON
{
|
|
"id": "coop.inference.member-portal",
|
|
"title": "Member Portal",
|
|
"author": "Inference Cooperative",
|
|
"description": "Membership middleware: syncs Open Collective members with Cloudron users and LiteLLM keys, and injects per-member keys into inference requests.",
|
|
"version": "0.1.0",
|
|
"healthCheckPath": "/health",
|
|
"httpPort": 8000,
|
|
"addons": {
|
|
"localstorage": {},
|
|
"oidc": {
|
|
"loginRedirectUri": "/",
|
|
"logoutRedirectUri": "/"
|
|
},
|
|
"sendmail": {},
|
|
"scheduler": {
|
|
"membership_sweep": {
|
|
"schedule": "0 3 * * *",
|
|
"command": "/app/code/sweep.sh"
|
|
},
|
|
"rag_refresh": {
|
|
"schedule": "30 3 * * *",
|
|
"command": "/app/code/rag_refresh.py"
|
|
}
|
|
}
|
|
},
|
|
"manifestVersion": 2,
|
|
"website": "https://inference.coop",
|
|
"contactEmail": "info@inference.coop",
|
|
"dockerImage": "registry.inference.coop/co-op/member-portal:20261026-e55d8a3"
|
|
}
|