Closes #227. Auth is disabled by default (AUTH_ENABLED=false) so localhost usage is unaffected. Set AUTH_ENABLED=true + NEXT_PUBLIC_AUTH_ENABLED=true to require login when hosting publicly. Backend - New deeptutor/services/auth.py: bcrypt password hashing, JWT create/decode, multi-user JSON store with role + created_at schema, auto-migration of old flat-hash format, first-user → admin bootstrap - New deeptutor/api/routers/auth.py: require_auth / require_admin FastAPI dependencies; public endpoints /login /logout /status /register /is_first_user; admin-only /users /users/{u}/role - deeptutor/api/main.py: Depends(require_auth) applied to all 14 protected routers - deeptutor/api/routers/unified_ws.py: cookie-based JWT check before ws.accept() when AUTH_ENABLED - Added bcrypt>=4.0.0 and python-jose[cryptography]>=3.3.0 to requirements/server.txt and pyproject.toml extras Frontend - web/middleware.ts: route protection; /login and /register are public - web/lib/api.ts: apiFetch wrapper — credentials:include + 401→login - web/lib/auth.ts: login/logout/fetchAuthStatus + register() + checkIsFirstUser() - web/lib/admin-api.ts: listUsers / deleteUser / setUserRole - web/lib/session-api.ts: credentials:include on all fetches; expectJson redirects to /login on 401 instead of throwing - web/app/(auth)/login/page.tsx: auto-redirects to /register when no users exist; shows success banner after registration - web/app/(auth)/register/page.tsx: new registration page with first-user admin notice and password confirmation - web/app/(admin)/admin/users/page.tsx: admin dashboard — user table with role toggle and delete; guards against self-demotion/deletion - AdminLink and LogoutButton hidden when AUTH_ENABLED=false - .env.example and README.md updated with auth vars and setup guide Made-with: Cursor
378 lines
11 KiB
Plaintext
378 lines
11 KiB
Plaintext
{
|
|
"version": "1.5.0",
|
|
"plugins_used": [
|
|
{
|
|
"name": "ArtifactoryDetector"
|
|
},
|
|
{
|
|
"name": "AWSKeyDetector"
|
|
},
|
|
{
|
|
"name": "AzureStorageKeyDetector"
|
|
},
|
|
{
|
|
"name": "Base64HighEntropyString",
|
|
"limit": 4.5
|
|
},
|
|
{
|
|
"name": "BasicAuthDetector"
|
|
},
|
|
{
|
|
"name": "CloudantDetector"
|
|
},
|
|
{
|
|
"name": "DiscordBotTokenDetector"
|
|
},
|
|
{
|
|
"name": "GitHubTokenDetector"
|
|
},
|
|
{
|
|
"name": "GitLabTokenDetector"
|
|
},
|
|
{
|
|
"name": "HexHighEntropyString",
|
|
"limit": 3.0
|
|
},
|
|
{
|
|
"name": "IbmCloudIamDetector"
|
|
},
|
|
{
|
|
"name": "IbmCosHmacDetector"
|
|
},
|
|
{
|
|
"name": "IPPublicDetector"
|
|
},
|
|
{
|
|
"name": "JwtTokenDetector"
|
|
},
|
|
{
|
|
"name": "KeywordDetector",
|
|
"keyword_exclude": ""
|
|
},
|
|
{
|
|
"name": "MailchimpDetector"
|
|
},
|
|
{
|
|
"name": "NpmDetector"
|
|
},
|
|
{
|
|
"name": "OpenAIDetector"
|
|
},
|
|
{
|
|
"name": "PrivateKeyDetector"
|
|
},
|
|
{
|
|
"name": "PypiTokenDetector"
|
|
},
|
|
{
|
|
"name": "SendGridDetector"
|
|
},
|
|
{
|
|
"name": "SlackDetector"
|
|
},
|
|
{
|
|
"name": "SoftlayerDetector"
|
|
},
|
|
{
|
|
"name": "SquareOAuthDetector"
|
|
},
|
|
{
|
|
"name": "StripeDetector"
|
|
},
|
|
{
|
|
"name": "TelegramBotTokenDetector"
|
|
},
|
|
{
|
|
"name": "TwilioKeyDetector"
|
|
}
|
|
],
|
|
"filters_used": [
|
|
{
|
|
"path": "detect_secrets.filters.allowlist.is_line_allowlisted"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
|
|
"min_level": 2
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_indirect_reference"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_likely_id_string"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_lock_file"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_potential_uuid"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_sequential_string"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_swagger_file"
|
|
},
|
|
{
|
|
"path": "detect_secrets.filters.heuristic.is_templated_secret"
|
|
}
|
|
],
|
|
"results": {
|
|
".env.example_CN": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": ".env.example_CN",
|
|
"hashed_secret": "ec417f567082612f8fd6afafe1abcab831fca840",
|
|
"is_verified": false,
|
|
"line_number": 19
|
|
}
|
|
],
|
|
"deeptutor/agents/guide/agents/interactive_agent.py": [
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "deeptutor/agents/guide/agents/interactive_agent.py",
|
|
"hashed_secret": "559f33e318ea8360e316ec7409de63272a7daea0",
|
|
"is_verified": false,
|
|
"line_number": 88
|
|
},
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "deeptutor/agents/guide/agents/interactive_agent.py",
|
|
"hashed_secret": "fe9ae166dc80168f37e50564be9e45c016a48cd0",
|
|
"is_verified": false,
|
|
"line_number": 89
|
|
},
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "deeptutor/agents/guide/agents/interactive_agent.py",
|
|
"hashed_secret": "482f1d4d250823ce0ff5fad9dfaf0d471835aedb",
|
|
"is_verified": false,
|
|
"line_number": 90
|
|
}
|
|
],
|
|
"deeptutor/agents/solve/main_solver.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "deeptutor/agents/solve/main_solver.py",
|
|
"hashed_secret": "985b05576c57bdeccfcaf33261ea1c43ce7e3155",
|
|
"is_verified": false,
|
|
"line_number": 184
|
|
}
|
|
],
|
|
"deeptutor/api/routers/system.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "deeptutor/api/routers/system.py",
|
|
"hashed_secret": "985b05576c57bdeccfcaf33261ea1c43ce7e3155",
|
|
"is_verified": false,
|
|
"line_number": 160
|
|
}
|
|
],
|
|
"deeptutor/services/config/provider_runtime.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "deeptutor/services/config/provider_runtime.py",
|
|
"hashed_secret": "985b05576c57bdeccfcaf33261ea1c43ce7e3155",
|
|
"is_verified": false,
|
|
"line_number": 331
|
|
}
|
|
],
|
|
"deeptutor/services/search/base.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "deeptutor/services/search/base.py",
|
|
"hashed_secret": "8ee9d3cc35862a8ad26f9e27fb60db0e22ffe145",
|
|
"is_verified": false,
|
|
"line_number": 18
|
|
}
|
|
],
|
|
"tests/agents/test_base_agent_binding.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/agents/test_base_agent_binding.py",
|
|
"hashed_secret": "e9a5f12a8ecbb3eb46eca5096b5c52aa5e7c9fdd",
|
|
"is_verified": false,
|
|
"line_number": 18
|
|
}
|
|
],
|
|
"tests/core/test_builtin_tools.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/core/test_builtin_tools.py",
|
|
"hashed_secret": "a62f2225bf70bfaccbc7f1ef2a397836717377de",
|
|
"is_verified": false,
|
|
"line_number": 188
|
|
}
|
|
],
|
|
"tests/services/config/test_embedding_runtime.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_embedding_runtime.py",
|
|
"hashed_secret": "9aaa910eb49fa1f278c7288f0fa6001c16965716",
|
|
"is_verified": false,
|
|
"line_number": 68
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_embedding_runtime.py",
|
|
"hashed_secret": "985b05576c57bdeccfcaf33261ea1c43ce7e3155",
|
|
"is_verified": false,
|
|
"line_number": 134
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_embedding_runtime.py",
|
|
"hashed_secret": "e9a5f12a8ecbb3eb46eca5096b5c52aa5e7c9fdd",
|
|
"is_verified": false,
|
|
"line_number": 144
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_embedding_runtime.py",
|
|
"hashed_secret": "8c895e1fc99e38655efea259aaa5510bde46b81c",
|
|
"is_verified": false,
|
|
"line_number": 182
|
|
}
|
|
],
|
|
"tests/services/config/test_provider_runtime.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_provider_runtime.py",
|
|
"hashed_secret": "b07bfd6660c8a5e8f47ed4967498d25f095cb7c5",
|
|
"is_verified": false,
|
|
"line_number": 95
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_provider_runtime.py",
|
|
"hashed_secret": "1e8f4accfda4813178f4f6317c767a915bfbf227",
|
|
"is_verified": false,
|
|
"line_number": 115
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/config/test_provider_runtime.py",
|
|
"hashed_secret": "985b05576c57bdeccfcaf33261ea1c43ce7e3155",
|
|
"is_verified": false,
|
|
"line_number": 163
|
|
}
|
|
],
|
|
"tests/services/embedding/test_client_runtime.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/embedding/test_client_runtime.py",
|
|
"hashed_secret": "e9a5f12a8ecbb3eb46eca5096b5c52aa5e7c9fdd",
|
|
"is_verified": false,
|
|
"line_number": 35
|
|
}
|
|
],
|
|
"tests/services/llm/test_config_module.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/llm/test_config_module.py",
|
|
"hashed_secret": "6b8f36db289d14c3c7ba1bb21147b7a4fa7e7536",
|
|
"is_verified": false,
|
|
"line_number": 40
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/llm/test_config_module.py",
|
|
"hashed_secret": "3acfb2c2b433c0ea7ff107e33df91b18e52f960f",
|
|
"is_verified": false,
|
|
"line_number": 102
|
|
}
|
|
],
|
|
"tests/services/llm/test_factory_provider_exec.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/llm/test_factory_provider_exec.py",
|
|
"hashed_secret": "6b8f36db289d14c3c7ba1bb21147b7a4fa7e7536",
|
|
"is_verified": false,
|
|
"line_number": 15
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/llm/test_factory_provider_exec.py",
|
|
"hashed_secret": "9247e92e3d5c3957c5f5480ec8917b9100baa32d",
|
|
"is_verified": false,
|
|
"line_number": 41
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/llm/test_factory_provider_exec.py",
|
|
"hashed_secret": "627a27ae52d38269376e0117355fefc891b60334",
|
|
"is_verified": false,
|
|
"line_number": 84
|
|
}
|
|
],
|
|
"tests/services/test_model_catalog.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/test_model_catalog.py",
|
|
"hashed_secret": "f2bb1f20475e99c2af44a6f6844c1329bea9d3d2",
|
|
"is_verified": false,
|
|
"line_number": 89
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/test_model_catalog.py",
|
|
"hashed_secret": "21729167f484c69c93d2a1956dace832faee1e6a",
|
|
"is_verified": false,
|
|
"line_number": 107
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/test_model_catalog.py",
|
|
"hashed_secret": "3090ca86558e326f27cb6f36d0592ed339f108be",
|
|
"is_verified": false,
|
|
"line_number": 141
|
|
},
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/services/test_model_catalog.py",
|
|
"hashed_secret": "c02d46771666140734db6f2e650f2b051f448aad",
|
|
"is_verified": false,
|
|
"line_number": 146
|
|
}
|
|
],
|
|
"tests/test_openrouter_provider.py": [
|
|
{
|
|
"type": "Secret Keyword",
|
|
"filename": "tests/test_openrouter_provider.py",
|
|
"hashed_secret": "3acfb2c2b433c0ea7ff107e33df91b18e52f960f",
|
|
"is_verified": false,
|
|
"line_number": 10
|
|
}
|
|
],
|
|
"web/app/(workspace)/guide/hooks/useKaTeXInjection.ts": [
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "web/app/(workspace)/guide/hooks/useKaTeXInjection.ts",
|
|
"hashed_secret": "559f33e318ea8360e316ec7409de63272a7daea0",
|
|
"is_verified": false,
|
|
"line_number": 25
|
|
},
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "web/app/(workspace)/guide/hooks/useKaTeXInjection.ts",
|
|
"hashed_secret": "fe9ae166dc80168f37e50564be9e45c016a48cd0",
|
|
"is_verified": false,
|
|
"line_number": 27
|
|
},
|
|
{
|
|
"type": "Base64 High Entropy String",
|
|
"filename": "web/app/(workspace)/guide/hooks/useKaTeXInjection.ts",
|
|
"hashed_secret": "482f1d4d250823ce0ff5fad9dfaf0d471835aedb",
|
|
"is_verified": false,
|
|
"line_number": 29
|
|
}
|
|
]
|
|
},
|
|
"generated_at": "2026-04-06T16:37:14Z"
|
|
}
|