5 Commits
Author SHA1 Message Date
30f9ba92df feat(dashboard): shared resource avatar picker across create/edit drawers (#2285)
* feat(dashboard): shared resource avatar picker across create/edit drawers

Extract ResourceAvatarPicker for experts, teams, skill packages, knowledge
bases, and bridge connections, with upload APIs and schema fold-in for
icon_url. Add team cartoon presets and local/cloud filters on My Experts
and My Teams.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(users): add bridge cloud-collab to the permission catalog

Expose 云端协同 in user/role permission pickers, gate the sidebar and
API behind it, and grant existing accounts once so prior open access is
preserved.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(dashboard): rename built-in experts tab and drop Beta badges

Use “内置专家模板” for the library tab, and remove Beta labels from
My Teams and the cloud-collab nav item.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 13:07:12 +08:00
42e41ed33e feat: add one-shot tasks and split personalization permissions (#2157)
Scheduled jobs can run once and then stop, personalization tabs can be granted separately, and rotated logs use a date-before-extension name.

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-18 07:11:24 +08:00
HUANG Cheng dcb680b421 feat(auth): optional login captcha (slider + tencent/turnstile/hcaptcha/recaptcha) (#679)
* feat(auth): add optional login captcha (slider, turnstile/hcaptcha/recaptcha, tencent)

Password login can now be guarded by a captcha. Default slider stays
client-only; strong providers are verified server-side with the vendor
(Cloudflare Turnstile, hCaptcha, reCAPTCHA v2/v3, Tencent Cloud Captcha).

- infra/auth/captcha: env snapshot + settings blob resolution, provider
  registry with per-vendor verify calls, siteverify with 10s timeout
- GET /api/auth/captcha (public widget config); POST /api/auth/login
  accepts captcha_token; tencent token carries ticket:randstr and is
  checked via GET with the client IP
- admin GET/PUT /api/settings/captcha behind the new captcha permission;
  OCTOP_CAPTCHA_SECRET redacted in envs API; boot validation for strong
  env providers
- dashboard: CaptchaField with slider/checkbox/invisible/popup modes,
  login page wiring, advanced-settings captcha panel
- docs + i18n (en/zh) + unit/integration/frontend tests

* fix(captcha): verify Tencent tickets via DescribeCaptchaResult (TC3)

The legacy ssl.captcha.qq.com/ticket/verify endpoint rejects current
tickets with response=15 "decrypt fail" even for correct
CaptchaAppId/AppSecretKey pairs. Switch to the official ticket-check API:

- POST captcha.tencentcloudapi.com DescribeCaptchaResult (2019-07-22),
  TC3-HMAC-SHA256 signed with CAM API keys; AppSecretKey stays in the body
- captcha settings gain cam_secret_id/cam_secret (encrypted at rest,
  env fallback OCTOP_CAPTCHA_CAM_SECRET_ID/KEY); settings view exposes
  cam_secret_id + has_cam_secret; dashboard shows the two fields for the
  tencent provider only
- interpret maps CaptchaCode (1 OK; 7/8/9/15/16/21/100 fail) and
  EvilLevel=100 (malicious) instead of the legacy response=="1"
- TC3 signer moved voice/tencent_sign.py -> utils/tencent_sign.py (shared)
- drop the redundant Host header from signed requests: httpx sets Host
  from the URL (same value the signature covers), and an explicit Host
  let host-routing system proxies intercept localhost mock calls
- secrets no longer appear in httpx URL logs (payload is in the body)
- move the Login Captcha settings tab next to HTTPS

* polish(dashboard): show reCAPTCHA v3 min score only when that provider is active

* fix(dashboard): captcha widgets follow the site locale, not the browser

- tencent popup: userLanguage from i18n.language (was navigator.language)
- turnstile: pass language render option
- hcaptcha/recaptcha/recaptcha-v3: hl script param from UI locale
- slider already renders site-provided labels

* feat(captcha): unlist reCAPTCHA v2 from the settings catalog

No verified deployment key for v2; keep the provider registered so
existing configs still verify, but stop offering it in the dropdown
(list_providers now filters on a per-provider listed flag).

* feat(cli): octop captcha reset — offline lockout escape hatch

Clears the stored captcha settings blob so login falls back to the
built-in slider when a misconfigured provider blocks all logins
(settings UI requires login, so it cannot fix itself). Boot-env
captcha is untouched; a running server needs a restart.
CHANGELOG: cover reset command, TC3 switch, widget language, v2 unlist.

* feat(cli): register octop captcha reset command and add changelog

Without the registry entry the command module from c5a7649d was
unreachable; CHANGELOG covers the login captcha feature, the TC3
ticket-check switch, widget locale, v2 unlisting, and captcha reset.

* fix(captcha): close pre-merge gaps + document the provider architecture

- envs API: redact OCTOP_CAPTCHA_CAM_SECRET_KEY like OCTOP_CAPTCHA_SECRET
  (was exposed in plaintext by GET /api/envs)
- validate_boot: env-only tencent provider now requires the CAM keys,
  failing fast at boot instead of at first login
- docs/configuration.md: document the two CAM env vars; note recaptcha
  v2 is unlisted but resolvable
- providers.py: architecture docstring (four layers + settled design
  decisions + adding-a-vendor recipe); rename _SuccessProvider to
  _FormPostProvider; drop the register() cast, which exposed a real
  structural bug: frozen-dataclass providers never satisfied the
  Protocol's mutable metadata members — declare them read-only
  properties so the structural check is real
- verify.py: docstring naming it the execution layer
2026-09-16 21:23:32 +08:00
jubaoliang fa2f6a7f56 feat(browser): isolate harness-browser profiles per Octop user
Replace the legacy shared/default Playwright session router with
per-user harness-browser profiles (`user-<id>`) so concurrent users no
longer share one Chrome session, cookie jar, or recording. The backend
now always derives the profile from the authenticated user (or the IM
thread's agent owner) instead of trusting client-supplied profile/session
ids, and a BrowserProfileMiddleware pins tool-selected profiles to the
same boundary. Also dedupes ThreadRegistry's session-refresh logic.
2026-09-05 08:35:26 +08:00
jubaoliangandjubaoliang 041628cb76 feat: per-user module permissions (RBAC) with admin bypass (#276)
* feat: add per-user module permissions (RBAC) with admin bypass

Introduce a module-level permission system so non-admin users can be
scoped to a subset of dashboard modules. Adds a `permissions` TEXT column
on the `users` table (migration 006, SQLite + PostgreSQL), a central
permission catalog in `infra/users/permissions.py`, backend ACL checks
across routers, and dashboard gating via `RequirePermission` /
`ForbiddenPage` keyed by nav module. `admin` always bypasses every gate;
read access and chat/agent use are never gated.

* fix: gate connector install-cli by connectors permission (not admin-only)

The host CLI installer is a connectors-module operation and should be
gated by the `connectors` module permission, consistent with the rest of
the connector routes, instead of being admin-only.

The earlier RBAC change demoted this route from `current_admin` but the
test `test_install_cli_forbidden_for_non_admin` still failed because the
`create_user` test helper grants `BASELINE_PERMISSIONS` (which includes
`connectors`) by default, so the "non-admin" user actually held the
permission. Gate the route with `require_permission("connectors")` and
create the test user with `permissions=[]` so it genuinely lacks the
key and is rejected with 403.

---------

Co-authored-by: jubaoliang <jubaoliang@tencent.com>
2026-08-14 14:05:37 +08:00