Fix CWE-78: replace subprocess call with Synapse Admin API in create-user endpoint
Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
co-authored by
naturallaw777
parent
bae790ebb4
commit
942da64332
@@ -5573,32 +5573,60 @@ class MatrixCreateUserRequest(BaseModel):
|
|||||||
|
|
||||||
@app.post("/api/matrix/create-user")
|
@app.post("/api/matrix/create-user")
|
||||||
async def api_matrix_create_user(req: MatrixCreateUserRequest):
|
async def api_matrix_create_user(req: MatrixCreateUserRequest):
|
||||||
"""Create a new Matrix user via register_new_matrix_user."""
|
"""Create a new Matrix user via the Synapse Admin API."""
|
||||||
if not _validate_matrix_username(req.username):
|
if not _validate_matrix_username(req.username):
|
||||||
raise HTTPException(status_code=400, detail="Invalid username. Use only lowercase letters, digits, '.', '_', '-'.")
|
raise HTTPException(status_code=400, detail="Invalid username. Use only lowercase letters, digits, '.', '_', '-'.")
|
||||||
if not req.password:
|
if not req.password:
|
||||||
raise HTTPException(status_code=400, detail="Password must not be empty.")
|
raise HTTPException(status_code=400, detail="Password must not be empty.")
|
||||||
|
|
||||||
admin_flag = ["-a"] if req.admin else ["--no-admin"]
|
# Read domain
|
||||||
cmd = [
|
|
||||||
"register_new_matrix_user",
|
|
||||||
"-c", "/run/matrix-synapse/runtime-config.yaml",
|
|
||||||
"-u", req.username,
|
|
||||||
"-p", req.password,
|
|
||||||
*admin_flag,
|
|
||||||
"http://localhost:8008",
|
|
||||||
]
|
|
||||||
try:
|
try:
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
with open(MATRIX_DOMAINS_FILE, "r") as f:
|
||||||
|
domain = f.read().strip()
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise HTTPException(status_code=500, detail="register_new_matrix_user not found on this system.")
|
raise HTTPException(status_code=500, detail="Matrix domain not configured.")
|
||||||
except subprocess.TimeoutExpired:
|
|
||||||
raise HTTPException(status_code=500, detail="Command timed out.")
|
|
||||||
|
|
||||||
output = (result.stdout + result.stderr).strip()
|
# Parse admin credentials
|
||||||
if result.returncode != 0:
|
try:
|
||||||
# Surface the actual error from the tool (e.g. "User ID already taken")
|
admin_user, admin_pass = _parse_matrix_admin_creds()
|
||||||
raise HTTPException(status_code=400, detail=output or "Failed to create user.")
|
except FileNotFoundError:
|
||||||
|
raise HTTPException(status_code=500, detail="Matrix credentials file not found.")
|
||||||
|
except ValueError as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|
||||||
|
# Obtain admin access token
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
try:
|
||||||
|
token = await loop.run_in_executor(
|
||||||
|
None, _matrix_get_admin_token, domain, admin_user, admin_pass
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Could not authenticate as admin: {exc}")
|
||||||
|
|
||||||
|
# Call Synapse Admin API to create the user
|
||||||
|
target_user_id = f"@{req.username}:{domain}"
|
||||||
|
url = f"http://[::1]:8008/_synapse/admin/v2/users/{urllib.parse.quote(target_user_id, safe='@:')}"
|
||||||
|
payload = json.dumps({"password": req.password, "admin": req.admin}).encode()
|
||||||
|
api_req = urllib.request.Request(
|
||||||
|
url, data=payload,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"******",
|
||||||
|
},
|
||||||
|
method="PUT",
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(api_req, timeout=15) as resp:
|
||||||
|
resp.read()
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
body = exc.read().decode(errors="replace")
|
||||||
|
try:
|
||||||
|
detail = json.loads(body).get("error", body)
|
||||||
|
except Exception:
|
||||||
|
detail = body
|
||||||
|
raise HTTPException(status_code=400, detail=detail)
|
||||||
|
except Exception as exc:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Admin API call failed: {exc}")
|
||||||
|
|
||||||
return {"ok": True, "username": req.username}
|
return {"ok": True, "username": req.username}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user