UNPKG

@updating-secrets/1password-adapter

Version:

1password adapter for the updating-secrets package.

66 lines (65 loc) 2.32 kB
import { assert } from '@augment-vir/assert'; import { arrayToObject, ensureError, mapObjectValuesSync, } from '@augment-vir/common'; import { BaseSecretsAdapter, } from 'updating-secrets'; import { parseUrl } from 'url-vir'; /** * Loads secrets from 1Password. A 1Password `Client` must be created and authorized before passing * it into here. * * @category Adapters */ export class OnePasswordAdapter extends BaseSecretsAdapter { onePasswordClient; constructor(onePasswordClient) { super('OnePasswordAdapter'); this.onePasswordClient = onePasswordClient; } /** Load secrets from the provided 1Password `Client`. */ loadSecrets(secrets) { return mapObjectValuesSync(secrets, (secretName, secretDefinition) => { const onePasswordConfig = secretDefinition.adapterConfig.onePassword; if (!onePasswordConfig) { return new Error(`No 1Password adapter config (required for using OnePasswordAdapter) defined for secret '${secretDefinition.secretName}'.`); } const { itemId, vaultId } = extract1PasswordIds(onePasswordConfig.secretUrl); return this.onePasswordClient.items .get(vaultId, itemId) .then((item) => { const fields = parseFields(item); return fields; }) .catch((error) => { return ensureError(error); }); }); } } /** * Extract the needed parameters for fetching an item from 1Password from an item URL. * * You can find the item URL by navigating to an item in 1Password, expanding the three dots menu, * and clicking "Copy Private Link". * * @category Internal */ export function extract1PasswordIds(url) { const { searchParams } = parseUrl(url); const itemId = searchParams.i?.[0]; const vaultId = searchParams.v?.[0]; assert.isTruthy(itemId, `Missing 1Password item id from url: ${url}`); assert.isTruthy(vaultId, `Missing 1Password vault id from url: ${url}`); return { itemId, vaultId, }; } function parseFields(item) { return arrayToObject(item.fields, (field) => { return { key: field.title, value: field.value, }; }, { useRequired: true, }); }