/
awsConfigCredentials.js
182 lines (152 loc) · 5.9 KB
/
awsConfigCredentials.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
'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;