From 0dc67edc9baafaff19d7edebc1ccb3144d5397e8 Mon Sep 17 00:00:00 2001 From: xfarrow Date: Thu, 22 Feb 2024 17:30:31 +0100 Subject: [PATCH] ran 'npx standard --fix' --- backend/apis/nodejs/src/app.js | 81 +++--- .../nodejs/src/models/organization_model.js | 156 +++++------ .../apis/nodejs/src/models/person_model.js | 173 +++++++------ .../src/routes/organization_admin_routes.js | 88 +++---- .../src/routes/organization_post_routes.js | 107 ++++---- .../nodejs/src/routes/organization_routes.js | 132 +++++----- .../apis/nodejs/src/routes/person_routes.js | 243 +++++++++--------- backend/apis/nodejs/src/utils/jwt_utils.js | 76 +++--- backend/apis/nodejs/src/utils/knex_config.js | 28 +- backend/apis/nodejs/src/utils/validation.js | 32 +-- backend/apis/nodejs/tests/person.test.js | 42 +-- frontend/vanilla/constants.js | 2 +- 12 files changed, 564 insertions(+), 596 deletions(-) diff --git a/backend/apis/nodejs/src/app.js b/backend/apis/nodejs/src/app.js index ab8bca9..b87909b 100644 --- a/backend/apis/nodejs/src/app.js +++ b/backend/apis/nodejs/src/app.js @@ -2,65 +2,64 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Importing modules // TODO: clean up -require('dotenv').config(); -const express = require('express'); -const cors = require('cors'); -const rateLimit = require('express-rate-limit'); -const personRoutes = require('./routes/person_routes.js'); -const organizationRoutes = require('./routes/organization_routes.js'); -const organizationAdminRoutes = require('./routes/organization_admin_routes.js'); +require('dotenv').config() +const express = require('express') +const cors = require('cors') +const rateLimit = require('express-rate-limit') +const personRoutes = require('./routes/person_routes.js') +const organizationRoutes = require('./routes/organization_routes.js') +const organizationAdminRoutes = require('./routes/organization_admin_routes.js') const organizationPostRoutes = require('./routes/organization_post_routes.js') -const jwt_utils = require('./utils/jwt_utils.js'); - +const jwt_utils = require('./utils/jwt_utils.js') // Application configuration -const app = express(); -app.use(express.json()); // Middleware which parses JSON for POST requests -app.use(cors()); // Enable CORS for all routes +const app = express() +app.use(express.json()) // Middleware which parses JSON for POST requests +app.use(cors()) // Enable CORS for all routes app.use(rateLimit({ windowMs: process.env.LIMITER_WINDOW, max: process.env.LIMITER_MAXIMUM_PER_WINDOW, - message: {error : "Too many requests from this IP, please try again later"} -})); // Apply the rate limiter middleware to all routes + message: { error: 'Too many requests from this IP, please try again later' } +})) // Apply the rate limiter middleware to all routes -const publicRoutes = express.Router(); -publicRoutes.post('/register', personRoutes.registerPerson); -publicRoutes.post('/login', personRoutes.login); +const publicRoutes = express.Router() +publicRoutes.post('/register', personRoutes.registerPerson) +publicRoutes.post('/login', personRoutes.login) -const protectedRoutes = express.Router(); -protectedRoutes.use(jwt_utils.verifyToken); -protectedRoutes.get('/person/myself', personRoutes.getMyself); -protectedRoutes.get('/person/:id', personRoutes.getPerson); -protectedRoutes.put('/person/:id', personRoutes.updatePerson); -protectedRoutes.delete('/person/delete', personRoutes.deletePerson); -protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin); -protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin); -protectedRoutes.post('/organization', organizationRoutes.createOrganization); -protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization); -protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization); -protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization); -protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost); -protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost); +const protectedRoutes = express.Router() +protectedRoutes.use(jwt_utils.verifyToken) +protectedRoutes.get('/person/myself', personRoutes.getMyself) +protectedRoutes.get('/person/:id', personRoutes.getPerson) +protectedRoutes.put('/person/:id', personRoutes.updatePerson) +protectedRoutes.delete('/person/delete', personRoutes.deletePerson) +protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin) +protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin) +protectedRoutes.post('/organization', organizationRoutes.createOrganization) +protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization) +protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization) +protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization) +protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost) +protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost) // Mounting routes -app.use('/api', publicRoutes); // Routes not requiring token -app.use('/api', protectedRoutes); // Routes requiring token +app.use('/api', publicRoutes) // Routes not requiring token +app.use('/api', protectedRoutes) // Routes requiring token // Start the server. Default port is 3000 -const port = process.env.API_SERVER_PORT || 3000; +const port = process.env.API_SERVER_PORT || 3000 app.listen(port, () => { - console.log(`Blink API server is running on port ${port}`); -}); + console.log(`Blink API server is running on port ${port}`) +}) -module.exports = app; \ No newline at end of file +module.exports = app diff --git a/backend/apis/nodejs/src/models/organization_model.js b/backend/apis/nodejs/src/models/organization_model.js index 0574565..e3b53b1 100644 --- a/backend/apis/nodejs/src/models/organization_model.js +++ b/backend/apis/nodejs/src/models/organization_model.js @@ -2,116 +2,116 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const knex = require('../utils/knex_config'); +const knex = require('../utils/knex_config') /** * Create Organization object - * @param {*} name - * @param {*} location - * @param {*} description - * @param {*} is_hiring - * @returns + * @param {*} name + * @param {*} location + * @param {*} description + * @param {*} is_hiring + * @returns */ -function organization(name, location, description, is_hiring){ - const organization = { - name: name, - location: location, - description: description, - is_hiring: is_hiring - }; - return organization; +function organization (name, location, description, is_hiring) { + const organization = { + name, + location, + description, + is_hiring + } + return organization } /** * Gets an Organization by its identifier - * @param {*} id - * @returns + * @param {*} id + * @returns */ -async function getOrganizationById(id){ +async function getOrganizationById (id) { const organization = await knex('Organization') .where('id', id) .select('*') - .first(); - return organization; + .first() + return organization } /** * Insert an Organization and its relative Administrator - * @param {*} organization + * @param {*} organization */ -async function insertOrganization(organization, organizationAdministratorId){ - await knex.transaction(async (trx) => { - // We have to insert either both in Organization and in OrganizationAdministrator - // or in neither - const organizationResult = await trx('Organization') - .insert(organization, '*'); - - // Inserting in the "OrganizationAdministrator" table - await trx('OrganizationAdministrator') - .insert({ - id_person: organizationAdministratorId, - id_organization: organizationResult[0].id, - }); - }); +async function insertOrganization (organization, organizationAdministratorId) { + await knex.transaction(async (trx) => { + // We have to insert either both in Organization and in OrganizationAdministrator + // or in neither + const organizationResult = await trx('Organization') + .insert(organization, '*') + + // Inserting in the "OrganizationAdministrator" table + await trx('OrganizationAdministrator') + .insert({ + id_person: organizationAdministratorId, + id_organization: organizationResult[0].id + }) + }) } /** * Updates an Organization specified by the OrganizationId, if and * only if the specified personId is one of its Administrator - * @param {*} organization - * @param {*} organizationId - * @param {*} personId + * @param {*} organization + * @param {*} organizationId + * @param {*} personId * @returns true if the row was updated, false otherwise */ -async function updateOrganizationIfAdministrator(organization, organizationId, personId){ - // // const isOrganizationAdmin = await knex('OrganizationAdministrator') - // // .where('id_person', req.jwt.person_id) - // // .where('id_organization', req.params.id) - // // .select('*') - // // .first(); - - // // // This introduces a Time of check Time of use weakeness - // // // which could'have been fixed by either - // // // 1) Using "whereExists", thanks to the "it's easier to ask for - // // // forgiveness than for permission" padarigm. Or, - // // // 2) Using a serializable transaction. - // // // - // // // The undersigned chose not to follow these approaches because - // // // this does not introduces any serious vulnerability. In this - // // // way it seems more readable. - - // // if(!isOrganizationAdmin){ - // // return res.status(403).json({error : "Forbidden"}); - // // } - - // // await knex('Organization') - // // .where('id', req.params.id) - // // .update({ - // // name: req.body.name, - // // location: req.body.location, - // // description: req.body.description, - // // is_hiring: req.body.is_hiring - // // }); +async function updateOrganizationIfAdministrator (organization, organizationId, personId) { + // // const isOrganizationAdmin = await knex('OrganizationAdministrator') + // // .where('id_person', req.jwt.person_id) + // // .where('id_organization', req.params.id) + // // .select('*') + // // .first(); + + // // // This introduces a Time of check Time of use weakeness + // // // which could'have been fixed by either + // // // 1) Using "whereExists", thanks to the "it's easier to ask for + // // // forgiveness than for permission" padarigm. Or, + // // // 2) Using a serializable transaction. + // // // + // // // The undersigned chose not to follow these approaches because + // // // this does not introduces any serious vulnerability. In this + // // // way it seems more readable. + + // // if(!isOrganizationAdmin){ + // // return res.status(403).json({error : "Forbidden"}); + // // } + + // // await knex('Organization') + // // .where('id', req.params.id) + // // .update({ + // // name: req.body.name, + // // location: req.body.location, + // // description: req.body.description, + // // is_hiring: req.body.is_hiring + // // }); const numberOfUpdatedRows = await knex('Organization') .where('id', organizationId) - .whereExists(function(){ + .whereExists(function () { this.select('*') .from('OrganizationAdministrator') .where('id_person', personId) .where('id_organization', organizationId) }) - .update(organization); - return numberOfUpdatedRows == 1; + .update(organization) + return numberOfUpdatedRows == 1 } /** @@ -121,17 +121,17 @@ async function updateOrganizationIfAdministrator(organization, organizationId, p * @param {*} personId PersonId of the supposedly administrator * @returns true if the Organization was successfully deleted, false otherwise */ -async function deleteOrganizationIfAdmin(organizationId, personId){ +async function deleteOrganizationIfAdmin (organizationId, personId) { const numberOfDeletedRows = await knex('Organization') .where({ id: organizationId }) - .whereExists(function(){ + .whereExists(function () { this.select('*') .from('OrganizationAdministrator') .where('id_person', personId) .where('id_organization', organizationId) }) - .del(); - return numberOfDeletedRows == 1; + .del() + return numberOfDeletedRows == 1 } // Exporting a function @@ -144,4 +144,4 @@ module.exports = { updateOrganizationIfAdministrator, updateOrganizationIfAdministrator, deleteOrganizationIfAdmin -}; \ No newline at end of file +} diff --git a/backend/apis/nodejs/src/models/person_model.js b/backend/apis/nodejs/src/models/person_model.js index 1453142..05b8a43 100644 --- a/backend/apis/nodejs/src/models/person_model.js +++ b/backend/apis/nodejs/src/models/person_model.js @@ -2,40 +2,40 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const knex = require('../utils/knex_config'); -const bcrypt = require('bcrypt'); +const knex = require('../utils/knex_config') +const bcrypt = require('bcrypt') /** * Creates Person object by the specified fields - * @param {*} email - * @param {*} password - * @param {*} display_name - * @param {*} date_of_birth - * @param {*} available - * @param {*} enabled - * @param {*} place_of_living - * @returns + * @param {*} email + * @param {*} password + * @param {*} display_name + * @param {*} date_of_birth + * @param {*} available + * @param {*} enabled + * @param {*} place_of_living + * @returns */ -function person(email, password, display_name, date_of_birth, available, enabled, place_of_living) { - const person = { - email: email.toLowerCase(), - password: password, - display_name: display_name, - date_of_birth: date_of_birth, - available: available, - enabled: enabled, - place_of_living: place_of_living - }; - return person; +function person (email, password, display_name, date_of_birth, available, enabled, place_of_living) { + const person = { + email: email.toLowerCase(), + password, + display_name, + date_of_birth, + available, + enabled, + place_of_living + } + return person } /** @@ -43,22 +43,22 @@ function person(email, password, display_name, date_of_birth, available, enabled * @param {*} email email to look the Person for * @returns the Person object */ -async function getPersonByEmail(email){ - return await knex('Person') - .where('email', email.toLowerCase()) - .first(); +async function getPersonByEmail (email) { + return await knex('Person') + .where('email', email.toLowerCase()) + .first() } /** * Get Person by Id * @param {*} id - The id to look the person for - * @returns + * @returns */ -async function getPersonById(id){ - return await knex('Person') - .select('*') - .where({ id: id }) - .first(); +async function getPersonById (id) { + return await knex('Person') + .select('*') + .where({ id }) + .first() } /** @@ -67,27 +67,27 @@ async function getPersonById(id){ * @param {*} person A Person object * @param {*} activationLink the activationLink identifier */ -async function registerPerson(person, activationLink){ - // We need to insert either both in the "Person" table - // and in the "ActivationLink" one, or in neither - await knex.transaction(async (tr) => { - const personIdResult = await tr('Person') - .insert({ - email: person.email.toLowerCase(), - password: person.password, - display_name: person.display_name, - date_of_birth: person.date_of_birth, - available: person.available, - enabled: person.enabled, - place_of_living: person.place_of_living - }) - .returning("id"); - await tr('ActivationLink') - .insert({ - person_id: personIdResult[0].id, - identifier: activationLink - }); - }); +async function registerPerson (person, activationLink) { + // We need to insert either both in the "Person" table + // and in the "ActivationLink" one, or in neither + await knex.transaction(async (tr) => { + const personIdResult = await tr('Person') + .insert({ + email: person.email.toLowerCase(), + password: person.password, + display_name: person.display_name, + date_of_birth: person.date_of_birth, + available: person.available, + enabled: person.enabled, + place_of_living: person.place_of_living + }) + .returning('id') + await tr('ActivationLink') + .insert({ + person_id: personIdResult[0].id, + identifier: activationLink + }) + }) } /** @@ -95,22 +95,22 @@ async function registerPerson(person, activationLink){ * Used for log-in * @param {*} email * @param {*} password - * @returns + * @returns */ -async function getPersonByEmailAndPassword(email, password){ - const person = await knex('Person') - .where('email', email.toLowerCase()) - .where('enabled', true) - .select('*') - .first(); +async function getPersonByEmailAndPassword (email, password) { + const person = await knex('Person') + .where('email', email.toLowerCase()) + .where('enabled', true) + .select('*') + .first() - if(person){ - const passwordMatches = await bcrypt.compare(password, person.password); - if (passwordMatches) { - return person; - } + if (person) { + const passwordMatches = await bcrypt.compare(password, person.password) + if (passwordMatches) { + return person } - return null; + } + return null } /** @@ -118,32 +118,31 @@ async function getPersonByEmailAndPassword(email, password){ * @param {*} person The Person to update * @param {*} person_id The database id of the Person to update */ -async function updatePerson(person, person_id){ - await knex('Person') - .where('id', person_id) - .update(person); +async function updatePerson (person, person_id) { + await knex('Person') + .where('id', person_id) + .update(person) } /** * Deletes a Person specified by its database id. - * @param {*} person_id + * @param {*} person_id */ -async function deletePerson(person_id){ - await knex('Person') - .where({id : person_id}) - .del(); +async function deletePerson (person_id) { + await knex('Person') + .where({ id: person_id }) + .del() } - // Exporting a function // means making a JavaScript function defined in one // module available for use in another module. module.exports = { - person, - getPersonByEmail, - getPersonById, - getPersonByEmailAndPassword, - registerPerson, - updatePerson, - deletePerson -}; \ No newline at end of file + person, + getPersonByEmail, + getPersonById, + getPersonByEmailAndPassword, + registerPerson, + updatePerson, + deletePerson +} diff --git a/backend/apis/nodejs/src/routes/organization_admin_routes.js b/backend/apis/nodejs/src/routes/organization_admin_routes.js index a76fe36..90c0c3a 100644 --- a/backend/apis/nodejs/src/routes/organization_admin_routes.js +++ b/backend/apis/nodejs/src/routes/organization_admin_routes.js @@ -2,75 +2,71 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const knex = require('../utils/knex_config'); -const organization_admin_model = require('../models/organization_admin_model'); +const knex = require('../utils/knex_config') +const organization_admin_model = require('../models/organization_admin_model') /** * POST Method - * + * * Add an Administrator to an Organization. Allowed only if the * logged user is an Administrator themselves. - * + * * Required field(s): organization_id, person_id */ -async function addOrganizationAdmin(req, res){ +async function addOrganizationAdmin (req, res) { + // Ensure that the required fields are present before proceeding + if (!req.body.organization_id || !req.body.person_id) { + return res.status(400).json({ error: 'Invalid request' }) + } - // Ensure that the required fields are present before proceeding - if (!req.body.organization_id || !req.body.person_id) { - return res.status(400).json({ error : "Invalid request"}); - } - - try { - const isPersonAdmin = await organization_admin_model.isPersonAdmin(req.jwt.person_id, req.body.organization_id); - // TOC/TOU - if(!isPersonAdmin){ - return res.status(401).json({error : "Forbidden"}); - } - await organization_admin_model.addOrganizationAdministrator(req.body.person_id, req.body.organization_id); - return res.status(200).json({success : true}); - } - catch (error) { - console.error('Error while adding organization admin: ' + error); - res.status(500).json({error : "Internal server error"}); + try { + const isPersonAdmin = await organization_admin_model.isPersonAdmin(req.jwt.person_id, req.body.organization_id) + // TOC/TOU + if (!isPersonAdmin) { + return res.status(401).json({ error: 'Forbidden' }) } + await organization_admin_model.addOrganizationAdministrator(req.body.person_id, req.body.organization_id) + return res.status(200).json({ success: true }) + } catch (error) { + console.error('Error while adding organization admin: ' + error) + res.status(500).json({ error: 'Internal server error' }) + } } - - /** + +/** * DELETE Request - * + * * Deletes a Person from the list of Administrators of an Organization. * The logged user can only remove themselves. If no more Administrators * are left, the Organization is removed. - * + * * Required field(s): organization_id */ - async function removeOrganizationAdmin(req, res){ - - // Ensure that the required fields are present before proceeding - if (!req.body.organization_id) { - return res.status(400).json({ error : "Invalid request"}); - } - - try{ - await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id); - return res.status(200).json({success : true}); - } - catch (error){ - console.error(error); - return res.status(500).json({ error: "Internal server error"}); - } +async function removeOrganizationAdmin (req, res) { + // Ensure that the required fields are present before proceeding + if (!req.body.organization_id) { + return res.status(400).json({ error: 'Invalid request' }) + } + + try { + await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id) + return res.status(200).json({ success: true }) + } catch (error) { + console.error(error) + return res.status(500).json({ error: 'Internal server error' }) + } } module.exports = { addOrganizationAdmin, removeOrganizationAdmin -}; \ No newline at end of file +} diff --git a/backend/apis/nodejs/src/routes/organization_post_routes.js b/backend/apis/nodejs/src/routes/organization_post_routes.js index 98ae01c..3225dc5 100644 --- a/backend/apis/nodejs/src/routes/organization_post_routes.js +++ b/backend/apis/nodejs/src/routes/organization_post_routes.js @@ -2,95 +2,90 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const knex = require('../utils/knex_config'); +const knex = require('../utils/knex_config') /** * POST Request - * + * * Creates a Post belonging to an organization * * Required field(s): organization_id, content - * @returns the inserted Post + * @returns the inserted Post */ -async function createOrganizationPost(req, res){ +async function createOrganizationPost (req, res) { + // Ensure that the required fields are present before proceeding + if (!req.body.organization_id || !req.body.content) { + return res.status(400).json({ error: 'Invalid request' }) + } - // Ensure that the required fields are present before proceeding - if (!req.body.organization_id || !req.body.content) { - return res.status(400).json({ error : "Invalid request"}); - } - - try { - // Check if the current user is a organization's administrator - const isOrganizationAdmin = await knex('OrganizationAdministrator') + try { + // Check if the current user is a organization's administrator + const isOrganizationAdmin = await knex('OrganizationAdministrator') .where('id_person', req.jwt.person_id) .where('id_organization', req.body.organization_id) .select('*') - .first(); - - // Non-exploitable TOC/TOU weakness - // For more information https://softwareengineering.stackexchange.com/questions/451038/when-should-i-be-worried-of-time-of-check-time-of-use-vulnerabilities-during-dat - if(!isOrganizationAdmin){ - return res.status(403).json({error : "Forbidden"}); - } - - const organizationPost = await knex('OrganizationPost') + .first() + + // Non-exploitable TOC/TOU weakness + // For more information https://softwareengineering.stackexchange.com/questions/451038/when-should-i-be-worried-of-time-of-check-time-of-use-vulnerabilities-during-dat + if (!isOrganizationAdmin) { + return res.status(403).json({ error: 'Forbidden' }) + } + + const organizationPost = await knex('OrganizationPost') .insert({ organization_id: req.body.organization_id, content: req.body.content, original_author: req.jwt.person_id }) - .returning('*'); - return res.status(200).json(organizationPost[0]); - } - catch (error) { - console.log("Error while creating Organization Post: " + error); - return res.status(500).json({error : "Internal server error"}); - } + .returning('*') + return res.status(200).json(organizationPost[0]) + } catch (error) { + console.log('Error while creating Organization Post: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } +} /** * DELETE Request - * + * * Deletes a Post belonging to an Organization, only if * the logged user is an administrator of that Organization. - * + * * Required field(s): none. */ -async function deleteOrganizationPost(req, res){ +async function deleteOrganizationPost (req, res) { + const organizationPostIdToDelete = req.params.id - const organizationPostIdToDelete = req.params.id; - - try{ + try { const isOrganizationAdmin = await knex('OrganizationPost') .join('OrganizationAdministrator', 'OrganizationPost.organization_id', 'OrganizationAdministrator.id_organization') .where('OrganizationPost.id', organizationPostIdToDelete) .where('OrganizationAdministrator.id_person', req.jwt.person_id) .select('*') - .first(); + .first() - // Unexploitable TOC/TOU - if(isOrganizationAdmin){ - await knex('OrganizationPost') - .where('id', organizationPostIdToDelete) - .del(); - return res.status(200).json({success : true}); - } - else{ - return res.status(401).json({error : "Forbidden"}); - } - } - catch (error) { - console.log(error); - res.status(500).json({error : "Internal server error"}); + // Unexploitable TOC/TOU + if (isOrganizationAdmin) { + await knex('OrganizationPost') + .where('id', organizationPostIdToDelete) + .del() + return res.status(200).json({ success: true }) + } else { + return res.status(401).json({ error: 'Forbidden' }) + } + } catch (error) { + console.log(error) + res.status(500).json({ error: 'Internal server error' }) } } @@ -98,6 +93,6 @@ async function deleteOrganizationPost(req, res){ // means making a JavaScript function defined in one // module available for use in another module. module.exports = { - createOrganizationPost, - deleteOrganizationPost -}; \ No newline at end of file + createOrganizationPost, + deleteOrganizationPost +} diff --git a/backend/apis/nodejs/src/routes/organization_routes.js b/backend/apis/nodejs/src/routes/organization_routes.js index 3f64f42..0d1cf2d 100644 --- a/backend/apis/nodejs/src/routes/organization_routes.js +++ b/backend/apis/nodejs/src/routes/organization_routes.js @@ -2,133 +2,124 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const organization_model = require('../models/organization_model'); +const organization_model = require('../models/organization_model') /** * POST Request - * + * * Creates an Organization and its Administrator. - * + * * Required field(s): name * * @returns the inserted organization */ -async function createOrganization(req, res){ - +async function createOrganization (req, res) { // Ensure that the required fields are present before proceeding if (!req.body.name) { - return res.status(400).json({ error : "Invalid request"}); + return res.status(400).json({ error: 'Invalid request' }) } - try{ - const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring); - await organization_model.insertOrganization(organization, req.jwt.person_id); - return res.status(200).json({ Organization: organization }); - } - catch (error){ - console.error('Error creating Organization:', error); - res.status(500).json({error : "Internal server error"}); + try { + const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring) + await organization_model.insertOrganization(organization, req.jwt.person_id) + return res.status(200).json({ Organization: organization }) + } catch (error) { + console.error('Error creating Organization:', error) + res.status(500).json({ error: 'Internal server error' }) } } - + /** * PUT Request * Updates an Organization's details * * Required field(s): none. */ -async function updateOrganization(req, res){ +async function updateOrganization (req, res) { + const updateOrganization = {} - const updateOrganization = {}; - - if(req.body.name){ - updateOrganization.name = req.body.name; + if (req.body.name) { + updateOrganization.name = req.body.name } - if(req.body.location){ - updateOrganization.location = req.body.location; + if (req.body.location) { + updateOrganization.location = req.body.location } - if(req.body.description){ - updateOrganization.description = req.body.description; + if (req.body.description) { + updateOrganization.description = req.body.description } - if(req.body.is_hiring){ - updateOrganization.is_hiring = req.body.is_hiring; + if (req.body.is_hiring) { + updateOrganization.is_hiring = req.body.is_hiring } if (Object.keys(updateOrganization).length === 0) { - return res.status(400).json({ error : "Bad request. No data to update"}); + return res.status(400).json({ error: 'Bad request. No data to update' }) } try { - const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id); - if(isUpdateSuccessful){ - return res.status(200).json({ success : "true"}); + const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id) + if (isUpdateSuccessful) { + return res.status(200).json({ success: 'true' }) + } else { + return res.status(404).json({ error: 'Organization either not found or insufficient permissions' }) } - else{ - return res.status(404).json({error : "Organization either not found or insufficient permissions"}); - } - } - catch (error) { - console.log(error); - return res.status(500).json({error : "Internal server error"}); + } catch (error) { + console.log(error) + return res.status(500).json({ error: 'Internal server error' }) } } /** * DELETE Request - * + * * Deletes the specified organization if the logged user is - * one of its administrator + * one of its administrator */ -async function deleteOrganization(req, res){ +async function deleteOrganization (req, res) { try { - const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id); - if(isDeleteSuccessful){ - return res.status(403).json({error: "Forbidden"}); + const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id) + if (isDeleteSuccessful) { + return res.status(403).json({ error: 'Forbidden' }) + } else { + return res.status(200).json({ success: true }) } - else{ - return res.status(200).json({success: true}); - } - } - catch (error) { - console.error(error); - return res.status(500).json({error : "Internal server error"}); + } catch (error) { + console.error(error) + return res.status(500).json({ error: 'Internal server error' }) } } - + /** * GET Request - * + * * Obtains an organization by its identifier. - * + * * Required field(s): none. - * + * * @returns the organization. */ -async function getOrganization(req, res){ +async function getOrganization (req, res) { try { - const organization = await organization_model.getOrganizationById(req.params.id); - if(organization) { - return res.status(200).json(organization); + const organization = await organization_model.getOrganizationById(req.params.id) + if (organization) { + return res.status(200).json(organization) + } else { + return res.status(404).json({ error: 'Not found' }) } - else{ - return res.status(404).json({error : "Not found"}); - } - } - catch (error) { - console.error("Error retrieving an organization: " + error); - return res.status(500).json({error : "Internal server error"}); + } catch (error) { + console.error('Error retrieving an organization: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } } @@ -137,5 +128,4 @@ module.exports = { getOrganization, updateOrganization, deleteOrganization -}; - +} diff --git a/backend/apis/nodejs/src/routes/person_routes.js b/backend/apis/nodejs/src/routes/person_routes.js index cd6f270..13230a2 100644 --- a/backend/apis/nodejs/src/routes/person_routes.js +++ b/backend/apis/nodejs/src/routes/person_routes.js @@ -2,102 +2,98 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const validator = require('../utils/validation'); -const knex = require('../utils/knex_config'); -const jwt_utils = require('../utils/jwt_utils'); -const bcrypt = require('bcrypt'); -const crypto = require('crypto'); -const person_model = require('../models/person_model'); +const validator = require('../utils/validation') +const knex = require('../utils/knex_config') +const jwt_utils = require('../utils/jwt_utils') +const bcrypt = require('bcrypt') +const crypto = require('crypto') +const person_model = require('../models/person_model') /** * POST Request * * Registers a Person - * + * * Required field(s): name, email (valid ISO standard), password - * + * * @returns The activationlink identifier */ -async function registerPerson(req, res){ - +async function registerPerson (req, res) { // Does this server allow users to register? - if (process.env.ALLOW_USER_REGISTRATION === 'false'){ - return res.status(403).json({error : "Users cannot register on this server"}); + if (process.env.ALLOW_USER_REGISTRATION === 'false') { + return res.status(403).json({ error: 'Users cannot register on this server' }) } // Ensure that the required fields are present before proceeding if (!req.body.display_name || !req.body.email || !req.body.password) { - return res.status(400).json({ error : "Some or all required fields are missing"}); + return res.status(400).json({ error: 'Some or all required fields are missing' }) } - if(!validator.validateEmail(req.body.email)){ - return res.status(400).json({ error : "The email is not in a valid format"}); + if (!validator.validateEmail(req.body.email)) { + return res.status(400).json({ error: 'The email is not in a valid format' }) } // Generate activation link token - const activationLink = crypto.randomBytes(16).toString('hex'); + const activationLink = crypto.randomBytes(16).toString('hex') // Hash provided password - const hashPasswordPromise = bcrypt.hash(req.body.password, 10); + const hashPasswordPromise = bcrypt.hash(req.body.password, 10) - try{ + try { // Check whether e-mail exists already (enforced by database constraints) - const existingUser = await person_model.getPersonByEmail(req.body.email); - if(existingUser){ - return res.status(409).json({ error: "E-mail already in use" }); + const existingUser = await person_model.getPersonByEmail(req.body.email) + if (existingUser) { + return res.status(409).json({ error: 'E-mail already in use' }) } const personToInsert = person_model.person( - req.body.email, + req.body.email, await hashPasswordPromise, req.body.display_name, req.body.date_of_birth, req.body.available, true, - req.body.place_of_living); - await person_model.registerPerson(personToInsert, activationLink); - return res.status(200).json({ activationLink: activationLink }); - } - catch (error){ - console.error('Error registering person:', error); - res.status(500).json({error : "Internal server error"}); + req.body.place_of_living) + await person_model.registerPerson(personToInsert, activationLink) + return res.status(200).json({ activationLink }) + } catch (error) { + console.error('Error registering person:', error) + res.status(500).json({ error: 'Internal server error' }) } } /** * POST Request - * + * * Creates a token if the specified email * and password are valid. - * + * * Required field(s): email, password * * @returns The token */ -async function login(req, res){ - +async function login (req, res) { // Ensure that the required fields are present before proceeding if (!req.body.email || !req.body.password) { - return res.status(400).json({error : "Invalid request"}); + return res.status(400).json({ error: 'Invalid request' }) } - try{ - const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password); - if (person){ - const token = jwt_utils.generateToken(person.id); - res.status(200).json({token: token }); + try { + const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password) + if (person) { + const token = jwt_utils.generateToken(person.id) + res.status(200).json({ token }) + } else { + res.status(401).json({ error: 'Unauthorized' }) } - else{ - res.status(401).json({error : "Unauthorized"}); - } - } catch(error){ - console.error('Error logging in: ', error); - res.status(500).json({error : "Internal server error"}); + } catch (error) { + console.error('Error logging in: ', error) + res.status(500).json({ error: 'Internal server error' }) } } @@ -105,138 +101,131 @@ async function login(req, res){ * Obtain a Person's details if the * Person to retrieve is either myself or an * enabled Person. - * + * * Required field(s): none * * @returns The Person */ -async function getPerson(req, res){ +async function getPerson (req, res) { try { - const person = await person_model.getPersonById(req.params.id); - if(person){ + const person = await person_model.getPersonById(req.params.id) + if (person) { // I am retrieving either myself or an enabled user - if(person.id == req.jwt.person_id || person.enabled){ - delete person['password']; // remove password field for security reasons - return res.status(200).send(person); + if (person.id == req.jwt.person_id || person.enabled) { + delete person.password // remove password field for security reasons + return res.status(200).send(person) } } - return res.status(404).json({error: "Not found"}); - } - catch (error) { - console.log("Error while getting person: " + error); - return res.status(500).json({error : "Internal server error"}); + return res.status(404).json({ error: 'Not found' }) + } catch (error) { + console.log('Error while getting person: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } } /** - * + * * GET Request - * + * * Get myself, from the JWT token * * @returns Person's details */ -async function getMyself(req, res){ - try{ - const person = await person_model.getPersonById(req.jwt.person_id); - if(person){ - delete person['password']; - return res.status(200).send(person); +async function getMyself (req, res) { + try { + const person = await person_model.getPersonById(req.jwt.person_id) + if (person) { + delete person.password + return res.status(200).send(person) } - return res.status(404).json({error: "Not found"}); - } - catch (error){ - console.log("Error while getting myself: " + error); - return res.status(500).json({error : "Internal server error"}); + return res.status(404).json({ error: 'Not found' }) + } catch (error) { + console.log('Error while getting myself: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } } /** * PUT request - * + * * Updates a Person's details. If some details are * not present, they shall be ignored. - * + * * Required field(s): none. Both old_password and * new_password if updating the password. * */ -async function updatePerson(req, res){ - - if (req.jwt.person_id != req.params.id){ - return res.status(403).json({ error : "Forbidden"}); +async function updatePerson (req, res) { + if (req.jwt.person_id != req.params.id) { + return res.status(403).json({ error: 'Forbidden' }) } - const updatePerson = {}; + const updatePerson = {} - if(req.body.display_name){ - updatePerson.display_name = req.body.display_name; + if (req.body.display_name) { + updatePerson.display_name = req.body.display_name } - if(req.body.date_of_birth){ - if(validator.isPostgresDateFormatValid(req.body.date_of_birth)){ - updatePerson.date_of_birth = req.body.date_of_birth; - } - else{ - return res.status(400).json({ error : "Date of birth format not valid. Please specify a YYYY-MM-DD date"}); + if (req.body.date_of_birth) { + if (validator.isPostgresDateFormatValid(req.body.date_of_birth)) { + updatePerson.date_of_birth = req.body.date_of_birth + } else { + return res.status(400).json({ error: 'Date of birth format not valid. Please specify a YYYY-MM-DD date' }) } } - if(req.body.available){ - updatePerson.available = req.body.available; + if (req.body.available) { + updatePerson.available = req.body.available } - if(req.body.place_of_living){ - updatePerson.place_of_living = req.body.place_of_living; + if (req.body.place_of_living) { + updatePerson.place_of_living = req.body.place_of_living } - + // If we are tying to change password, the old password must be provided - if(req.body.old_password && req.body.new_password){ + if (req.body.old_password && req.body.new_password) { const user = await knex('Person') .select('password') .where({ id: req.jwt.person_id }) - .first(); - const passwordMatches = await bcrypt.compare(req.body.old_password, user.password); - if(passwordMatches){ - updatePerson.password = await bcrypt.hash(req.body.new_password, 10); - } - else{ - return res.status(401).json({ error : "Password verification failed"}); - } + .first() + const passwordMatches = await bcrypt.compare(req.body.old_password, user.password) + if (passwordMatches) { + updatePerson.password = await bcrypt.hash(req.body.new_password, 10) + } else { + return res.status(401).json({ error: 'Password verification failed' }) + } } if (Object.keys(updatePerson).length === 0) { - return res.status(400).json({ error : "Bad request. No data to update"}); + return res.status(400).json({ error: 'Bad request. No data to update' }) } try { - await person_model.updatePerson(updatePerson, req.params.id); - return res.status(200).json({ success : "true"}); - } - catch (error) { - console.log("Error while updating a Person: " + error); - return res.status(500).json({ error : "Internal server error"}); + await person_model.updatePerson(updatePerson, req.params.id) + return res.status(200).json({ success: 'true' }) + } catch (error) { + console.log('Error while updating a Person: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } } /** * GET Request - * - * Deletes a Person. An user can only delete + * + * Deletes a Person. An user can only delete * themselves. - * + * * Required field(s): none * */ -async function deletePerson(req, res) { +async function deletePerson (req, res) { // TODO: Delete Organization if this user was its only administrator try { - await person_model.deletePerson(req.jwt.person_id); - return res.status(200).json({success: true}); - } - catch (error) { - console.log("Error deleting a Person: " + error); - return res.status(500).json({error : "Internal server error"}); + await person_model.deletePerson(req.jwt.person_id) + return res.status(200).json({ success: true }) + } catch (error) { + console.log('Error deleting a Person: ' + error) + return res.status(500).json({ error: 'Internal server error' }) } } @@ -244,10 +233,10 @@ async function deletePerson(req, res) { // means making a JavaScript function defined in one // module available for use in another module. module.exports = { - registerPerson, - login, - getPerson, - getMyself, - updatePerson, - deletePerson -}; \ No newline at end of file + registerPerson, + login, + getPerson, + getMyself, + updatePerson, + deletePerson +} diff --git a/backend/apis/nodejs/src/utils/jwt_utils.js b/backend/apis/nodejs/src/utils/jwt_utils.js index 4d138fa..efafa55 100644 --- a/backend/apis/nodejs/src/utils/jwt_utils.js +++ b/backend/apis/nodejs/src/utils/jwt_utils.js @@ -2,50 +2,50 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -const jwt = require('jsonwebtoken'); +const jwt = require('jsonwebtoken') -function generateToken(person_id) { - // The payload the JWT will carry within itself - const payload = { - person_id: person_id - }; - - const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, { - expiresIn: '8h' - }); - return token; +function generateToken (person_id) { + // The payload the JWT will carry within itself + const payload = { + person_id } - - // Middlware - function verifyToken(req, res, next) { - const token = req.headers.authorization; - - if (!token) { - return res.status(401).send({error : 'No token provided'}); + + const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, { + expiresIn: '8h' + }) + return token +} + +// Middlware +function verifyToken (req, res, next) { + const token = req.headers.authorization + + if (!token) { + return res.status(401).send({ error: 'No token provided' }) + } + + jwt.verify(token, process.env.JWT_SECRET_KEY, (err, decoded) => { + if (err) { + return res.status(401).send({ error: 'Failed to authenticate token' }) } - - jwt.verify(token, process.env.JWT_SECRET_KEY, (err, decoded) => { - if (err) { - return res.status(401).send({error : 'Failed to authenticate token'}); - } - - // If the token is valid, store the decoded data in the request object - // req.jwt will contain the payload created in generateToken - req.jwt = decoded; - next(); - }); - } - module.exports = { - generateToken, - verifyToken -}; \ No newline at end of file + // If the token is valid, store the decoded data in the request object + // req.jwt will contain the payload created in generateToken + req.jwt = decoded + next() + }) +} + +module.exports = { + generateToken, + verifyToken +} diff --git a/backend/apis/nodejs/src/utils/knex_config.js b/backend/apis/nodejs/src/utils/knex_config.js index 25ac3cf..e4cc40d 100644 --- a/backend/apis/nodejs/src/utils/knex_config.js +++ b/backend/apis/nodejs/src/utils/knex_config.js @@ -2,24 +2,24 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ const knexInstance = require('knex')({ - client: 'pg', - connection: { - host: process.env.POSTGRES_SERVER, - user: process.env.POSTGRES_USERNAME, - password: process.env.POSTGRES_PASSWORD, - port: process.env.POSTGRES_PORT, - database: 'Blink' - } - }); + client: 'pg', + connection: { + host: process.env.POSTGRES_SERVER, + user: process.env.POSTGRES_USERNAME, + password: process.env.POSTGRES_PASSWORD, + port: process.env.POSTGRES_PORT, + database: 'Blink' + } +}) - module.exports = knexInstance; \ No newline at end of file +module.exports = knexInstance diff --git a/backend/apis/nodejs/src/utils/validation.js b/backend/apis/nodejs/src/utils/validation.js index 4b6fc34..c21b790 100644 --- a/backend/apis/nodejs/src/utils/validation.js +++ b/backend/apis/nodejs/src/utils/validation.js @@ -2,37 +2,37 @@ This code is part of Blink licensed under GPLv3 - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * Checks whether an e-mail is in a valid format - * @param {*} email email to validate + * @param {*} email email to validate * @returns true or false */ -function validateEmail(email) { - const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/; - return regex.test(email); +function validateEmail (email) { + const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/ + return regex.test(email) } - + /** * Checks whether a date is in a correct Postgres * format (YYYY-MM-DD) - * @param {*} dateString the date to validate + * @param {*} dateString the date to validate * @returns true or false */ -function isPostgresDateFormatValid(dateString) { - const regex = /^\d{4}-\d{2}-\d{2}$/; - return regex.test(dateString); +function isPostgresDateFormatValid (dateString) { + const regex = /^\d{4}-\d{2}-\d{2}$/ + return regex.test(dateString) } module.exports = { - validateEmail, - isPostgresDateFormatValid -}; \ No newline at end of file + validateEmail, + isPostgresDateFormatValid +} diff --git a/backend/apis/nodejs/tests/person.test.js b/backend/apis/nodejs/tests/person.test.js index 8710f90..a40b11c 100644 --- a/backend/apis/nodejs/tests/person.test.js +++ b/backend/apis/nodejs/tests/person.test.js @@ -1,30 +1,30 @@ // Run me with "npm test" -const request = require('supertest'); -const app = require('../src/app'); -require('dotenv').config({ path: '../src/.env' }); +const request = require('supertest') +const app = require('../src/app') +require('dotenv').config({ path: '../src/.env' }) describe('Person Tests', () => { test('Correct registration', async () => { const response = await request(app) - .post('/api/register') - .send({ - email : "johntestdoe@mail.org", - password : "password", - display_name : "John Doe" - }) - expect(response.status).toBe(200); - expect(response.body).toEqual({ activationLink: expect.any(String) }); - }); + .post('/api/register') + .send({ + email: 'johntestdoe@mail.org', + password: 'password', + display_name: 'John Doe' + }) + expect(response.status).toBe(200) + expect(response.body).toEqual({ activationLink: expect.any(String) }) + }) test('Incorrect registration', async () => { const response = await request(app) - .post('/api/register') - .send({ - email : "this is not an email", - password : "password", - display_name : "John Doe" - }) - expect(response.status).toBe(400); - }); -}); + .post('/api/register') + .send({ + email: 'this is not an email', + password: 'password', + display_name: 'John Doe' + }) + expect(response.status).toBe(400) + }) +}) diff --git a/frontend/vanilla/constants.js b/frontend/vanilla/constants.js index 06efcb3..55498f7 100644 --- a/frontend/vanilla/constants.js +++ b/frontend/vanilla/constants.js @@ -1 +1 @@ -const apiUrl = "http://localhost:3000/blinkapi"; \ No newline at end of file +const apiUrl = 'http://localhost:3000/blinkapi'