diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | CHANGELOG | 3 | ||||
-rw-r--r-- | CloudronManifest.json | 1 | ||||
-rw-r--r-- | npm-shrinkwrap.json | 25 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rwxr-xr-x | server.js | 21 | ||||
-rw-r--r-- | src/auth.js | 46 | ||||
-rwxr-xr-x | start.sh | 1 |
8 files changed, 36 insertions, 63 deletions
@@ -2,3 +2,4 @@ node_modules/ | |||
2 | files/ | 2 | files/ |
3 | .users.json | 3 | .users.json |
4 | .config.json | 4 | .config.json |
5 | .tokens.json | ||
@@ -67,3 +67,6 @@ | |||
67 | [5.2.0] | 67 | [5.2.0] |
68 | * Disable folder listing by default | 68 | * Disable folder listing by default |
69 | * Do not render welcome screen if folder listing is enabled | 69 | * Do not render welcome screen if folder listing is enabled |
70 | |||
71 | [5.3.0] | ||
72 | * Replacing redis token store with local json file | ||
diff --git a/CloudronManifest.json b/CloudronManifest.json index 9e16c41..a58e260 100644 --- a/CloudronManifest.json +++ b/CloudronManifest.json | |||
@@ -19,7 +19,6 @@ | |||
19 | "icon": "logo.png", | 19 | "icon": "logo.png", |
20 | "addons": { | 20 | "addons": { |
21 | "ldap": {}, | 21 | "ldap": {}, |
22 | "redis": {}, | ||
23 | "localstorage": {} | 22 | "localstorage": {} |
24 | }, | 23 | }, |
25 | "mediaLinks": [ | 24 | "mediaLinks": [ |
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 2edb3ea..1d88103 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json | |||
@@ -429,11 +429,6 @@ | |||
429 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", | 429 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", |
430 | "dev": true | 430 | "dev": true |
431 | }, | 431 | }, |
432 | "double-ended-queue": { | ||
433 | "version": "2.1.0-0", | ||
434 | "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", | ||
435 | "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" | ||
436 | }, | ||
437 | "dtrace-provider": { | 432 | "dtrace-provider": { |
438 | "version": "0.2.8", | 433 | "version": "0.2.8", |
439 | "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.2.8.tgz", | 434 | "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.2.8.tgz", |
@@ -1300,26 +1295,6 @@ | |||
1300 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", | 1295 | "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.9.tgz", |
1301 | "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" | 1296 | "integrity": "sha1-PtqOZfI80qF+YTAbHwADOWr17No=" |
1302 | }, | 1297 | }, |
1303 | "redis": { | ||
1304 | "version": "2.8.0", | ||
1305 | "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", | ||
1306 | "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", | ||
1307 | "requires": { | ||
1308 | "double-ended-queue": "2.1.0-0", | ||
1309 | "redis-commands": "1.3.1", | ||
1310 | "redis-parser": "2.6.0" | ||
1311 | } | ||
1312 | }, | ||
1313 | "redis-commands": { | ||
1314 | "version": "1.3.1", | ||
1315 | "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", | ||
1316 | "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=" | ||
1317 | }, | ||
1318 | "redis-parser": { | ||
1319 | "version": "2.6.0", | ||
1320 | "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", | ||
1321 | "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" | ||
1322 | }, | ||
1323 | "reduce-component": { | 1298 | "reduce-component": { |
1324 | "version": "1.0.1", | 1299 | "version": "1.0.1", |
1325 | "resolved": "http://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz", | 1300 | "resolved": "http://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz", |
diff --git a/package.json b/package.json index 07e052d..159dddb 100644 --- a/package.json +++ b/package.json | |||
@@ -40,7 +40,6 @@ | |||
40 | "passport-http-bearer": "^1.0.1", | 40 | "passport-http-bearer": "^1.0.1", |
41 | "passport-ldapjs": "^1.0.3", | 41 | "passport-ldapjs": "^1.0.3", |
42 | "readline-sync": "^1.4.9", | 42 | "readline-sync": "^1.4.9", |
43 | "redis": "^2.8.0", | ||
44 | "request": "^2.83.0", | 43 | "request": "^2.83.0", |
45 | "safetydance": "^0.1.1", | 44 | "safetydance": "^0.1.1", |
46 | "serve-index": "^1.9.1", | 45 | "serve-index": "^1.9.1", |
@@ -22,11 +22,11 @@ var express = require('express'), | |||
22 | files = require('./src/files.js')(path.resolve(__dirname, process.argv[2] || 'files')); | 22 | files = require('./src/files.js')(path.resolve(__dirname, process.argv[2] || 'files')); |
23 | 23 | ||
24 | 24 | ||
25 | var rootFolder = path.resolve(__dirname, process.argv[2] || 'files'); | 25 | const ROOT_FOLDER = path.resolve(__dirname, process.argv[2] || 'files'); |
26 | var configFile = path.resolve(__dirname, process.argv[3] || '.config.json'); | 26 | const CONFIG_FILE = path.resolve(__dirname, process.argv[3] || '.config.json'); |
27 | 27 | ||
28 | // Ensure the root folder exists | 28 | // Ensure the root folder exists |
29 | mkdirp.sync(rootFolder); | 29 | mkdirp.sync(ROOT_FOLDER); |
30 | 30 | ||
31 | var config = { | 31 | var config = { |
32 | folderListingEnabled: false | 32 | folderListingEnabled: false |
@@ -41,7 +41,7 @@ function setSettings(req, res, next) { | |||
41 | 41 | ||
42 | config.folderListingEnabled = !!req.body.folderListingEnabled; | 42 | config.folderListingEnabled = !!req.body.folderListingEnabled; |
43 | 43 | ||
44 | fs.writeFile(configFile, JSON.stringify(config), function (error) { | 44 | fs.writeFile(CONFIG_FILE, JSON.stringify(config), function (error) { |
45 | if (error) return next(new HttpError(500, 'unable to save settings')); | 45 | if (error) return next(new HttpError(500, 'unable to save settings')); |
46 | 46 | ||
47 | next(new HttpSuccess(201, {})); | 47 | next(new HttpSuccess(201, {})); |
@@ -50,10 +50,11 @@ function setSettings(req, res, next) { | |||
50 | 50 | ||
51 | // Load the config file | 51 | // Load the config file |
52 | try { | 52 | try { |
53 | config = require(configFile); | 53 | console.log(`Using config file: ${CONFIG_FILE}`); |
54 | config = require(CONFIG_FILE); | ||
54 | } catch (e) { | 55 | } catch (e) { |
55 | if (e.code === 'MODULE_NOT_FOUND') console.log(`Config file ${configFile} not found`); | 56 | if (e.code === 'MODULE_NOT_FOUND') console.log(`Config file ${CONFIG_FILE} not found`); |
56 | else console.log(`Cannot load config file ${configFile}`, e); | 57 | else console.log(`Cannot load config file ${CONFIG_FILE}`, e); |
57 | } | 58 | } |
58 | 59 | ||
59 | if (typeof config.folderListingEnabled === 'undefined') config.folderListingEnabled = true; | 60 | if (typeof config.folderListingEnabled === 'undefined') config.folderListingEnabled = true; |
@@ -85,7 +86,7 @@ app.use('/api', passport.initialize()); | |||
85 | app.use('/api', passport.session()); | 86 | app.use('/api', passport.session()); |
86 | app.use(router); | 87 | app.use(router); |
87 | app.use('/_admin', express.static(__dirname + '/frontend')); | 88 | app.use('/_admin', express.static(__dirname + '/frontend')); |
88 | app.use('/', express.static(rootFolder)); | 89 | app.use('/', express.static(ROOT_FOLDER)); |
89 | app.use('/', function welcomePage(req, res, next) { | 90 | app.use('/', function welcomePage(req, res, next) { |
90 | if (config.folderListingEnabled || req.path !== '/') return next(); | 91 | if (config.folderListingEnabled || req.path !== '/') return next(); |
91 | res.status(200).sendFile(path.join(__dirname, '/frontend/welcome.html')); | 92 | res.status(200).sendFile(path.join(__dirname, '/frontend/welcome.html')); |
@@ -94,7 +95,7 @@ app.use('/', function (req, res, next) { | |||
94 | if (config.folderListingEnabled) return next(); | 95 | if (config.folderListingEnabled) return next(); |
95 | res.sendFile(__dirname + '/frontend/404.html'); | 96 | res.sendFile(__dirname + '/frontend/404.html'); |
96 | }); | 97 | }); |
97 | app.use('/', serveIndex(rootFolder, { icons: true })); | 98 | app.use('/', serveIndex(ROOT_FOLDER, { icons: true })); |
98 | app.use(lastMile()); | 99 | app.use(lastMile()); |
99 | 100 | ||
100 | var server = app.listen(3000, function () { | 101 | var server = app.listen(3000, function () { |
@@ -102,5 +103,5 @@ var server = app.listen(3000, function () { | |||
102 | var port = server.address().port; | 103 | var port = server.address().port; |
103 | 104 | ||
104 | console.log('Surfer listening on http://%s:%s', host, port); | 105 | console.log('Surfer listening on http://%s:%s', host, port); |
105 | console.log('Using base path', rootFolder); | 106 | console.log('Using base path', ROOT_FOLDER); |
106 | }); | 107 | }); |
diff --git a/src/auth.js b/src/auth.js index 0338632..093f297 100644 --- a/src/auth.js +++ b/src/auth.js | |||
@@ -3,53 +3,47 @@ | |||
3 | var passport = require('passport'), | 3 | var passport = require('passport'), |
4 | path = require('path'), | 4 | path = require('path'), |
5 | safe = require('safetydance'), | 5 | safe = require('safetydance'), |
6 | fs = require('fs'), | ||
6 | bcrypt = require('bcryptjs'), | 7 | bcrypt = require('bcryptjs'), |
7 | uuid = require('uuid/v4'), | 8 | uuid = require('uuid/v4'), |
8 | redis = require('redis'), | ||
9 | BearerStrategy = require('passport-http-bearer').Strategy, | 9 | BearerStrategy = require('passport-http-bearer').Strategy, |
10 | LdapStrategy = require('passport-ldapjs').Strategy, | 10 | LdapStrategy = require('passport-ldapjs').Strategy, |
11 | HttpError = require('connect-lastmile').HttpError, | 11 | HttpError = require('connect-lastmile').HttpError, |
12 | HttpSuccess = require('connect-lastmile').HttpSuccess; | 12 | HttpSuccess = require('connect-lastmile').HttpSuccess; |
13 | 13 | ||
14 | var LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json'); | 14 | const LOCAL_AUTH_FILE = path.resolve(process.env.LOCAL_AUTH_FILE || './.users.json'); |
15 | const TOKENSTORE_FILE = path.resolve(process.env.TOKENSTORE_FILE || './.tokens.json'); | ||
15 | 16 | ||
16 | var tokenStore = { | 17 | var tokenStore = { |
17 | data: {}, | 18 | data: {}, |
19 | save: function () { | ||
20 | try { | ||
21 | fs.writeFileSync(TOKENSTORE_FILE, JSON.stringify(tokenStore.data), 'utf-8'); | ||
22 | } catch (e) { | ||
23 | console.error(`Unable to save tokenstore file at ${TOKENSTORE_FILE}`, e); | ||
24 | } | ||
25 | }, | ||
18 | get: function (token, callback) { | 26 | get: function (token, callback) { |
19 | callback(tokenStore.data[token] ? null : 'not found', tokenStore.data[token]); | 27 | callback(tokenStore.data[token] ? null : 'not found', tokenStore.data[token]); |
20 | }, | 28 | }, |
21 | set: function (token, data, callback) { | 29 | set: function (token, data, callback) { |
22 | tokenStore.data[token] = data; | 30 | tokenStore.data[token] = data; |
31 | tokenStore.save(); | ||
23 | callback(null); | 32 | callback(null); |
24 | }, | 33 | }, |
25 | del: function (token, callback) { | 34 | del: function (token, callback) { |
26 | delete tokenStore.data[token]; | 35 | delete tokenStore.data[token]; |
36 | tokenStore.save(); | ||
27 | callback(null); | 37 | callback(null); |
28 | } | 38 | } |
29 | }; | 39 | }; |
30 | 40 | ||
31 | if (process.env.REDIS_URL) { | 41 | // load token store data if any |
32 | console.log('Enable redis token store'); | 42 | try { |
33 | 43 | console.log(`Using tokenstore file: ${TOKENSTORE_FILE}`); | |
34 | var redisClient = redis.createClient(process.env.REDIS_URL); | 44 | tokenStore.data = JSON.parse(fs.readFileSync(TOKENSTORE_FILE, 'utf-8')); |
35 | 45 | } catch (e) { | |
36 | if (process.env.REDIS_PASSWORD) { | 46 | // start with empty token store |
37 | console.log('Using redis auth'); | ||
38 | redisClient.auth(process.env.REDIS_PASSWORD); | ||
39 | } | ||
40 | |||
41 | // overwrite the tokenStore api | ||
42 | tokenStore.get = function (token, callback) { | ||
43 | redisClient.get(token, function (error, result) { | ||
44 | callback(error || null, safe.JSON.parse(result)); | ||
45 | }); | ||
46 | }; | ||
47 | tokenStore.set = function (token, data, callback) { | ||
48 | redisClient.set(token, JSON.stringify(data), callback); | ||
49 | }; | ||
50 | tokenStore.del = redisClient.del.bind(redisClient); | ||
51 | } else { | ||
52 | console.log('Use in-memory token store'); | ||
53 | } | 47 | } |
54 | 48 | ||
55 | function issueAccessToken() { | 49 | function issueAccessToken() { |
@@ -77,11 +71,11 @@ var LDAP_URL = process.env.LDAP_URL; | |||
77 | var LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN; | 71 | var LDAP_USERS_BASE_DN = process.env.LDAP_USERS_BASE_DN; |
78 | 72 | ||
79 | if (LDAP_URL && LDAP_USERS_BASE_DN) { | 73 | if (LDAP_URL && LDAP_USERS_BASE_DN) { |
80 | console.log('Enable ldap auth'); | 74 | console.log('Using ldap auth'); |
81 | 75 | ||
82 | exports.login = [ passport.authenticate('ldap'), issueAccessToken() ]; | 76 | exports.login = [ passport.authenticate('ldap'), issueAccessToken() ]; |
83 | } else { | 77 | } else { |
84 | console.log('Use local user file:', LOCAL_AUTH_FILE); | 78 | console.log(`Using local user file: ${LOCAL_AUTH_FILE}`); |
85 | 79 | ||
86 | exports.login = [ | 80 | exports.login = [ |
87 | function (req, res, next) { | 81 | function (req, res, next) { |
@@ -3,6 +3,7 @@ | |||
3 | set -eu | 3 | set -eu |
4 | 4 | ||
5 | export NODE_ENV=production | 5 | export NODE_ENV=production |
6 | export TOKENSTORE_FILE=/app/data/tokens.json | ||
6 | 7 | ||
7 | if [[ ! -d "/app/data/surfer_root" ]]; then | 8 | if [[ ! -d "/app/data/surfer_root" ]]; then |
8 | echo "=> Migrating root folder from /app/data to /app/data/surfer_root" | 9 | echo "=> Migrating root folder from /app/data to /app/data/surfer_root" |