From 371352e83609c765b6f75a60e243bd407698708f Mon Sep 17 00:00:00 2001 From: Paul O'Fallon Date: Sun, 24 Feb 2019 17:47:50 -0500 Subject: [PATCH] Update packaging, bump version --- lib/alks.node.js => dist/alks.cjs.js | 2 +- dist/alks.esm.js | 566 ++++++++++++++++++++++++++ dist/alks.js | 146 ------- dist/alks.min.js | 2 +- dist/alks.umd.js | 578 +++++++++++++++++++++++++++ karma.conf.js | 2 +- package.json | 9 +- rollup.config.js | 31 +- 8 files changed, 1171 insertions(+), 165 deletions(-) rename lib/alks.node.js => dist/alks.cjs.js (99%) create mode 100644 dist/alks.esm.js delete mode 100644 dist/alks.js create mode 100644 dist/alks.umd.js diff --git a/lib/alks.node.js b/dist/alks.cjs.js similarity index 99% rename from lib/alks.node.js rename to dist/alks.cjs.js index ebb30900..a25b2f6c 100644 --- a/lib/alks.node.js +++ b/dist/alks.cjs.js @@ -1,6 +1,6 @@ 'use strict'; -var version = "1.0.1"; +var version = "1.1.0"; const Buffer = require('buffer').Buffer; const fetch = require('node-fetch'); diff --git a/dist/alks.esm.js b/dist/alks.esm.js new file mode 100644 index 00000000..9107b737 --- /dev/null +++ b/dist/alks.esm.js @@ -0,0 +1,566 @@ +var version = "1.1.0"; + +const fetch = window.fetch.bind(window); + +/** + * ALKS JavaScript API + * + */ +class alks { + constructor(props, existing = {}) { + this.defaults = Object.assign({}, existing, { _fetch: fetch }, props); + } + + /** + * Encodes a string to base 64 + * + * @param {string} str - the string to encode + * @private + * @returns {string} the base64 encoded string + * @example + * var input = 'password' + * alks.base64Encode(input) + */ + _base64Encode(str = '') { + { + return btoa(str) + } + } + + /** + * Returns a new instance of alks with pre-defined properties (which don't need to be supplied to every method). + * + * Any of the properties required by other methods can be specified here. + * + * Properties present on the current object are carried through to the newly created one. + * + * @param {Object} props - An object containing settings for the new ALKS object + * @returns {alks} + * @example + * var myAlks = alks.create({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }) + * + * myAlks.getKeys({ + * account: 'anAccount', + * role: 'PowerUser', + * sessionTime: 2 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + create(props) { + return(new alks(props, this.defaults)) + } + + /** + * AWS Account + * @typedef {Object} account + * @property {String} account - The name of the account + * @property {String} role - The user's role in this account + * @property {Boolean} iamKeyActive - Whether credentials with IAM permissions can be provisioned from this account + */ + + /** + * Returns a Promise for an array of AWS accounts (and roles) accessible by the user + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise} + * @example + * alks.getAccounts({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((accounts) => { + * // accounts[0].account, accounts[0].role, accounts[0].iamKeyActive + * }) + */ + getAccounts(props) { + return(this._doFetch('getAccounts', props).then(results => + Object.keys(results.accountListRole).map((key) => ({ + account: key, + role: results.accountListRole[key][0].role, + iamKeyActive: results.accountListRole[key][0].iamKeyActive + })) + )) + } + + /** + * AWS STS Credentials + * @typedef {Object} credentials + * @property {String} accessKey - AWS access key + * @property {String} secretKey - AWS secret key + * @property {String} sessionToken - AWS STS session token + */ + + /** + * Returns a Promise for AWS STS credentials from ALKS. + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The AWS account to use when provisioning the credentials + * @param {string} props.role - The ALKS role to use when provisioning the credentials + * @param {string} props.sessionTime - The session length for the credentials + * @returns {Promise} + * @example + * alks.getKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'PowerUser', + * sessionTime: 2 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + getKeys(props) { + return(this._doFetch('getKeys', props).then(results => + pick(results, ['accessKey', 'secretKey', 'sessionToken']) + )) + } + + /** + * Returns a Promise for AWS STS credentials with IAM permissions from ALKS. + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The AWS account to use when provisioning the credentials + * @param {string} props.role - The ALKS role to use when provisioning the credentials + * @param {number} props.sessionTime - The session length for the credentials + * @returns {Promise} + * @example + * alks.getIAMKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * sessionTime: 1 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + getIAMKeys(props) { + return(this._doFetch('getIAMKeys', props).then(results => + pick(results, ['accessKey', 'secretKey', 'sessionToken']) + )) + } + + /** + * Returns a Promise for an array of available AWS IAM role types + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise>} + * @example + * alks.getAWSRoleTypes({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((roleTypes) { + * // ['AWS Lambda', 'Amazon EC2', ... ] + * }) + */ + getAWSRoleTypes(props) { + return(this._doFetch('getAWSRoleTypes', props).then(results => + JSON.parse(results.roleTypes) + )) + } + + /** + * Returns a Promise for an array of available custom role types + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise>} + * @example + * alks.getNonServiceAWSRoleTypes({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((roleTypes) => { + * // ['AWS Lambda', 'Amazon EC2', ...] + * }) + */ + getNonServiceAWSRoleTypes(props) { + return(this._doFetch('getNonServiceAWSRoleTypes', props).then(results => + JSON.parse(results.roleTypes) + )) + } + + /** + * Custom AWS IAM account role + * @typedef {Object} customRole + * @property {String} roleArn - The Amazon Resource Name (ARN) associated with the new role + * @property {String} denyArns - The ARNs for the deny policies associated with this role + * @property {String} instanceProfileArn - The Instance Profile ARN associated with this role + * @property {Boolean} addedRoleToInstanceProfile - Whether this role was added to an Instance Profile + */ + + /** + * Returns a Promise for the results of creating a new custom AWS IAM account role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role to create + * @param {string} props.roleType - The type of AWS role to use when creating the new role + * @param {number} props.includeDefaultPolicy - Whether to include the default policy in the new role (1 = yes, 0 = no) + * @returns {Promise} + * @example + * alks.createRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName', + * roleType: 'Amazon EC2', + * includeDefaultPolicy: 1 + * }).then((role) => { + * // role.roleArn, role.denyArns, role.instanceProfileArn, role.addedRoleToInstanceProfile + * }) + */ + createRole(props) { + return(this._doFetch('createRole', props).then((results) => { + results.denyArns = results.denyArns.split(','); + return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) + })) + } + + /** + * Returns a Promise for the results of creating a new custom AWS IAM trust role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role to create + * @param {string} props.roleType - The type of AWS role to use when creating the new role + * @param {number} props.includeDefaultPolicy - Whether to include the default policy in the new role (1 = yes, 0 = no) + * @param {string} props.trustArn - The Arn of the existing role to trust + * @param {string} props.trustType - Whether the trust is 'Cross Account' or 'Inner Account' + * @returns {Promise} + * @example + * alks.createNonServiceRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName', + * roleType: 'Amazon EC2', + * includeDefaultPolicy: 1, + * trustArn: 'anExistingRoleArn', + * trustType: 'Cross Account' + * }).then((role) => { + * // role.roleArn, role.denyArns, role.instanceProfileArn, role.addedRoleToInstanceProfile + * }) + */ + createNonServiceRole(props) { + return(this._doFetch('createNonServiceRole', props).then((results) => { + results.denyArns = results.denyArns.split(','); + return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) + })) + } + + /** + * Returns a Promise for an array of AWS custom AWS IAM account roles + * + * @param {Object} props - An object containing the following properties + * @param {String} props.baseUrl - The base URL of the ALKS service + * @param {String} props.accessToken - The OAuth2 access token used to authorize the request + * @param {String} props.account - The user's account associated with the custom role + * @param {String} props.role - The user's role associated with the account + * @returns {Promise} + * @example + * alks.listAWSAccountRoles({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * }).then((roleNames) => { + * // ['customRole1', 'customRole2', ...] + * }) + */ + + listAWSAccountRoles(props) { + return(this._doFetch('listAWSAccountRoles', props).then(results => + JSON.parse(results.jsonAWSRoleList).map(r => r.split('/').slice(-1)[0]) + )) + } + + /** + * Returns a Promise for the Amazon Resource Name (ARN) of a custom AWS IAM account role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWs IAM role + * @returns {Promise} + * @example + * alks.getAccountRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName' + * }).then((roleARN) => { + * // arn:aws:iam::123:role/acct-managed/awsRoleName + * }) + */ + getAccountRole(props) { + return(this._doFetch('getAccountRole', props).then((results) => { + if (!results.roleExists) { + throw new Error(`Role ${props.roleName} does not exist in this account`) + } + return(results.roleARN) + })) + } + + /** + * Returns a Promise for a boolean "true" indicating the role was deleted + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role + * @returns {Promise} + * @example + * alks.deleteRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName' + * }).then(() => { + * // success! + * }) + */ + deleteRole(props) { + return(this._doFetch('deleteRole', props).then(() => true )) + } + + /** + * Response containing access keys. + * + * @typedef {Object} AccessKeys + * @property {string} iamUserArn - the arn of the IAM user owning the long term access keys + * @property {string} accessKey - the long term access key + * @property {string} secretKey - the secret key for the long term access key + * @property {boolean} addedIAMUserToGroup - whether the user was successfuly added to the deny policy group + */ + + /** + * Returns a Promise for the results of creating new IAM user and long-term access keys + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.iamUserName - The name of the IAM user to create + * @returns {Promise} + * @example + * alks.createAccessKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * iamUserName: 'iamUserName' + * }).then((user) => { + * // user.iamUserArn, user.accessKey, user.secretKey, user.addedIAMUserToGroup + * }) + */ + createAccessKeys(props) { + return(this._doFetch('accessKeys', props).then((results) => + pick(results,['iamUserArn', 'accessKey', 'secretKey', 'addedIAMUserToGroup'])) + ) + } + + /** + * Returns a Promise for a boolean "true" indicating the IAM user and long-term access keys were deleted + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.iamUserName - The name of the IAM user to delete + * @returns {Promise} + * @example + * alks.deleteIAMUser({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * iamUserName: 'iamUserName' + * }).then(() => { + * // success! + * }) + */ + deleteIAMUser(props) { + return(this._doFetch('IAMUser', props, 'DELETE').then(() => true )) + } + + /** + * Returns the version of the ALKS Rest API + * + * @param {Object} props - An object containing the following properties + * @returns {Promise} + * @example + * alks.version({ + * ... + * }).then((data) => { + * // data.version + * }) + */ + version(props) { + return this._doFetch('version', props, 'GET').then((results) => pick(results, ['version'])) + } + + /** + * Returns information about one of the roles used to generate keys + * + * @param {Object} props - An object containing the following properties + * @param {string} props.accountId - The 12-digit account ID associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @returns {Promise} + * @example + * alks.getLoginRole({ + * ... + * }).then((loginRole) => { + * // loginRole.account, loginRole.role, loginRole.iamKeyActive, loginRole.maxKeyDuration + * }) + */ + getLoginRole(props) { + const {accountId, role} = props; + return this._doFetch(`loginRoles/id/${accountId}/${role}`, null).then((results) => + pick(results, ['account', 'role', 'iamKeyActive', 'maxKeyDuration'])) + } + + /** + * Exchanges a refresh token for an access token + * + * @param {Object} props - An object containing the following properties + * @param {string} props.refreshToken - the refresh token to exchange + * @returns {Promise} + * @example + * alks.getAccessToken({ + * ... + * }).then((data) => { + * // data.accessToken, data.expiresIn + * }) + */ + getAccessToken(props) { + return this._doFetch('accessToken', props).then((results) => + pick(results, ['accessToken', 'expiresIn']) + ) + } + + /** + * Returns a list of a user's refresh tokens (Does not return the full token) + * + * @param {Object} props - An object containing the following properties + * @returns {Array} + * @example + * alks.getRefreshTokens({ + * ... + * }).then((tokens) => { + * // token[i].clientId, token[i].id, token[i].userId, token[i].value + * }) + */ + getRefreshTokens(props) { + return this._doFetch('refreshTokens', props, 'GET').then((results) => + results.refreshTokens.map((token) => pick(token, ['clientId', 'id', 'userId', 'value'])) + ) + } + + /** + * Revokes a refresh or access token + * + * @param {Object} props - An object containing the following properties + * @param {string} [props.token] - the access or refresh token to revoke (Required if tokenId not specified) + * @param {string} [props.tokenId] - the ID of the refresh token to revoke (Required if token not specified) + * @returns {boolean} + * @example + * alks.revoke({ + * token: '...', + * ... + * }).then((success) => { + * // success == true + * }) + * + * // or + * + * alks.revoke({ + * tokenId: '...', + * ... + * }).then((success) => { + * // success == true + * }) + */ + revoke(props) { + return this._doFetch('revoke', props).then((results) => + results.statusMessage == 'Success' + ) + } + + _doFetch(path, args = { }, method = 'POST') { + let opts = Object.assign({}, this.defaults, args); + + let headers = { + 'Content-Type': 'application/json', + 'User-Agent': `AlksJS/${version}`, + }; + + if (opts.accessToken) { + headers['Authorization'] = `Bearer ${opts.accessToken}`; + delete opts.accessToken; + } + + if (opts.userid || opts.password) { + console.error('The userid and password properties are deprecated and should be replaced with an access token'); + const credentials = this._base64Encode(`${opts.userid}:${opts.password}`); + headers['Authorization'] = `Basic ${credentials}`; + delete opts.userid; + delete opts.password; + } + + var responsePromise = opts._fetch(`${opts.baseUrl}/${path}/`, { + method, headers, body: method == 'GET' ? undefined : JSON.stringify(opts) + }); + + // Add catch here to swallow the JSON parsing error (it'll get picked up below) + let jsonPromise = responsePromise.then(r => r.json()).catch(() => {}); + + return Promise.all([responsePromise, jsonPromise]).then(([response, json]) => { + if (!response.ok) { + throw new AlksError(response, json) + } + return(json) + }) + } +} + +const pick = (obj, props) => props.reduce((a, e) => (a[e] = obj[e], a), {}); + +class AlksError extends Error { + constructor(response, json) { + super(response.statusText); + this.status = response.status; + Object.assign(this, json); + } +} + +var alks$1 = new alks(); + +export default alks$1; diff --git a/dist/alks.js b/dist/alks.js deleted file mode 100644 index e5a56e19..00000000 --- a/dist/alks.js +++ /dev/null @@ -1,146 +0,0 @@ -var alks = (function () { - 'use strict'; - - var version = "1.0.1"; - - var fetch = window.fetch.bind(window); - var alks = function alks(props, existing) { - if ( existing === void 0 ) existing = {}; - this.defaults = Object.assign({}, existing, { _fetch: fetch }, props); - }; - alks.prototype._base64Encode = function _base64Encode (str) { - if ( str === void 0 ) str = ''; - { - return btoa(str) - } - }; - alks.prototype.create = function create (props) { - return(new alks(props, this.defaults)) - }; - alks.prototype.getAccounts = function getAccounts (props) { - return(this._doFetch('getAccounts', props).then(function (results) { return Object.keys(results.accountListRole).map(function (key) { return ({ - account: key, - role: results.accountListRole[key][0].role, - iamKeyActive: results.accountListRole[key][0].iamKeyActive - }); }); } - )) - }; - alks.prototype.getKeys = function getKeys (props) { - return(this._doFetch('getKeys', props).then(function (results) { return pick(results, ['accessKey', 'secretKey', 'sessionToken']); } - )) - }; - alks.prototype.getIAMKeys = function getIAMKeys (props) { - return(this._doFetch('getIAMKeys', props).then(function (results) { return pick(results, ['accessKey', 'secretKey', 'sessionToken']); } - )) - }; - alks.prototype.getAWSRoleTypes = function getAWSRoleTypes (props) { - return(this._doFetch('getAWSRoleTypes', props).then(function (results) { return JSON.parse(results.roleTypes); } - )) - }; - alks.prototype.getNonServiceAWSRoleTypes = function getNonServiceAWSRoleTypes (props) { - return(this._doFetch('getNonServiceAWSRoleTypes', props).then(function (results) { return JSON.parse(results.roleTypes); } - )) - }; - alks.prototype.createRole = function createRole (props) { - return(this._doFetch('createRole', props).then(function (results) { - results.denyArns = results.denyArns.split(','); - return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) - })) - }; - alks.prototype.createNonServiceRole = function createNonServiceRole (props) { - return(this._doFetch('createNonServiceRole', props).then(function (results) { - results.denyArns = results.denyArns.split(','); - return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) - })) - }; - alks.prototype.listAWSAccountRoles = function listAWSAccountRoles (props) { - return(this._doFetch('listAWSAccountRoles', props).then(function (results) { return JSON.parse(results.jsonAWSRoleList).map(function (r) { return r.split('/').slice(-1)[0]; }); } - )) - }; - alks.prototype.getAccountRole = function getAccountRole (props) { - return(this._doFetch('getAccountRole', props).then(function (results) { - if (!results.roleExists) { - throw new Error(("Role " + (props.roleName) + " does not exist in this account")) - } - return(results.roleARN) - })) - }; - alks.prototype.deleteRole = function deleteRole (props) { - return(this._doFetch('deleteRole', props).then(function () { return true; } )) - }; - alks.prototype.createAccessKeys = function createAccessKeys (props) { - return(this._doFetch('accessKeys', props).then(function (results) { return pick(results,['iamUserArn', 'accessKey', 'secretKey', 'addedIAMUserToGroup']); }) - ) - }; - alks.prototype.deleteIAMUser = function deleteIAMUser (props) { - return(this._doFetch('IAMUser', props, 'DELETE').then(function () { return true; } )) - }; - alks.prototype.version = function version (props) { - return this._doFetch('version', props, 'GET').then(function (results) { return pick(results, ['version']); }) - }; - alks.prototype.getLoginRole = function getLoginRole (props) { - var accountId = props.accountId; - var role = props.role; - return this._doFetch(("loginRoles/id/" + accountId + "/" + role), null).then(function (results) { return pick(results, ['account', 'role', 'iamKeyActive', 'maxKeyDuration']); }) - }; - alks.prototype.getAccessToken = function getAccessToken (props) { - return this._doFetch('accessToken', props).then(function (results) { return pick(results, ['accessToken', 'expiresIn']); } - ) - }; - alks.prototype.getRefreshTokens = function getRefreshTokens (props) { - return this._doFetch('refreshTokens', props, 'GET').then(function (results) { return results.refreshTokens.map(function (token) { return pick(token, ['clientId', 'id', 'userId', 'value']); }); } - ) - }; - alks.prototype.revoke = function revoke (props) { - return this._doFetch('revoke', props).then(function (results) { return results.statusMessage == 'Success'; } - ) - }; - alks.prototype._doFetch = function _doFetch (path, args, method) { - if ( args === void 0 ) args = { }; - if ( method === void 0 ) method = 'POST'; - var opts = Object.assign({}, this.defaults, args); - var headers = { - 'Content-Type': 'application/json', - 'User-Agent': ("AlksJS/" + (version)), - }; - if (opts.accessToken) { - headers['Authorization'] = "Bearer " + (opts.accessToken); - delete opts.accessToken; - } - if (opts.userid || opts.password) { - console.error('The userid and password properties are deprecated and should be replaced with an access token'); - var credentials = this._base64Encode(((opts.userid) + ":" + (opts.password))); - headers['Authorization'] = "Basic " + credentials; - delete opts.userid; - delete opts.password; - } - var responsePromise = opts._fetch(((opts.baseUrl) + "/" + path + "/"), { - method: method, headers: headers, body: method == 'GET' ? undefined : JSON.stringify(opts) - }); - var jsonPromise = responsePromise.then(function (r) { return r.json(); }).catch(function () {}); - return Promise.all([responsePromise, jsonPromise]).then(function (ref) { - var response = ref[0]; - var json = ref[1]; - if (!response.ok) { - throw new AlksError(response, json) - } - return(json) - }) - }; - var pick = function (obj, props) { return props.reduce(function (a, e) { return (a[e] = obj[e], a); }, {}); }; - var AlksError = (function (Error) { - function AlksError(response, json) { - Error.call(this, response.statusText); - this.status = response.status; - Object.assign(this, json); - } - if ( Error ) AlksError.__proto__ = Error; - AlksError.prototype = Object.create( Error && Error.prototype ); - AlksError.prototype.constructor = AlksError; - return AlksError; - }(Error)); - var alks$1 = new alks(); - - return alks$1; - -}()); diff --git a/dist/alks.min.js b/dist/alks.min.js index d62ddd53..97aa4263 100644 --- a/dist/alks.min.js +++ b/dist/alks.min.js @@ -1 +1 @@ -var alks=function(){"use strict";var n=window.fetch.bind(window),t=function(e,t){void 0===t&&(t={}),this.defaults=Object.assign({},t,{_fetch:n},e)};t.prototype._base64Encode=function(e){return void 0===e&&(e=""),btoa(e)},t.prototype.create=function(e){return new t(e,this.defaults)},t.prototype.getAccounts=function(e){return this._doFetch("getAccounts",e).then(function(t){return Object.keys(t.accountListRole).map(function(e){return{account:e,role:t.accountListRole[e][0].role,iamKeyActive:t.accountListRole[e][0].iamKeyActive}})})},t.prototype.getKeys=function(e){return this._doFetch("getKeys",e).then(function(e){return o(e,["accessKey","secretKey","sessionToken"])})},t.prototype.getIAMKeys=function(e){return this._doFetch("getIAMKeys",e).then(function(e){return o(e,["accessKey","secretKey","sessionToken"])})},t.prototype.getAWSRoleTypes=function(e){return this._doFetch("getAWSRoleTypes",e).then(function(e){return JSON.parse(e.roleTypes)})},t.prototype.getNonServiceAWSRoleTypes=function(e){return this._doFetch("getNonServiceAWSRoleTypes",e).then(function(e){return JSON.parse(e.roleTypes)})},t.prototype.createRole=function(e){return this._doFetch("createRole",e).then(function(e){return e.denyArns=e.denyArns.split(","),o(e,["roleArn","denyArns","instanceProfileArn","addedRoleToInstanceProfile"])})},t.prototype.createNonServiceRole=function(e){return this._doFetch("createNonServiceRole",e).then(function(e){return e.denyArns=e.denyArns.split(","),o(e,["roleArn","denyArns","instanceProfileArn","addedRoleToInstanceProfile"])})},t.prototype.listAWSAccountRoles=function(e){return this._doFetch("listAWSAccountRoles",e).then(function(e){return JSON.parse(e.jsonAWSRoleList).map(function(e){return e.split("/").slice(-1)[0]})})},t.prototype.getAccountRole=function(t){return this._doFetch("getAccountRole",t).then(function(e){if(!e.roleExists)throw new Error("Role "+t.roleName+" does not exist in this account");return e.roleARN})},t.prototype.deleteRole=function(e){return this._doFetch("deleteRole",e).then(function(){return!0})},t.prototype.createAccessKeys=function(e){return this._doFetch("accessKeys",e).then(function(e){return o(e,["iamUserArn","accessKey","secretKey","addedIAMUserToGroup"])})},t.prototype.deleteIAMUser=function(e){return this._doFetch("IAMUser",e,"DELETE").then(function(){return!0})},t.prototype.version=function(e){return this._doFetch("version",e,"GET").then(function(e){return o(e,["version"])})},t.prototype.getLoginRole=function(e){var t=e.accountId,n=e.role;return this._doFetch("loginRoles/id/"+t+"/"+n,null).then(function(e){return o(e,["account","role","iamKeyActive","maxKeyDuration"])})},t.prototype.getAccessToken=function(e){return this._doFetch("accessToken",e).then(function(e){return o(e,["accessToken","expiresIn"])})},t.prototype.getRefreshTokens=function(e){return this._doFetch("refreshTokens",e,"GET").then(function(e){return e.refreshTokens.map(function(e){return o(e,["clientId","id","userId","value"])})})},t.prototype.revoke=function(e){return this._doFetch("revoke",e).then(function(e){return"Success"==e.statusMessage})},t.prototype._doFetch=function(e,t,n){void 0===t&&(t={}),void 0===n&&(n="POST");var o=Object.assign({},this.defaults,t),r={"Content-Type":"application/json","User-Agent":"AlksJS/1.0.1"};if(o.accessToken&&(r.Authorization="Bearer "+o.accessToken,delete o.accessToken),o.userid||o.password){console.error("The userid and password properties are deprecated and should be replaced with an access token");var s=this._base64Encode(o.userid+":"+o.password);r.Authorization="Basic "+s,delete o.userid,delete o.password}var c=o._fetch(o.baseUrl+"/"+e+"/",{method:n,headers:r,body:"GET"==n?void 0:JSON.stringify(o)}),i=c.then(function(e){return e.json()}).catch(function(){});return Promise.all([c,i]).then(function(e){var t=e[0],n=e[1];if(!t.ok)throw new u(t,n);return n})};var o=function(n,e){return e.reduce(function(e,t){return e[t]=n[t],e},{})},u=function(n){function e(e,t){n.call(this,e.statusText),this.status=e.status,Object.assign(this,t)}return n&&(e.__proto__=n),(e.prototype=Object.create(n&&n.prototype)).constructor=e}(Error);return new t}(); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).alks=t()}(this,function(){"use strict";var n=window.fetch.bind(window),t=function(e,t){void 0===t&&(t={}),this.defaults=Object.assign({},t,{_fetch:n},e)};t.prototype._base64Encode=function(e){return void 0===e&&(e=""),btoa(e)},t.prototype.create=function(e){return new t(e,this.defaults)},t.prototype.getAccounts=function(e){return this._doFetch("getAccounts",e).then(function(t){return Object.keys(t.accountListRole).map(function(e){return{account:e,role:t.accountListRole[e][0].role,iamKeyActive:t.accountListRole[e][0].iamKeyActive}})})},t.prototype.getKeys=function(e){return this._doFetch("getKeys",e).then(function(e){return o(e,["accessKey","secretKey","sessionToken"])})},t.prototype.getIAMKeys=function(e){return this._doFetch("getIAMKeys",e).then(function(e){return o(e,["accessKey","secretKey","sessionToken"])})},t.prototype.getAWSRoleTypes=function(e){return this._doFetch("getAWSRoleTypes",e).then(function(e){return JSON.parse(e.roleTypes)})},t.prototype.getNonServiceAWSRoleTypes=function(e){return this._doFetch("getNonServiceAWSRoleTypes",e).then(function(e){return JSON.parse(e.roleTypes)})},t.prototype.createRole=function(e){return this._doFetch("createRole",e).then(function(e){return e.denyArns=e.denyArns.split(","),o(e,["roleArn","denyArns","instanceProfileArn","addedRoleToInstanceProfile"])})},t.prototype.createNonServiceRole=function(e){return this._doFetch("createNonServiceRole",e).then(function(e){return e.denyArns=e.denyArns.split(","),o(e,["roleArn","denyArns","instanceProfileArn","addedRoleToInstanceProfile"])})},t.prototype.listAWSAccountRoles=function(e){return this._doFetch("listAWSAccountRoles",e).then(function(e){return JSON.parse(e.jsonAWSRoleList).map(function(e){return e.split("/").slice(-1)[0]})})},t.prototype.getAccountRole=function(t){return this._doFetch("getAccountRole",t).then(function(e){if(!e.roleExists)throw new Error("Role "+t.roleName+" does not exist in this account");return e.roleARN})},t.prototype.deleteRole=function(e){return this._doFetch("deleteRole",e).then(function(){return!0})},t.prototype.createAccessKeys=function(e){return this._doFetch("accessKeys",e).then(function(e){return o(e,["iamUserArn","accessKey","secretKey","addedIAMUserToGroup"])})},t.prototype.deleteIAMUser=function(e){return this._doFetch("IAMUser",e,"DELETE").then(function(){return!0})},t.prototype.version=function(e){return this._doFetch("version",e,"GET").then(function(e){return o(e,["version"])})},t.prototype.getLoginRole=function(e){var t=e.accountId,n=e.role;return this._doFetch("loginRoles/id/"+t+"/"+n,null).then(function(e){return o(e,["account","role","iamKeyActive","maxKeyDuration"])})},t.prototype.getAccessToken=function(e){return this._doFetch("accessToken",e).then(function(e){return o(e,["accessToken","expiresIn"])})},t.prototype.getRefreshTokens=function(e){return this._doFetch("refreshTokens",e,"GET").then(function(e){return e.refreshTokens.map(function(e){return o(e,["clientId","id","userId","value"])})})},t.prototype.revoke=function(e){return this._doFetch("revoke",e).then(function(e){return"Success"==e.statusMessage})},t.prototype._doFetch=function(e,t,n){void 0===t&&(t={}),void 0===n&&(n="POST");var o=Object.assign({},this.defaults,t),r={"Content-Type":"application/json","User-Agent":"AlksJS/1.1.0"};if(o.accessToken&&(r.Authorization="Bearer "+o.accessToken,delete o.accessToken),o.userid||o.password){console.error("The userid and password properties are deprecated and should be replaced with an access token");var s=this._base64Encode(o.userid+":"+o.password);r.Authorization="Basic "+s,delete o.userid,delete o.password}var c=o._fetch(o.baseUrl+"/"+e+"/",{method:n,headers:r,body:"GET"==n?void 0:JSON.stringify(o)}),i=c.then(function(e){return e.json()}).catch(function(){});return Promise.all([c,i]).then(function(e){var t=e[0],n=e[1];if(!t.ok)throw new u(t,n);return n})};var o=function(n,e){return e.reduce(function(e,t){return e[t]=n[t],e},{})},u=function(n){function e(e,t){n.call(this,e.statusText),this.status=e.status,Object.assign(this,t)}return n&&(e.__proto__=n),(e.prototype=Object.create(n&&n.prototype)).constructor=e}(Error);return new t}); diff --git a/dist/alks.umd.js b/dist/alks.umd.js new file mode 100644 index 00000000..46815313 --- /dev/null +++ b/dist/alks.umd.js @@ -0,0 +1,578 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.alks = factory()); +}(this, function () { 'use strict'; + + var version = "1.1.0"; + + var fetch = window.fetch.bind(window); + + /** + * ALKS JavaScript API + * + */ + var alks = function alks(props, existing) { + if ( existing === void 0 ) existing = {}; + + this.defaults = Object.assign({}, existing, { _fetch: fetch }, props); + }; + + /** + * Encodes a string to base 64 + * + * @param {string} str - the string to encode + * @private + * @returns {string} the base64 encoded string + * @example + * var input = 'password' + * alks.base64Encode(input) + */ + alks.prototype._base64Encode = function _base64Encode (str) { + if ( str === void 0 ) str = ''; + + { + return btoa(str) + } + }; + + /** + * Returns a new instance of alks with pre-defined properties (which don't need to be supplied to every method). + * + * Any of the properties required by other methods can be specified here. + * + * Properties present on the current object are carried through to the newly created one. + * + * @param {Object} props - An object containing settings for the new ALKS object + * @returns {alks} + * @example + * var myAlks = alks.create({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }) + * + * myAlks.getKeys({ + * account: 'anAccount', + * role: 'PowerUser', + * sessionTime: 2 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + alks.prototype.create = function create (props) { + return(new alks(props, this.defaults)) + }; + + /** + * AWS Account + * @typedef {Object} account + * @property {String} account - The name of the account + * @property {String} role - The user's role in this account + * @property {Boolean} iamKeyActive - Whether credentials with IAM permissions can be provisioned from this account + */ + + /** + * Returns a Promise for an array of AWS accounts (and roles) accessible by the user + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise} + * @example + * alks.getAccounts({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((accounts) => { + * // accounts[0].account, accounts[0].role, accounts[0].iamKeyActive + * }) + */ + alks.prototype.getAccounts = function getAccounts (props) { + return(this._doFetch('getAccounts', props).then(function (results) { return Object.keys(results.accountListRole).map(function (key) { return ({ + account: key, + role: results.accountListRole[key][0].role, + iamKeyActive: results.accountListRole[key][0].iamKeyActive + }); }); } + )) + }; + + /** + * AWS STS Credentials + * @typedef {Object} credentials + * @property {String} accessKey - AWS access key + * @property {String} secretKey - AWS secret key + * @property {String} sessionToken - AWS STS session token + */ + + /** + * Returns a Promise for AWS STS credentials from ALKS. + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The AWS account to use when provisioning the credentials + * @param {string} props.role - The ALKS role to use when provisioning the credentials + * @param {string} props.sessionTime - The session length for the credentials + * @returns {Promise} + * @example + * alks.getKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'PowerUser', + * sessionTime: 2 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + alks.prototype.getKeys = function getKeys (props) { + return(this._doFetch('getKeys', props).then(function (results) { return pick(results, ['accessKey', 'secretKey', 'sessionToken']); } + )) + }; + + /** + * Returns a Promise for AWS STS credentials with IAM permissions from ALKS. + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The AWS account to use when provisioning the credentials + * @param {string} props.role - The ALKS role to use when provisioning the credentials + * @param {number} props.sessionTime - The session length for the credentials + * @returns {Promise} + * @example + * alks.getIAMKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * sessionTime: 1 + * }).then((creds) => { + * // creds.accessKey, creds.secretKey, creds.sessionToken + * }) + */ + alks.prototype.getIAMKeys = function getIAMKeys (props) { + return(this._doFetch('getIAMKeys', props).then(function (results) { return pick(results, ['accessKey', 'secretKey', 'sessionToken']); } + )) + }; + + /** + * Returns a Promise for an array of available AWS IAM role types + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise>} + * @example + * alks.getAWSRoleTypes({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((roleTypes) { + * // ['AWS Lambda', 'Amazon EC2', ... ] + * }) + */ + alks.prototype.getAWSRoleTypes = function getAWSRoleTypes (props) { + return(this._doFetch('getAWSRoleTypes', props).then(function (results) { return JSON.parse(results.roleTypes); } + )) + }; + + /** + * Returns a Promise for an array of available custom role types + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @returns {Promise>} + * @example + * alks.getNonServiceAWSRoleTypes({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * }).then((roleTypes) => { + * // ['AWS Lambda', 'Amazon EC2', ...] + * }) + */ + alks.prototype.getNonServiceAWSRoleTypes = function getNonServiceAWSRoleTypes (props) { + return(this._doFetch('getNonServiceAWSRoleTypes', props).then(function (results) { return JSON.parse(results.roleTypes); } + )) + }; + + /** + * Custom AWS IAM account role + * @typedef {Object} customRole + * @property {String} roleArn - The Amazon Resource Name (ARN) associated with the new role + * @property {String} denyArns - The ARNs for the deny policies associated with this role + * @property {String} instanceProfileArn - The Instance Profile ARN associated with this role + * @property {Boolean} addedRoleToInstanceProfile - Whether this role was added to an Instance Profile + */ + + /** + * Returns a Promise for the results of creating a new custom AWS IAM account role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role to create + * @param {string} props.roleType - The type of AWS role to use when creating the new role + * @param {number} props.includeDefaultPolicy - Whether to include the default policy in the new role (1 = yes, 0 = no) + * @returns {Promise} + * @example + * alks.createRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName', + * roleType: 'Amazon EC2', + * includeDefaultPolicy: 1 + * }).then((role) => { + * // role.roleArn, role.denyArns, role.instanceProfileArn, role.addedRoleToInstanceProfile + * }) + */ + alks.prototype.createRole = function createRole (props) { + return(this._doFetch('createRole', props).then(function (results) { + results.denyArns = results.denyArns.split(','); + return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) + })) + }; + + /** + * Returns a Promise for the results of creating a new custom AWS IAM trust role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role to create + * @param {string} props.roleType - The type of AWS role to use when creating the new role + * @param {number} props.includeDefaultPolicy - Whether to include the default policy in the new role (1 = yes, 0 = no) + * @param {string} props.trustArn - The Arn of the existing role to trust + * @param {string} props.trustType - Whether the trust is 'Cross Account' or 'Inner Account' + * @returns {Promise} + * @example + * alks.createNonServiceRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName', + * roleType: 'Amazon EC2', + * includeDefaultPolicy: 1, + * trustArn: 'anExistingRoleArn', + * trustType: 'Cross Account' + * }).then((role) => { + * // role.roleArn, role.denyArns, role.instanceProfileArn, role.addedRoleToInstanceProfile + * }) + */ + alks.prototype.createNonServiceRole = function createNonServiceRole (props) { + return(this._doFetch('createNonServiceRole', props).then(function (results) { + results.denyArns = results.denyArns.split(','); + return(pick(results,['roleArn', 'denyArns','instanceProfileArn','addedRoleToInstanceProfile'])) + })) + }; + + /** + * Returns a Promise for an array of AWS custom AWS IAM account roles + * + * @param {Object} props - An object containing the following properties + * @param {String} props.baseUrl - The base URL of the ALKS service + * @param {String} props.accessToken - The OAuth2 access token used to authorize the request + * @param {String} props.account - The user's account associated with the custom role + * @param {String} props.role - The user's role associated with the account + * @returns {Promise} + * @example + * alks.listAWSAccountRoles({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * }).then((roleNames) => { + * // ['customRole1', 'customRole2', ...] + * }) + */ + + alks.prototype.listAWSAccountRoles = function listAWSAccountRoles (props) { + return(this._doFetch('listAWSAccountRoles', props).then(function (results) { return JSON.parse(results.jsonAWSRoleList).map(function (r) { return r.split('/').slice(-1)[0]; }); } + )) + }; + + /** + * Returns a Promise for the Amazon Resource Name (ARN) of a custom AWS IAM account role + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWs IAM role + * @returns {Promise} + * @example + * alks.getAccountRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName' + * }).then((roleARN) => { + * // arn:aws:iam::123:role/acct-managed/awsRoleName + * }) + */ + alks.prototype.getAccountRole = function getAccountRole (props) { + return(this._doFetch('getAccountRole', props).then(function (results) { + if (!results.roleExists) { + throw new Error(("Role " + (props.roleName) + " does not exist in this account")) + } + return(results.roleARN) + })) + }; + + /** + * Returns a Promise for a boolean "true" indicating the role was deleted + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.roleName - The name of the custom AWS IAM role + * @returns {Promise} + * @example + * alks.deleteRole({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * roleName: 'awsRoleName' + * }).then(() => { + * // success! + * }) + */ + alks.prototype.deleteRole = function deleteRole (props) { + return(this._doFetch('deleteRole', props).then(function () { return true; } )) + }; + + /** + *Response containing access keys. + * + *@typedef {Object} AccessKeys + *@property {string} iamUserArn - the arn of the IAM user owning the long term access keys + *@property {string} accessKey - the long term access key + *@property {string} secretKey - the secret key for the long term access key + *@property {boolean} addedIAMUserToGroup - whether the user was successfuly added to the deny policy group + */ + + /** + * Returns a Promise for the results of creating new IAM user and long-term access keys + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.iamUserName - The name of the IAM user to create + * @returns {Promise} + * @example + * alks.createAccessKeys({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * iamUserName: 'iamUserName' + * }).then((user) => { + * // user.iamUserArn, user.accessKey, user.secretKey, user.addedIAMUserToGroup + * }) + */ + alks.prototype.createAccessKeys = function createAccessKeys (props) { + return(this._doFetch('accessKeys', props).then(function (results) { return pick(results,['iamUserArn', 'accessKey', 'secretKey', 'addedIAMUserToGroup']); }) + ) + }; + + /** + * Returns a Promise for a boolean "true" indicating the IAM user and long-term access keys were deleted + * + * @param {Object} props - An object containing the following properties + * @param {string} props.baseUrl - The base URL of the ALKS service + * @param {string} props.accessToken - The OAuth2 access token used to authorize the request + * @param {string} props.account - The user's account associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @param {string} props.iamUserName - The name of the IAM user to delete + * @returns {Promise} + * @example + * alks.deleteIAMUser({ + * baseUrl: 'https://your.alks-host.com', + * accessToken: 'abc123', + * account: 'anAccount', + * role: 'IAMAdmin', + * iamUserName: 'iamUserName' + * }).then(() => { + * // success! + * }) + */ + alks.prototype.deleteIAMUser = function deleteIAMUser (props) { + return(this._doFetch('IAMUser', props, 'DELETE').then(function () { return true; } )) + }; + + /** + * Returns the version of the ALKS Rest API + * + * @param {Object} props - An object containing the following properties + * @returns {Promise} + * @example + * alks.version({ + * ... + * }).then((data) => { + * // data.version + * }) + */ + alks.prototype.version = function version (props) { + return this._doFetch('version', props, 'GET').then(function (results) { return pick(results, ['version']); }) + }; + + /** + * Returns information about one of the roles used to generate keys + * + * @param {Object} props - An object containing the following properties + * @param {string} props.accountId - The 12-digit account ID associated with the custom role + * @param {string} props.role - The user's role associated with the account + * @returns {Promise} + * @example + * alks.getLoginRole({ + * ... + * }).then((loginRole) => { + * // loginRole.account, loginRole.role, loginRole.iamKeyActive, loginRole.maxKeyDuration + * }) + */ + alks.prototype.getLoginRole = function getLoginRole (props) { + var accountId = props.accountId; + var role = props.role; + return this._doFetch(("loginRoles/id/" + accountId + "/" + role), null).then(function (results) { return pick(results, ['account', 'role', 'iamKeyActive', 'maxKeyDuration']); }) + }; + + /** + * Exchanges a refresh token for an access token + * + * @param {Object} props - An object containing the following properties + * @param {string} props.refreshToken - the refresh token to exchange + * @returns {Promise} + * @example + * alks.getAccessToken({ + * ... + * }).then((data) => { + * // data.accessToken, data.expiresIn + * }) + */ + alks.prototype.getAccessToken = function getAccessToken (props) { + return this._doFetch('accessToken', props).then(function (results) { return pick(results, ['accessToken', 'expiresIn']); } + ) + }; + + /** + * Returns a list of a user's refresh tokens (Does not return the full token) + * + * @param {Object} props - An object containing the following properties + * @returns {Array} + * @example + * alks.getRefreshTokens({ + * ... + * }).then((tokens) => { + * // token[i].clientId, token[i].id, token[i].userId, token[i].value + * }) + */ + alks.prototype.getRefreshTokens = function getRefreshTokens (props) { + return this._doFetch('refreshTokens', props, 'GET').then(function (results) { return results.refreshTokens.map(function (token) { return pick(token, ['clientId', 'id', 'userId', 'value']); }); } + ) + }; + + /** + * Revokes a refresh or access token + * + * @param {Object} props - An object containing the following properties + * @param {string} [props.token] - the access or refresh token to revoke (Required if tokenId not specified) + * @param {string} [props.tokenId] - the ID of the refresh token to revoke (Required if token not specified) + * @returns {boolean} + * @example + * alks.revoke({ + * token: '...', + * ... + * }).then((success) => { + * // success == true + * }) + * + * // or + * + * alks.revoke({ + * tokenId: '...', + * ... + * }).then((success) => { + * // success == true + * }) + */ + alks.prototype.revoke = function revoke (props) { + return this._doFetch('revoke', props).then(function (results) { return results.statusMessage == 'Success'; } + ) + }; + + alks.prototype._doFetch = function _doFetch (path, args, method) { + if ( args === void 0 ) args = { }; + if ( method === void 0 ) method = 'POST'; + + var opts = Object.assign({}, this.defaults, args); + + var headers = { + 'Content-Type': 'application/json', + 'User-Agent': ("AlksJS/" + (version)), + }; + + if (opts.accessToken) { + headers['Authorization'] = "Bearer " + (opts.accessToken); + delete opts.accessToken; + } + + if (opts.userid || opts.password) { + console.error('The userid and password properties are deprecated and should be replaced with an access token'); + var credentials = this._base64Encode(((opts.userid) + ":" + (opts.password))); + headers['Authorization'] = "Basic " + credentials; + delete opts.userid; + delete opts.password; + } + + var responsePromise = opts._fetch(((opts.baseUrl) + "/" + path + "/"), { + method: method, headers: headers, body: method == 'GET' ? undefined : JSON.stringify(opts) + }); + + // Add catch here to swallow the JSON parsing error (it'll get picked up below) + var jsonPromise = responsePromise.then(function (r) { return r.json(); }).catch(function () {}); + + return Promise.all([responsePromise, jsonPromise]).then(function (ref) { + var response = ref[0]; + var json = ref[1]; + + if (!response.ok) { + throw new AlksError(response, json) + } + return(json) + }) + }; + + var pick = function (obj, props) { return props.reduce(function (a, e) { return (a[e] = obj[e], a); }, {}); }; + + var AlksError = /*@__PURE__*/(function (Error) { + function AlksError(response, json) { + Error.call(this, response.statusText); + this.status = response.status; + Object.assign(this, json); + } + + if ( Error ) AlksError.__proto__ = Error; + AlksError.prototype = Object.create( Error && Error.prototype ); + AlksError.prototype.constructor = AlksError; + + return AlksError; + }(Error)); + + var alks$1 = new alks(); + + return alks$1; + +})); diff --git a/karma.conf.js b/karma.conf.js index 26db34c5..0b470fbd 100755 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ - './dist/alks.js', + './dist/alks.min.js', './test/test.js' ], diff --git a/package.json b/package.json index f8da1fae..0dca1dec 100755 --- a/package.json +++ b/package.json @@ -1,14 +1,17 @@ { "name": "alks.js", - "version": "1.0.1", + "version": "1.1.0", "description": "JavaScript client for the ALKS API, usable in both modern browsers and node.js", - "main": "lib/alks.node.js", + "main": "dist/alks.cjs.js", + "unpkg": "dist/alks.min.js", + "browser": "dist/alks.umd.js", + "module": "dist/alks.esm.js", "scripts": { "rmdirs": "rimraf lib dist", "mkdirs": "mkdirp lib dist", "clean": "npm run rmdirs && npm run mkdirs", "rollup": "rollup -c rollup.config.js", - "minify": "uglifyjs -mc < dist/alks.js > dist/alks.min.js", + "minify": "uglifyjs -mc < dist/alks.umd.js > dist/alks.min.js", "prepublish": "npm run build && npm run docs", "build": "npm run clean && npm run rollup && npm run minify", "lint": "eslint src/*.js test/*.js", diff --git a/rollup.config.js b/rollup.config.js index 5dfc6d84..ec4541bc 100755 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,39 +1,44 @@ import buble from 'rollup-plugin-buble' import replace from 'rollup-plugin-replace' -import cleanup from 'rollup-plugin-cleanup' import json from 'rollup-plugin-json' +import pkg from './package.json' export default [ { input: 'src/alks.js', output: { - file: 'dist/alks.js', - format: 'iife', - name: 'alks', - globals: { - alks: 'alks', - buffer: 'buffer', - } + file: pkg.browser, + format: 'umd', + name: 'alks' }, plugins: [ json(), buble({ objectAssign: 'Object.assign' }), - replace({'process.browser': true}), - cleanup() + replace({'process.browser': true}) ] }, { input: 'src/alks.js', output: { - file: 'lib/alks.node.js', - format: 'cjs', - name: 'alks', + file: pkg.main, + format: 'cjs' }, plugins: [ json(), replace({'process.browser': false}) ] + }, + { + input: 'src/alks.js', + output: { + file: pkg.module, + format: 'es' + }, + plugins: [ + json(), + replace({'process.browser': true}) + ] } ]