chore(security): remove committed secrets/dumps, .env-based config, hardened deploy webhook
- Delete backups/*.dump and all real credentials from README/docs
(prod MinIO creds, Casdoor passwords, server IP, admin password)
- All stack secrets now come from git-ignored .env (.env.example added);
docker-compose.prod.yml refuses to boot without them (${VAR:?})
- seed_casdoor.py: bcrypt password hashing, generated console/client secrets
- Harden infra/deploy-webhook: HMAC-verified Gitea webhook receiver
+ systemd unit + README (replaces unauthenticated deploy endpoint)
- docs/SECRET-MANAGEMENT.md: secret inventory + rotation checklist
This commit is contained in:
@@ -18,24 +18,39 @@ for the in-page login flow.
|
||||
import http.cookiejar
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import urllib.request
|
||||
|
||||
import bcrypt
|
||||
|
||||
BASE = os.environ.get("CASDOOR_BASE", "http://localhost:8080")
|
||||
ADMIN = os.environ.get("CASDOOR_ADMIN", "admin")
|
||||
ADMIN_PW = os.environ.get("CASDOOR_ADMIN_PW", "123")
|
||||
# Console admin password — MUST be overridden outside local dev (see
|
||||
# docs/SECRET-MANAGEMENT.md); the historical default "123" is gone.
|
||||
ADMIN_PW = os.environ.get("CASDOOR_ADMIN_PW", "")
|
||||
if not ADMIN_PW:
|
||||
ADMIN_PW = secrets.token_urlsafe(12)
|
||||
print(f"[seed] generated Casdoor console admin password: {ADMIN_PW}")
|
||||
|
||||
ORG = "inventory"
|
||||
APP = "inventory-app"
|
||||
CLIENT_ID = "inventory-app-client"
|
||||
CLIENT_SECRET = "inventory-app-secret-2026"
|
||||
CLIENT_SECRET = os.environ.get("CASDOOR_CLIENT_SECRET", "")
|
||||
if not CLIENT_SECRET:
|
||||
CLIENT_SECRET = secrets.token_urlsafe(24)
|
||||
print(f"[seed] generated Casdoor client secret: {CLIENT_SECRET}")
|
||||
REDIRECT_URI = "http://localhost/login" # Traefik edge (v1.3); unused by the in-page flow
|
||||
|
||||
# One password for all seeded dev users — override with CASDOOR_SEED_PASSWORD;
|
||||
# stored as a bcrypt hash (passwordType "bcrypt"), never plaintext.
|
||||
SEED_PASSWORD = os.environ.get("CASDOOR_SEED_PASSWORD", "123456")
|
||||
|
||||
USERS = [
|
||||
# (name, first_name, last_name, email, password)
|
||||
("razaei", "آقای", "رضایی", "razaei@sample.ir", "123456"),
|
||||
("mousavi", "آقای", "موسوی", "mousavi@sample.ir", "123456"),
|
||||
("mohaghegh", "آقای", "محقق", "mohaghegh@sample.ir", "123456"),
|
||||
("tester", "کاربر", "تست", "tester@sample.ir", "123456"),
|
||||
# (name, first_name, last_name, email)
|
||||
("razaei", "آقای", "رضایی", "razaei@sample.ir"),
|
||||
("mousavi", "آقای", "موسوی", "mousavi@sample.ir"),
|
||||
("mohaghegh", "آقای", "محقق", "mohaghegh@sample.ir"),
|
||||
("tester", "کاربر", "تست", "tester@sample.ir"),
|
||||
]
|
||||
|
||||
|
||||
@@ -69,17 +84,21 @@ def _login():
|
||||
return jar
|
||||
|
||||
|
||||
def _bcrypt(pw: str) -> str:
|
||||
return bcrypt.hashpw(pw.encode("utf-8"), bcrypt.gensalt()).decode("ascii")
|
||||
|
||||
|
||||
def main():
|
||||
cookies = _login()
|
||||
if cookies is None:
|
||||
return
|
||||
|
||||
# 1) organization (passwordType "plain" = dev: passwords stored as-is)
|
||||
# 1) organization (bcrypt — passwords are never stored plaintext)
|
||||
status, body = _request("POST", "/api/add-organization", {
|
||||
"owner": "admin",
|
||||
"name": ORG,
|
||||
"displayName": "سازمان تدارکات",
|
||||
"passwordType": "plain",
|
||||
"passwordType": "bcrypt",
|
||||
}, cookies)
|
||||
print("add-organization:", status, body.get("msg", body.get("error", "")))
|
||||
|
||||
@@ -102,7 +121,8 @@ def main():
|
||||
print("add-application:", status, body.get("msg", body.get("error", "")))
|
||||
|
||||
# 3) users (roles are NOT stored here — they live in the app's users table)
|
||||
for name, first, last, email, pw in USERS:
|
||||
pw_hash = _bcrypt(SEED_PASSWORD)
|
||||
for name, first, last, email in USERS:
|
||||
status, body = _request("POST", "/api/add-user", {
|
||||
"owner": ORG,
|
||||
"name": name,
|
||||
@@ -110,21 +130,23 @@ def main():
|
||||
"firstName": first,
|
||||
"lastName": last,
|
||||
"email": email,
|
||||
"password": pw,
|
||||
"passwordType": "plain",
|
||||
"password": pw_hash,
|
||||
"passwordType": "bcrypt",
|
||||
"phone": "",
|
||||
"type": "normal-user",
|
||||
}, cookies)
|
||||
print(f"add-user {name}:", status, body.get("msg", body.get("error", "")))
|
||||
# Ensure passwordType even for already-existing users (this Casdoor
|
||||
# version refuses login when both user and org passwordType are empty).
|
||||
status, body = _request("POST", f"/api/update-user?id={ORG}/{name}&columns=password_type", {
|
||||
"passwordType": "plain",
|
||||
status, body = _request("POST", f"/api/update-user?id={ORG}/{name}&columns=password_type,password", {
|
||||
"passwordType": "bcrypt",
|
||||
"password": pw_hash,
|
||||
}, cookies)
|
||||
print(f"set-password-type {name}:", status, body.get("msg", body.get("error", "")))
|
||||
|
||||
print("\nDone. Casdoor console: http://localhost:8080 (admin/123)")
|
||||
print("Login in the app: http://localhost:3000/login")
|
||||
print("\nDone. Casdoor console: http://localhost:8080")
|
||||
print(f"Seeded users password: {SEED_PASSWORD} (change via CASDOOR_SEED_PASSWORD)")
|
||||
print("Login in the app: http://localhost/login")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user