mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
181 lines
5.9 KiB
JavaScript
181 lines
5.9 KiB
JavaScript
'use strict';
|
|
|
|
const BbPromise = require('bluebird');
|
|
const constants = require('constants');
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const fse = require('fs-extra');
|
|
const os = require('os');
|
|
const _ = require('lodash');
|
|
|
|
class AwsConfigCredentials {
|
|
constructor(serverless, options) {
|
|
this.serverless = serverless;
|
|
this.options = options;
|
|
// Note: we're not setting the provider here as this plugin should also be
|
|
// run when the CWD is not an AWS service
|
|
|
|
// this will be merged with the core config commands
|
|
this.commands = {
|
|
config: {
|
|
commands: {
|
|
credentials: {
|
|
lifecycleEvents: ['config'],
|
|
options: {
|
|
key: {
|
|
usage: 'Access key for the provider',
|
|
shortcut: 'k',
|
|
required: true,
|
|
},
|
|
secret: {
|
|
usage: 'Secret key for the provider',
|
|
shortcut: 's',
|
|
required: true,
|
|
},
|
|
profile: {
|
|
usage: 'Name of the profile you wish to create. Defaults to "default"',
|
|
shortcut: 'n',
|
|
},
|
|
overwrite: {
|
|
usage: 'Overwrite the existing profile configuration in the credentials file',
|
|
shortcut: 'o',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
if (!os.homedir()) {
|
|
throw new this.serverless.classes.Error(
|
|
"Can't find home directory on your local file system."
|
|
);
|
|
}
|
|
|
|
this.credentialsFilePath = path.join(os.homedir(), '.aws', 'credentials');
|
|
// Create the credentials file alongside the .aws directory if it's not yet present
|
|
fse.ensureFileSync(this.credentialsFilePath);
|
|
|
|
this.hooks = {
|
|
'config:credentials:config': () => BbPromise.bind(this).then(this.configureCredentials),
|
|
};
|
|
}
|
|
|
|
configureCredentials() {
|
|
// sanitize
|
|
this.options.provider = this.options.provider.toLowerCase();
|
|
this.options.profile = this.options.profile ? this.options.profile : 'default';
|
|
|
|
// resolve if provider option is not 'aws'
|
|
if (this.options.provider !== 'aws') {
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
// validate
|
|
if (!this.options.key || !this.options.secret) {
|
|
throw new this.serverless.classes.Error('Please include --key and --secret options for AWS.');
|
|
}
|
|
|
|
this.serverless.cli.log('Setting up AWS...');
|
|
|
|
this.credentials = this.getCredentials();
|
|
|
|
// Get the profile start line and end line numbers inside the credentials array
|
|
const profileBoundaries = this.getProfileBoundaries();
|
|
|
|
// Check if the profile exists
|
|
const isNewProfile = profileBoundaries.start === -1;
|
|
if (isNewProfile) {
|
|
this.addProfile();
|
|
} else {
|
|
// Only update the profile if the overwrite flag was set
|
|
if (!this.options.overwrite) {
|
|
const message = [
|
|
`Failed! ~/.aws/credentials already has a "${this.options.profile}" profile.`,
|
|
' Use the overwrite flag ("-o" or "--overwrite") to force the update',
|
|
].join('');
|
|
this.serverless.cli.log(message);
|
|
return BbPromise.resolve();
|
|
}
|
|
|
|
this.updateProfile(profileBoundaries);
|
|
}
|
|
|
|
return this.saveCredentialsFile();
|
|
}
|
|
|
|
getCredentials() {
|
|
// Get the credentials file lines
|
|
const credentialsFileContent = this.serverless.utils.readFileSync(this.credentialsFilePath);
|
|
return credentialsFileContent ? credentialsFileContent.split('\n') : [];
|
|
}
|
|
|
|
addProfile() {
|
|
this.credentials.push(
|
|
`[${this.options.profile}]`,
|
|
`aws_access_key_id = ${this.options.key}`,
|
|
`aws_secret_access_key = ${this.options.secret}`
|
|
);
|
|
}
|
|
|
|
updateProfile(profileBoundries) {
|
|
let currentLine = profileBoundries.start;
|
|
let endLine = profileBoundries.end;
|
|
|
|
// Remove existing 'aws_access_key_id' and 'aws_secret_access_key' properties
|
|
while (currentLine < endLine) {
|
|
const line = this.credentials[currentLine];
|
|
if (line.indexOf('aws_access_key_id') > -1 || line.indexOf('aws_secret_access_key') > -1) {
|
|
this.credentials.splice(currentLine, 1);
|
|
endLine--;
|
|
} else {
|
|
currentLine++;
|
|
}
|
|
}
|
|
|
|
// Add the key and the secret to the beginning of the section
|
|
const keyLine = `aws_access_key_id = ${this.options.key}`;
|
|
const secretLine = `aws_secret_access_key = ${this.options.secret}`;
|
|
|
|
this.credentials.splice(profileBoundries.start + 1, 0, secretLine);
|
|
this.credentials.splice(profileBoundries.start + 1, 0, keyLine);
|
|
}
|
|
|
|
saveCredentialsFile() {
|
|
// Generate the file content and add a line break at the end
|
|
const updatedCredsFileContent = `${this.credentials.join('\n')}\n`;
|
|
|
|
this.serverless.cli.log('Saving your AWS profile in "~/.aws/credentials"...');
|
|
|
|
return this.serverless.utils
|
|
.writeFile(this.credentialsFilePath, updatedCredsFileContent)
|
|
.then(() => {
|
|
// set file permissions to only readable/writable by owner (equivalent to 'chmod 600')
|
|
// NOTE: `chmod` doesn't behave as intended on Windows, so skip if we're on Windows.
|
|
if (os.platform() !== 'win32') {
|
|
fs.chmodSync(
|
|
this.credentialsFilePath,
|
|
(fs.constants || constants).S_IRUSR | (fs.constants || constants).S_IWUSR
|
|
);
|
|
}
|
|
|
|
this.serverless.cli.log(
|
|
`Success! Your AWS access keys were stored under the "${this.options.profile}" profile.`
|
|
);
|
|
});
|
|
}
|
|
|
|
getProfileBoundaries() {
|
|
// Get the line number of the aws profile definition, defaults to -1
|
|
const start = this.credentials.indexOf(`[${this.options.profile}]`);
|
|
|
|
const nextProfile = _.findIndex(this.credentials, line => /\[[^\]]+\]/.test(line), start + 1);
|
|
// Get the line number of the next aws profile definition, defaults to the file lines number
|
|
const end = nextProfile + 1 || this.credentials.length;
|
|
|
|
return { start, end };
|
|
}
|
|
}
|
|
|
|
module.exports = AwsConfigCredentials;
|