From cfe0ae1eda4090404a297dba55f44683cbd4a630 Mon Sep 17 00:00:00 2001 From: azivner Date: Fri, 30 Mar 2018 17:29:13 -0400 Subject: [PATCH] converted file, script, search and sender routes --- src/routes/api/file_upload.js | 48 +++++++++++------------- src/routes/api/script.js | 43 +++++++++++----------- src/routes/api/search.js | 21 +++++------ src/routes/api/sender.js | 69 +++++++++++++---------------------- src/routes/routes.js | 22 +++++++++-- src/services/auth.js | 17 ++++++++- 6 files changed, 114 insertions(+), 106 deletions(-) diff --git a/src/routes/api/file_upload.js b/src/routes/api/file_upload.js index 6567c2193..59551a002 100644 --- a/src/routes/api/file_upload.js +++ b/src/routes/api/file_upload.js @@ -1,16 +1,11 @@ "use strict"; -const express = require('express'); -const router = express.Router(); const sql = require('../../services/sql'); -const auth = require('../../services/auth'); const notes = require('../../services/notes'); const labels = require('../../services/labels'); const protected_session = require('../../services/protected_session'); -const multer = require('multer')(); -const wrap = require('express-promise-wrap').wrap; -router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single('upload'), wrap(async (req, res, next) => { +async function uploadFile(req) { const sourceId = req.headers.source_id; const parentNoteId = req.params.parentNoteId; const file = req.file; @@ -20,29 +15,27 @@ router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single( const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]); if (!note) { - return res.status(404).send(`Note ${parentNoteId} doesn't exist.`); + return [404, `Note ${parentNoteId} doesn't exist.`]; } - await sql.doInTransaction(async () => { - const noteId = (await notes.createNewNote(parentNoteId, { - title: originalName, - content: file.buffer, - target: 'into', - isProtected: false, - type: 'file', - mime: file.mimetype - }, req, sourceId)).noteId; + const {noteId} = await notes.createNewNote(parentNoteId, { + title: originalName, + content: file.buffer, + target: 'into', + isProtected: false, + type: 'file', + mime: file.mimetype + }, req, sourceId); - await labels.createLabel(noteId, "original_file_name", originalName, sourceId); - await labels.createLabel(noteId, "file_size", size, sourceId); + await labels.createLabel(noteId, "original_file_name", originalName, sourceId); + await labels.createLabel(noteId, "file_size", size, sourceId); - res.send({ - noteId: noteId - }); - }); -})); + return { + noteId: noteId + }; +} -router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => { +async function downloadFile(req, res) { const noteId = req.params.noteId; const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); const protectedSessionId = req.query.protectedSessionId; @@ -69,6 +62,9 @@ router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, re res.setHeader('Content-Type', note.mime); res.send(note.content); -})); +} -module.exports = router; \ No newline at end of file +module.exports = { + uploadFile, + downloadFile +}; \ No newline at end of file diff --git a/src/routes/api/script.js b/src/routes/api/script.js index b644e09e4..4f5d3b1ab 100644 --- a/src/routes/api/script.js +++ b/src/routes/api/script.js @@ -1,55 +1,56 @@ "use strict"; -const express = require('express'); -const router = express.Router(); -const auth = require('../../services/auth'); -const wrap = require('express-promise-wrap').wrap; const labels = require('../../services/labels'); const script = require('../../services/script'); const Repository = require('../../services/repository'); -router.post('/exec', auth.checkApiAuth, wrap(async (req, res, next) => { +async function exec(req) { const ret = await script.executeScript(req, req.body.script, req.body.params, req.body.startNoteId, req.body.currentNoteId); - res.send({ + return { executionResult: ret - }); -})); + }; +} -router.post('/run/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { +async function run(req) { const repository = new Repository(req); const note = await repository.getNote(req.params.noteId); const ret = await script.executeNote(req, note); - res.send({ + return { executionResult: ret - }); -})); + }; +} -router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { +async function getStartupBundles(req) { const repository = new Repository(req); const notes = await labels.getNotesWithLabel(repository, "run", "frontend_startup"); - const scripts = []; + const bundles = []; for (const note of notes) { const bundle = await script.getScriptBundle(note); if (bundle) { - scripts.push(bundle); + bundles.push(bundle); } } - res.send(scripts); -})); + return bundles; +} -router.get('/bundle/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { +async function getBundle(req) { const repository = new Repository(req); const note = await repository.getNote(req.params.noteId); const bundle = await script.getScriptBundle(note); - res.send(bundle); -})); + return bundle; +} -module.exports = router; \ No newline at end of file +module.exports = { + exec, + run, + getStartupBundles, + getBundle +}; \ No newline at end of file diff --git a/src/routes/api/search.js b/src/routes/api/search.js index 7d280260c..2b7e0249c 100644 --- a/src/routes/api/search.js +++ b/src/routes/api/search.js @@ -1,25 +1,21 @@ "use strict"; -const express = require('express'); -const router = express.Router(); -const auth = require('../../services/auth'); const sql = require('../../services/sql'); const notes = require('../../services/notes'); -const wrap = require('express-promise-wrap').wrap; const parseFilters = require('../../services/parse_filters'); const buildSearchQuery = require('../../services/build_search_query'); -router.get('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => { +async function searchNotes(req) { const {attrFilters, searchText} = parseFilters(req.params.searchString); const {query, params} = buildSearchQuery(attrFilters, searchText); const noteIds = await sql.getColumn(query, params); - res.send(noteIds); -})); + return noteIds; +} -router.post('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => { +async function saveSearchToNote(req) { const noteContent = { searchString: req.params.searchString }; @@ -30,7 +26,10 @@ router.post('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) => mime: "application/json" }); - res.send({ noteId }); -})); + return { noteId }; +} -module.exports = router; \ No newline at end of file +module.exports = { + searchNotes, + saveSearchToNote +}; \ No newline at end of file diff --git a/src/routes/api/sender.js b/src/routes/api/sender.js index a85d3e188..f7f8ba3da 100644 --- a/src/routes/api/sender.js +++ b/src/routes/api/sender.js @@ -13,7 +13,7 @@ const password_encryption = require('../../services/password_encryption'); const options = require('../../services/options'); const sync_table = require('../../services/sync_table'); -router.post('/login', wrap(async (req, res, next) => { +async function login(req) { const username = req.body.username; const password = req.body.password; @@ -21,61 +21,44 @@ router.post('/login', wrap(async (req, res, next) => { const isPasswordValid = await password_encryption.verifyPassword(password); if (!isUsernameValid || !isPasswordValid) { - res.status(401).send("Incorrect username/password"); + return [401, "Incorrect username/password"]; } - else { - const token = utils.randomSecureToken(); - await sql.doInTransaction(async () => { - const apiTokenId = utils.newApiTokenId(); + const token = utils.randomSecureToken(); - await sql.insert("api_tokens", { - apiTokenId: apiTokenId, - token: token, - dateCreated: utils.nowDate(), - isDeleted: false - }); + const apiTokenId = utils.newApiTokenId(); - await sync_table.addApiTokenSync(apiTokenId); - }); + await sql.insert("api_tokens", { + apiTokenId: apiTokenId, + token: token, + dateCreated: utils.nowDate(), + isDeleted: false + }); - res.send({ - token: token - }); - } -})); + await sync_table.addApiTokenSync(apiTokenId); -async function checkSenderToken(req, res, next) { - const token = req.headers.authorization; - - if (await sql.getValue("SELECT COUNT(*) FROM api_tokens WHERE isDeleted = 0 AND token = ?", [token]) === 0) { - res.status(401).send("Not authorized"); - } - else if (await sql.isDbUpToDate()) { - next(); - } - else { - res.status(409).send("Mismatched app versions"); // need better response than that - } + return { + token: token + }; } -router.post('/image', checkSenderToken, multer.single('upload'), wrap(async (req, res, next) => { +async function uploadImage(req) { const file = req.file; if (!["image/png", "image/jpeg", "image/gif"].includes(file.mimetype)) { - return res.status(400).send("Unknown image type: " + file.mimetype); + return [400, "Unknown image type: " + file.mimetype]; } const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); - const noteId = (await notes.createNewNote(parentNoteId, { + const {noteId} = await notes.createNewNote(parentNoteId, { title: "Sender image", content: "", target: 'into', isProtected: false, type: 'text', mime: 'text/html' - })).noteId; + }); const {fileName, imageId} = await image.saveImage(file, null, noteId); @@ -84,11 +67,9 @@ router.post('/image', checkSenderToken, multer.single('upload'), wrap(async (req const content = ``; await sql.execute("UPDATE notes SET content = ? WHERE noteId = ?", [content, noteId]); +} - res.send({}); -})); - -router.post('/note', checkSenderToken, wrap(async (req, res, next) => { +async function saveNote(req) { const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); await notes.createNewNote(parentNoteId, { @@ -99,8 +80,10 @@ router.post('/note', checkSenderToken, wrap(async (req, res, next) => { type: 'text', mime: 'text/html' }); +} - res.send({}); -})); - -module.exports = router; \ No newline at end of file +module.exports = { + login, + uploadImage, + saveNote +}; \ No newline at end of file diff --git a/src/routes/routes.js b/src/routes/routes.js index 67280e248..602721963 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -92,6 +92,7 @@ function route(method, path, middleware, routeHandler, resultHandler) { } const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete'; +const uploadMiddleware = multer.single('upload'); function register(app) { app.use('/', indexRoute); @@ -180,10 +181,23 @@ function register(app) { httpApiRoute(GET, '/api/images/:imageId/:filename', imageRoute.returnImage); httpApiRoute(POST, '/api/images', imageRoute.uploadImage); - app.use('/api/script', scriptRoute); - app.use('/api/sender', senderRoute); - app.use('/api/files', filesRoute); - app.use('/api/search', searchRoute); + + apiRoute(POST, '/api/script/exec', scriptRoute.exec); + apiRoute(POST, '/api/script/run/:noteId', scriptRoute.run); + apiRoute(GET, '/api/script/startup', scriptRoute.getStartupBundles); + apiRoute(GET, '/api/script/bundle/:noteId', scriptRoute.getBundle); + + route(POST, '/api/sender/login', [], senderRoute.login, apiResultHandler); + route(POST, '/api/sender/image', [auth.checkSenderToken], senderRoute.uploadImage, apiResultHandler); + route(POST, '/api/sender/note', [auth.checkSenderToken], senderRoute.saveNote, apiResultHandler); + + route(POST, '/api/files/upload/:parentNoteId', [auth.checkApiAuthOrElectron, uploadMiddleware], + filesRoute.uploadFile, apiResultHandler); + + route(GET, '/api/files/download/:noteId', [auth.checkApiAuthOrElectron], filesRoute.downloadFile); + + apiRoute(GET, '/api/search/:searchString', searchRoute.searchNotes); + apiRoute(POST, '/api/search/:searchString', searchRoute.saveSearchToNote); app.use('', router); diff --git a/src/services/auth.js b/src/services/auth.js index 40a2bec57..0cb574ee1 100644 --- a/src/services/auth.js +++ b/src/services/auth.js @@ -72,11 +72,26 @@ async function checkAppNotInitialized(req, res, next) { } } +async function checkSenderToken(req, res, next) { + const token = req.headers.authorization; + + if (await sql.getValue("SELECT COUNT(*) FROM api_tokens WHERE isDeleted = 0 AND token = ?", [token]) === 0) { + res.status(401).send("Not authorized"); + } + else if (await sql.isDbUpToDate()) { + next(); + } + else { + res.status(409).send("Mismatched app versions"); // need better response than that + } +} + module.exports = { checkAuth, checkAuthForMigrationPage, checkApiAuth, checkApiAuthForMigrationPage, checkAppNotInitialized, - checkApiAuthOrElectron + checkApiAuthOrElectron, + checkSenderToken }; \ No newline at end of file