@fishawack/lab-env 2.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/_Test/_fixtures/.gitkeep +0 -0
- package/_Test/_helpers/globals.js +10 -0
- package/_Test/key.js +33 -0
- package/_Test/provision.js +33 -0
- package/cli.js +6 -6
- package/commands/create/cmds/dekey.js +75 -0
- package/commands/create/cmds/deprovision.js +54 -0
- package/commands/create/cmds/diagnose.js +5 -3
- package/commands/create/cmds/key.js +99 -0
- package/commands/create/cmds/provision.js +120 -0
- package/commands/create/libs/aws-cloudfront-auth.js +77 -0
- package/commands/create/libs/aws-cloudfront-simple.js +51 -0
- package/commands/create/libs/utilities.js +49 -2
- package/commands/create/services/aws/cloudfront.js +295 -0
- package/commands/create/services/aws/iam.js +170 -0
- package/commands/create/services/aws/index.js +25 -0
- package/commands/create/services/aws/misc.js +9 -0
- package/commands/create/services/aws/s3.js +109 -0
- package/commands/create/services/guide.js +13 -0
- package/core/{0.0.21 → 0.1.0}/Dockerfile +6 -0
- package/core/{0.0.21 → 0.1.0}/entrypoint.sh +0 -0
- package/core/CHANGELOG.md +4 -0
- package/core/package.json +1 -1
- package/drupal/9/apache/apache.conf +1 -0
- package/drupal/9/docker-compose.yml +1 -1
- package/drupal/9/php/Dockerfile +1 -1
- package/globals.js +8 -0
- package/package.json +16 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
## Changelog
|
|
2
2
|
|
|
3
|
+
### 3.0.0 (2022-08-17)
|
|
4
|
+
* [Feature] Added newly setup AWS accounts to the client prompts on `fw provision`
|
|
5
|
+
* [Feature] Added key/dekey commands
|
|
6
|
+
* [Change] Provisioned environment variables now append client to uniqueify the services created
|
|
7
|
+
* [Change] `fw provision` no longer does two polls to cloudfront to speed up the process
|
|
8
|
+
* [Change] Drupal now defaults to 8.1 php
|
|
9
|
+
* [Bug] Added protocol to www in cloudfront function to ensure redirect works correctly
|
|
10
|
+
* [Bug] Added posiexem to fix M1 chip issue on drupal
|
|
11
|
+
|
|
12
|
+
### 2.2.0 (2022-08-10)
|
|
13
|
+
* [Feature] Can now skip diagnose in `fw diagnose`
|
|
14
|
+
* [Feature] Can now provision AWS environments using `fw provision`
|
|
15
|
+
* [Change] Now requires node > 16
|
|
16
|
+
* [Change] Auditted npm dependencies
|
|
17
|
+
* [Misc] Added test coverage for new AWS service
|
|
18
|
+
|
|
19
|
+
### 2.1.0 (2022-05-27)
|
|
20
|
+
* [Change] Bumped core `0.0.21` to `0.1.0`
|
|
21
|
+
|
|
3
22
|
### 2.0.2 (2022-04-26)
|
|
4
23
|
* [Change] Bumped core `0.0.20` to `0.0.21`
|
|
5
24
|
* [Bug] Lock eb-cli due to breaking change
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const host = "ftp-fishawack.egnyte.com";
|
|
4
|
+
const creds = JSON.parse(fs.readFileSync(`${os.homedir()}/targets/.ftppass`))[host];
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
opts: {encoding: 'utf8', stdio: process.argv.includes('--publish') ? 'pipe' : 'inherit'},
|
|
8
|
+
host,
|
|
9
|
+
creds
|
|
10
|
+
};
|
package/_Test/key.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const aws = require("../commands/create/services/aws/index.js");
|
|
5
|
+
|
|
6
|
+
describe('key', async () => {
|
|
7
|
+
let account = 'fishawack';
|
|
8
|
+
|
|
9
|
+
before(async () => {
|
|
10
|
+
let res = await aws.iam.createFWIAMUser('fw-test-user', account);
|
|
11
|
+
|
|
12
|
+
// Wait for key as AWS doesn't provide a way to wait for it to becom eactive
|
|
13
|
+
await new Promise(resolve => setTimeout(() => resolve(), 10000));
|
|
14
|
+
|
|
15
|
+
process.env.AWS_ACCESS_KEY_ID = res.AccessKey.AccessKeyId;
|
|
16
|
+
process.env.AWS_SECRET_ACCESS_KEY = res.AccessKey.SecretAccessKey;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('Should be able to access AWS service', async () => {
|
|
20
|
+
let res;
|
|
21
|
+
|
|
22
|
+
try{ res = await aws.s3.listS3Buckets(); } catch(e){ console.log(e.message); }
|
|
23
|
+
|
|
24
|
+
expect(res).to.not.be.undefined;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
after(async () => {
|
|
28
|
+
delete process.env.AWS_ACCESS_KEY_ID;
|
|
29
|
+
delete process.env.AWS_SECRET_ACCESS_KEY;
|
|
30
|
+
|
|
31
|
+
await aws.iam.removeIAMUser('fw-test-user', account);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const aws = require("../commands/create/services/aws/index.js");
|
|
5
|
+
var fetch;
|
|
6
|
+
|
|
7
|
+
describe('provision', async () => {
|
|
8
|
+
let config;
|
|
9
|
+
let repo = 'lab-env-test-suite';
|
|
10
|
+
let account = 'fishawack';
|
|
11
|
+
|
|
12
|
+
before(async () => {
|
|
13
|
+
fetch = (await import('node-fetch')).default;
|
|
14
|
+
|
|
15
|
+
config = await aws.static(repo, account);
|
|
16
|
+
|
|
17
|
+
await aws.s3.addFileToS3Bucket(repo, account, 'index.html', new TextEncoder().encode("test"));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('Should provision s3 bucket', async () => {
|
|
21
|
+
expect((await fetch(config.url)).status).to.be.equal(200);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
after(async () => {
|
|
25
|
+
await aws.s3.removeFileToS3Bucket(repo, account, 'index.html');
|
|
26
|
+
|
|
27
|
+
await aws.s3.removeS3Bucket(repo, account);
|
|
28
|
+
|
|
29
|
+
await aws.cloudfront.removeCloudFrontDistribution(config.cloudfront, account);
|
|
30
|
+
|
|
31
|
+
await aws.cloudfront.removeCloudFrontFunction(repo, account);
|
|
32
|
+
});
|
|
33
|
+
});
|
package/cli.js
CHANGED
|
@@ -4,10 +4,6 @@ process.env.CWD = process.cwd();
|
|
|
4
4
|
|
|
5
5
|
const _ = require('./globals.js');
|
|
6
6
|
|
|
7
|
-
const updateNotifier = require('update-notifier');
|
|
8
|
-
const pkg = require('./package.json');
|
|
9
|
-
updateNotifier({pkg, updateCheckInterval: 0}).notify();
|
|
10
|
-
|
|
11
7
|
const execSync = require('child_process').execSync;
|
|
12
8
|
|
|
13
9
|
const yargs = require('yargs/yargs');
|
|
@@ -16,9 +12,13 @@ const { hideBin } = require('yargs/helpers');
|
|
|
16
12
|
const args = hideBin(process.argv);
|
|
17
13
|
|
|
18
14
|
// Stop here if docker process not running and command isn't version or origin which don't require docker
|
|
19
|
-
if(!_.services && !(args[0] === 'origin' || args[0] === '--version'))
|
|
15
|
+
if(!_.services && !(args[0] === 'origin' || args[0] === '--version')) process.exit();
|
|
20
16
|
|
|
21
17
|
(async () => {
|
|
18
|
+
const updateNotifier = (await import('update-notifier')).default;
|
|
19
|
+
const pkg = require('./package.json');
|
|
20
|
+
updateNotifier({pkg, updateCheckInterval: 0}).notify();
|
|
21
|
+
|
|
22
22
|
process.env.REPO = _.repo;
|
|
23
23
|
|
|
24
24
|
await _.ports.set();
|
|
@@ -59,7 +59,7 @@ if(!_.services && !(args[0] === 'origin' || args[0] === '--version')) return;
|
|
|
59
59
|
['build', 'config', 'down', 'mocha', 'rebuild', 'up', 'volumes', 'compose'].forEach(d => cli.command(...require(`./commands/docker/${d}.js`)));
|
|
60
60
|
|
|
61
61
|
// Create commands
|
|
62
|
-
['new', 'diagnose', 'delete'].forEach(d => cli.command(...require(`./commands/create/cmds/${d}.js`)));
|
|
62
|
+
['new', 'provision', 'deprovision', 'diagnose', 'delete', 'key', 'dekey'].forEach(d => cli.command(...require(`./commands/create/cmds/${d}.js`)));
|
|
63
63
|
|
|
64
64
|
cli.demandCommand(1, '')
|
|
65
65
|
.wrap(null)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const _ = require('../../../globals.js');
|
|
2
|
+
const utilities = require('../libs/utilities');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const aws = require('../services/aws/index.js');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
module.exports = [
|
|
9
|
+
'dekey',
|
|
10
|
+
false,
|
|
11
|
+
yargs => {},
|
|
12
|
+
async argv => {
|
|
13
|
+
let config = JSON.parse(fs.readFileSync(`${os.homedir()}/.lab-env`, {encoding: 'utf8'}));
|
|
14
|
+
let users = [];
|
|
15
|
+
let clients = [];
|
|
16
|
+
|
|
17
|
+
let answer = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'confirm',
|
|
20
|
+
name: 'check',
|
|
21
|
+
message: `Remove keys for all users`,
|
|
22
|
+
default: 'Y'
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
if(answer.check){
|
|
27
|
+
users = config.users.map(d => d.username);
|
|
28
|
+
} else {
|
|
29
|
+
answer = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'checkbox',
|
|
32
|
+
name: 'users',
|
|
33
|
+
message: 'Select users',
|
|
34
|
+
choices: config.users.map(d => d.username)
|
|
35
|
+
}
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
users = answer.users;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
answer = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: 'confirm',
|
|
44
|
+
name: 'check',
|
|
45
|
+
message: `Remove keys for all clients`,
|
|
46
|
+
default: 'Y'
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
if(answer.check){
|
|
51
|
+
clients = aws.clients;
|
|
52
|
+
} else {
|
|
53
|
+
answer = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'checkbox',
|
|
56
|
+
name: 'clients',
|
|
57
|
+
message: 'Select clients',
|
|
58
|
+
choices: aws.clients
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
clients = answer.clients;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for(let i = 0; i < clients.length; i++){
|
|
66
|
+
let client = clients[i];
|
|
67
|
+
|
|
68
|
+
for(let j = 0; j < users.length; j++){
|
|
69
|
+
let user = users[j];
|
|
70
|
+
|
|
71
|
+
await aws.iam.removeIAMUser(`fw-automation-${user}`, client);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const _ = require('../../../globals.js');
|
|
2
|
+
const inquirer = require('inquirer');
|
|
3
|
+
const aws = require('../services/aws/index.js');
|
|
4
|
+
const utilities = require('../libs/utilities');
|
|
5
|
+
|
|
6
|
+
module.exports = [
|
|
7
|
+
['deprovision', 'deprov'],
|
|
8
|
+
false,
|
|
9
|
+
yargs => {
|
|
10
|
+
yargs.option('branch', {
|
|
11
|
+
alias: 'b',
|
|
12
|
+
describe: 'Branch to configure',
|
|
13
|
+
type: 'string'
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
async argv => {
|
|
17
|
+
let branch = argv.branch || _.branch;
|
|
18
|
+
|
|
19
|
+
const answers = await inquirer.prompt([
|
|
20
|
+
{
|
|
21
|
+
type: 'input',
|
|
22
|
+
name: 'id',
|
|
23
|
+
message: 'What is the Id of the CloudFront distribution?',
|
|
24
|
+
validate: (input) => !!input.length
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
type: 'list',
|
|
28
|
+
name: 'client',
|
|
29
|
+
message: 'Which AWS account is this deployed too?',
|
|
30
|
+
choices: aws.clients,
|
|
31
|
+
default: 'fishawack'
|
|
32
|
+
}
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
let answer = await inquirer.prompt([
|
|
36
|
+
{
|
|
37
|
+
type: 'confirm',
|
|
38
|
+
name: 'check',
|
|
39
|
+
message: `Deprovisioning ${utilities.colorize(aws.slug(_.repo, answers.client, branch), 'error')} from ${utilities.colorize(answers.client, 'error')} AWS account, are you sure you want to continue?`,
|
|
40
|
+
default: false
|
|
41
|
+
}
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
if(!answer.check){
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try { await aws.s3.removeS3Bucket(aws.slug(_.repo, answers.client, branch), answers.client); } catch(e) {}
|
|
49
|
+
|
|
50
|
+
try { await aws.cloudfront.removeCloudFrontDistribution(answers.id, answers.client); } catch(e) {}
|
|
51
|
+
|
|
52
|
+
try { await aws.cloudfront.removeCloudFrontFunction(aws.slug(_.repo, answers.client, branch), answers.client); } catch(e) {}
|
|
53
|
+
}
|
|
54
|
+
];
|
|
@@ -57,9 +57,11 @@ module.exports = [
|
|
|
57
57
|
while(!await test.bitbucket() || !await bitbucket.check()){
|
|
58
58
|
await guide.bitbucket();
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
await
|
|
60
|
+
|
|
61
|
+
if(!await guide.gitlabSkip()) {
|
|
62
|
+
while(!await test.gitlab() || !await gitlab.check()){
|
|
63
|
+
await guide.gitlab();
|
|
64
|
+
}
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
const userRepoName = vars.misc.bitbucket.username.split('@')[0].replace(/\./, '-');
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const _ = require('../../../globals.js');
|
|
2
|
+
const utilities = require('../libs/utilities');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
const aws = require('../services/aws/index.js');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
module.exports = [
|
|
9
|
+
'key',
|
|
10
|
+
false,
|
|
11
|
+
yargs => {},
|
|
12
|
+
async argv => {
|
|
13
|
+
let config = JSON.parse(fs.readFileSync(`${os.homedir()}/.lab-env`, {encoding: 'utf8'}));
|
|
14
|
+
let users = [];
|
|
15
|
+
let clients = [];
|
|
16
|
+
|
|
17
|
+
let answer = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'confirm',
|
|
20
|
+
name: 'check',
|
|
21
|
+
message: `Set keys for all users`,
|
|
22
|
+
default: 'Y'
|
|
23
|
+
}
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
if(answer.check){
|
|
27
|
+
users = config.users.map(d => d.username);
|
|
28
|
+
} else {
|
|
29
|
+
answer = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'checkbox',
|
|
32
|
+
name: 'users',
|
|
33
|
+
message: 'Select users',
|
|
34
|
+
choices: config.users.map(d => d.username)
|
|
35
|
+
}
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
users = answer.users;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
answer = await inquirer.prompt([
|
|
42
|
+
{
|
|
43
|
+
type: 'confirm',
|
|
44
|
+
name: 'check',
|
|
45
|
+
message: `Set keys for all clients`,
|
|
46
|
+
default: 'Y'
|
|
47
|
+
}
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
if(answer.check){
|
|
51
|
+
clients = aws.clients;
|
|
52
|
+
} else {
|
|
53
|
+
answer = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'checkbox',
|
|
56
|
+
name: 'clients',
|
|
57
|
+
message: 'Select clients',
|
|
58
|
+
choices: aws.clients
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
clients = answer.clients;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let credentials = {};
|
|
66
|
+
|
|
67
|
+
for(let i = 0; i < clients.length; i++){
|
|
68
|
+
let client = clients[i];
|
|
69
|
+
|
|
70
|
+
for(let j = 0; j < users.length; j++){
|
|
71
|
+
let user = users[j];
|
|
72
|
+
|
|
73
|
+
if(!credentials[user]){
|
|
74
|
+
credentials[user] = {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let res = await aws.iam.createFWIAMUser(`fw-automation-${user}`, client);
|
|
78
|
+
|
|
79
|
+
credentials[user][client] = {
|
|
80
|
+
key: res.AccessKey && res.AccessKey.AccessKeyId || res.AccessKeyMetadata[0].AccessKeyId,
|
|
81
|
+
secret: res.AccessKey && res.AccessKey.SecretAccessKey || '** secret **'
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let output = '';
|
|
87
|
+
|
|
88
|
+
for(var user in credentials){
|
|
89
|
+
output += utilities.colorize(`\n${user}\n`, 'title');
|
|
90
|
+
for(var client in credentials[user]){
|
|
91
|
+
output += `\n[${client}]\n`;
|
|
92
|
+
output += `aws_access_key_id = ${credentials[user][client].key}\n`;
|
|
93
|
+
output += `aws_secret_access_key = ${credentials[user][client].secret}\n`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log(output);
|
|
98
|
+
}
|
|
99
|
+
];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
const _ = require('../../../globals.js');
|
|
2
|
+
const utilities = require('../libs/utilities');
|
|
3
|
+
const execSync = require('child_process').execSync;
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const aws = require('../services/aws/index.js');
|
|
6
|
+
const generator = require('generate-password');
|
|
7
|
+
|
|
8
|
+
module.exports = [
|
|
9
|
+
['provision', 'prov'],
|
|
10
|
+
'Provisions the deployment target',
|
|
11
|
+
yargs => {
|
|
12
|
+
yargs.option('branch', {
|
|
13
|
+
alias: 'b',
|
|
14
|
+
describe: 'Branch to configure',
|
|
15
|
+
type: 'string'
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
async argv => {
|
|
19
|
+
let branch = argv.branch || _.branch;
|
|
20
|
+
|
|
21
|
+
let answer = await inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'confirm',
|
|
24
|
+
name: 'check',
|
|
25
|
+
message: `Provisioning the ${utilities.colorize(branch, 'success')} branch, is this correct?`,
|
|
26
|
+
default: 'Y'
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
if(!answer.check){
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const answers = await inquirer.prompt([
|
|
35
|
+
{
|
|
36
|
+
type: 'list',
|
|
37
|
+
name: 'stack',
|
|
38
|
+
message: 'What type of project are you deploying?',
|
|
39
|
+
choices: ['static'],
|
|
40
|
+
default: 'static'
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
type: 'list',
|
|
44
|
+
name: 'client',
|
|
45
|
+
message: 'Which AWS account should this be deployed too?',
|
|
46
|
+
choices: aws.clients,
|
|
47
|
+
default: 'fishawack'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'confirm',
|
|
51
|
+
name: 'protected',
|
|
52
|
+
message: 'Should the site be password protected?',
|
|
53
|
+
default: true
|
|
54
|
+
}
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
let credentials = [];
|
|
58
|
+
|
|
59
|
+
if(answers.protected){
|
|
60
|
+
let user = {
|
|
61
|
+
another: true
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
while(user.another){
|
|
65
|
+
user = await inquirer.prompt([
|
|
66
|
+
{
|
|
67
|
+
type: 'input',
|
|
68
|
+
name: 'username',
|
|
69
|
+
message: 'Username',
|
|
70
|
+
default: `${_.repo_safe}User${credentials.length ? `-${credentials.length}` : ''}`,
|
|
71
|
+
validate: (input) => !!input.length
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'input',
|
|
75
|
+
name: 'password',
|
|
76
|
+
message: 'Password (leave empty to generate)',
|
|
77
|
+
default: generator.generate({ length: 10, numbers: true }),
|
|
78
|
+
validate: (input) => !!input.length
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: 'confirm',
|
|
82
|
+
name: 'another',
|
|
83
|
+
message: 'Add another user?',
|
|
84
|
+
default: false
|
|
85
|
+
}
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
credentials.push({username: user.username, password: user.password});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let config = {};
|
|
93
|
+
let infastructure;
|
|
94
|
+
|
|
95
|
+
try{
|
|
96
|
+
infastructure = await aws.static(aws.slug(_.repo, answers.client, branch), answers.client, [{Key: 'repository', Value: _.repo}, {Key: 'environment', Value: branch}], credentials);
|
|
97
|
+
} catch(e){
|
|
98
|
+
console.log(e.message);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
config[branch] = {
|
|
103
|
+
deploy: {
|
|
104
|
+
"url": infastructure.url,
|
|
105
|
+
"location": infastructure.bucket.slice(1), // Remove / from start
|
|
106
|
+
"aws-s3": answers.client,
|
|
107
|
+
"aws-cloudfront": infastructure.cloudfront
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if(credentials.length){
|
|
112
|
+
config[branch].deploy.users = credentials;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let stringify = JSON.stringify(config, null, 4);
|
|
116
|
+
let output = stringify.substring(1, stringify.length-1).trim();
|
|
117
|
+
execSync(`printf '${output}' | pbcopy`);
|
|
118
|
+
console.log(utilities.colorize(`\n${output}\n\n(copied to clipboard)`, 'title'));
|
|
119
|
+
}
|
|
120
|
+
];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
function handler(event) {
|
|
2
|
+
// Redirect if www to non-www
|
|
3
|
+
if (event.request.headers.host.value.includes('www.')) {
|
|
4
|
+
var query = '';
|
|
5
|
+
var index = 0;
|
|
6
|
+
|
|
7
|
+
for(var key in event.request.querystring){
|
|
8
|
+
query += `${index ? '&' : '?'}${key}=${event.request.querystring[key].value}`;
|
|
9
|
+
index++;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var response = {
|
|
13
|
+
statusCode: 301,
|
|
14
|
+
statusDescription: 'Moved Permanently',
|
|
15
|
+
headers: { "location": { "value": `https://${event.request.headers.host.value.split('www.')[1]}${event.request.uri}${query}` } }
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return response;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Redirect if no trailing slash
|
|
22
|
+
if(!event.request.uri.includes('.') && !event.request.uri.endsWith('/')){
|
|
23
|
+
var query = '';
|
|
24
|
+
var index = 0;
|
|
25
|
+
|
|
26
|
+
for(var key in event.request.querystring){
|
|
27
|
+
query += `${index ? '&' : '?'}${key}=${event.request.querystring[key].value}`;
|
|
28
|
+
index++;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
statusCode: 301,
|
|
33
|
+
statusDescription: 'Moved Permanently',
|
|
34
|
+
headers: { "location": { "value": `${event.request.uri}/${query}` } }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var authHeaders = event.request.headers.authorization;
|
|
39
|
+
|
|
40
|
+
// The Base64-encoded Auth string that should be present.
|
|
41
|
+
// It is an encoding of `Basic base64([username]:[password])`
|
|
42
|
+
var expected = <%= credentials %>;
|
|
43
|
+
|
|
44
|
+
// If an Authorization header is supplied and it's an exact match, pass the
|
|
45
|
+
// request on through to CF/the origin without any modification.
|
|
46
|
+
if(authHeaders && expected.find(d => d === authHeaders.value)) {
|
|
47
|
+
// Rewrite url to append index.html if not present
|
|
48
|
+
var request = event.request;
|
|
49
|
+
var uri = request.uri;
|
|
50
|
+
|
|
51
|
+
// Check whether the URI is missing a file name.
|
|
52
|
+
if(uri.endsWith('/')) {
|
|
53
|
+
request.uri += 'index.html';
|
|
54
|
+
}
|
|
55
|
+
// Check whether the URI is missing a file extension.
|
|
56
|
+
else if(!uri.includes('.')) {
|
|
57
|
+
request.uri += '/index.html';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return request;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// But if we get here, we must either be missing the auth header or the
|
|
64
|
+
// credentials failed to match what we expected.
|
|
65
|
+
// Request the browser present the Basic Auth dialog.
|
|
66
|
+
var response = {
|
|
67
|
+
statusCode: 401,
|
|
68
|
+
statusDescription: 'Unauthorized',
|
|
69
|
+
headers: {
|
|
70
|
+
"www-authenticate": {
|
|
71
|
+
value: 'Basic'
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
return response;
|
|
77
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function handler(event) {
|
|
2
|
+
// Redirect if www to non-www
|
|
3
|
+
if (event.request.headers.host.value.includes('www.')) {
|
|
4
|
+
var query = '';
|
|
5
|
+
var index = 0;
|
|
6
|
+
|
|
7
|
+
for(var key in event.request.querystring){
|
|
8
|
+
query += `${index ? '&' : '?'}${key}=${event.request.querystring[key].value}`;
|
|
9
|
+
index++;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
var response = {
|
|
13
|
+
statusCode: 301,
|
|
14
|
+
statusDescription: 'Moved Permanently',
|
|
15
|
+
headers: { "location": { "value": `https://${event.request.headers.host.value.split('www.')[1]}${event.request.uri}${query}` } }
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return response;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Redirect if no trailing slash
|
|
22
|
+
if(!event.request.uri.includes('.') && !event.request.uri.endsWith('/')){
|
|
23
|
+
var query = '';
|
|
24
|
+
var index = 0;
|
|
25
|
+
|
|
26
|
+
for(var key in event.request.querystring){
|
|
27
|
+
query += `${index ? '&' : '?'}${key}=${event.request.querystring[key].value}`;
|
|
28
|
+
index++;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
statusCode: 301,
|
|
33
|
+
statusDescription: 'Moved Permanently',
|
|
34
|
+
headers: { "location": { "value": `${event.request.uri}/${query}` } }
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var request = event.request;
|
|
39
|
+
var uri = request.uri;
|
|
40
|
+
|
|
41
|
+
// Check whether the URI is missing a file name.
|
|
42
|
+
if(uri.endsWith('/')) {
|
|
43
|
+
request.uri += 'index.html';
|
|
44
|
+
}
|
|
45
|
+
// Check whether the URI is missing a file extension.
|
|
46
|
+
else if(!uri.includes('.')) {
|
|
47
|
+
request.uri += '/index.html';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return request;
|
|
51
|
+
}
|