@campus-explorer/aws-credentials
Advanced tools
Comparing version
{ | ||
"name": "@campus-explorer/aws-credentials", | ||
"description": "JavaScript helper code to manage AWS credentials", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"author": "Stephen Caldwell <steve@campusexplorer.com>", | ||
"bugs": "https://github.com/campus-explorer/aws-credentials-js/issues", | ||
"dependencies": { | ||
"aws-sdk": "^2.602.0", | ||
"aws-sdk": "^2.648.0", | ||
"inquirer": "^7.0.3", | ||
@@ -15,2 +15,6 @@ "lodash": "^4.17.15", | ||
"devDependencies": { | ||
"@types/inquirer": "^6.5.0", | ||
"@types/lodash": "^4.14.150", | ||
"@types/memoizee": "^0.4.3", | ||
"@types/mkdirp": "^1.0.0", | ||
"eslint-plugin-prettier": "^3.1.2", | ||
@@ -22,2 +26,3 @@ "fixpack": "^2.3.1", | ||
"prettier": "^1.19.1", | ||
"typescript": "^3.8.3", | ||
"xo": "^0.25.3" | ||
@@ -43,4 +48,7 @@ }, | ||
"posttest": "yarn lint", | ||
"test": "true" | ||
"test": "true", | ||
"ts:check": "tsc", | ||
"ts:watch": "tsc --watch" | ||
}, | ||
"types": "src/index.d.ts", | ||
"xo": { | ||
@@ -47,0 +55,0 @@ "prettier": true, |
@@ -7,2 +7,3 @@ const fs = require('fs'); | ||
/** @type {(cacheDir: string) => void} */ | ||
const mkdirIfNotExists = cacheDir => { | ||
@@ -15,3 +16,4 @@ if (!fs.existsSync(cacheDir)) { | ||
const getFilename = ({ profile, cacheDir }) => { | ||
/** @type {(profile: string, cacheDir: string) => string} */ | ||
const getFilename = (profile, cacheDir) => { | ||
const profileConfig = getProfileConfig(profile); | ||
@@ -28,2 +30,3 @@ const { role_arn: roleArn, mfa_serial: mfaSerial } = profileConfig; | ||
/** @type {(filename: string) => AWS.Credentials | void} */ | ||
const getCredentialsFromFile = filename => { | ||
@@ -55,2 +58,3 @@ if (!fs.existsSync(filename)) return undefined; | ||
/** @type {(params: {cacheDir: string, filename: string, credentials: AWS.Credentials}) => void} */ | ||
const writeCredentialsToFile = ({ cacheDir, filename, credentials }) => { | ||
@@ -72,7 +76,7 @@ const { sessionToken, expireTime } = credentials; | ||
const withCache = fn => async ({ cacheDir, ...args }) => { | ||
const { profile } = args; | ||
const filename = getFilename({ profile, cacheDir }); | ||
/** @type {(cacheDir: string, profile: string, getCredentials: () => Promise<AWS.Credentials>) => Promise<AWS.Credentials>} */ | ||
const getCredentialsUseCache = async (cacheDir, profile, getCredentials) => { | ||
const filename = getFilename(profile, cacheDir); | ||
const cached = getCredentialsFromFile(filename); | ||
const credentials = cached ? cached : await fn(args); | ||
const credentials = cached ? cached : await getCredentials(); | ||
writeCredentialsToFile({ cacheDir, filename, credentials }); | ||
@@ -82,2 +86,2 @@ return credentials; | ||
module.exports = withCache; | ||
module.exports = getCredentialsUseCache; |
@@ -6,2 +6,3 @@ const getProfileConfig = require('./profile-config'); | ||
/** @type {(params: { profile: string, duration?: number, getMfaToken: (mfaSerial: string) => Promise<{ token: string }>}) => Promise<AWS.Credentials>} */ | ||
const getCredentials = async ({ profile, duration, getMfaToken }) => { | ||
@@ -8,0 +9,0 @@ const profileConfig = getProfileConfig(profile); |
@@ -5,2 +5,3 @@ const inquirer = require('inquirer'); | ||
/** @type {(mfaSerial: string) => Promise<{ token: string }>} */ | ||
const getMfaToken = async serial => | ||
@@ -7,0 +8,0 @@ prompt({ |
@@ -8,4 +8,15 @@ /* | ||
const AWS = require('aws-sdk'); | ||
const { merge } = require('lodash'); | ||
const getProfileConfig = require('./profile-config'); | ||
/** | ||
* @typedef {{ | ||
* accessKeyId: string, | ||
* secretAccessKey: string, | ||
* sessionToken: string, | ||
* expireTime: Date, | ||
* }} RoleCredentials | ||
*/ | ||
/** @type {(params: {profile: string, duration?: number, getMfaToken: (mfaSerial: string) => Promise<{ token: string }>}) => Promise<RoleCredentials>} */ | ||
const getRoleCredentials = async ({ | ||
@@ -23,5 +34,4 @@ profile: roleProfile, | ||
if (!sourceProfileName) { | ||
throw AWS.util.error( | ||
new Error(`source_profile is not set using profile ${roleProfile}`), | ||
{ code: 'SharedIniFileCredentialsProviderFailure' }, | ||
throw new Error( | ||
`source_profile is not set using profile ${roleProfile}`, | ||
); | ||
@@ -31,7 +41,4 @@ } | ||
if (typeof getProfileConfig(sourceProfileName) !== 'object') { | ||
throw AWS.util.error( | ||
new Error( | ||
`source_profile ${sourceProfileName} using profile ${roleProfile} does not exist`, | ||
), | ||
{ code: 'SharedIniFileCredentialsProviderFailure' }, | ||
throw new TypeError( | ||
`source_profile ${sourceProfileName} using profile ${roleProfile} does not exist`, | ||
); | ||
@@ -41,6 +48,9 @@ } | ||
const sourceCredentials = new AWS.SharedIniFileCredentials( | ||
AWS.util.merge(this.options || {}, { | ||
profile: sourceProfileName, | ||
preferStaticCredentials: true, | ||
}), | ||
merge( | ||
{}, | ||
{ | ||
profile: sourceProfileName, | ||
preferStaticCredentials: true, | ||
}, | ||
), | ||
); | ||
@@ -66,2 +76,4 @@ | ||
const response = await sts.assumeRole(roleParams).promise(); | ||
if (!response.Credentials) throw new Error('Failed to assume role'); | ||
const { | ||
@@ -68,0 +80,0 @@ AccessKeyId: accessKeyId, |
@@ -1,4 +0,10 @@ | ||
const AWS = require('aws-sdk'); | ||
const getProfileConfig = require('./profile-config'); | ||
/** | ||
* @type {(profile: string) => { | ||
* accessKeyId: string, | ||
* secretAccessKey: string, | ||
* sessionToken?: string, | ||
* }} | ||
*/ | ||
const getStaticCredentials = profile => { | ||
@@ -12,6 +18,3 @@ const { | ||
if (!accessKeyId || !secretAccessKey) { | ||
throw AWS.util.error( | ||
new Error(`Credentials not set for profile ${profile}`), | ||
{ code: 'SharedIniFileCredentialsProviderFailure' }, | ||
); | ||
throw new Error(`Credentials not set for profile ${profile}`); | ||
} | ||
@@ -18,0 +21,0 @@ |
const adminTtl = 60 * 60 * 1; // Admin : 1h | ||
const normalTtl = 60 * 60 * 8; // Default : 8h | ||
const getTtl = profile => (profile.endsWith('-admin') ? adminTtl : normalTtl); | ||
/** @type {(profile: string) => number} */ | ||
const getTtl = profile => ((profile.endsWith('-admin') ? adminTtl : normalTtl)); | ||
module.exports = getTtl; |
@@ -1,2 +0,2 @@ | ||
process.env.AWS_SDK_LOAD_CONFIG = 1; | ||
process.env.AWS_SDK_LOAD_CONFIG = '1'; | ||
@@ -6,3 +6,3 @@ const assert = require('assert'); | ||
const defaultGetMfaToken = require('./get-mfa-token'); | ||
const withCache = require('./cache'); | ||
const getCredentialsUseCache = require('./cache'); | ||
const getCredentials = require('./get-credentials'); | ||
@@ -13,3 +13,11 @@ const getProfileConfig = require('./profile-config'); | ||
const getProfileCredentials = (profile, options = {}) => { | ||
/** | ||
* @param {string} profile | ||
* @param {{ | ||
* cacheDir: string, | ||
* duration: number, | ||
* getMfaToken: (mfaSerial: string) => Promise<{ token: string }>, | ||
* } | void} [options] | ||
*/ | ||
const getProfileCredentials = (profile, options) => { | ||
const { | ||
@@ -19,14 +27,21 @@ cacheDir = defaultCacheDir, | ||
getMfaToken = defaultGetMfaToken, | ||
} = options; | ||
} = options || {}; | ||
assert(profile, 'getProfileCredentials(): no profile provided'); | ||
const duration = specifiedDuration ? specifiedDuration : getTtl(profile); | ||
return withCache(getCredentials)({ | ||
profile, | ||
cacheDir, | ||
duration, | ||
getMfaToken, | ||
}); | ||
return getCredentialsUseCache(cacheDir, profile, () => | ||
getCredentials({ profile, duration, getMfaToken }), | ||
); | ||
}; | ||
/** | ||
* @param {string} profile | ||
* @param {AWS} AWS | ||
* @param {{ | ||
* cacheDir: string, | ||
* duration: number, | ||
* getMfaToken: (mfaSerial: string) => Promise<{ token: string }>, | ||
* } | void} [options] | ||
* @returns {Promise<void>} | ||
*/ | ||
const useProfile = async (profile, AWS, options) => { | ||
@@ -33,0 +48,0 @@ const credentials = await getProfileCredentials(profile, options); |
const AWS = require('aws-sdk'); | ||
/** | ||
* | ||
* @param {object} params | ||
* @param {string} params.accessKeyId | ||
* @param {string} params.secretAccessKey | ||
* @param {string | undefined} [params.sessionToken] | ||
* @param {number | undefined} [params.expireTime] | ||
* @returns {AWS.Credentials} | ||
*/ | ||
const makeCredentialsObj = ({ | ||
@@ -4,0 +13,0 @@ accessKeyId, |
@@ -11,10 +11,18 @@ /* | ||
/** | ||
* @typedef {Record<string, Record<string,string>>} IniFileContent | ||
*/ | ||
const configOptInEnv = 'AWS_SDK_LOAD_CONFIG'; | ||
const sharedConfigFileEnv = 'AWS_CONFIG_FILE'; | ||
/** @type {() => IniFileContent} */ | ||
const getProfileConfigs = memoize(() => { | ||
const { iniLoader } = AWS.util; | ||
const iniLoader = new AWS.IniLoader(); | ||
let profilesFromConfig = {}; | ||
if (process.env[AWS.util.configOptInEnv]) { | ||
if (process.env[configOptInEnv]) { | ||
profilesFromConfig = iniLoader.loadFrom({ | ||
isConfig: true, | ||
filename: process.env[AWS.util.sharedConfigFileEnv], | ||
filename: process.env[sharedConfigFileEnv], | ||
}); | ||
@@ -25,4 +33,3 @@ } | ||
filename: | ||
process.env[AWS.util.configOptInEnv] && | ||
process.env[AWS.util.sharedCredentialsFileEnv], | ||
process.env[configOptInEnv] && process.env[sharedConfigFileEnv], | ||
}); | ||
@@ -33,2 +40,3 @@ | ||
/** @type {(profileConfigs: IniFileContent, profile: string) => void} */ | ||
const assertProfileExists = (profileConfigs, profile) => { | ||
@@ -38,8 +46,7 @@ const profileConfig = profileConfigs[profile] || {}; | ||
if (Object.keys(profileConfig).length === 0) { | ||
throw AWS.util.error(new Error(`Profile ${profile} not found`), { | ||
code: 'SharedIniFileCredentialsProviderFailure', | ||
}); | ||
throw new Error(`Profile ${profile} not found`); | ||
} | ||
}; | ||
/** @type {(profile:string) => Record<string,string>} */ | ||
const getProfileConfig = memoize(profile => { | ||
@@ -46,0 +53,0 @@ const profileConfigs = getProfileConfigs(); |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
15187
20.53%12
9.09%340
24.09%12
71.43%Updated