mirror of
https://github.com/cderche/greenlock-storage-s3
synced 2025-05-13 16:16:32 +00:00
209 lines
6.2 KiB
JavaScript
209 lines
6.2 KiB
JavaScript
var AWS = require('../core'),
|
|
ENV_RELATIVE_URI = 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI',
|
|
ENV_FULL_URI = 'AWS_CONTAINER_CREDENTIALS_FULL_URI',
|
|
ENV_AUTH_TOKEN = 'AWS_CONTAINER_AUTHORIZATION_TOKEN',
|
|
FULL_URI_UNRESTRICTED_PROTOCOLS = ['https:'],
|
|
FULL_URI_ALLOWED_PROTOCOLS = ['http:', 'https:'],
|
|
FULL_URI_ALLOWED_HOSTNAMES = ['localhost', '127.0.0.1'],
|
|
RELATIVE_URI_HOST = '169.254.170.2';
|
|
|
|
/**
|
|
* Represents credentials received from specified URI.
|
|
*
|
|
* This class will request refreshable credentials from the relative URI
|
|
* specified by the AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or the
|
|
* AWS_CONTAINER_CREDENTIALS_FULL_URI environment variable. If valid credentials
|
|
* are returned in the response, these will be used with zero configuration.
|
|
*
|
|
* This credentials class will by default timeout after 1 second of inactivity
|
|
* and retry 3 times.
|
|
* If your requests to the relative URI are timing out, you can increase
|
|
* the value by configuring them directly:
|
|
*
|
|
* ```javascript
|
|
* AWS.config.credentials = new AWS.RemoteCredentials({
|
|
* httpOptions: { timeout: 5000 }, // 5 second timeout
|
|
* maxRetries: 10, // retry 10 times
|
|
* retryDelayOptions: { base: 200 } // see AWS.Config for information
|
|
* });
|
|
* ```
|
|
*
|
|
* @see AWS.Config.retryDelayOptions
|
|
*
|
|
* @!macro nobrowser
|
|
*/
|
|
AWS.RemoteCredentials = AWS.util.inherit(AWS.Credentials, {
|
|
constructor: function RemoteCredentials(options) {
|
|
AWS.Credentials.call(this);
|
|
options = options ? AWS.util.copy(options) : {};
|
|
if (!options.httpOptions) options.httpOptions = {};
|
|
options.httpOptions = AWS.util.merge(
|
|
this.httpOptions, options.httpOptions);
|
|
AWS.util.update(this, options);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
httpOptions: { timeout: 1000 },
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
maxRetries: 3,
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
isConfiguredForEcsCredentials: function isConfiguredForEcsCredentials() {
|
|
return Boolean(
|
|
process &&
|
|
process.env &&
|
|
(process.env[ENV_RELATIVE_URI] || process.env[ENV_FULL_URI])
|
|
);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
getECSFullUri: function getECSFullUri() {
|
|
if (process && process.env) {
|
|
var relative = process.env[ENV_RELATIVE_URI],
|
|
full = process.env[ENV_FULL_URI];
|
|
if (relative) {
|
|
return 'http://' + RELATIVE_URI_HOST + relative;
|
|
} else if (full) {
|
|
var parsed = AWS.util.urlParse(full);
|
|
if (FULL_URI_ALLOWED_PROTOCOLS.indexOf(parsed.protocol) < 0) {
|
|
throw AWS.util.error(
|
|
new Error('Unsupported protocol: AWS.RemoteCredentials supports '
|
|
+ FULL_URI_ALLOWED_PROTOCOLS.join(',') + ' only; '
|
|
+ parsed.protocol + ' requested.'),
|
|
{ code: 'ECSCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
|
|
if (FULL_URI_UNRESTRICTED_PROTOCOLS.indexOf(parsed.protocol) < 0 &&
|
|
FULL_URI_ALLOWED_HOSTNAMES.indexOf(parsed.hostname) < 0) {
|
|
throw AWS.util.error(
|
|
new Error('Unsupported hostname: AWS.RemoteCredentials only supports '
|
|
+ FULL_URI_ALLOWED_HOSTNAMES.join(',') + ' for ' + parsed.protocol + '; '
|
|
+ parsed.protocol + '//' + parsed.hostname + ' requested.'),
|
|
{ code: 'ECSCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
|
|
return full;
|
|
} else {
|
|
throw AWS.util.error(
|
|
new Error('Variable ' + ENV_RELATIVE_URI + ' or ' + ENV_FULL_URI +
|
|
' must be set to use AWS.RemoteCredentials.'),
|
|
{ code: 'ECSCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
} else {
|
|
throw AWS.util.error(
|
|
new Error('No process info available'),
|
|
{ code: 'ECSCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
getECSAuthToken: function getECSAuthToken() {
|
|
if (process && process.env && process.env[ENV_FULL_URI]) {
|
|
return process.env[ENV_AUTH_TOKEN];
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
credsFormatIsValid: function credsFormatIsValid(credData) {
|
|
return (!!credData.accessKeyId && !!credData.secretAccessKey &&
|
|
!!credData.sessionToken && !!credData.expireTime);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
formatCreds: function formatCreds(credData) {
|
|
if (!!credData.credentials) {
|
|
credData = credData.credentials;
|
|
}
|
|
|
|
return {
|
|
expired: false,
|
|
accessKeyId: credData.accessKeyId || credData.AccessKeyId,
|
|
secretAccessKey: credData.secretAccessKey || credData.SecretAccessKey,
|
|
sessionToken: credData.sessionToken || credData.Token,
|
|
expireTime: new Date(credData.expiration || credData.Expiration)
|
|
};
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
request: function request(url, callback) {
|
|
var httpRequest = new AWS.HttpRequest(url);
|
|
httpRequest.method = 'GET';
|
|
httpRequest.headers.Accept = 'application/json';
|
|
var token = this.getECSAuthToken();
|
|
if (token) {
|
|
httpRequest.headers.Authorization = token;
|
|
}
|
|
AWS.util.handleRequestWithRetries(httpRequest, this, callback);
|
|
},
|
|
|
|
/**
|
|
* Loads the credentials from the relative URI specified by container
|
|
*
|
|
* @callback callback function(err)
|
|
* Called when the request to the relative URI responds (or fails). When
|
|
* this callback is called with no error, it means that the credentials
|
|
* information has been loaded into the object (as the `accessKeyId`,
|
|
* `secretAccessKey`, `sessionToken`, and `expireTime` properties).
|
|
* @param err [Error] if an error occurred, this value will be filled
|
|
* @see get
|
|
*/
|
|
refresh: function refresh(callback) {
|
|
this.coalesceRefresh(callback || AWS.util.fn.callback);
|
|
},
|
|
|
|
/**
|
|
* @api private
|
|
*/
|
|
load: function load(callback) {
|
|
var self = this;
|
|
var fullUri;
|
|
|
|
try {
|
|
fullUri = this.getECSFullUri();
|
|
} catch (err) {
|
|
callback(err);
|
|
return;
|
|
}
|
|
|
|
this.request(fullUri, function(err, data) {
|
|
if (!err) {
|
|
try {
|
|
data = JSON.parse(data);
|
|
var creds = self.formatCreds(data);
|
|
if (!self.credsFormatIsValid(creds)) {
|
|
throw AWS.util.error(
|
|
new Error('Response data is not in valid format'),
|
|
{ code: 'ECSCredentialsProviderFailure' }
|
|
);
|
|
}
|
|
AWS.util.update(self, creds);
|
|
} catch (dataError) {
|
|
err = dataError;
|
|
}
|
|
}
|
|
callback(err, creds);
|
|
});
|
|
}
|
|
});
|