This commit is contained in:
Manchik
2026-04-25 04:17:13 +03:00
parent c82866b58a
commit 9b7001407f
23 changed files with 1225 additions and 258 deletions
+36 -13
View File
@@ -215,7 +215,9 @@ async def import_accounts(file: UploadFile = File(...)):
Supported formats (: or | separator):
login|password|{mafile_json}
login|password|email|email_password|{mafile_json}
login|password|email|email_password|{mafile_json}|notes
login|password|email|email_password
login|password|email|email_password|notes (no mafile, with notes)
"""
content = (await file.read()).decode("utf-8", errors="ignore")
result = BulkImportResult()
@@ -226,11 +228,27 @@ async def import_accounts(file: UploadFile = File(...)):
if not line:
continue
# Split off embedded mafile JSON (everything from first '{' onward)
notes: str | None = None
# Split off embedded mafile JSON — find matching braces
json_start = line.find("{")
if json_start != -1:
mafile_str = line[json_start:]
depth = 0
json_end = json_start
for i in range(json_start, len(line)):
if line[i] == "{":
depth += 1
elif line[i] == "}":
depth -= 1
if depth == 0:
json_end = i
break
mafile_str = line[json_start : json_end + 1]
prefix = line[:json_start].rstrip("|:")
suffix = line[json_end + 1 :].lstrip("|:")
if suffix:
notes = suffix
else:
mafile_str = None
prefix = line
@@ -262,12 +280,15 @@ async def import_accounts(file: UploadFile = File(...)):
email = mafile_data.get("mail") or mafile_data.get("email") or None
email_password = mafile_data.get("mail_password") or mafile_data.get("email_password") or None
else:
# No mafile — must be exactly 4 fields
if len(parts) != 4:
result.errors.append(f"Invalid line (need 4 fields): {line[:50]}")
# No mafile — 4 fields, or 5 fields with notes
if len(parts) == 5:
login, password, email, email_password, notes = parts
elif len(parts) == 4:
login, password, email, email_password = parts
else:
result.errors.append(f"Invalid line (need 4-5 fields): {line[:50]}")
result.skipped += 1
continue
login, password, email, email_password = parts
mafile_data = None
try:
@@ -281,9 +302,9 @@ async def import_accounts(file: UploadFile = File(...)):
continue
await db.execute(
"""INSERT INTO accounts (login, password, email, email_password)
VALUES (?, ?, ?, ?)""",
(login, password, email or None, email_password or None),
"""INSERT INTO accounts (login, password, email, email_password, notes)
VALUES (?, ?, ?, ?, ?)""",
(login, password, email or None, email_password or None, notes or None),
)
result.imported += 1
except Exception as exc:
@@ -298,7 +319,8 @@ async def import_accounts(file: UploadFile = File(...)):
steam_id = (mafile_data.get("Session") or {}).get("SteamID") or None
settings.mafiles_dir.mkdir(parents=True, exist_ok=True)
dest = settings.mafiles_dir / f"{account_name}.mafile"
safe_name = Path(account_name).name
dest = settings.mafiles_dir / f"{safe_name}.mafile"
dest.write_text(json.dumps(mafile_data, ensure_ascii=False), encoding="utf-8")
await db.execute(
@@ -325,12 +347,13 @@ async def upload_mafile(account_id: int, file: UploadFile = File(...)):
content = (await file.read()).decode("utf-8")
try:
mafile = MafileData.model_validate_json(content)
except Exception:
raise HTTPException(status_code=400, detail="Invalid mafile format")
except Exception as exc:
raise HTTPException(status_code=400, detail=f"Invalid mafile format: {exc}")
settings.mafiles_dir.mkdir(parents=True, exist_ok=True)
steam_id = mafile.Session.SteamID or row["steam_id"] or account_id
mafile_path = settings.mafiles_dir / f"{steam_id}.mafile"
safe_name = Path(str(steam_id)).name
mafile_path = settings.mafiles_dir / f"{safe_name}.mafile"
mafile_path.write_text(content, encoding="utf-8")
await db.execute(
+51
View File
@@ -84,3 +84,54 @@ async def generate_2fa_by_account(request: Generate2FAByAccountRequest):
if not row or not row["shared_secret"]:
raise HTTPException(status_code=404, detail="Account not found or has no shared_secret")
return {"code": gen_code(row["shared_secret"])}
class ConfirmationRespondRequest(BaseModel):
ids: list[str]
nonces: list[str]
accept: bool
@router.get("/confirmations/{account_id}")
async def get_confirmations(account_id: int):
"""Fetch pending Steam confirmations for an account."""
from app.services.steam_confirmations import fetch_confirmations
db = await get_db()
cursor = await db.execute("SELECT * FROM accounts WHERE id = ?", (account_id,))
account = await cursor.fetchone()
if not account:
raise HTTPException(status_code=404, detail="Account not found")
try:
confirmations = await fetch_confirmations(dict(account))
return {"success": True, "confirmations": confirmations}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"[confirmations] Error fetching for account {account_id}: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/confirmations/{account_id}/respond")
async def respond_confirmations(account_id: int, request: ConfirmationRespondRequest):
"""Accept or deny confirmations for an account."""
from app.services.steam_confirmations import respond_to_confirmation
if len(request.ids) != len(request.nonces):
raise HTTPException(status_code=400, detail="ids and nonces must have same length")
db = await get_db()
cursor = await db.execute("SELECT * FROM accounts WHERE id = ?", (account_id,))
account = await cursor.fetchone()
if not account:
raise HTTPException(status_code=404, detail="Account not found")
try:
success = await respond_to_confirmation(dict(account), request.ids, request.nonces, request.accept)
return {"success": success}
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
logger.error(f"[confirmations] Error responding for account {account_id}: {e}")
raise HTTPException(status_code=500, detail=str(e))
+6 -2
View File
@@ -53,19 +53,23 @@ async def upload_mafiles(files: list[UploadFile] = File(...)):
try:
mafile = MafileData.model_validate_json(content)
steam_id = mafile.Session.SteamID or mafile.account_name or file.filename
dest = settings.mafiles_dir / f"{steam_id}.mafile"
safe_name = Path(str(steam_id)).name
dest = settings.mafiles_dir / f"{safe_name}.mafile"
dest.write_text(content, encoding="utf-8")
uploaded += 1
if mafile.account_name:
mafile_steam_id = str(mafile.Session.SteamID) if mafile.Session.SteamID else None
await db.execute(
"""UPDATE accounts
SET mafile_path = ?, shared_secret = ?, identity_secret = ?
SET mafile_path = ?, shared_secret = ?, identity_secret = ?,
steam_id = COALESCE(steam_id, ?)
WHERE login = ?""",
(
str(dest),
mafile.shared_secret or "",
mafile.identity_secret or "",
mafile_steam_id,
mafile.account_name,
),
)