From 826e0b419800b7500fb5fefac958a98cd1da4cd6 Mon Sep 17 00:00:00 2001 From: dv Date: Mon, 4 May 2026 17:43:53 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BA=D1=80=D0=B5?= =?UTF-8?q?=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/services/ssh.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/app/services/ssh.py b/backend/app/services/ssh.py index c5c8c9c..c1c2ff3 100644 --- a/backend/app/services/ssh.py +++ b/backend/app/services/ssh.py @@ -17,6 +17,7 @@ If the last_auth method fails it is cleared and the full list is tried. """ import asyncio +import hashlib import logging import time from dataclasses import dataclass, field @@ -84,7 +85,13 @@ def _opt_key(opt: _AuthOption) -> str: """Deduplication key for an auth option.""" if opt.type == "key": return f"key:{opt.key_id}:{opt.username}" - return f"password:{opt.cred_id}:{opt.username}" + # For DB-backed credentials we can deduplicate by (cred_id, username). + # For legacy/fallback credentials (cred_id is None), include a password + # fingerprint so different passwords for the same username are still tried. + if opt.cred_id is not None: + return f"password:{opt.cred_id}:{opt.username}" + pwd_fingerprint = hashlib.sha256(opt.password.encode("utf-8")).hexdigest()[:16] + return f"password:inline:{opt.username}:{pwd_fingerprint}" async def _load_key_path(db: AsyncSession, key_id: int) -> Optional[str]: