diff --git a/bin/web.js b/bin/web.js index 9e7c0aab..8bceb597 100644 --- a/bin/web.js +++ b/bin/web.js @@ -18,11 +18,24 @@ if (process.env.ANALYTICS_TOKEN) { } var myNuts = nuts.Nuts({ + backend: process.env.NUTS_BACKEND, repository: process.env.GITHUB_REPO, token: process.env.GITHUB_TOKEN, endpoint: process.env.GITHUB_ENDPOINT, username: process.env.GITHUB_USERNAME, password: process.env.GITHUB_PASSWORD, + credentials: { + aws: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY + } + }, + configuration: { + aws: { + bucket: process.env.AWS_BUCKET, + releasesPrefix: process.env.AWS_RELEASES_PREFIX + } + }, timeout: process.env.VERSIONS_TIMEOUT, cache: process.env.VERSIONS_CACHE, refreshSecret: process.env.GITHUB_SECRET, diff --git a/lib/backends/index.js b/lib/backends/index.js index 193703c9..a5cd4d4d 100644 --- a/lib/backends/index.js +++ b/lib/backends/index.js @@ -1,7 +1,8 @@ var _ = require('lodash'); var BACKENDS = { - github: require('./github') + github: require('./github'), + s3: require('./s3') }; module.exports = function(backend) { diff --git a/lib/backends/s3.js b/lib/backends/s3.js new file mode 100644 index 00000000..2a1bdbd5 --- /dev/null +++ b/lib/backends/s3.js @@ -0,0 +1,108 @@ +var _ = require('lodash'); +var Q = require('q'); +var util = require('util'); +var AWS = require('aws-sdk'); + +var Backend = require('./backend'); + +function S3Backend() { + var that = this; + Backend.apply(this, arguments); + + this.opts = _.defaults(this.opts || {}, { + proxyAssets: true + }); + + if (!this.opts.credentials.aws.accessKeyId || !this.opts.credentials.aws.secretAccessKey || !this.opts.configuration.aws.bucket) { + throw new Error('S3 backend requires "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", and "AWS_BUCKET" options'); + } + + AWS.config.accessKeyId = this.opts.credentials.aws.accessKeyId; + AWS.config.secretAccessKey = this.opts.credentials.aws.secretAccessKey; + + this.client = new AWS.S3(); + this.releases = this.memoize(this._releases); +} + +util.inherits(S3Backend, Backend); + +// List all releases for this repository +S3Backend.prototype._releases = function() { + var client = this.client; + var bucket = this.opts.configuration.aws.bucket; + var d = Q.defer(); + var params = { + Bucket: bucket, + Prefix: this.opts.configuration.aws.releasesPrefix + '/', + Delimiter: '/' + } + + client.listObjects(params, function (err, data) { + if (err) d.reject(err); + + var folders = data.CommonPrefixes.map(function (commonPrefix) { + var deferFolder = Q.defer(); + var folderParams = { + Bucket: bucket, + Prefix: commonPrefix.Prefix + } + + client.listObjects(folderParams, function (err, contents) { + if (err) d.reject(err); + + return deferFolder.resolve(contents); + }); + + return deferFolder.promise; + }); + + Q.all(folders).done(function (values) { + var releases = values.map(function (release) { + var tag = release.Prefix.split('/').slice(-2)[0]; + + return { + channel: 'stable', + tag_name: tag, + assets: release.Contents.map(function (content) { + return { + id: content.ETag, + tag_name: tag, + key: content.Key, + name: content.Key.split('/').slice(-1)[0], + size: content.Size, + content_type: 'application/zip' + } + }) + } + }); + + d.resolve(releases); + }); + }); + + return d.promise; +}; + +S3Backend.prototype.serveAsset = function(asset, req, res) { + if (!this.opts.proxyAssets) { + var s3url = s3.getSignedUrl('getObject', { + Bucket: this.opts.configuration.aws.bucket, + Key: asset.raw.key + }); + res.redirect(s3url); + } else { + return Backend.prototype.serveAsset.apply(this, arguments); + } +}; + +// Return stream for an asset +S3Backend.prototype.getAssetStream = function(asset) { + var params = { + Bucket: this.opts.configuration.aws.bucket, + Key: asset.raw.key + }; + + return Q(this.client.getObject(params).createReadStream()); +}; + +module.exports = S3Backend; diff --git a/package.json b/package.json index 3d1af7f9..a23e8ea7 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "license": "Apache-2.0", "dependencies": { "analytics-node": "1.2.2", + "aws-sdk": "^2.6.6", "basic-auth": "1.0.3", "body-parser": "1.12.3", "destroy": "1.0.3",