GitbookIO / nuts

:chestnut: Releases/downloads server with auto-updater and GitHub as a backend
http://nuts.gitbook.com
Apache License 2.0
1.25k stars 300 forks source link

RELEASES file generated with incorrect URLs when Nuts middleware is used on a path other than '/' in express and called with query parameters #150

Open pwik opened 7 years ago

pwik commented 7 years ago

I think I discovered a bug.

If I host the Nuts middleware on a route such as app.use('/myapp', Nuts.router) in express and GET the /update/:platform/:version/RELEASES route the generated filenames do not include my custom path /myapp if query parameters are present in the requested path. It does not seeem to matter what the query parameters are, only that they are present.

Calling http://myserver.com/myapp/update/:platform/:version/RELEASES generates a RELEASES file containing correct filename URLs with my custom path like so:

... http://myserver.com/myapp/download/x.x.x/...-full.nupkg ...

Calling http://myserver.com/myapp/update/:platform/:version/RELEASES?test=asd generates a RELEASES file containing filename URLs without the /myapp path:

... http://myserver.com/download/x.x.x/...-full.nupkg ...

I've had a quick look through the source code and I think the urljoin.js module does not handle query parameters correctly when transforming the RELEASES filenames.

sapiraz commented 6 years ago

I stumbled upon the exact same issue. After looking at the urljoin.js module I've noticed that it's using the Node.js URL module, which I believe handles URLs right, it's just not a great fit as it is for the "RELEASE" filenames.

What seemed to work well for me was to firstly strip down the URL from the query parameters and then pass it on to the urljoin.js module for parsing.

Example "nuts.js":

const url = require('url');
...
Nuts.prototype.onUpdateWin = function(req, res, next) {
...
// Change filename to use download proxy
.map(function(entry) {
   entry.filename = urljoin(fullUrl.replace(url.parse(fullUrl).search, ''), '/../../../../', '/download/'+entry.semver+'/'+entry.filename);
    return entry;
})