-
Notifications
You must be signed in to change notification settings - Fork 0
/
jsecrets.js
94 lines (85 loc) · 3.11 KB
/
jsecrets.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
const AWS = require("aws-sdk");
class jsecrets {
static devStubs(stubs) {
if (process.env.NODE_ENV == "production") {
const stubWarning =
"You have stubbed all calls to AWS Secrets manager. We recommend wrapping your call to `jsecrets.devStubs()` in an `if` block. See the jsecrets README for more info.";
console.warn(stubWarning);
}
this.stubs = stubs;
}
// If this.stubs == null, fetch the secrets from AWS Secrets Manager.
static async fetch(region, secrets) {
if (this.stubs) {
// find any unstubbed secrets
const unstubbedSecrets = secrets.filter(secret => {
return !Object.keys(this.stubs).includes(secret);
});
if (unstubbedSecrets.length) {
// if there are any secrets that do not have equivalent stubs
// raise an informative error.
throw {
message: `.fetch() errored. You have unstubbed secrets: [${unstubbedSecrets}]`
};
}
} else {
// Use AWS Secrets Manager if stubs haven't been set.
await this._fetchAWSSecrets(region, secrets);
}
this.fetched = true;
return;
}
// If this.stubs has been set, the secrets can be retrieved from
// this.stubs. If this.stubs hasn't been set, i.e. the app is
// running in production, the secrets are retrieved from this.secrets.
static get(secretId, key) {
// Ensure secrets have been fetched (or env vars have been loaded)
if (!this.fetched) {
throw { message: "You must call jsecrets.fetch() before jsecrets.get()" };
}
if (this.stubs && this.stubs[secretId][key]) {
// Use the stubs if set.
return this.stubs[secretId][key];
} else if (!this.stubs && this.secrets[secretId][key]) {
// Otherwise use secrets loaded from AWS.
return this.secrets[secretId][key];
} else {
// raise if key cannot be found in the secret.
throw { message: `${key} is undefined in ${secretId}`}
}
}
// Gets all secrets from AWS Secrets Manager from the SecretIds specified.
static _fetchAWSSecrets(region, secrets) {
const client = new AWS.SecretsManager({ region });
return Promise.all(
secrets.map(secretId => {
return this._getSecretValue(client, secretId);
})
);
}
// Gets a set of key/values from a single SecretId location in AWS Secrets
// Manager and adds them to this.secrets.
static _getSecretValue(client, secretId) {
return new Promise(resolve => {
client.getSecretValue({ SecretId: secretId }, (err, data) => {
// If AWS returns an error, raise it
if (err) {
throw err;
}
// Grab the secret from the data returned from AWS
const secrets = data.SecretString;
// If AWS returns no secret for some reason, raise an error
if (!secrets) {
// throw new Error("Missing secrets")
throw { message: "Missing secrets" };
}
// Otherwise, set the secrets on our singleton...
this.secrets[secretId] = JSON.parse(secrets);
// ...and resolve the promise
resolve();
});
});
}
}
jsecrets.secrets = {};
module.exports = jsecrets;