Support credit cards in 1Password credential parameters (#3746)
This commit is contained in:
committed by
GitHub
parent
e3ecc4b657
commit
75ce98e841
@@ -25,6 +25,7 @@ import { WorkflowParameterInput } from "../../WorkflowParameterInput";
|
||||
import { ParametersState } from "../types";
|
||||
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
|
||||
import { validateBitwardenLoginCredential } from "./util";
|
||||
import { HelpTooltip } from "@/components/HelpTooltip";
|
||||
|
||||
type Props = {
|
||||
type: WorkflowEditorParameterType;
|
||||
@@ -273,19 +274,32 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
|
||||
{type === "credential" && credentialType === "onepassword" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Vault ID</Label>
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Vault ID</Label>
|
||||
<HelpTooltip content="You can find the Vault ID and Item ID in the URL when viewing the item in 1Password on the web." />
|
||||
</div>
|
||||
<Input
|
||||
value={vaultId}
|
||||
onChange={(e) => setVaultId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<HelpTooltip content="Supports all 1Password item types: Logins, Passwords, Credit Cards, Secure Notes, and more." />
|
||||
</div>
|
||||
<Input
|
||||
value={itemId}
|
||||
onChange={(e) => setItemId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-md bg-slate-800 p-2">
|
||||
<div className="space-y-1 text-xs text-slate-400">
|
||||
* Credit Cards: Due to a 1Password limitation, add the
|
||||
expiration date as a separate text field named "Expire Date"
|
||||
in the format MM/YYYY (e.g. 09/2027).
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && credentialType === "azurevault" && (
|
||||
|
||||
@@ -31,6 +31,7 @@ import {
|
||||
} from "../types";
|
||||
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
|
||||
import { validateBitwardenLoginCredential } from "./util";
|
||||
import { HelpTooltip } from "@/components/HelpTooltip";
|
||||
|
||||
type Props = {
|
||||
type: WorkflowEditorParameterType;
|
||||
@@ -357,19 +358,32 @@ function WorkflowParameterEditPanel({
|
||||
{type === "credential" && credentialType === "onepassword" && (
|
||||
<>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Vault ID</Label>
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Vault ID</Label>
|
||||
<HelpTooltip content="You can find the Vault ID and Item ID in the URL when viewing the item in 1Password on the web." />
|
||||
</div>
|
||||
<Input
|
||||
value={vaultId}
|
||||
onChange={(e) => setVaultId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<div className="flex gap-2">
|
||||
<Label className="text-xs text-slate-300">Item ID</Label>
|
||||
<HelpTooltip content="Supports all 1Password item types: Logins, Passwords, Credit Cards, Secure Notes, and more." />
|
||||
</div>
|
||||
<Input
|
||||
value={opItemId}
|
||||
onChange={(e) => setOpItemId(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-md bg-slate-800 p-2">
|
||||
<div className="space-y-1 text-xs text-slate-400">
|
||||
Credit Cards: Due to a 1Password limitation, add the
|
||||
expiration date as a separate text field named “Expire Date”
|
||||
in the format MM/YYYY (e.g. 09/2027).
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{type === "credential" && credentialType === "azurevault" && (
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any, Self
|
||||
|
||||
import structlog
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
from onepassword import ItemFieldType
|
||||
from onepassword.client import Client as OnePasswordClient
|
||||
|
||||
from skyvern.config import settings
|
||||
@@ -452,24 +453,61 @@ class WorkflowRunContext:
|
||||
"context": "These values are placeholders. When you type this in, the real value gets inserted (For security reasons)",
|
||||
}
|
||||
|
||||
# Process all fields
|
||||
# Process all fields generically so it covers passwords and credit cards
|
||||
for field in item.fields:
|
||||
if field.value is None:
|
||||
if not field.value or field.field_type == ItemFieldType.UNSUPPORTED:
|
||||
continue
|
||||
random_secret_id = self.generate_random_secret_id()
|
||||
|
||||
# ignore irrelevant fields to avoid confusing AI
|
||||
if field.id in ["validFrom", "interest", "issuenumber"]:
|
||||
continue
|
||||
|
||||
field_type = field.field_type.value.lower()
|
||||
if field_type == "totp":
|
||||
random_secret_id = self.generate_random_secret_id()
|
||||
totp_secret_id = f"{random_secret_id}_totp"
|
||||
self.secrets[totp_secret_id] = OnePasswordConstants.TOTP
|
||||
totp_secret_value = self.totp_secret_value_key(totp_secret_id)
|
||||
self.secrets[totp_secret_value] = parse_totp_secret(field.value)
|
||||
self.values[parameter.key]["totp"] = totp_secret_id
|
||||
elif field.title and field.title.lower() in ["expire date", "expiry date", "expiration date"]:
|
||||
parts = [part.strip() for part in field.value.strip().split("/")]
|
||||
|
||||
if len(parts) == 2:
|
||||
month, year_part = parts
|
||||
month = month.zfill(2) # ensure '5' becomes '05'
|
||||
|
||||
if len(year_part) == 4:
|
||||
year = year_part[2:] # 2025 -> 25
|
||||
else:
|
||||
year = year_part
|
||||
|
||||
self._add_secret_parameter_value(parameter, "card_exp_month", month)
|
||||
self._add_secret_parameter_value(parameter, "card_exp_year", year)
|
||||
if len(year) == 2:
|
||||
self._add_secret_parameter_value(parameter, "card_exp_mmyy", f"{month}/{year}")
|
||||
self._add_secret_parameter_value(parameter, "card_exp_mmyyyy", f"{month}/20{year}")
|
||||
else:
|
||||
# store the 1password-provided value additionally
|
||||
self._add_secret_parameter_value(parameter, "card_exp", field.value)
|
||||
else:
|
||||
# fallback on the 1password-provided value
|
||||
self._add_secret_parameter_value(parameter, "card_exp", field.value)
|
||||
else:
|
||||
# this will be the username or password or other field
|
||||
key = field.id.replace(" ", "_")
|
||||
secret_id = f"{random_secret_id}_{key}"
|
||||
self.secrets[secret_id] = field.value
|
||||
self.values[parameter.key][key] = secret_id
|
||||
# using more descriptive keys than 1password provides by default
|
||||
if field.id == "ccnum":
|
||||
self._add_secret_parameter_value(parameter, "card_number", field.value)
|
||||
elif field.id == "cardholder":
|
||||
self._add_secret_parameter_value(parameter, "card_holder_name", field.value)
|
||||
elif field.id == "cvv":
|
||||
self._add_secret_parameter_value(parameter, "card_cvv", field.value)
|
||||
else:
|
||||
# this will be the username, password or other fields
|
||||
self._add_secret_parameter_value(parameter, field.id.replace(" ", "_"), field.value)
|
||||
|
||||
# Secure Note support
|
||||
if item.notes:
|
||||
self._add_secret_parameter_value(parameter, "notes", item.notes)
|
||||
|
||||
async def register_bitwarden_login_credential_parameter_value(
|
||||
self,
|
||||
@@ -981,6 +1019,15 @@ class WorkflowRunContext:
|
||||
azure_vault_client = AsyncAzureVaultClient.create_default()
|
||||
return azure_vault_client
|
||||
|
||||
def _add_secret_parameter_value(self, parameter: Parameter, key: str, value: str) -> None:
|
||||
if parameter.key not in self.values:
|
||||
raise ValueError(f"{parameter.key} is missing")
|
||||
|
||||
random_secret_id = self.generate_random_secret_id()
|
||||
secret_id = f"{random_secret_id}_{key}"
|
||||
self.secrets[secret_id] = value
|
||||
self.values[parameter.key][key] = secret_id
|
||||
|
||||
|
||||
class WorkflowContextManager:
|
||||
aws_client: AsyncAWSClient
|
||||
|
||||
Reference in New Issue
Block a user