fix bitwarden credential search (#932)

This commit is contained in:
LawyZheng
2024-10-09 02:38:34 +08:00
committed by GitHub
parent e2bff34a07
commit 18cebb21e1

View File

@@ -7,6 +7,7 @@ from enum import StrEnum
import structlog
import tldextract
from pydantic import BaseModel
from skyvern.config import settings
from skyvern.exceptions import (
@@ -53,6 +54,11 @@ class BitwardenConstants(StrEnum):
CREDIT_CARD_BRAND = "BW_CREDIT_CARD_BRAND"
class BitwardenQueryResult(BaseModel):
credential: dict[str, str]
uris: list[str]
class BitwardenService:
@staticmethod
def run_command(command: list[str], additional_env: dict[str, str] | None = None) -> subprocess.CompletedProcess:
@@ -157,8 +163,9 @@ class BitwardenService:
BitwardenService.sync()
session_key = BitwardenService.unlock(master_password)
# Extract the domain(with suffix) from the URL and search for items in Bitwarden with that domain
domain = tldextract.extract(url).registered_domain
# Extract the domain from the URL and search for items in Bitwarden with that domain
extract_url = tldextract.extract(url)
domain = extract_url.domain
list_command = [
"bw",
"list",
@@ -217,33 +224,40 @@ class BitwardenService:
e=BitwardenTOTPError(totp_result.stderr),
)
totp_code = totp_result.stdout
credentials: list[dict[str, str]] = [
{
BitwardenConstants.USERNAME: item["login"]["username"],
BitwardenConstants.PASSWORD: item["login"]["password"],
}
bitwarden_result: list[BitwardenQueryResult] = [
BitwardenQueryResult(
credential={
BitwardenConstants.USERNAME: item.get("login", {}).get("username", ""),
BitwardenConstants.PASSWORD: item.get("login", {}).get("password", ""),
},
uris=[uri.get("uri") for uri in item.get("login", {}).get("uris", []) if "uri" in uri],
)
for item in items
if "login" in item
]
if totp_code:
for credential in credentials:
credential[BitwardenConstants.TOTP] = totp_code
if len(credentials) == 0:
if totp_code:
for single_result in bitwarden_result:
single_result.credential[BitwardenConstants.TOTP] = totp_code
if len(bitwarden_result) == 0:
return {}
if len(credentials) == 1:
return credentials[0]
if len(bitwarden_result) == 1:
return bitwarden_result[0].credential
# Choose multiple credentials according to the defined rule,
# if no cred matches the rule, return the first one.
# TODO: For now hard code to choose the first valid email username
for cred in credentials:
if is_valid_email(cred.get(BitwardenConstants.USERNAME)):
return cred
# TODO: For now hard code to choose the first matched result
for single_result in bitwarden_result:
# check the username is a valid email
if is_valid_email(single_result.credential.get(BitwardenConstants.USERNAME)):
for uri in single_result.uris:
# check if the register_domain is the same
if extract_url.registered_domain == tldextract.extract(uri).registered_domain:
return single_result.credential
LOG.warning("No credential in Bitwarden matches the rule, returning the first match")
return credentials[0]
return bitwarden_result[0].credential
finally:
# Step 4: Log out
BitwardenService.logout()