From 78c1d4d60ca26917e152186ee0e057f7597b2088 Mon Sep 17 00:00:00 2001 From: lesion Date: Sun, 4 Sep 2016 16:23:41 +0200 Subject: [PATCH 1/3] baseURL option support. Needed if you want to host reStore without a domain for itself alone. Let's say you own your 'www.example.com' and want to host reStore at 'www.example.com/reStore' now you can. This PR introduces a new `baseURL` option you can use for this. --- lib/controllers/base.js | 2 ++ lib/restore.js | 30 ++++++++++++++++++++---------- lib/views/auth.html | 2 +- lib/views/index.html | 2 +- lib/views/layout.html | 6 +++--- lib/views/signup.html | 2 +- 6 files changed, 28 insertions(+), 16 deletions(-) diff --git a/lib/controllers/base.js b/lib/controllers/base.js index f18cc34..27393b3 100644 --- a/lib/controllers/base.js +++ b/lib/controllers/base.js @@ -104,10 +104,12 @@ Controller.prototype.renderHTML = function(status, file, locals) { body = this.readFile(viewDir + file); locals = locals || {}; + locals.baseURL = this.server._baseURL; var globals = { scheme: this.request.secure ? 'https' : 'http', host: this.getHost(), + baseURL: this.server._baseURL, title: locals.title || '', signup: this.server._allow.signup, body: ejs.render(body.toString(), locals) diff --git a/lib/restore.js b/lib/restore.js index 9d65164..b42303b 100644 --- a/lib/restore.js +++ b/lib/restore.js @@ -23,6 +23,7 @@ var Restore = function(options) { this._fileCache = {}; this._allow = options.allow || {}; this._cacheViews = options.cacheViews !== false; + this._baseURL = options.baseURL || '' var self = this; @@ -91,44 +92,53 @@ Restore.prototype.handle = function(request, response) { Restore.prototype.dispatch = function(request, response) { var method = request.method.toUpperCase(), uri = url.parse(request.url, true), - match = null; + match = null, + startBaseURL = new RegExp('^\/?' + this._baseURL + '\/?'); request.secure = this.isSecureRequest(request); + if (!uri.pathname.match(startBaseURL)) { + response.writeHead(302, { 'Location': this._baseURL}) + return response.end() + } + + // remove baseURL and eventually a final '/' before real path + uri.pathname = uri.pathname.replace(startBaseURL, '') + if (/(^|\/)\.\.(\/|$)/.test(uri.pathname)) { response.writeHead(400, {'Access-Control-Allow-Origin': request.headers.origin || '*'}); return response.end(); } - if (method === 'GET' && uri.pathname === '/') + if (method === 'GET' && uri.pathname === '') return new Assets(this, request, response).renderHTML(200, 'index.html', {title: 'reStore'}); - match = uri.pathname.match(/^\/assets\/([^\/]+)$/); + match = uri.pathname.match(/^assets\/([^\/]+)$/); if (method === 'GET' && match) return new Assets(this, request, response).serve(match[1]); - match = uri.pathname.match(/^\/\.well-known\/(host-meta|webfinger)(\.[a-z]+)?$/); + match = uri.pathname.match(/^\.well-known\/(host-meta|webfinger)(\.[a-z]+)?$/); if (method === 'GET' && match) return new WebFinger(this, request, response).hostMeta(match[1], match[2]); - match = uri.pathname.match(/^\/webfinger\/(jrd|xrd)$/); + match = uri.pathname.match(/^webfinger\/(jrd|xrd)$/); if (method === 'GET' && match) return new WebFinger(this, request, response).account(match[1]); - match = uri.pathname.match(/^\/oauth\/(.*)$/); + match = uri.pathname.match(/^oauth\/(.*)$/); if (method === 'GET' && match) return new OAuth(this, request, response).showForm(decodeURIComponent(match[1])); - if (method === 'POST' && uri.pathname === '/oauth') + if (method === 'POST' && uri.pathname === 'oauth') return new OAuth(this, request, response).authenticate(); - if (uri.pathname === '/signup') { + if (uri.pathname === 'signup') { var users = new Users(this, request, response); if (method === 'GET') return users.showForm(); if (method === 'POST') return users.register(); } - match = uri.pathname.match(/^\/storage\/([^\/]+)(.*)$/); + match = uri.pathname.match(/^storage\/([^\/]+)(.*)$/); if (match) { var username = decodeURIComponent(match[1]).split('@')[0], path = match[2], @@ -145,7 +155,7 @@ Restore.prototype.dispatch = function(request, response) { if (method === 'DELETE') return storage.delete(); } - new Assets(this, request, response).errorPage(404, 'Not found'); + new Assets(this, request, response).errorPage(404, 'Not found ' + uri.pathname); }; Restore.prototype.isSecureRequest = function(r) { diff --git a/lib/views/auth.html b/lib/views/auth.html index f450cfd..027d57e 100644 --- a/lib/views/auth.html +++ b/lib/views/auth.html @@ -16,7 +16,7 @@

Authorize

<%= error %>

<% } %> -
+ diff --git a/lib/views/index.html b/lib/views/index.html index c60e47b..6b547a0 100644 --- a/lib/views/index.html +++ b/lib/views/index.html @@ -1,4 +1,4 @@ -

+

This is reStore, an open-source remoteStorage server. If you would like diff --git a/lib/views/layout.html b/lib/views/layout.html index 09b56ef..b4b53fb 100644 --- a/lib/views/layout.html +++ b/lib/views/layout.html @@ -5,7 +5,7 @@ <%= title %> - + @@ -14,8 +14,8 @@

Remote Storage <%= host %>

diff --git a/lib/views/signup.html b/lib/views/signup.html index 894c14b..61d2f39 100644 --- a/lib/views/signup.html +++ b/lib/views/signup.html @@ -1,6 +1,6 @@

Sign up

- + <% if (error) { %>

<%= error.message %>

<% } %> From 29db244fe21511ccd8eceb3107cf454a35cd52ab Mon Sep 17 00:00:00 2001 From: lesion Date: Mon, 5 Sep 2016 02:15:24 +0200 Subject: [PATCH 2/3] adding baseURL to WebFinger path --- lib/controllers/web_finger.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/controllers/web_finger.js b/lib/controllers/web_finger.js index dfd0b76..0b84c99 100644 --- a/lib/controllers/web_finger.js +++ b/lib/controllers/web_finger.js @@ -77,7 +77,7 @@ WebFinger.prototype.getOrigin = function() { var scheme = (this.request.secure || this.server._forceSSL) ? 'https' : 'http', host = this.request.headers['x-forwarded-host'] || this.request.headers.host; - return scheme + '://' + host; + return scheme + '://' + host + this.server._baseURL; }; module.exports = WebFinger; From 4bcf39bca52edaace7ed9bfdb4664e7afd93cfc3 Mon Sep 17 00:00:00 2001 From: lesion Date: Mon, 5 Sep 2016 23:22:25 +0200 Subject: [PATCH 3/3] cleaning PR - s/baseURL/basePath/ - better regexp --- lib/controllers/base.js | 4 ++-- lib/controllers/web_finger.js | 2 +- lib/restore.js | 30 +++++++++++++++--------------- lib/views/auth.html | 2 +- lib/views/index.html | 2 +- lib/views/layout.html | 6 +++--- lib/views/signup.html | 2 +- 7 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/controllers/base.js b/lib/controllers/base.js index 27393b3..f9a7fbb 100644 --- a/lib/controllers/base.js +++ b/lib/controllers/base.js @@ -104,12 +104,12 @@ Controller.prototype.renderHTML = function(status, file, locals) { body = this.readFile(viewDir + file); locals = locals || {}; - locals.baseURL = this.server._baseURL; + locals.basePath = this.server._basePath; var globals = { scheme: this.request.secure ? 'https' : 'http', host: this.getHost(), - baseURL: this.server._baseURL, + basePath: this.server._basePath, title: locals.title || '', signup: this.server._allow.signup, body: ejs.render(body.toString(), locals) diff --git a/lib/controllers/web_finger.js b/lib/controllers/web_finger.js index 0b84c99..58a4652 100644 --- a/lib/controllers/web_finger.js +++ b/lib/controllers/web_finger.js @@ -77,7 +77,7 @@ WebFinger.prototype.getOrigin = function() { var scheme = (this.request.secure || this.server._forceSSL) ? 'https' : 'http', host = this.request.headers['x-forwarded-host'] || this.request.headers.host; - return scheme + '://' + host + this.server._baseURL; + return scheme + '://' + host + this.server._basePath; }; module.exports = WebFinger; diff --git a/lib/restore.js b/lib/restore.js index b42303b..bb7ea60 100644 --- a/lib/restore.js +++ b/lib/restore.js @@ -23,7 +23,7 @@ var Restore = function(options) { this._fileCache = {}; this._allow = options.allow || {}; this._cacheViews = options.cacheViews !== false; - this._baseURL = options.baseURL || '' + this._basePath = options.basePath || '' var self = this; @@ -93,52 +93,52 @@ Restore.prototype.dispatch = function(request, response) { var method = request.method.toUpperCase(), uri = url.parse(request.url, true), match = null, - startBaseURL = new RegExp('^\/?' + this._baseURL + '\/?'); + startBasePath = new RegExp('^\/?' + this._basePath + '\/?'); request.secure = this.isSecureRequest(request); - if (!uri.pathname.match(startBaseURL)) { - response.writeHead(302, { 'Location': this._baseURL}) + if (!uri.pathname.match(startBasePath)) { + response.writeHead(302, {'Location': this._basePath}) return response.end() } - // remove baseURL and eventually a final '/' before real path - uri.pathname = uri.pathname.replace(startBaseURL, '') + // remove basePath before real path + uri.pathname = uri.pathname.replace(startBasePath, '/') if (/(^|\/)\.\.(\/|$)/.test(uri.pathname)) { response.writeHead(400, {'Access-Control-Allow-Origin': request.headers.origin || '*'}); return response.end(); } - if (method === 'GET' && uri.pathname === '') + if (method === 'GET' && uri.pathname === '/') return new Assets(this, request, response).renderHTML(200, 'index.html', {title: 'reStore'}); - match = uri.pathname.match(/^assets\/([^\/]+)$/); + match = uri.pathname.match(/^\/assets\/([^\/]+)$/); if (method === 'GET' && match) return new Assets(this, request, response).serve(match[1]); - match = uri.pathname.match(/^\.well-known\/(host-meta|webfinger)(\.[a-z]+)?$/); + match = uri.pathname.match(/^\/\.well-known\/(host-meta|webfinger)(\.[a-z]+)?$/); if (method === 'GET' && match) return new WebFinger(this, request, response).hostMeta(match[1], match[2]); - match = uri.pathname.match(/^webfinger\/(jrd|xrd)$/); + match = uri.pathname.match(/^\/webfinger\/(jrd|xrd)$/); if (method === 'GET' && match) return new WebFinger(this, request, response).account(match[1]); - match = uri.pathname.match(/^oauth\/(.*)$/); + match = uri.pathname.match(/^\/oauth\/(.*)$/); if (method === 'GET' && match) return new OAuth(this, request, response).showForm(decodeURIComponent(match[1])); - if (method === 'POST' && uri.pathname === 'oauth') + if (method === 'POST' && uri.pathname === '/oauth') return new OAuth(this, request, response).authenticate(); - if (uri.pathname === 'signup') { + if (uri.pathname === '/signup') { var users = new Users(this, request, response); if (method === 'GET') return users.showForm(); if (method === 'POST') return users.register(); } - match = uri.pathname.match(/^storage\/([^\/]+)(.*)$/); + match = uri.pathname.match(/^\/storage\/([^\/]+)(.*)$/); if (match) { var username = decodeURIComponent(match[1]).split('@')[0], path = match[2], @@ -155,7 +155,7 @@ Restore.prototype.dispatch = function(request, response) { if (method === 'DELETE') return storage.delete(); } - new Assets(this, request, response).errorPage(404, 'Not found ' + uri.pathname); + new Assets(this, request, response).errorPage(404, 'Not found'); }; Restore.prototype.isSecureRequest = function(r) { diff --git a/lib/views/auth.html b/lib/views/auth.html index 027d57e..10936be 100644 --- a/lib/views/auth.html +++ b/lib/views/auth.html @@ -16,7 +16,7 @@

Authorize

<%= error %>

<% } %> - + diff --git a/lib/views/index.html b/lib/views/index.html index 6b547a0..f13960a 100644 --- a/lib/views/index.html +++ b/lib/views/index.html @@ -1,4 +1,4 @@ -

+

This is reStore, an open-source remoteStorage server. If you would like diff --git a/lib/views/layout.html b/lib/views/layout.html index b4b53fb..fb22900 100644 --- a/lib/views/layout.html +++ b/lib/views/layout.html @@ -5,7 +5,7 @@ <%= title %> - + @@ -14,8 +14,8 @@

Remote Storage <%= host %>

diff --git a/lib/views/signup.html b/lib/views/signup.html index 61d2f39..f4856ee 100644 --- a/lib/views/signup.html +++ b/lib/views/signup.html @@ -1,6 +1,6 @@

Sign up

- + <% if (error) { %>

<%= error.message %>

<% } %>