@axway/amplify-sdk
Version:
Axway Amplify SDK for Node.js
117 lines (103 loc) • 3.25 kB
JavaScript
import crypto from 'crypto';
import errors from '../errors.js';
import FileStore from './file-store.js';
import path from 'path';
import snooplogg from 'snooplogg';
import keytar from 'keytar';
import 'fs-extra';
import './token-store.js';
import 'pluralize';
import '@axway/amplify-utils';
/* eslint-disable security/detect-non-literal-require */
const { log, warn } = snooplogg('amplify-sdk:auth:secure-store');
/**
* A operating-specific secure token store.
*/
class SecureStore extends FileStore {
/**
* The name of the token store file.
* @type {String}
*/
filename = '.tokenstore.secure.v2';
/**
* Loads the `keytar` library and initializes the token file.
*
* @param {Object} opts - Various options.
* @param {String} opts.homeDir - The path to the home directory containing the `lib`
* directory where `keytar` is located.
* @param {Object} [opts.requestOptions] - HTTP client options.
* @param {String} [opts.secureServiceName="Axway AMPLIFY Auth"] - The name of the consumer
* using this library.
* @access public
*/
constructor(opts = {}) {
if (!opts || typeof opts !== 'object') {
throw errors.INVALID_ARGUMENT('Expected opts to be an object');
}
const { homeDir } = opts;
if (!homeDir || typeof homeDir !== 'string') {
throw errors.INVALID_PARAMETER('Secure store requires the home directory to be specified');
}
super(opts);
this.keytar = keytar;
this.serviceName = opts.secureServiceName || 'Axway AMPLIFY Auth';
this.tokenStoreFile = path.join(this.tokenStoreDir, this.filename);
}
/**
* Decodes the supplied string into an object.
*
* @param {String} str - The string to decode into an object.
* @returns {Array}
* @access private
*/
async decode(str) {
try {
return await super.decode(str);
} catch (e) {
if (e.amplifyCode === 'ERR_BAD_KEY') {
await this.keytar.deletePassword(this.serviceName, this.serviceName);
}
throw e;
}
}
/**
* Gets the decipher key or generates a new one if it doesn't exist.
*
* @returns {String}
* @access private
*/
async getKey() {
if (!this._key) {
let key;
try {
key = await this.keytar.getPassword(this.serviceName, this.serviceName);
} catch (err) {
if (process.platform === 'linux') {
// this is likely due to d-bus daemon not running (i.e. "Connection refused") or
// running in a non-desktop (headless) environment (i.e. "Cannot autolaunch D-Bus without X11")
warn(err.message);
throw new Error([
'Unable to get the secure token store key.',
'',
'On Linux, the secure token store requires a desktop environment.',
'SSH sessions and headless environments are not supported.',
'',
'To use the insecure token store, run the following:',
'',
' axway config set auth.tokenStoreType file'
].join('\n'));
}
throw err;
}
if (!key) {
log('Generating new key...');
key = crypto.randomBytes(16).toString('hex');
await this.keytar.setPassword(this.serviceName, this.serviceName, key);
}
Object.defineProperty(this, '_key', { value: Buffer.from(key, 'hex') });
}
return this._key;
}
}
export { SecureStore as default };
//# sourceMappingURL=secure-store.js.map