From 7268d24143dca10b75b64a6800cec9fdfa4e1d72 Mon Sep 17 00:00:00 2001 From: Pitu <7425261+Pitu@users.noreply.github.com> Date: Sun, 16 Sep 2018 00:55:30 -0300 Subject: Base structures --- src/api/structures/Route.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/api/structures/Route.js (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js new file mode 100644 index 0000000..77ebd32 --- /dev/null +++ b/src/api/structures/Route.js @@ -0,0 +1,44 @@ +const JWT = require('jsonwebtoken'); +const { server } = require('../../../config'); +const db = require('knex')(server.database); +const moment = require('moment'); + +class Route { + constructor(path, method, options) { + if (!path) throw new Error('Every route needs a URL associated with it.'); + if (!method) throw new Error('Every route needs its method specified.'); + + this.path = path; + this.method = method; + this.options = options || {}; + } + + authorize(req, res) { + if (this.options.bypassAuth) return this.run(req, res); + if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); + const token = req.headers.authorization.split(' ')[1]; + if (!token) return res.status(401).json({ message: 'No authorization header provided' }); + + return JWT.verify(token, server.secret, async (error, decoded) => { + if (error) { + console.log(error); + return res.status(401).json({ message: 'Your token appears to be invalid' }); + } + const id = decoded ? decoded.sub : ''; + const iat = decoded ? decoded.iat : ''; + + const user = await db.table('users').where({ id }).first(); + if (!user) return res.status(401).json({ message: 'Invalid authorization' }); + if (iat && iat < moment(user.passwordEditedAt).format('x')) return res.status(401).json({ message: 'Token expired' }); + if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); + + return this.run(req, res, user); + }); + } + + run(req, res, user) { // eslint-disable-line no-unused-vars + return; + } +} + +module.exports = Route; -- cgit v1.2.3 From f2c885b718528d42df412e612520fb471c46d0bd Mon Sep 17 00:00:00 2001 From: Pitu <7425261+Pitu@users.noreply.github.com> Date: Mon, 17 Sep 2018 04:55:42 -0300 Subject: Commented all the code --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 77ebd32..9ff65f0 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -2,6 +2,7 @@ const JWT = require('jsonwebtoken'); const { server } = require('../../../config'); const db = require('knex')(server.database); const moment = require('moment'); +const log = require('../utils/Log'); class Route { constructor(path, method, options) { @@ -21,7 +22,7 @@ class Route { return JWT.verify(token, server.secret, async (error, decoded) => { if (error) { - console.log(error); + log.error(error); return res.status(401).json({ message: 'Your token appears to be invalid' }); } const id = decoded ? decoded.sub : ''; -- cgit v1.2.3 From 89a271818ed25b0a17a17dd1d6804e34d1f2ec0f Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 19 Feb 2019 23:52:24 +0900 Subject: Switch config to .env --- src/api/structures/Route.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 9ff65f0..32d576f 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -1,6 +1,13 @@ const JWT = require('jsonwebtoken'); -const { server } = require('../../../config'); -const db = require('knex')(server.database); +const db = require('knex')({ + client: process.env.DB_CLIENT, + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_DATABASE + } +}); const moment = require('moment'); const log = require('../utils/Log'); @@ -15,12 +22,12 @@ class Route { } authorize(req, res) { - if (this.options.bypassAuth) return this.run(req, res); + if (this.options.bypassAuth) return this.run(req, res, db); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); const token = req.headers.authorization.split(' ')[1]; if (!token) return res.status(401).json({ message: 'No authorization header provided' }); - return JWT.verify(token, server.secret, async (error, decoded) => { + return JWT.verify(token, process.env.SECRET, async (error, decoded) => { if (error) { log.error(error); return res.status(401).json({ message: 'Your token appears to be invalid' }); @@ -33,13 +40,18 @@ class Route { if (iat && iat < moment(user.passwordEditedAt).format('x')) return res.status(401).json({ message: 'Token expired' }); if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); - return this.run(req, res, user); + return this.run(req, res, db, user); }); } - run(req, res, user) { // eslint-disable-line no-unused-vars + run(req, res, db) { // eslint-disable-line no-unused-vars return; } + + error(res, error) { + log.error(error); + return res.status(500).json({ message: 'There was a problem parsing the request' }); + } } module.exports = Route; -- cgit v1.2.3 From 25c5a06ec3e363f5b98607949b76b8b395e4c962 Mon Sep 17 00:00:00 2001 From: Pitu Date: Thu, 21 Feb 2019 23:05:56 +0900 Subject: derp --- src/api/structures/Route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 32d576f..480763e 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -4,7 +4,7 @@ const db = require('knex')({ connection: { host: process.env.DB_HOST, user: process.env.DB_USER, - password: process.env.DB_PASS, + password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE } }); -- cgit v1.2.3 From c7a4a39de4e6113e88f07fefb3668e9fd3b1372a Mon Sep 17 00:00:00 2001 From: Pitu Date: Fri, 22 Feb 2019 00:00:07 +0900 Subject: Add support for sqlite --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 480763e..4c89724 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -5,7 +5,8 @@ const db = require('knex')({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, - database: process.env.DB_DATABASE + database: process.env.DB_DATABASE, + filename: '../../../database.sqlite' } }); const moment = require('moment'); -- cgit v1.2.3 From 80a76d868fccc4639052a1cf605a495aa157dd72 Mon Sep 17 00:00:00 2001 From: Kana Date: Fri, 22 Feb 2019 15:06:29 +0900 Subject: Update Route.js --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 4c89724..5466147 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -1,3 +1,4 @@ +const nodePath = require('path'); const JWT = require('jsonwebtoken'); const db = require('knex')({ client: process.env.DB_CLIENT, @@ -6,7 +7,7 @@ const db = require('knex')({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, - filename: '../../../database.sqlite' + filename: nodePath.join(__dirname, '..', '..', '..', 'database.sqlite') } }); const moment = require('moment'); -- cgit v1.2.3 From fc95cb7b0f047806937c25f0fc1104c72b0a32cb Mon Sep 17 00:00:00 2001 From: Pitu Date: Sat, 23 Feb 2019 00:45:45 +0900 Subject: Better DB handling and stuff --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 5466147..60c8b06 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -8,7 +8,8 @@ const db = require('knex')({ password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, filename: nodePath.join(__dirname, '..', '..', '..', 'database.sqlite') - } + }, + useNullAsDefault: process.env.DB_CLIENT === 'sqlite' ? true : false }); const moment = require('moment'); const log = require('../utils/Log'); -- cgit v1.2.3 From ab66e095a8255f38dba4661951cc0359f309c403 Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 26 Feb 2019 22:26:35 +0900 Subject: Added adminOnly routes --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 60c8b06..a359488 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -33,7 +33,7 @@ class Route { return JWT.verify(token, process.env.SECRET, async (error, decoded) => { if (error) { log.error(error); - return res.status(401).json({ message: 'Your token appears to be invalid' }); + return res.status(401).json({ message: 'Invalid token' }); } const id = decoded ? decoded.sub : ''; const iat = decoded ? decoded.iat : ''; @@ -42,6 +42,7 @@ class Route { if (!user) return res.status(401).json({ message: 'Invalid authorization' }); if (iat && iat < moment(user.passwordEditedAt).format('x')) return res.status(401).json({ message: 'Token expired' }); if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); + if (this.options.adminOnly && !user.isAdmin) return res.status(401).json({ message: 'Invalid authorization' }); return this.run(req, res, db, user); }); -- cgit v1.2.3 From 107d1f4750e8f82a628b528c4ec200e918be271d Mon Sep 17 00:00:00 2001 From: Pitu Date: Tue, 19 Mar 2019 07:58:36 +0000 Subject: API key WIP --- src/api/structures/Route.js | 1 + 1 file changed, 1 insertion(+) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index a359488..19d33f9 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -26,6 +26,7 @@ class Route { authorize(req, res) { if (this.options.bypassAuth) return this.run(req, res, db); + console.log(req.headers); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); const token = req.headers.authorization.split(' ')[1]; if (!token) return res.status(401).json({ message: 'No authorization header provided' }); -- cgit v1.2.3 From b12cc4c28953ddef972193fd3986d6898bc4dba5 Mon Sep 17 00:00:00 2001 From: Pitu Date: Fri, 29 Mar 2019 00:36:50 +0900 Subject: WIP apiKey validation --- src/api/structures/Route.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index a359488..ecb2be0 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -13,6 +13,7 @@ const db = require('knex')({ }); const moment = require('moment'); const log = require('../utils/Log'); +const bcrypt = require('bcrypt'); class Route { constructor(path, method, options) { @@ -26,6 +27,8 @@ class Route { authorize(req, res) { if (this.options.bypassAuth) return this.run(req, res, db); + if (req.headers.apiKey) return this.authorizeApiKey(req, res, req.headers.apiKey); + if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); const token = req.headers.authorization.split(' ')[1]; if (!token) return res.status(401).json({ message: 'No authorization header provided' }); @@ -48,6 +51,17 @@ class Route { }); } + authorizeApiKey(req, res, apiKey) { + if (this.options.noApiKey) return res.status(401).json({ message: 'Api Key not allowed for this resource' }); + + /* + Need to read more into how api keys work before proceeding any further + + const comparePassword = await bcrypt.compare(password, user.password); + if (!comparePassword) return res.status(401).json({ message: 'Invalid authorization.' }); + */ + } + run(req, res, db) { // eslint-disable-line no-unused-vars return; } -- cgit v1.2.3 From 4b0966f857388ce5bfbd1ff04d51284647df593e Mon Sep 17 00:00:00 2001 From: Pitu Date: Fri, 5 Apr 2019 06:05:21 +0000 Subject: Ditched sqlite. Use postgres or mysql/mariadb --- src/api/structures/Route.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 8a73454..960dc4b 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -1,4 +1,3 @@ -const nodePath = require('path'); const JWT = require('jsonwebtoken'); const db = require('knex')({ client: process.env.DB_CLIENT, @@ -6,10 +5,8 @@ const db = require('knex')({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, - database: process.env.DB_DATABASE, - filename: nodePath.join(__dirname, '..', '..', '..', 'database.sqlite') - }, - useNullAsDefault: process.env.DB_CLIENT === 'sqlite' ? true : false + database: process.env.DB_DATABASE + } }); const moment = require('moment'); const log = require('../utils/Log'); -- cgit v1.2.3 From ac36cdc143f2210a746b22391b2a9160ddb57dcb Mon Sep 17 00:00:00 2001 From: Pitu Date: Wed, 24 Apr 2019 08:38:53 +0000 Subject: Standarize database calls to support sqlite as well as mysql/postgres --- src/api/structures/Route.js | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 960dc4b..17f210e 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -1,3 +1,4 @@ +const nodePath = require('path'); const JWT = require('jsonwebtoken'); const db = require('knex')({ client: process.env.DB_CLIENT, @@ -5,8 +6,38 @@ const db = require('knex')({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, - database: process.env.DB_DATABASE - } + database: process.env.DB_DATABASE, + filename: nodePath.join(__dirname, '..', '..', '..', 'database.sqlite') + }, + postProcessResponse: result => { + /* + Fun fact: Depending on the database used by the user and given that I don't want + to force a specific database for everyone because of the nature of this project, + some things like different data types for booleans need to be considered like in + the implementation below where sqlite returns 1 and 0 instead of true and false. + */ + const booleanFields = [ + 'enabled', + 'enableDownload', + 'isAdmin' + ]; + + const processResponse = row => { + Object.keys(row).forEach(key => { + if (booleanFields.includes(key)) { + row[key] = row[key] === 1 ? true : false; + } + }); + return row; + }; + + if (Array.isArray(result)) { + return result.map(row => processResponse(row)); + } + + return processResponse(result); + }, + useNullAsDefault: process.env.DB_CLIENT === 'sqlite3' ? true : false }); const moment = require('moment'); const log = require('../utils/Log'); -- cgit v1.2.3 From fec273b23b2d5792d0900151bb17a33ad3c8d9dc Mon Sep 17 00:00:00 2001 From: Pitu Date: Wed, 24 Apr 2019 08:41:49 +0000 Subject: Fix when response is not an object --- src/api/structures/Route.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 17f210e..cb2878b 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -31,11 +31,9 @@ const db = require('knex')({ return row; }; - if (Array.isArray(result)) { - return result.map(row => processResponse(row)); - } - - return processResponse(result); + if (Array.isArray(result)) return result.map(row => processResponse(row)); + if (typeof result === 'object') return processResponse(result); + return result; }, useNullAsDefault: process.env.DB_CLIENT === 'sqlite3' ? true : false }); -- cgit v1.2.3 From c074b5e1971c26a69c3f4801f92e8a1c1ad072cd Mon Sep 17 00:00:00 2001 From: Pitu Date: Wed, 24 Apr 2019 09:28:30 +0000 Subject: Fix database value conversion --- src/api/structures/Route.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index cb2878b..c04c585 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -25,7 +25,8 @@ const db = require('knex')({ const processResponse = row => { Object.keys(row).forEach(key => { if (booleanFields.includes(key)) { - row[key] = row[key] === 1 ? true : false; + if (row[key] === 0) row[key] = false; + else if (row[key] === 1) row[key] = true; } }); return row; -- cgit v1.2.3 From cba7bf8586f59a049f79aba586db201ac6f3530b Mon Sep 17 00:00:00 2001 From: Pitu Date: Sun, 13 Oct 2019 02:53:45 +0900 Subject: This commit adds a bunch of features for admins: * banning IP * see files from other users if you are admin * be able to see details of an uploaded file and it's user * improved display of thumbnails for non-image files --- src/api/structures/Route.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index c04c585..2db9bc6 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -52,7 +52,10 @@ class Route { this.options = options || {}; } - authorize(req, res) { + async authorize(req, res) { + const banned = await db.table('bans').where({ ip: req.ip }).first(); + if (banned) return res.status(401).json({ message: 'This IP has been banned from using the service.' }); + if (this.options.bypassAuth) return this.run(req, res, db); if (req.headers.apiKey) return this.authorizeApiKey(req, res, req.headers.apiKey); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); -- cgit v1.2.3 From 496477ebda3f6c347a9944e22daae447d15ebc31 Mon Sep 17 00:00:00 2001 From: Pitu Date: Mon, 11 May 2020 00:57:56 +0900 Subject: Feature: enable apiKey access to uploads and album fetching for the uploader/sharex/3rd party --- src/api/structures/Route.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 2db9bc6..23a3522 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -57,7 +57,9 @@ class Route { if (banned) return res.status(401).json({ message: 'This IP has been banned from using the service.' }); if (this.options.bypassAuth) return this.run(req, res, db); - if (req.headers.apiKey) return this.authorizeApiKey(req, res, req.headers.apiKey); + // The only reason I call it token here and not Api Key is to be backwards compatible with the uploader and sharex + // Small price to pay. + if (req.headers.token) return this.authorizeApiKey(req, res, req.headers.token); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); const token = req.headers.authorization.split(' ')[1]; @@ -81,15 +83,13 @@ class Route { }); } - authorizeApiKey(req, res, apiKey) { - if (this.options.noApiKey) return res.status(401).json({ message: 'Api Key not allowed for this resource' }); + async authorizeApiKey(req, res, apiKey) { + if (!this.options.canApiKey) return res.status(401).json({ message: 'Api Key not allowed for this resource' }); + const user = await db.table('users').where({ apiKey }).first(); + if (!user) return res.status(401).json({ message: 'Invalid authorization' }); + if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); - /* - Need to read more into how api keys work before proceeding any further - - const comparePassword = await bcrypt.compare(password, user.password); - if (!comparePassword) return res.status(401).json({ message: 'Invalid authorization.' }); - */ + return this.run(req, res, db, user); } run(req, res, db) { // eslint-disable-line no-unused-vars -- cgit v1.2.3 From f189ddf9e6e1dda0c8e56afd367bc378ee19b8fd Mon Sep 17 00:00:00 2001 From: Pitu Date: Thu, 25 Jun 2020 02:05:48 +0900 Subject: Cleanup --- src/api/structures/Route.js | 1 - 1 file changed, 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 23a3522..8956c24 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -40,7 +40,6 @@ const db = require('knex')({ }); const moment = require('moment'); const log = require('../utils/Log'); -const bcrypt = require('bcrypt'); class Route { constructor(path, method, options) { -- cgit v1.2.3 From dd46f79550d8e7a2f7a0364cc0fb8e7a38ed4aba Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Thu, 2 Jul 2020 23:40:35 +0300 Subject: feat: return APIKey when fetching user --- src/api/structures/Route.js | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 8956c24..2402481 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -7,7 +7,7 @@ const db = require('knex')({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, - filename: nodePath.join(__dirname, '..', '..', '..', 'database.sqlite') + filename: nodePath.join(__dirname, '../../../database.sqlite') }, postProcessResponse: result => { /* @@ -16,11 +16,7 @@ const db = require('knex')({ some things like different data types for booleans need to be considered like in the implementation below where sqlite returns 1 and 0 instead of true and false. */ - const booleanFields = [ - 'enabled', - 'enableDownload', - 'isAdmin' - ]; + const booleanFields = ['enabled', 'enableDownload', 'isAdmin']; const processResponse = row => { Object.keys(row).forEach(key => { @@ -52,7 +48,10 @@ class Route { } async authorize(req, res) { - const banned = await db.table('bans').where({ ip: req.ip }).first(); + const banned = await db + .table('bans') + .where({ ip: req.ip }) + .first(); if (banned) return res.status(401).json({ message: 'This IP has been banned from using the service.' }); if (this.options.bypassAuth) return this.run(req, res, db); @@ -72,11 +71,16 @@ class Route { const id = decoded ? decoded.sub : ''; const iat = decoded ? decoded.iat : ''; - const user = await db.table('users').where({ id }).first(); + const user = await db + .table('users') + .where({ id }) + .first(); if (!user) return res.status(401).json({ message: 'Invalid authorization' }); - if (iat && iat < moment(user.passwordEditedAt).format('x')) return res.status(401).json({ message: 'Token expired' }); + if (iat && iat < moment(user.passwordEditedAt).format('x')) + return res.status(401).json({ message: 'Token expired' }); if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); - if (this.options.adminOnly && !user.isAdmin) return res.status(401).json({ message: 'Invalid authorization' }); + if (this.options.adminOnly && !user.isAdmin) + return res.status(401).json({ message: 'Invalid authorization' }); return this.run(req, res, db, user); }); @@ -84,14 +88,18 @@ class Route { async authorizeApiKey(req, res, apiKey) { if (!this.options.canApiKey) return res.status(401).json({ message: 'Api Key not allowed for this resource' }); - const user = await db.table('users').where({ apiKey }).first(); + const user = await db + .table('users') + .where({ apiKey }) + .first(); if (!user) return res.status(401).json({ message: 'Invalid authorization' }); if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); return this.run(req, res, db, user); } - run(req, res, db) { // eslint-disable-line no-unused-vars + run(req, res, db) { + // eslint-disable-line no-unused-vars return; } -- cgit v1.2.3 From 49d3e3b203ee287a53beb2a04faa8bf38ace6834 Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Wed, 8 Jul 2020 03:15:27 +0300 Subject: feat: add morgan for logging requests if env is not production --- src/api/structures/Route.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 2402481..c2ad32e 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -7,9 +7,9 @@ const db = require('knex')({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, - filename: nodePath.join(__dirname, '../../../database.sqlite') + filename: nodePath.join(__dirname, '../../../database.sqlite'), }, - postProcessResponse: result => { + postProcessResponse: (result) => { /* Fun fact: Depending on the database used by the user and given that I don't want to force a specific database for everyone because of the nature of this project, @@ -18,8 +18,8 @@ const db = require('knex')({ */ const booleanFields = ['enabled', 'enableDownload', 'isAdmin']; - const processResponse = row => { - Object.keys(row).forEach(key => { + const processResponse = (row) => { + Object.keys(row).forEach((key) => { if (booleanFields.includes(key)) { if (row[key] === 0) row[key] = false; else if (row[key] === 1) row[key] = true; @@ -28,11 +28,11 @@ const db = require('knex')({ return row; }; - if (Array.isArray(result)) return result.map(row => processResponse(row)); + if (Array.isArray(result)) return result.map((row) => processResponse(row)); if (typeof result === 'object') return processResponse(result); return result; }, - useNullAsDefault: process.env.DB_CLIENT === 'sqlite3' ? true : false + useNullAsDefault: process.env.DB_CLIENT === 'sqlite3', }); const moment = require('moment'); const log = require('../utils/Log'); @@ -76,11 +76,9 @@ class Route { .where({ id }) .first(); if (!user) return res.status(401).json({ message: 'Invalid authorization' }); - if (iat && iat < moment(user.passwordEditedAt).format('x')) - return res.status(401).json({ message: 'Token expired' }); + if (iat && iat < moment(user.passwordEditedAt).format('x')) { return res.status(401).json({ message: 'Token expired' }); } if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); - if (this.options.adminOnly && !user.isAdmin) - return res.status(401).json({ message: 'Invalid authorization' }); + if (this.options.adminOnly && !user.isAdmin) { return res.status(401).json({ message: 'Invalid authorization' }); } return this.run(req, res, db, user); }); @@ -100,7 +98,7 @@ class Route { run(req, res, db) { // eslint-disable-line no-unused-vars - return; + } error(res, error) { -- cgit v1.2.3 From ad852de51a0d2dd5d29c08838d5a430c58849e74 Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Wed, 8 Jul 2020 04:00:12 +0300 Subject: chore: linter the entire project using the new rules --- src/api/structures/Route.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index c2ad32e..400ae3d 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -55,7 +55,8 @@ class Route { if (banned) return res.status(401).json({ message: 'This IP has been banned from using the service.' }); if (this.options.bypassAuth) return this.run(req, res, db); - // The only reason I call it token here and not Api Key is to be backwards compatible with the uploader and sharex + // The only reason I call it token here and not Api Key is to be backwards compatible + // with the uploader and sharex // Small price to pay. if (req.headers.token) return this.authorizeApiKey(req, res, req.headers.token); if (!req.headers.authorization) return res.status(401).json({ message: 'No authorization header provided' }); @@ -96,10 +97,7 @@ class Route { return this.run(req, res, db, user); } - run(req, res, db) { - // eslint-disable-line no-unused-vars - - } + run() {} error(res, error) { log.error(error); -- cgit v1.2.3 From 746a4546122be2ed79ad5858de6ce2c686f78ef0 Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Thu, 9 Jul 2020 02:22:08 +0300 Subject: fix: stop leaking user's password and their apikey to admins --- src/api/structures/Route.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 400ae3d..6be0dc7 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -77,7 +77,9 @@ class Route { .where({ id }) .first(); if (!user) return res.status(401).json({ message: 'Invalid authorization' }); - if (iat && iat < moment(user.passwordEditedAt).format('x')) { return res.status(401).json({ message: 'Token expired' }); } + if (iat && iat < moment(user.passwordEditedAt).format('x')) { + return res.status(401).json({ message: 'Token expired' }); + } if (!user.enabled) return res.status(401).json({ message: 'This account has been disabled' }); if (this.options.adminOnly && !user.isAdmin) { return res.status(401).json({ message: 'Invalid authorization' }); } -- cgit v1.2.3 From 90001c2df56d58e69fd199a518ae7f3e4ed327fc Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Thu, 24 Dec 2020 10:40:50 +0200 Subject: chore: remove trailing commas --- src/api/structures/Route.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 6be0dc7..74589c5 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -7,7 +7,7 @@ const db = require('knex')({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, - filename: nodePath.join(__dirname, '../../../database.sqlite'), + filename: nodePath.join(__dirname, '../../../database.sqlite') }, postProcessResponse: (result) => { /* @@ -32,7 +32,7 @@ const db = require('knex')({ if (typeof result === 'object') return processResponse(result); return result; }, - useNullAsDefault: process.env.DB_CLIENT === 'sqlite3', + useNullAsDefault: process.env.DB_CLIENT === 'sqlite3' }); const moment = require('moment'); const log = require('../utils/Log'); -- cgit v1.2.3 From fb2c27086f570fec60f4d52dcc9ca80e53186293 Mon Sep 17 00:00:00 2001 From: Pitu Date: Thu, 24 Dec 2020 23:45:16 +0900 Subject: Fix ESLint rules once and for all --- src/api/structures/Route.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 74589c5..3806325 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -9,7 +9,7 @@ const db = require('knex')({ database: process.env.DB_DATABASE, filename: nodePath.join(__dirname, '../../../database.sqlite') }, - postProcessResponse: (result) => { + postProcessResponse: result => { /* Fun fact: Depending on the database used by the user and given that I don't want to force a specific database for everyone because of the nature of this project, @@ -18,8 +18,8 @@ const db = require('knex')({ */ const booleanFields = ['enabled', 'enableDownload', 'isAdmin']; - const processResponse = (row) => { - Object.keys(row).forEach((key) => { + const processResponse = row => { + Object.keys(row).forEach(key => { if (booleanFields.includes(key)) { if (row[key] === 0) row[key] = false; else if (row[key] === 1) row[key] = true; @@ -28,7 +28,7 @@ const db = require('knex')({ return row; }; - if (Array.isArray(result)) return result.map((row) => processResponse(row)); + if (Array.isArray(result)) return result.map(row => processResponse(row)); if (typeof result === 'object') return processResponse(result); return result; }, -- cgit v1.2.3 From f73cde6bb501d72e46f0aadf95e6809e9d265e5b Mon Sep 17 00:00:00 2001 From: Pitu Date: Fri, 25 Dec 2020 03:58:19 +0900 Subject: Chore: Move database to a subfolder for docker purposes --- src/api/structures/Route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index 3806325..ff69e77 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -7,7 +7,7 @@ const db = require('knex')({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_DATABASE, - filename: nodePath.join(__dirname, '../../../database.sqlite') + filename: nodePath.join(__dirname, '../../../database/database.sqlite') }, postProcessResponse: result => { /* -- cgit v1.2.3 From 13058d99d658c0920ce75b79d6b24df18a873ea9 Mon Sep 17 00:00:00 2001 From: Zephyrrus Date: Sun, 27 Dec 2020 18:18:06 +0200 Subject: fix: nsfw album toggle doesn't propagate the changes properly fix: add nsfw flag to the booleanFields in knex postProcessResponse --- src/api/structures/Route.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/api/structures/Route.js') diff --git a/src/api/structures/Route.js b/src/api/structures/Route.js index ff69e77..bb7ba87 100644 --- a/src/api/structures/Route.js +++ b/src/api/structures/Route.js @@ -16,7 +16,7 @@ const db = require('knex')({ some things like different data types for booleans need to be considered like in the implementation below where sqlite returns 1 and 0 instead of true and false. */ - const booleanFields = ['enabled', 'enableDownload', 'isAdmin']; + const booleanFields = ['enabled', 'enableDownload', 'isAdmin', 'nsfw']; const processResponse = row => { Object.keys(row).forEach(key => { -- cgit v1.2.3