@updating-secrets/1password-adapter
Version:
1password adapter for the updating-secrets package.
66 lines (65 loc) • 2.32 kB
JavaScript
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,
});
}