converted file, script, search and sender routes

This commit is contained in:
azivner 2018-03-30 17:29:13 -04:00
parent aa57a64c61
commit cfe0ae1eda
6 changed files with 114 additions and 106 deletions

View File

@ -1,16 +1,11 @@
"use strict"; "use strict";
const express = require('express');
const router = express.Router();
const sql = require('../../services/sql'); const sql = require('../../services/sql');
const auth = require('../../services/auth');
const notes = require('../../services/notes'); const notes = require('../../services/notes');
const labels = require('../../services/labels'); const labels = require('../../services/labels');
const protected_session = require('../../services/protected_session'); 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 sourceId = req.headers.source_id;
const parentNoteId = req.params.parentNoteId; const parentNoteId = req.params.parentNoteId;
const file = req.file; 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]); const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]);
if (!note) { 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, {
const noteId = (await notes.createNewNote(parentNoteId, { title: originalName,
title: originalName, content: file.buffer,
content: file.buffer, target: 'into',
target: 'into', isProtected: false,
isProtected: false, type: 'file',
type: 'file', mime: file.mimetype
mime: file.mimetype }, req, sourceId);
}, req, sourceId)).noteId;
await labels.createLabel(noteId, "original_file_name", originalName, sourceId); await labels.createLabel(noteId, "original_file_name", originalName, sourceId);
await labels.createLabel(noteId, "file_size", size, sourceId); await labels.createLabel(noteId, "file_size", size, sourceId);
res.send({ return {
noteId: noteId noteId: noteId
}); };
}); }
}));
router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => { async function downloadFile(req, res) {
const noteId = req.params.noteId; const noteId = req.params.noteId;
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
const protectedSessionId = req.query.protectedSessionId; 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.setHeader('Content-Type', note.mime);
res.send(note.content); res.send(note.content);
})); }
module.exports = router; module.exports = {
uploadFile,
downloadFile
};

View File

@ -1,55 +1,56 @@
"use strict"; "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 labels = require('../../services/labels');
const script = require('../../services/script'); const script = require('../../services/script');
const Repository = require('../../services/repository'); 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); const ret = await script.executeScript(req, req.body.script, req.body.params, req.body.startNoteId, req.body.currentNoteId);
res.send({ return {
executionResult: ret executionResult: ret
}); };
})); }
router.post('/run/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => { async function run(req) {
const repository = new Repository(req); const repository = new Repository(req);
const note = await repository.getNote(req.params.noteId); const note = await repository.getNote(req.params.noteId);
const ret = await script.executeNote(req, note); const ret = await script.executeNote(req, note);
res.send({ return {
executionResult: ret executionResult: ret
}); };
})); }
router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => { async function getStartupBundles(req) {
const repository = new Repository(req); const repository = new Repository(req);
const notes = await labels.getNotesWithLabel(repository, "run", "frontend_startup"); const notes = await labels.getNotesWithLabel(repository, "run", "frontend_startup");
const scripts = []; const bundles = [];
for (const note of notes) { for (const note of notes) {
const bundle = await script.getScriptBundle(note); const bundle = await script.getScriptBundle(note);
if (bundle) { 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 repository = new Repository(req);
const note = await repository.getNote(req.params.noteId); const note = await repository.getNote(req.params.noteId);
const bundle = await script.getScriptBundle(note); const bundle = await script.getScriptBundle(note);
res.send(bundle); return bundle;
})); }
module.exports = router; module.exports = {
exec,
run,
getStartupBundles,
getBundle
};

View File

@ -1,25 +1,21 @@
"use strict"; "use strict";
const express = require('express');
const router = express.Router();
const auth = require('../../services/auth');
const sql = require('../../services/sql'); const sql = require('../../services/sql');
const notes = require('../../services/notes'); const notes = require('../../services/notes');
const wrap = require('express-promise-wrap').wrap;
const parseFilters = require('../../services/parse_filters'); const parseFilters = require('../../services/parse_filters');
const buildSearchQuery = require('../../services/build_search_query'); 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 {attrFilters, searchText} = parseFilters(req.params.searchString);
const {query, params} = buildSearchQuery(attrFilters, searchText); const {query, params} = buildSearchQuery(attrFilters, searchText);
const noteIds = await sql.getColumn(query, params); 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 = { const noteContent = {
searchString: req.params.searchString searchString: req.params.searchString
}; };
@ -30,7 +26,10 @@ router.post('/:searchString', auth.checkApiAuth, wrap(async (req, res, next) =>
mime: "application/json" mime: "application/json"
}); });
res.send({ noteId }); return { noteId };
})); }
module.exports = router; module.exports = {
searchNotes,
saveSearchToNote
};

View File

@ -13,7 +13,7 @@ const password_encryption = require('../../services/password_encryption');
const options = require('../../services/options'); const options = require('../../services/options');
const sync_table = require('../../services/sync_table'); 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 username = req.body.username;
const password = req.body.password; const password = req.body.password;
@ -21,61 +21,44 @@ router.post('/login', wrap(async (req, res, next) => {
const isPasswordValid = await password_encryption.verifyPassword(password); const isPasswordValid = await password_encryption.verifyPassword(password);
if (!isUsernameValid || !isPasswordValid) { 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 token = utils.randomSecureToken();
const apiTokenId = utils.newApiTokenId();
await sql.insert("api_tokens", { const apiTokenId = utils.newApiTokenId();
apiTokenId: apiTokenId,
token: token,
dateCreated: utils.nowDate(),
isDeleted: false
});
await sync_table.addApiTokenSync(apiTokenId); await sql.insert("api_tokens", {
}); apiTokenId: apiTokenId,
token: token,
dateCreated: utils.nowDate(),
isDeleted: false
});
res.send({ await sync_table.addApiTokenSync(apiTokenId);
token: token
});
}
}));
async function checkSenderToken(req, res, next) { return {
const token = req.headers.authorization; token: token
};
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
}
} }
router.post('/image', checkSenderToken, multer.single('upload'), wrap(async (req, res, next) => { async function uploadImage(req) {
const file = req.file; const file = req.file;
if (!["image/png", "image/jpeg", "image/gif"].includes(file.mimetype)) { 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 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", title: "Sender image",
content: "", content: "",
target: 'into', target: 'into',
isProtected: false, isProtected: false,
type: 'text', type: 'text',
mime: 'text/html' mime: 'text/html'
})).noteId; });
const {fileName, imageId} = await image.saveImage(file, null, 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 = `<img src="${url}"/>`; const content = `<img src="${url}"/>`;
await sql.execute("UPDATE notes SET content = ? WHERE noteId = ?", [content, noteId]); await sql.execute("UPDATE notes SET content = ? WHERE noteId = ?", [content, noteId]);
}
res.send({}); async function saveNote(req) {
}));
router.post('/note', checkSenderToken, wrap(async (req, res, next) => {
const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']); const parentNoteId = await date_notes.getDateNoteId(req.headers['x-local-date']);
await notes.createNewNote(parentNoteId, { await notes.createNewNote(parentNoteId, {
@ -99,8 +80,10 @@ router.post('/note', checkSenderToken, wrap(async (req, res, next) => {
type: 'text', type: 'text',
mime: 'text/html' mime: 'text/html'
}); });
}
res.send({}); module.exports = {
})); login,
uploadImage,
module.exports = router; saveNote
};

View File

@ -92,6 +92,7 @@ function route(method, path, middleware, routeHandler, resultHandler) {
} }
const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete'; const GET = 'get', POST = 'post', PUT = 'put', DELETE = 'delete';
const uploadMiddleware = multer.single('upload');
function register(app) { function register(app) {
app.use('/', indexRoute); app.use('/', indexRoute);
@ -180,10 +181,23 @@ function register(app) {
httpApiRoute(GET, '/api/images/:imageId/:filename', imageRoute.returnImage); httpApiRoute(GET, '/api/images/:imageId/:filename', imageRoute.returnImage);
httpApiRoute(POST, '/api/images', imageRoute.uploadImage); httpApiRoute(POST, '/api/images', imageRoute.uploadImage);
app.use('/api/script', scriptRoute);
app.use('/api/sender', senderRoute); apiRoute(POST, '/api/script/exec', scriptRoute.exec);
app.use('/api/files', filesRoute); apiRoute(POST, '/api/script/run/:noteId', scriptRoute.run);
app.use('/api/search', searchRoute); 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); app.use('', router);

View File

@ -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 = { module.exports = {
checkAuth, checkAuth,
checkAuthForMigrationPage, checkAuthForMigrationPage,
checkApiAuth, checkApiAuth,
checkApiAuthForMigrationPage, checkApiAuthForMigrationPage,
checkAppNotInitialized, checkAppNotInitialized,
checkApiAuthOrElectron checkApiAuthOrElectron,
checkSenderToken
}; };