From 4b23c63b2a9464958e73e6345ff7bfbafa0d3639 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 22 Feb 2018 07:43:53 -0700 Subject: [PATCH 1/5] support a route prefix, useful if you need to path route traffic behind a reverse proxy --- app.json | 5 ++++- bin/web.js | 1 + lib/nuts.js | 45 ++++++++++++++++++++++++++------------------- 3 files changed, 31 insertions(+), 20 deletions(-) diff --git a/app.json b/app.json index fa7b54dd..239c959a 100644 --- a/app.json +++ b/app.json @@ -16,6 +16,9 @@ }, "API_PASSWORD": { "description": "Password for private API access" + }, + "ROUTE_PREFIX": { + "description": "Custom prefix for all routes, defaults to /" } } -} \ No newline at end of file +} diff --git a/bin/web.js b/bin/web.js index 9e7c0aab..38e54bfc 100644 --- a/bin/web.js +++ b/bin/web.js @@ -18,6 +18,7 @@ if (process.env.ANALYTICS_TOKEN) { } var myNuts = nuts.Nuts({ + routePrefix: process.env.ROUTE_PREFIX, repository: process.env.GITHUB_REPO, token: process.env.GITHUB_TOKEN, endpoint: process.env.GITHUB_ENDPOINT, diff --git a/lib/nuts.js b/lib/nuts.js index 1642158b..89142835 100644 --- a/lib/nuts.js +++ b/lib/nuts.js @@ -35,9 +35,16 @@ function Nuts(opts) { preFetch: true, // Secret for GitHub webhook - refreshSecret: 'secret' + refreshSecret: 'secret', + + // Prefix for all routes + routePrefix: '/' }); + if (this.opts.routePrefix.substr(this.opts.routePrefix.length - 1, 1) !== '/') { + throw new Error('ROUTE_PREIX must end with a slash'); + } + // .init() is now a memoized version of ._init() this.init = _.memoize(this._init); @@ -51,26 +58,26 @@ function Nuts(opts) { // Bind routes this.router.use(useragent.express()); - this.router.get('/', this.onDownload); - this.router.get('/download/channel/:channel/:platform?', this.onDownload); - this.router.get('/download/version/:tag/:platform?', this.onDownload); - this.router.get('/download/:tag/:filename', this.onDownload); - this.router.get('/download/:platform?', this.onDownload); + this.router.get(`${that.opts.routePrefix}`, this.onDownload); + this.router.get(`${that.opts.routePrefix}download/channel/:channel/:platform?`, this.onDownload); + this.router.get(`${that.opts.routePrefix}download/version/:tag/:platform?`, this.onDownload); + this.router.get(`${that.opts.routePrefix}download/:tag/:filename`, this.onDownload); + this.router.get(`${that.opts.routePrefix}download/:platform?`, this.onDownload); - this.router.get('/feed/channel/:channel.atom', this.onServeVersionsFeed); + this.router.get(`${that.opts.routePrefix}feed/channel/:channel.atom`, this.onServeVersionsFeed); - this.router.get('/update', this.onUpdateRedirect); - this.router.get('/update/:platform/:version', this.onUpdate); - this.router.get('/update/channel/:channel/:platform/:version', this.onUpdate); - this.router.get('/update/:platform/:version/RELEASES', this.onUpdateWin); - this.router.get('/update/channel/:channel/:platform/:version/RELEASES', this.onUpdateWin); + this.router.get(`${that.opts.routePrefix}update`, this.onUpdateRedirect); + this.router.get(`${that.opts.routePrefix}update/:platform/:version`, this.onUpdate); + this.router.get(`${that.opts.routePrefix}update/channel/:channel/:platform/:version`, this.onUpdate); + this.router.get(`${that.opts.routePrefix}update/:platform/:version/RELEASES`, this.onUpdateWin); + this.router.get(`${that.opts.routePrefix}update/channel/:channel/:platform/:version/RELEASES`, this.onUpdateWin); - this.router.get('/notes/:version?', this.onServeNotes); + this.router.get(`${that.opts.routePrefix}notes/:version?`, this.onServeNotes); // Bind API - this.router.use('/api', this.onAPIAccessControl); + this.router.use(`${that.opts.routePrefix}api`, this.onAPIAccessControl); _.each(API_METHODS, function(method, route) { - this.router.get('/api/' + route, function(req, res, next) { + this.router.get(`${that.opts.routePrefix}api/${route}`, function(req, res, next) { return Q() .then(function() { return method.call(that, req); @@ -202,7 +209,7 @@ Nuts.prototype.onUpdateRedirect = function(req, res, next) { if (!req.query.version) throw new Error('Requires "version" parameter'); if (!req.query.platform) throw new Error('Requires "platform" parameter'); - return res.redirect('/update/'+req.query.platform+'/'+req.query.version); + return res.redirect(`${this.opts.routePrefix}update/${req.query.platform}/${req.query.version}`); }) .fail(next); }; @@ -241,7 +248,7 @@ Nuts.prototype.onUpdate = function(req, res, next) { console.error(latest.tag); var gitFilePath = (channel === '*' ? '/../../../' : '/../../../../../'); res.status(200).send({ - "url": urljoin(fullUrl, gitFilePath, '/download/version/'+latest.tag+'/'+platform+'?filetype='+filetype), + "url": urljoin(fullUrl, gitFilePath, `${this.opts.routePrefix}download/version/${latest.tag}/${platform}?filetype=${filetype}`), "name": latest.tag, "notes": releaseNotes, "pub_date": latest.published_at.toISOString() @@ -291,7 +298,7 @@ Nuts.prototype.onUpdateWin = function(req, res, next) { // Change filename to use download proxy .map(function(entry) { var gitFilePath = (channel === '*' ? '../../../../' : '../../../../../../'); - entry.filename = urljoin(fullUrl, gitFilePath, '/download/'+entry.semver+'/'+entry.filename); + entry.filename = urljoin(fullUrl, gitFilePath, `${that.opts.routePrefix}download/${entry.semver}/${entry.filename}`); return entry; }) @@ -366,7 +373,7 @@ Nuts.prototype.onServeVersionsFeed = function(req, res, next) { _.each(versions, function(version) { feed.addItem({ title: version.tag, - link: urljoin(fullUrl, '/../../../', '/download/version/'+version.tag), + link: urljoin(fullUrl, '/../../../', `download/version/${version.tag}`), description: version.notes, date: version.published_at, author: [] From b5165e95a5a0a1cba010c1257900e99829ab98d9 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 22 Feb 2018 07:45:10 -0700 Subject: [PATCH 2/5] rework Dockerfile, use official base image for node, use dumb-init for proper signal handling, zombie reaping, structure instructions in a more cachable way --- Dockerfile | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2438298e..dded2696 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,20 @@ -FROM mhart/alpine-node:5.8.0 +FROM node:6-alpine -# Switch to /app +# Setup Container WORKDIR /app +ENTRYPOINT ["/usr/local/bin/dumb-init", "--"] +CMD ["npm", "start"] +EXPOSE 80 + +# Dumb-init, proper signal handling, and zombie reaping +ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 /usr/local/bin/dumb-init + # Install deps -COPY package.json ./ +COPY package.json /app/package.json RUN npm install --production -# Copy source -COPY . ./ + +# Copy Source +COPY . /app # Ports ENV PORT 80 -EXPOSE 80 - -ENTRYPOINT ["npm", "start"] From d180a70417083f3f45f635e17df465c6098bc122 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 22 Feb 2018 08:15:04 -0700 Subject: [PATCH 3/5] fix execute bit on dumb-init --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index dded2696..d057241e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ EXPOSE 80 # Dumb-init, proper signal handling, and zombie reaping ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.1/dumb-init_1.2.1_amd64 /usr/local/bin/dumb-init +RUN chmod +x /usr/local/bin/dumb-init # Install deps COPY package.json /app/package.json From 58a2d06d7e2fd438105fb02c1b6484edee46d839 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 22 Feb 2018 08:22:21 -0700 Subject: [PATCH 4/5] fix two this/that references --- lib/nuts.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/nuts.js b/lib/nuts.js index 89142835..43ab1efe 100644 --- a/lib/nuts.js +++ b/lib/nuts.js @@ -204,12 +204,14 @@ Nuts.prototype.onDownload = function(req, res, next) { // Request to update Nuts.prototype.onUpdateRedirect = function(req, res, next) { + var that = this; + Q() .then(function() { if (!req.query.version) throw new Error('Requires "version" parameter'); if (!req.query.platform) throw new Error('Requires "platform" parameter'); - return res.redirect(`${this.opts.routePrefix}update/${req.query.platform}/${req.query.version}`); + return res.redirect(`${that.opts.routePrefix}update/${req.query.platform}/${req.query.version}`); }) .fail(next); }; @@ -248,7 +250,7 @@ Nuts.prototype.onUpdate = function(req, res, next) { console.error(latest.tag); var gitFilePath = (channel === '*' ? '/../../../' : '/../../../../../'); res.status(200).send({ - "url": urljoin(fullUrl, gitFilePath, `${this.opts.routePrefix}download/version/${latest.tag}/${platform}?filetype=${filetype}`), + "url": urljoin(fullUrl, gitFilePath, `${that.opts.routePrefix}download/version/${latest.tag}/${platform}?filetype=${filetype}`), "name": latest.tag, "notes": releaseNotes, "pub_date": latest.published_at.toISOString() From 3089452c2557864979dc91d07a223775b4852516 Mon Sep 17 00:00:00 2001 From: Erik Kristensen Date: Thu, 22 Feb 2018 08:30:11 -0700 Subject: [PATCH 5/5] fix a double prefix issue --- lib/nuts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nuts.js b/lib/nuts.js index 43ab1efe..9219d790 100644 --- a/lib/nuts.js +++ b/lib/nuts.js @@ -250,7 +250,7 @@ Nuts.prototype.onUpdate = function(req, res, next) { console.error(latest.tag); var gitFilePath = (channel === '*' ? '/../../../' : '/../../../../../'); res.status(200).send({ - "url": urljoin(fullUrl, gitFilePath, `${that.opts.routePrefix}download/version/${latest.tag}/${platform}?filetype=${filetype}`), + "url": urljoin(fullUrl, gitFilePath, `download/version/${latest.tag}/${platform}?filetype=${filetype}`), "name": latest.tag, "notes": releaseNotes, "pub_date": latest.published_at.toISOString() @@ -300,7 +300,7 @@ Nuts.prototype.onUpdateWin = function(req, res, next) { // Change filename to use download proxy .map(function(entry) { var gitFilePath = (channel === '*' ? '../../../../' : '../../../../../../'); - entry.filename = urljoin(fullUrl, gitFilePath, `${that.opts.routePrefix}download/${entry.semver}/${entry.filename}`); + entry.filename = urljoin(fullUrl, gitFilePath, `download/${entry.semver}/${entry.filename}`); return entry; })