mirror of
				https://github.com/xfarrow/blink
				synced 2025-06-27 09:03:02 +02:00 
			
		
		
		
	ran 'npx standard --fix'
This commit is contained in:
		| @@ -2,65 +2,64 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| // Importing modules | // Importing modules | ||||||
| // TODO: clean up | // TODO: clean up | ||||||
| require('dotenv').config(); | require('dotenv').config() | ||||||
| const express = require('express'); | const express = require('express') | ||||||
| const cors = require('cors'); | const cors = require('cors') | ||||||
| const rateLimit = require('express-rate-limit'); | const rateLimit = require('express-rate-limit') | ||||||
| const personRoutes = require('./routes/person_routes.js'); | const personRoutes = require('./routes/person_routes.js') | ||||||
| const organizationRoutes = require('./routes/organization_routes.js'); | const organizationRoutes = require('./routes/organization_routes.js') | ||||||
| const organizationAdminRoutes = require('./routes/organization_admin_routes.js'); | const organizationAdminRoutes = require('./routes/organization_admin_routes.js') | ||||||
| const organizationPostRoutes = require('./routes/organization_post_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 | // Application configuration | ||||||
| const app = express(); | const app = express() | ||||||
| app.use(express.json()); // Middleware which parses JSON for POST requests | app.use(express.json()) // Middleware which parses JSON for POST requests | ||||||
| app.use(cors()); // Enable CORS for all routes | app.use(cors()) // Enable CORS for all routes | ||||||
| app.use(rateLimit({ | app.use(rateLimit({ | ||||||
|   windowMs: process.env.LIMITER_WINDOW, |   windowMs: process.env.LIMITER_WINDOW, | ||||||
|   max: process.env.LIMITER_MAXIMUM_PER_WINDOW, |   max: process.env.LIMITER_MAXIMUM_PER_WINDOW, | ||||||
|   message: {error : "Too many requests from this IP, please try again later"} |   message: { error: 'Too many requests from this IP, please try again later' } | ||||||
| })); // Apply the rate limiter middleware to all routes | })) // Apply the rate limiter middleware to all routes | ||||||
|  |  | ||||||
| const publicRoutes = express.Router(); | const publicRoutes = express.Router() | ||||||
| publicRoutes.post('/register', personRoutes.registerPerson); | publicRoutes.post('/register', personRoutes.registerPerson) | ||||||
| publicRoutes.post('/login', personRoutes.login); | publicRoutes.post('/login', personRoutes.login) | ||||||
|  |  | ||||||
| const protectedRoutes = express.Router(); | const protectedRoutes = express.Router() | ||||||
| protectedRoutes.use(jwt_utils.verifyToken); | protectedRoutes.use(jwt_utils.verifyToken) | ||||||
| protectedRoutes.get('/person/myself', personRoutes.getMyself); | protectedRoutes.get('/person/myself', personRoutes.getMyself) | ||||||
| protectedRoutes.get('/person/:id', personRoutes.getPerson); | protectedRoutes.get('/person/:id', personRoutes.getPerson) | ||||||
| protectedRoutes.put('/person/:id', personRoutes.updatePerson); | protectedRoutes.put('/person/:id', personRoutes.updatePerson) | ||||||
| protectedRoutes.delete('/person/delete', personRoutes.deletePerson); | protectedRoutes.delete('/person/delete', personRoutes.deletePerson) | ||||||
| protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin); | protectedRoutes.post('/organization/admin', organizationAdminRoutes.addOrganizationAdmin) | ||||||
| protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin); | protectedRoutes.delete('/organization/removeadmin', organizationAdminRoutes.removeOrganizationAdmin) | ||||||
| protectedRoutes.post('/organization', organizationRoutes.createOrganization); | protectedRoutes.post('/organization', organizationRoutes.createOrganization) | ||||||
| protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization); | protectedRoutes.get('/organization/:id', organizationRoutes.getOrganization) | ||||||
| protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization); | protectedRoutes.put('/organization/:id', organizationRoutes.updateOrganization) | ||||||
| protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization); | protectedRoutes.delete('/organization/:id', organizationRoutes.deleteOrganization) | ||||||
| protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost); | protectedRoutes.post('/organization/post', organizationPostRoutes.createOrganizationPost) | ||||||
| protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost); | protectedRoutes.delete('/organization/post/:id', organizationPostRoutes.deleteOrganizationPost) | ||||||
|  |  | ||||||
| // Mounting routes | // Mounting routes | ||||||
| app.use('/api', publicRoutes); // Routes not requiring token | app.use('/api', publicRoutes) // Routes not requiring token | ||||||
| app.use('/api', protectedRoutes); // Routes requiring token | app.use('/api', protectedRoutes) // Routes requiring token | ||||||
|  |  | ||||||
| // Start the server. Default port is 3000 | // 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, () => { | 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; | module.exports = app | ||||||
|   | |||||||
| @@ -2,116 +2,116 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const knex = require('../utils/knex_config'); | const knex = require('../utils/knex_config') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Create Organization object |  * Create Organization object | ||||||
|  * @param {*} name  |  * @param {*} name | ||||||
|  * @param {*} location  |  * @param {*} location | ||||||
|  * @param {*} description  |  * @param {*} description | ||||||
|  * @param {*} is_hiring  |  * @param {*} is_hiring | ||||||
|  * @returns  |  * @returns | ||||||
|  */ |  */ | ||||||
| function organization(name, location, description, is_hiring){ | function organization (name, location, description, is_hiring) { | ||||||
|     const organization = { |   const organization = { | ||||||
|         name: name, |     name, | ||||||
|         location: location, |     location, | ||||||
|         description: description, |     description, | ||||||
|         is_hiring: is_hiring |     is_hiring | ||||||
|     }; |   } | ||||||
|     return organization; |   return organization | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Gets an Organization by its identifier |  * Gets an Organization by its identifier | ||||||
|  * @param {*} id  |  * @param {*} id | ||||||
|  * @returns  |  * @returns | ||||||
|  */ |  */ | ||||||
| async function getOrganizationById(id){ | async function getOrganizationById (id) { | ||||||
|   const organization = await knex('Organization') |   const organization = await knex('Organization') | ||||||
|     .where('id', id) |     .where('id', id) | ||||||
|     .select('*') |     .select('*') | ||||||
|     .first(); |     .first() | ||||||
|   return organization; |   return organization | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Insert an Organization and its relative Administrator |  * Insert an Organization and its relative Administrator | ||||||
|  * @param {*} organization  |  * @param {*} organization | ||||||
|  */ |  */ | ||||||
| async function insertOrganization(organization, organizationAdministratorId){ | async function insertOrganization (organization, organizationAdministratorId) { | ||||||
|     await knex.transaction(async (trx) => { |   await knex.transaction(async (trx) => { | ||||||
|         // We have to insert either both in Organization and in OrganizationAdministrator |     // We have to insert either both in Organization and in OrganizationAdministrator | ||||||
|         // or in neither |     // or in neither | ||||||
|         const organizationResult = await trx('Organization') |     const organizationResult = await trx('Organization') | ||||||
|           .insert(organization, '*'); |       .insert(organization, '*') | ||||||
|    |  | ||||||
|         // Inserting in the "OrganizationAdministrator" table |     // Inserting in the "OrganizationAdministrator" table | ||||||
|         await trx('OrganizationAdministrator') |     await trx('OrganizationAdministrator') | ||||||
|           .insert({ |       .insert({ | ||||||
|             id_person: organizationAdministratorId, |         id_person: organizationAdministratorId, | ||||||
|             id_organization: organizationResult[0].id, |         id_organization: organizationResult[0].id | ||||||
|           }); |       }) | ||||||
|   }); |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Updates an Organization specified by the OrganizationId, if and |  * Updates an Organization specified by the OrganizationId, if and | ||||||
|  * only if the specified personId is one of its Administrator |  * only if the specified personId is one of its Administrator | ||||||
|  * @param {*} organization  |  * @param {*} organization | ||||||
|  * @param {*} organizationId  |  * @param {*} organizationId | ||||||
|  * @param {*} personId  |  * @param {*} personId | ||||||
|  * @returns true if the row was updated, false otherwise |  * @returns true if the row was updated, false otherwise | ||||||
|  */ |  */ | ||||||
| async function updateOrganizationIfAdministrator(organization, organizationId, personId){ | async function updateOrganizationIfAdministrator (organization, organizationId, personId) { | ||||||
|       // // const isOrganizationAdmin = await knex('OrganizationAdministrator') |   // // const isOrganizationAdmin = await knex('OrganizationAdministrator') | ||||||
|       // // .where('id_person', req.jwt.person_id) |   // // .where('id_person', req.jwt.person_id) | ||||||
|       // // .where('id_organization', req.params.id) |   // // .where('id_organization', req.params.id) | ||||||
|       // // .select('*') |   // // .select('*') | ||||||
|       // // .first(); |   // // .first(); | ||||||
|    |  | ||||||
|       // // // This introduces a Time of check Time of use weakeness |   // // // This introduces a Time of check Time of use weakeness | ||||||
|       // // // which could'have been fixed by either |   // // // which could'have been fixed by either | ||||||
|       // // // 1) Using "whereExists", thanks to the "it's easier to ask for |   // // // 1) Using "whereExists", thanks to the "it's easier to ask for | ||||||
|       // // // forgiveness than for permission" padarigm. Or, |   // // // forgiveness than for permission" padarigm. Or, | ||||||
|       // // // 2) Using a serializable transaction. |   // // // 2) Using a serializable transaction. | ||||||
|       // // // |   // // // | ||||||
|       // // // The undersigned chose not to follow these approaches because |   // // // The undersigned chose not to follow these approaches because | ||||||
|       // // // this does not introduces any serious vulnerability. In this |   // // // this does not introduces any serious vulnerability. In this | ||||||
|       // // // way it seems more readable. |   // // // way it seems more readable. | ||||||
|    |  | ||||||
|       // // if(!isOrganizationAdmin){ |   // // if(!isOrganizationAdmin){ | ||||||
|       // //   return res.status(403).json({error : "Forbidden"}); |   // //   return res.status(403).json({error : "Forbidden"}); | ||||||
|       // // } |   // // } | ||||||
|    |  | ||||||
|       // // await knex('Organization') |   // // await knex('Organization') | ||||||
|       // // .where('id', req.params.id) |   // // .where('id', req.params.id) | ||||||
|       // // .update({ |   // // .update({ | ||||||
|       // //   name: req.body.name, |   // //   name: req.body.name, | ||||||
|       // //   location: req.body.location, |   // //   location: req.body.location, | ||||||
|       // //   description: req.body.description, |   // //   description: req.body.description, | ||||||
|       // //   is_hiring: req.body.is_hiring |   // //   is_hiring: req.body.is_hiring | ||||||
|       // // }); |   // // }); | ||||||
|  |  | ||||||
|   const numberOfUpdatedRows = await knex('Organization') |   const numberOfUpdatedRows = await knex('Organization') | ||||||
|     .where('id', organizationId) |     .where('id', organizationId) | ||||||
|     .whereExists(function(){ |     .whereExists(function () { | ||||||
|       this.select('*') |       this.select('*') | ||||||
|         .from('OrganizationAdministrator') |         .from('OrganizationAdministrator') | ||||||
|         .where('id_person', personId) |         .where('id_person', personId) | ||||||
|         .where('id_organization', organizationId) |         .where('id_organization', organizationId) | ||||||
|     }) |     }) | ||||||
|     .update(organization); |     .update(organization) | ||||||
|   return numberOfUpdatedRows == 1; |   return numberOfUpdatedRows == 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -121,17 +121,17 @@ async function updateOrganizationIfAdministrator(organization, organizationId, p | |||||||
|  * @param {*} personId PersonId of the supposedly administrator |  * @param {*} personId PersonId of the supposedly administrator | ||||||
|  * @returns true if the Organization was successfully deleted, false otherwise |  * @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') |   const numberOfDeletedRows = await knex('Organization') | ||||||
|     .where({ id: organizationId }) |     .where({ id: organizationId }) | ||||||
|     .whereExists(function(){ |     .whereExists(function () { | ||||||
|       this.select('*') |       this.select('*') | ||||||
|         .from('OrganizationAdministrator') |         .from('OrganizationAdministrator') | ||||||
|         .where('id_person', personId) |         .where('id_person', personId) | ||||||
|         .where('id_organization', organizationId) |         .where('id_organization', organizationId) | ||||||
|     }) |     }) | ||||||
|     .del(); |     .del() | ||||||
|   return numberOfDeletedRows == 1; |   return numberOfDeletedRows == 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| // Exporting a function | // Exporting a function | ||||||
| @@ -144,4 +144,4 @@ module.exports = { | |||||||
|   updateOrganizationIfAdministrator, |   updateOrganizationIfAdministrator, | ||||||
|   updateOrganizationIfAdministrator, |   updateOrganizationIfAdministrator, | ||||||
|   deleteOrganizationIfAdmin |   deleteOrganizationIfAdmin | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -2,40 +2,40 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const knex = require('../utils/knex_config'); | const knex = require('../utils/knex_config') | ||||||
| const bcrypt = require('bcrypt'); | const bcrypt = require('bcrypt') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Creates Person object by the specified fields |  * Creates Person object by the specified fields | ||||||
|  * @param {*} email  |  * @param {*} email | ||||||
|  * @param {*} password  |  * @param {*} password | ||||||
|  * @param {*} display_name  |  * @param {*} display_name | ||||||
|  * @param {*} date_of_birth  |  * @param {*} date_of_birth | ||||||
|  * @param {*} available  |  * @param {*} available | ||||||
|  * @param {*} enabled  |  * @param {*} enabled | ||||||
|  * @param {*} place_of_living  |  * @param {*} place_of_living | ||||||
|  * @returns  |  * @returns | ||||||
|  */ |  */ | ||||||
| function person(email, password, display_name, date_of_birth, available, enabled, place_of_living) { | function person (email, password, display_name, date_of_birth, available, enabled, place_of_living) { | ||||||
|     const person = { |   const person = { | ||||||
|         email: email.toLowerCase(), |     email: email.toLowerCase(), | ||||||
|         password: password, |     password, | ||||||
|         display_name: display_name, |     display_name, | ||||||
|         date_of_birth: date_of_birth, |     date_of_birth, | ||||||
|         available: available, |     available, | ||||||
|         enabled: enabled, |     enabled, | ||||||
|         place_of_living: place_of_living |     place_of_living | ||||||
|     }; |   } | ||||||
|     return person; |   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 |  * @param {*} email email to look the Person for | ||||||
|  * @returns the Person object |  * @returns the Person object | ||||||
|  */ |  */ | ||||||
| async function getPersonByEmail(email){ | async function getPersonByEmail (email) { | ||||||
|     return await knex('Person') |   return await knex('Person') | ||||||
|         .where('email', email.toLowerCase()) |     .where('email', email.toLowerCase()) | ||||||
|         .first(); |     .first() | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Get Person by Id |  * Get Person by Id | ||||||
|  * @param {*} id - The id to look the person for |  * @param {*} id - The id to look the person for | ||||||
|  * @returns  |  * @returns | ||||||
|  */ |  */ | ||||||
| async function getPersonById(id){ | async function getPersonById (id) { | ||||||
|     return await knex('Person') |   return await knex('Person') | ||||||
|       .select('*') |     .select('*') | ||||||
|       .where({ id: id }) |     .where({ id }) | ||||||
|       .first(); |     .first() | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -67,27 +67,27 @@ async function getPersonById(id){ | |||||||
|  * @param {*} person A Person object |  * @param {*} person A Person object | ||||||
|  * @param {*} activationLink the activationLink identifier |  * @param {*} activationLink the activationLink identifier | ||||||
|  */ |  */ | ||||||
| async function registerPerson(person, activationLink){ | async function registerPerson (person, activationLink) { | ||||||
|     // We need to insert either both in the "Person" table |   // We need to insert either both in the "Person" table | ||||||
|     // and in the "ActivationLink" one, or in neither |   // and in the "ActivationLink" one, or in neither | ||||||
|     await knex.transaction(async (tr) => { |   await knex.transaction(async (tr) => { | ||||||
|       const personIdResult = await tr('Person') |     const personIdResult = await tr('Person') | ||||||
|         .insert({  |       .insert({ | ||||||
|           email: person.email.toLowerCase(),  |         email: person.email.toLowerCase(), | ||||||
|           password: person.password, |         password: person.password, | ||||||
|           display_name: person.display_name, |         display_name: person.display_name, | ||||||
|           date_of_birth: person.date_of_birth, |         date_of_birth: person.date_of_birth, | ||||||
|           available: person.available, |         available: person.available, | ||||||
|           enabled: person.enabled, |         enabled: person.enabled, | ||||||
|           place_of_living: person.place_of_living |         place_of_living: person.place_of_living | ||||||
|         }) |       }) | ||||||
|         .returning("id"); |       .returning('id') | ||||||
|       await tr('ActivationLink') |     await tr('ActivationLink') | ||||||
|         .insert({ |       .insert({ | ||||||
|           person_id: personIdResult[0].id, |         person_id: personIdResult[0].id, | ||||||
|           identifier: activationLink |         identifier: activationLink | ||||||
|         }); |       }) | ||||||
|     }); |   }) | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -95,22 +95,22 @@ async function registerPerson(person, activationLink){ | |||||||
|  * Used for log-in |  * Used for log-in | ||||||
|  * @param {*} email |  * @param {*} email | ||||||
|  * @param {*} password |  * @param {*} password | ||||||
|  * @returns  |  * @returns | ||||||
|  */ |  */ | ||||||
| async function getPersonByEmailAndPassword(email, password){ | async function getPersonByEmailAndPassword (email, password) { | ||||||
|     const person = await knex('Person') |   const person = await knex('Person') | ||||||
|       .where('email', email.toLowerCase()) |     .where('email', email.toLowerCase()) | ||||||
|       .where('enabled', true) |     .where('enabled', true) | ||||||
|       .select('*') |     .select('*') | ||||||
|       .first(); |     .first() | ||||||
|  |  | ||||||
|     if(person){ |   if (person) { | ||||||
|       const passwordMatches = await bcrypt.compare(password, person.password); |     const passwordMatches = await bcrypt.compare(password, person.password) | ||||||
|       if (passwordMatches) { |     if (passwordMatches) { | ||||||
|         return person; |       return person | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|     return null; |   } | ||||||
|  |   return null | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -118,32 +118,31 @@ async function getPersonByEmailAndPassword(email, password){ | |||||||
|  * @param {*} person The Person to update |  * @param {*} person The Person to update | ||||||
|  * @param {*} person_id The database id of the Person to update |  * @param {*} person_id The database id of the Person to update | ||||||
|  */ |  */ | ||||||
| async function updatePerson(person, person_id){ | async function updatePerson (person, person_id) { | ||||||
|     await knex('Person') |   await knex('Person') | ||||||
|       .where('id', person_id) |     .where('id', person_id) | ||||||
|       .update(person); |     .update(person) | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Deletes a Person specified by its database id. |  * Deletes a Person specified by its database id. | ||||||
|  * @param {*} person_id  |  * @param {*} person_id | ||||||
|  */ |  */ | ||||||
| async function deletePerson(person_id){ | async function deletePerson (person_id) { | ||||||
|     await knex('Person') |   await knex('Person') | ||||||
|       .where({id : person_id}) |     .where({ id: person_id }) | ||||||
|       .del(); |     .del() | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| // Exporting a function | // Exporting a function | ||||||
| // means making a JavaScript function defined in one | // means making a JavaScript function defined in one | ||||||
| // module available for use in another module. | // module available for use in another module. | ||||||
| module.exports = { | module.exports = { | ||||||
|     person, |   person, | ||||||
|     getPersonByEmail, |   getPersonByEmail, | ||||||
|     getPersonById, |   getPersonById, | ||||||
|     getPersonByEmailAndPassword, |   getPersonByEmailAndPassword, | ||||||
|     registerPerson, |   registerPerson, | ||||||
|     updatePerson, |   updatePerson, | ||||||
|     deletePerson |   deletePerson | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -2,75 +2,71 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const knex = require('../utils/knex_config'); | const knex = require('../utils/knex_config') | ||||||
| const organization_admin_model = require('../models/organization_admin_model'); | const organization_admin_model = require('../models/organization_admin_model') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * POST Method |  * POST Method | ||||||
|  *  |  * | ||||||
|  * Add an Administrator to an Organization. Allowed only if the |  * Add an Administrator to an Organization. Allowed only if the | ||||||
|  * logged user is an Administrator themselves. |  * logged user is an Administrator themselves. | ||||||
|  *  |  * | ||||||
|  * Required field(s): organization_id, person_id |  * 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 |   try { | ||||||
|     if (!req.body.organization_id || !req.body.person_id) { |     const isPersonAdmin = await organization_admin_model.isPersonAdmin(req.jwt.person_id, req.body.organization_id) | ||||||
|       return res.status(400).json({ error : "Invalid request"}); |     // TOC/TOU | ||||||
|     } |     if (!isPersonAdmin) { | ||||||
|    |       return res.status(401).json({ error: 'Forbidden' }) | ||||||
|     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"}); |  | ||||||
|     } |     } | ||||||
|  |     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 |    * DELETE Request | ||||||
|    *  |    * | ||||||
|    * Deletes a Person from the list of Administrators of an Organization. |    * Deletes a Person from the list of Administrators of an Organization. | ||||||
|    * The logged user can only remove themselves. If no more Administrators |    * The logged user can only remove themselves. If no more Administrators | ||||||
|    * are left, the Organization is removed. |    * are left, the Organization is removed. | ||||||
|    *  |    * | ||||||
|    * Required field(s): organization_id |    * Required field(s): organization_id | ||||||
|    */ |    */ | ||||||
|   async function removeOrganizationAdmin(req, res){ | async function removeOrganizationAdmin (req, res) { | ||||||
|      |   // Ensure that the required fields are present before proceeding | ||||||
|       // Ensure that the required fields are present before proceeding |   if (!req.body.organization_id) { | ||||||
|       if (!req.body.organization_id) { |     return res.status(400).json({ error: 'Invalid request' }) | ||||||
|         return res.status(400).json({ error : "Invalid request"}); |   } | ||||||
|       } |  | ||||||
|    |   try { | ||||||
|       try{ |     await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id) | ||||||
|         await organization_admin_model.removeOrganizationAdmin(req.jwt.person_id, req.body.organization_id); |     return res.status(200).json({ success: true }) | ||||||
|         return res.status(200).json({success : true}); |   } catch (error) { | ||||||
|       } |     console.error(error) | ||||||
|       catch (error){ |     return res.status(500).json({ error: 'Internal server error' }) | ||||||
|         console.error(error); |   } | ||||||
|         return res.status(500).json({ error: "Internal server error"}); |  | ||||||
|       } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|   addOrganizationAdmin, |   addOrganizationAdmin, | ||||||
|   removeOrganizationAdmin |   removeOrganizationAdmin | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -2,95 +2,90 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const knex = require('../utils/knex_config'); | const knex = require('../utils/knex_config') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|    * POST Request |    * POST Request | ||||||
|    *  |    * | ||||||
|    * Creates a Post belonging to an organization |    * Creates a Post belonging to an organization | ||||||
|    * |    * | ||||||
|    * Required field(s): organization_id, content |    * 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 |   try { | ||||||
|     if (!req.body.organization_id || !req.body.content) { |     // Check if the current user is a organization's administrator | ||||||
|       return res.status(400).json({ error : "Invalid request"}); |     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_person', req.jwt.person_id) | ||||||
|       .where('id_organization', req.body.organization_id) |       .where('id_organization', req.body.organization_id) | ||||||
|       .select('*') |       .select('*') | ||||||
|       .first(); |       .first() | ||||||
|        |  | ||||||
|       // Non-exploitable TOC/TOU weakness |     // 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 |     // 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){ |     if (!isOrganizationAdmin) { | ||||||
|         return res.status(403).json({error : "Forbidden"}); |       return res.status(403).json({ error: 'Forbidden' }) | ||||||
|       } |     } | ||||||
|    |  | ||||||
|       const organizationPost = await knex('OrganizationPost') |     const organizationPost = await knex('OrganizationPost') | ||||||
|       .insert({ |       .insert({ | ||||||
|         organization_id: req.body.organization_id, |         organization_id: req.body.organization_id, | ||||||
|         content: req.body.content, |         content: req.body.content, | ||||||
|         original_author: req.jwt.person_id |         original_author: req.jwt.person_id | ||||||
|       }) |       }) | ||||||
|       .returning('*'); |       .returning('*') | ||||||
|       return res.status(200).json(organizationPost[0]); |     return res.status(200).json(organizationPost[0]) | ||||||
|     }  |   } catch (error) { | ||||||
|     catch (error) { |     console.log('Error while creating Organization Post: ' + error) | ||||||
|       console.log("Error while creating Organization Post: " + error); |     return res.status(500).json({ error: 'Internal server error' }) | ||||||
|       return res.status(500).json({error : "Internal server error"}); |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * DELETE Request |  * DELETE Request | ||||||
|  *  |  * | ||||||
|  * Deletes a Post belonging to an Organization, only if |  * Deletes a Post belonging to an Organization, only if | ||||||
|  * the logged user is an administrator of that Organization. |  * the logged user is an administrator of that Organization. | ||||||
|  *  |  * | ||||||
|  * Required field(s): none. |  * 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') |     const isOrganizationAdmin = await knex('OrganizationPost') | ||||||
|       .join('OrganizationAdministrator', 'OrganizationPost.organization_id', 'OrganizationAdministrator.id_organization') |       .join('OrganizationAdministrator', 'OrganizationPost.organization_id', 'OrganizationAdministrator.id_organization') | ||||||
|       .where('OrganizationPost.id', organizationPostIdToDelete) |       .where('OrganizationPost.id', organizationPostIdToDelete) | ||||||
|       .where('OrganizationAdministrator.id_person', req.jwt.person_id) |       .where('OrganizationAdministrator.id_person', req.jwt.person_id) | ||||||
|       .select('*') |       .select('*') | ||||||
|       .first(); |       .first() | ||||||
|  |  | ||||||
|       // Unexploitable TOC/TOU |     // Unexploitable TOC/TOU | ||||||
|       if(isOrganizationAdmin){ |     if (isOrganizationAdmin) { | ||||||
|         await knex('OrganizationPost') |       await knex('OrganizationPost') | ||||||
|           .where('id', organizationPostIdToDelete) |         .where('id', organizationPostIdToDelete) | ||||||
|           .del(); |         .del() | ||||||
|         return res.status(200).json({success : true}); |       return res.status(200).json({ success: true }) | ||||||
|       } |     } else { | ||||||
|       else{ |       return res.status(401).json({ error: 'Forbidden' }) | ||||||
|         return res.status(401).json({error : "Forbidden"}); |     } | ||||||
|       } |   } catch (error) { | ||||||
|   } |     console.log(error) | ||||||
|   catch (error) { |     res.status(500).json({ error: 'Internal server 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 | // means making a JavaScript function defined in one | ||||||
| // module available for use in another module. | // module available for use in another module. | ||||||
| module.exports = { | module.exports = { | ||||||
|     createOrganizationPost, |   createOrganizationPost, | ||||||
|     deleteOrganizationPost |   deleteOrganizationPost | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -2,133 +2,124 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const organization_model = require('../models/organization_model'); | const organization_model = require('../models/organization_model') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * POST Request |  * POST Request | ||||||
|  *  |  * | ||||||
|  * Creates an Organization and its Administrator. |  * Creates an Organization and its Administrator. | ||||||
|  *  |  * | ||||||
|  * Required field(s): name |  * Required field(s): name | ||||||
|  * |  * | ||||||
|  * @returns the inserted organization |  * @returns the inserted organization | ||||||
|  */ |  */ | ||||||
| async function createOrganization(req, res){ | async function createOrganization (req, res) { | ||||||
|  |  | ||||||
|   // Ensure that the required fields are present before proceeding |   // Ensure that the required fields are present before proceeding | ||||||
|   if (!req.body.name) { |   if (!req.body.name) { | ||||||
|     return res.status(400).json({ error : "Invalid request"}); |     return res.status(400).json({ error: 'Invalid request' }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   try{ |   try { | ||||||
|     const organization = organization_model.organization(req.body.name, req.body.location, req.body.description, req.body.is_hiring); |     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); |     await organization_model.insertOrganization(organization, req.jwt.person_id) | ||||||
|     return res.status(200).json({ Organization: organization }); |     return res.status(200).json({ Organization: organization }) | ||||||
|   } |   } catch (error) { | ||||||
|   catch (error){ |     console.error('Error creating Organization:', error) | ||||||
|     console.error('Error creating Organization:', error); |     res.status(500).json({ error: 'Internal server error' }) | ||||||
|     res.status(500).json({error : "Internal server error"}); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|    |  | ||||||
| /** | /** | ||||||
|  * PUT Request |  * PUT Request | ||||||
|  * Updates an Organization's details |  * Updates an Organization's details | ||||||
|  * |  * | ||||||
|  * Required field(s): none. |  * 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){ |   if (req.body.location) { | ||||||
|     updateOrganization.location = req.body.location; |     updateOrganization.location = req.body.location | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(req.body.description){ |   if (req.body.description) { | ||||||
|     updateOrganization.description = req.body.description; |     updateOrganization.description = req.body.description | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(req.body.is_hiring){ |   if (req.body.is_hiring) { | ||||||
|     updateOrganization.is_hiring = req.body.is_hiring; |     updateOrganization.is_hiring = req.body.is_hiring | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (Object.keys(updateOrganization).length === 0) { |   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 { |   try { | ||||||
|     const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id); |     const isUpdateSuccessful = organization_model.updateOrganizationIfAdministrator(updateOrganization, req.params.id, req.jwt.person_id) | ||||||
|     if(isUpdateSuccessful){ |     if (isUpdateSuccessful) { | ||||||
|       return res.status(200).json({ success : "true"}); |       return res.status(200).json({ success: 'true' }) | ||||||
|  |     } else { | ||||||
|  |       return res.status(404).json({ error: 'Organization either not found or insufficient permissions' }) | ||||||
|     } |     } | ||||||
|     else{ |   } catch (error) { | ||||||
|       return res.status(404).json({error : "Organization either not found or insufficient permissions"}); |     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 |  * DELETE Request | ||||||
|  *  |  * | ||||||
|  * Deletes the specified organization if the logged user is |  * 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 { |   try { | ||||||
|     const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id); |     const isDeleteSuccessful = organization_model.deleteOrganizationIfAdmin(req.params.id, req.jwt.person_id) | ||||||
|     if(isDeleteSuccessful){ |     if (isDeleteSuccessful) { | ||||||
|       return res.status(403).json({error: "Forbidden"}); |       return res.status(403).json({ error: 'Forbidden' }) | ||||||
|  |     } else { | ||||||
|  |       return res.status(200).json({ success: true }) | ||||||
|     } |     } | ||||||
|     else{ |   } catch (error) { | ||||||
|       return res.status(200).json({success: true}); |     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 |  * GET Request | ||||||
|  *  |  * | ||||||
|  * Obtains an organization by its identifier. |  * Obtains an organization by its identifier. | ||||||
|  *  |  * | ||||||
|  * Required field(s): none. |  * Required field(s): none. | ||||||
|  *  |  * | ||||||
|  * @returns the organization. |  * @returns the organization. | ||||||
|  */ |  */ | ||||||
| async function getOrganization(req, res){ | async function getOrganization (req, res) { | ||||||
|   try { |   try { | ||||||
|     const organization = await organization_model.getOrganizationById(req.params.id); |     const organization = await organization_model.getOrganizationById(req.params.id) | ||||||
|     if(organization) { |     if (organization) { | ||||||
|       return res.status(200).json(organization); |       return res.status(200).json(organization) | ||||||
|  |     } else { | ||||||
|  |       return res.status(404).json({ error: 'Not found' }) | ||||||
|     } |     } | ||||||
|     else{ |   } catch (error) { | ||||||
|       return res.status(404).json({error : "Not found"}); |     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, |   getOrganization, | ||||||
|   updateOrganization, |   updateOrganization, | ||||||
|   deleteOrganization |   deleteOrganization | ||||||
| }; | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,102 +2,98 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const validator = require('../utils/validation'); | const validator = require('../utils/validation') | ||||||
| const knex = require('../utils/knex_config'); | const knex = require('../utils/knex_config') | ||||||
| const jwt_utils = require('../utils/jwt_utils'); | const jwt_utils = require('../utils/jwt_utils') | ||||||
| const bcrypt = require('bcrypt'); | const bcrypt = require('bcrypt') | ||||||
| const crypto = require('crypto'); | const crypto = require('crypto') | ||||||
| const person_model = require('../models/person_model'); | const person_model = require('../models/person_model') | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * POST Request |  * POST Request | ||||||
|  * |  * | ||||||
|  * Registers a Person |  * Registers a Person | ||||||
|  *  |  * | ||||||
|  * Required field(s): name, email (valid ISO standard), password |  * Required field(s): name, email (valid ISO standard), password | ||||||
|  *  |  * | ||||||
|  * @returns The activationlink identifier |  * @returns The activationlink identifier | ||||||
|  */ |  */ | ||||||
| async function registerPerson(req, res){ | async function registerPerson (req, res) { | ||||||
|    |  | ||||||
|   // Does this server allow users to register? |   // Does this server allow users to register? | ||||||
|   if (process.env.ALLOW_USER_REGISTRATION === 'false'){ |   if (process.env.ALLOW_USER_REGISTRATION === 'false') { | ||||||
|     return res.status(403).json({error : "Users cannot register on this server"}); |     return res.status(403).json({ error: 'Users cannot register on this server' }) | ||||||
|   } |   } | ||||||
|   // Ensure that the required fields are present before proceeding |   // Ensure that the required fields are present before proceeding | ||||||
|   if (!req.body.display_name || !req.body.email || !req.body.password) { |   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)){ |   if (!validator.validateEmail(req.body.email)) { | ||||||
|     return res.status(400).json({ error : "The email is not in a valid format"}); |     return res.status(400).json({ error: 'The email is not in a valid format' }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Generate activation link token |   // Generate activation link token | ||||||
|   const activationLink = crypto.randomBytes(16).toString('hex'); |   const activationLink = crypto.randomBytes(16).toString('hex') | ||||||
|   // Hash provided password |   // 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) |     // Check whether e-mail exists already (enforced by database constraints) | ||||||
|     const existingUser = await person_model.getPersonByEmail(req.body.email); |     const existingUser = await person_model.getPersonByEmail(req.body.email) | ||||||
|     if(existingUser){ |     if (existingUser) { | ||||||
|       return res.status(409).json({ error: "E-mail already in use" }); |       return res.status(409).json({ error: 'E-mail already in use' }) | ||||||
|     } |     } | ||||||
|     const personToInsert = person_model.person( |     const personToInsert = person_model.person( | ||||||
|       req.body.email,  |       req.body.email, | ||||||
|       await hashPasswordPromise, |       await hashPasswordPromise, | ||||||
|       req.body.display_name, |       req.body.display_name, | ||||||
|       req.body.date_of_birth, |       req.body.date_of_birth, | ||||||
|       req.body.available, |       req.body.available, | ||||||
|       true, |       true, | ||||||
|       req.body.place_of_living); |       req.body.place_of_living) | ||||||
|     await person_model.registerPerson(personToInsert, activationLink); |     await person_model.registerPerson(personToInsert, activationLink) | ||||||
|     return res.status(200).json({ activationLink: activationLink }); |     return res.status(200).json({ activationLink }) | ||||||
|   } |   } catch (error) { | ||||||
|   catch (error){ |     console.error('Error registering person:', error) | ||||||
|     console.error('Error registering person:', error); |     res.status(500).json({ error: 'Internal server error' }) | ||||||
|     res.status(500).json({error : "Internal server error"}); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * POST Request |  * POST Request | ||||||
|  *  |  * | ||||||
|  * Creates a token if the specified email |  * Creates a token if the specified email | ||||||
|  * and password are valid. |  * and password are valid. | ||||||
|  *  |  * | ||||||
|  * Required field(s): email, password |  * Required field(s): email, password | ||||||
|  * |  * | ||||||
|  * @returns The token |  * @returns The token | ||||||
|  */ |  */ | ||||||
| async function login(req, res){ | async function login (req, res) { | ||||||
|  |  | ||||||
|   // Ensure that the required fields are present before proceeding |   // Ensure that the required fields are present before proceeding | ||||||
|   if (!req.body.email || !req.body.password) { |   if (!req.body.email || !req.body.password) { | ||||||
|     return res.status(400).json({error : "Invalid request"}); |     return res.status(400).json({ error: 'Invalid request' }) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   try{ |   try { | ||||||
|     const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password); |     const person = await person_model.getPersonByEmailAndPassword(req.body.email, req.body.password) | ||||||
|     if (person){ |     if (person) { | ||||||
|       const token = jwt_utils.generateToken(person.id); |       const token = jwt_utils.generateToken(person.id) | ||||||
|       res.status(200).json({token: token }); |       res.status(200).json({ token }) | ||||||
|  |     } else { | ||||||
|  |       res.status(401).json({ error: 'Unauthorized' }) | ||||||
|     } |     } | ||||||
|     else{  |   } catch (error) { | ||||||
|       res.status(401).json({error : "Unauthorized"}); |     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 |  * Obtain a Person's details if the | ||||||
|  * Person to retrieve is either myself or an |  * Person to retrieve is either myself or an | ||||||
|  * enabled Person. |  * enabled Person. | ||||||
|  *  |  * | ||||||
|  * Required field(s): none |  * Required field(s): none | ||||||
|  * |  * | ||||||
|  * @returns The Person |  * @returns The Person | ||||||
|  */ |  */ | ||||||
| async function getPerson(req, res){ | async function getPerson (req, res) { | ||||||
|   try { |   try { | ||||||
|     const person = await person_model.getPersonById(req.params.id); |     const person = await person_model.getPersonById(req.params.id) | ||||||
|     if(person){ |     if (person) { | ||||||
|       // I am retrieving either myself or an enabled user |       // I am retrieving either myself or an enabled user | ||||||
|       if(person.id == req.jwt.person_id || person.enabled){ |       if (person.id == req.jwt.person_id || person.enabled) { | ||||||
|         delete person['password']; // remove password field for security reasons |         delete person.password // remove password field for security reasons | ||||||
|         return res.status(200).send(person); |         return res.status(200).send(person) | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     return res.status(404).json({error: "Not found"}); |     return res.status(404).json({ error: 'Not found' }) | ||||||
|   } |   } catch (error) { | ||||||
|   catch (error) { |     console.log('Error while getting person: ' + error) | ||||||
|     console.log("Error while getting person: " + error); |     return res.status(500).json({ error: 'Internal server error' }) | ||||||
|     return res.status(500).json({error : "Internal server error"}); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  *  |  * | ||||||
|  * GET Request |  * GET Request | ||||||
|  *  |  * | ||||||
|  * Get myself, from the JWT token |  * Get myself, from the JWT token | ||||||
|  * |  * | ||||||
|  * @returns Person's details |  * @returns Person's details | ||||||
|  */ |  */ | ||||||
| async function getMyself(req, res){ | async function getMyself (req, res) { | ||||||
|   try{ |   try { | ||||||
|     const person = await person_model.getPersonById(req.jwt.person_id); |     const person = await person_model.getPersonById(req.jwt.person_id) | ||||||
|     if(person){ |     if (person) { | ||||||
|       delete person['password']; |       delete person.password | ||||||
|       return res.status(200).send(person); |       return res.status(200).send(person) | ||||||
|     } |     } | ||||||
|     return res.status(404).json({error: "Not found"}); |     return res.status(404).json({ error: 'Not found' }) | ||||||
|   } |   } catch (error) { | ||||||
|   catch (error){ |     console.log('Error while getting myself: ' + error) | ||||||
|     console.log("Error while getting myself: " + error); |     return res.status(500).json({ error: 'Internal server error' }) | ||||||
|     return res.status(500).json({error : "Internal server error"}); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * PUT request |  * PUT request | ||||||
|  *  |  * | ||||||
|  * Updates a Person's details. If some details are |  * Updates a Person's details. If some details are | ||||||
|  * not present, they shall be ignored. |  * not present, they shall be ignored. | ||||||
|  *  |  * | ||||||
|  * Required field(s): none. Both old_password and |  * Required field(s): none. Both old_password and | ||||||
|  * new_password if updating the password. |  * new_password if updating the password. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| async function updatePerson(req, res){ | async function updatePerson (req, res) { | ||||||
|    |   if (req.jwt.person_id != req.params.id) { | ||||||
|   if (req.jwt.person_id != req.params.id){ |     return res.status(403).json({ error: 'Forbidden' }) | ||||||
|     return res.status(403).json({ error : "Forbidden"}); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   const updatePerson = {}; |   const updatePerson = {} | ||||||
|  |  | ||||||
|   if(req.body.display_name){ |   if (req.body.display_name) { | ||||||
|     updatePerson.display_name = req.body.display_name; |     updatePerson.display_name = req.body.display_name | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(req.body.date_of_birth){ |   if (req.body.date_of_birth) { | ||||||
|     if(validator.isPostgresDateFormatValid(req.body.date_of_birth)){ |     if (validator.isPostgresDateFormatValid(req.body.date_of_birth)) { | ||||||
|       updatePerson.date_of_birth = req.body.date_of_birth; |       updatePerson.date_of_birth = req.body.date_of_birth | ||||||
|     } |     } else { | ||||||
|     else{ |       return res.status(400).json({ error: 'Date of birth format not valid. Please specify a YYYY-MM-DD date' }) | ||||||
|       return res.status(400).json({ error : "Date of birth format not valid. Please specify a YYYY-MM-DD date"}); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(req.body.available){ |   if (req.body.available) { | ||||||
|     updatePerson.available = req.body.available; |     updatePerson.available = req.body.available | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if(req.body.place_of_living){ |   if (req.body.place_of_living) { | ||||||
|     updatePerson.place_of_living = 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 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') |     const user = await knex('Person') | ||||||
|       .select('password') |       .select('password') | ||||||
|       .where({ id: req.jwt.person_id }) |       .where({ id: req.jwt.person_id }) | ||||||
|       .first(); |       .first() | ||||||
|       const passwordMatches = await bcrypt.compare(req.body.old_password, user.password); |     const passwordMatches = await bcrypt.compare(req.body.old_password, user.password) | ||||||
|       if(passwordMatches){ |     if (passwordMatches) { | ||||||
|         updatePerson.password = await bcrypt.hash(req.body.new_password, 10); |       updatePerson.password = await bcrypt.hash(req.body.new_password, 10) | ||||||
|       } |     } else { | ||||||
|       else{ |       return res.status(401).json({ error: 'Password verification failed' }) | ||||||
|         return res.status(401).json({ error : "Password verification failed"}); |     } | ||||||
|       } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (Object.keys(updatePerson).length === 0) { |   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 { |   try { | ||||||
|     await person_model.updatePerson(updatePerson, req.params.id); |     await person_model.updatePerson(updatePerson, req.params.id) | ||||||
|     return res.status(200).json({ success : "true"}); |     return res.status(200).json({ success: 'true' }) | ||||||
|   } |   } catch (error) { | ||||||
|   catch (error) { |     console.log('Error while updating a Person: ' + error) | ||||||
|     console.log("Error while updating a Person: " + error); |     return res.status(500).json({ error: 'Internal server error' }) | ||||||
|     return res.status(500).json({ error : "Internal server error"}); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * GET Request |  * GET Request | ||||||
|  *  |  * | ||||||
|  * Deletes a Person. An user can only delete  |  * Deletes a Person. An user can only delete | ||||||
|  * themselves. |  * themselves. | ||||||
|  *  |  * | ||||||
|  * Required field(s): none |  * Required field(s): none | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| async function deletePerson(req, res) { | async function deletePerson (req, res) { | ||||||
|   // TODO: Delete Organization if this user was its only administrator |   // TODO: Delete Organization if this user was its only administrator | ||||||
|   try { |   try { | ||||||
|     await person_model.deletePerson(req.jwt.person_id); |     await person_model.deletePerson(req.jwt.person_id) | ||||||
|     return res.status(200).json({success: true}); |     return res.status(200).json({ success: true }) | ||||||
|   }  |   } catch (error) { | ||||||
|   catch (error) { |     console.log('Error deleting a Person: ' + error) | ||||||
|     console.log("Error deleting a Person: " + error); |     return res.status(500).json({ error: 'Internal server 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 | // means making a JavaScript function defined in one | ||||||
| // module available for use in another module. | // module available for use in another module. | ||||||
| module.exports = { | module.exports = { | ||||||
|     registerPerson, |   registerPerson, | ||||||
|     login, |   login, | ||||||
|     getPerson, |   getPerson, | ||||||
|     getMyself, |   getMyself, | ||||||
|     updatePerson, |   updatePerson, | ||||||
|     deletePerson |   deletePerson | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -2,50 +2,50 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const jwt = require('jsonwebtoken'); | const jwt = require('jsonwebtoken') | ||||||
|  |  | ||||||
| function generateToken(person_id) { | function generateToken (person_id) { | ||||||
|     // The payload the JWT will carry within itself |   // The payload the JWT will carry within itself | ||||||
|     const payload = { |   const payload = { | ||||||
|       person_id: person_id |     person_id | ||||||
|     }; |  | ||||||
|    |  | ||||||
|     const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, {  |  | ||||||
|       expiresIn: '8h'  |  | ||||||
|     }); |  | ||||||
|     return token; |  | ||||||
|   } |   } | ||||||
|    |  | ||||||
|   // Middlware |   const token = jwt.sign(payload, process.env.JWT_SECRET_KEY, { | ||||||
|   function verifyToken(req, res, next) { |     expiresIn: '8h' | ||||||
|     const token = req.headers.authorization; |   }) | ||||||
|    |   return token | ||||||
|     if (!token) { | } | ||||||
|       return res.status(401).send({error : 'No token provided'}); |  | ||||||
|  | // 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 = { |     // If the token is valid, store the decoded data in the request object | ||||||
|     generateToken, |     // req.jwt will contain the payload created in generateToken | ||||||
|     verifyToken |     req.jwt = decoded | ||||||
| }; |     next() | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = { | ||||||
|  |   generateToken, | ||||||
|  |   verifyToken | ||||||
|  | } | ||||||
|   | |||||||
| @@ -2,24 +2,24 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| const knexInstance = require('knex')({ | const knexInstance = require('knex')({ | ||||||
|     client: 'pg', |   client: 'pg', | ||||||
|     connection: { |   connection: { | ||||||
|       host: process.env.POSTGRES_SERVER, |     host: process.env.POSTGRES_SERVER, | ||||||
|       user: process.env.POSTGRES_USERNAME, |     user: process.env.POSTGRES_USERNAME, | ||||||
|       password: process.env.POSTGRES_PASSWORD, |     password: process.env.POSTGRES_PASSWORD, | ||||||
|       port: process.env.POSTGRES_PORT, |     port: process.env.POSTGRES_PORT, | ||||||
|       database: 'Blink' |     database: 'Blink' | ||||||
|     } |   } | ||||||
|   }); | }) | ||||||
|  |  | ||||||
|   module.exports = knexInstance; | module.exports = knexInstance | ||||||
|   | |||||||
| @@ -2,37 +2,37 @@ | |||||||
|     This code is part of Blink |     This code is part of Blink | ||||||
|     licensed under GPLv3 |     licensed under GPLv3 | ||||||
|  |  | ||||||
|     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  |     IMPLIED,  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||||
|     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |     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 |     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||||||
|     IN THE SOFTWARE. |     IN THE SOFTWARE. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Checks whether an e-mail is in a valid format |  * Checks whether an e-mail is in a valid format | ||||||
|  * @param {*} email email to validate  |  * @param {*} email email to validate | ||||||
|  * @returns true or false |  * @returns true or false | ||||||
|  */ |  */ | ||||||
| function validateEmail(email) { | function validateEmail (email) { | ||||||
|     const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/; |   const regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/ | ||||||
|     return regex.test(email); |   return regex.test(email) | ||||||
| } | } | ||||||
|    |  | ||||||
| /** | /** | ||||||
|  * Checks whether a date is in a correct Postgres |  * Checks whether a date is in a correct Postgres | ||||||
|  * format (YYYY-MM-DD) |  * format (YYYY-MM-DD) | ||||||
|  * @param {*} dateString the date to validate  |  * @param {*} dateString the date to validate | ||||||
|  * @returns true or false |  * @returns true or false | ||||||
|  */ |  */ | ||||||
| function isPostgresDateFormatValid(dateString) { | function isPostgresDateFormatValid (dateString) { | ||||||
|     const regex = /^\d{4}-\d{2}-\d{2}$/; |   const regex = /^\d{4}-\d{2}-\d{2}$/ | ||||||
|     return regex.test(dateString); |   return regex.test(dateString) | ||||||
| } | } | ||||||
|  |  | ||||||
| module.exports = { | module.exports = { | ||||||
|     validateEmail, |   validateEmail, | ||||||
|     isPostgresDateFormatValid |   isPostgresDateFormatValid | ||||||
| }; | } | ||||||
|   | |||||||
| @@ -1,30 +1,30 @@ | |||||||
| // Run me with "npm test" | // Run me with "npm test" | ||||||
|  |  | ||||||
| const request = require('supertest'); | const request = require('supertest') | ||||||
| const app = require('../src/app'); | const app = require('../src/app') | ||||||
| require('dotenv').config({ path: '../src/.env' }); | require('dotenv').config({ path: '../src/.env' }) | ||||||
|  |  | ||||||
| describe('Person Tests', () => { | describe('Person Tests', () => { | ||||||
|   test('Correct registration', async () => { |   test('Correct registration', async () => { | ||||||
|     const response = await request(app) |     const response = await request(app) | ||||||
|         .post('/api/register') |       .post('/api/register') | ||||||
|         .send({ |       .send({ | ||||||
|             email : "johntestdoe@mail.org", |         email: 'johntestdoe@mail.org', | ||||||
|             password : "password", |         password: 'password', | ||||||
|             display_name : "John Doe" |         display_name: 'John Doe' | ||||||
|         }) |       }) | ||||||
|     expect(response.status).toBe(200); |     expect(response.status).toBe(200) | ||||||
|     expect(response.body).toEqual({ activationLink: expect.any(String) }); |     expect(response.body).toEqual({ activationLink: expect.any(String) }) | ||||||
|   }); |   }) | ||||||
|  |  | ||||||
|   test('Incorrect registration', async () => { |   test('Incorrect registration', async () => { | ||||||
|     const response = await request(app) |     const response = await request(app) | ||||||
|         .post('/api/register') |       .post('/api/register') | ||||||
|         .send({ |       .send({ | ||||||
|             email : "this is not an email", |         email: 'this is not an email', | ||||||
|             password : "password", |         password: 'password', | ||||||
|             display_name : "John Doe" |         display_name: 'John Doe' | ||||||
|         }) |       }) | ||||||
|     expect(response.status).toBe(400); |     expect(response.status).toBe(400) | ||||||
|   }); |   }) | ||||||
| }); | }) | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| const apiUrl = "http://localhost:3000/blinkapi"; | const apiUrl = 'http://localhost:3000/blinkapi' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user