diff --git a/Dockerfile b/Dockerfile index c7ee609..0e4b52e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,10 @@ # if you update this version, please update .circleci/config.yml FROM mhart/alpine-node:14.6.0 +# 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 ./ COPY yarn.lock ./ @@ -8,4 +12,5 @@ RUN yarn install --production # Copy source COPY . ./ -ENTRYPOINT ["yarn", "start"] +ENTRYPOINT ["/usr/local/bin/dumb-init", "--"] +CMD ["yarn", "start"] diff --git a/app.json b/app.json index be97c6b..89c1eac 100644 --- a/app.json +++ b/app.json @@ -16,6 +16,10 @@ }, "API_PASSWORD": { "description": "Password for private API access" + }, + "ROUTE_PREFIX": { + "description": "Custom prefix for all routes, defaults to /", + "required": "false" } } } diff --git a/bin/web.js b/bin/web.js index 053bd1a..ce6d027 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/book.js b/book.js index 32d867b..2b5bf22 100644 --- a/book.js +++ b/book.js @@ -1,24 +1,24 @@ -var pkg = require('./package.json'); +var pkg = require("./package.json") module.exports = { - // Documentation for Nuts is stored under "docs" - root: './docs', - title: 'Nuts Documentation', + // Documentation for Nuts is stored under "docs" + root: "./docs", + title: "Nuts Documentation", - // Enforce use of GitBook v3 - gitbook: '>=3.0.0-pre.0', + // Enforce use of GitBook v3 + gitbook: ">=3.0.0-pre.0", - // Use the "official" theme - plugins: ['theme-official', 'sitemap'], - theme: 'official', + // Use the "official" theme + plugins: ["theme-official", "sitemap"], + theme: "official", - variables: { - version: pkg.version - }, + variables: { + version: pkg.version, + }, - pluginsConfig: { - sitemap: { - hostname: 'https://nuts.gitbook.com' - } - } -}; + pluginsConfig: { + sitemap: { + hostname: "https://nuts.gitbook.com", + }, + }, +} diff --git a/lib/nuts.js b/lib/nuts.js index 8750944..ad7f4be 100644 --- a/lib/nuts.js +++ b/lib/nuts.js @@ -36,8 +36,17 @@ function Nuts(opts) { // Secret for GitHub webhook 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,31 +60,48 @@ 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) + const withPrefix = (s) => `${that.opts.routePrefix}${s}` - this.router.get("/feed/channel/:channel.atom", this.onServeVersionsFeed) + this.router.get(withPrefix(""), this.onDownload) + this.router.get( + withPrefix(`download/channel/:channel/:platform?`), + this.onDownload, + ) + this.router.get( + withPrefix(`download/version/:tag/:platform?`), + this.onDownload, + ) + this.router.get(withPrefix(`download/:tag/:filename`), this.onDownload) + this.router.get(withPrefix(`download/:platform?`), this.onDownload) - 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", + withPrefix(`feed/channel/:channel.atom`), + this.onServeVersionsFeed, + ) + + this.router.get(withPrefix(`update`), this.onUpdateRedirect) + this.router.get(withPrefix(`update/:platform/:version`), this.onUpdate) + this.router.get( + withPrefix(`update/channel/:channel/:platform/:version`), + this.onUpdate, + ) + this.router.get( + withPrefix(`update/:platform/:version/RELEASES`), + this.onUpdateWin, + ) + this.router.get( + withPrefix(`update/channel/:channel/:platform/:version/RELEASES`), this.onUpdateWin, ) - this.router.get("/notes/:version?", this.onServeNotes) + this.router.get(withPrefix(`notes/:version?`), this.onServeNotes) // Bind API - this.router.use("/api", this.onAPIAccessControl) + this.router.use(withPrefix(`api`), this.onAPIAccessControl) _.each( API_METHODS, function (method, route) { - this.router.get("/api/" + route, function (req, res, next) { + this.router.get(withPrefix(`api/${route}`), function (req, res, next) { return Q() .then(function () { return method.call(that, req) @@ -220,13 +246,15 @@ 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( - "/update/" + _.escape(req.query.platform) + "/" + req.query.version, + `${that.opts.routePrefix}update/${req.query.platform}/${req.query.version}`, ) }) .fail(next) @@ -270,12 +298,7 @@ Nuts.prototype.onUpdate = function (req, res, next) { url: urljoin( fullUrl, gitFilePath, - "/download/version/" + - latest.tag + - "/" + - platform + - "?filetype=" + - filetype, + `download/version/${latest.tag}/${platform}?filetype=${filetype}`, ), name: latest.tag, notes: releaseNotes, @@ -330,7 +353,7 @@ Nuts.prototype.onUpdateWin = function (req, res, next) { entry.filename = urljoin( fullUrl, gitFilePath, - "/download/" + entry.semver + "/" + entry.filename, + `download/${entry.semver}/${entry.filename}`, ) return entry @@ -409,7 +432,7 @@ Nuts.prototype.onServeVersionsFeed = function (req, res, next) { link: urljoin( fullUrl, "/../../../", - "/download/version/" + version.tag, + `download/version/${version.tag}`, ), description: version.notes, date: version.published_at,