Skip to content

Commit 559634f

Browse files
authored
Fix regex check in background + admin check for managers (#626)
* Changes * Also increase api key size * Update auth.js * Regex + fix project deletion * Fix admin check for managers * typos * fix * debug? * remove number in names for test * fixes
1 parent 0dde046 commit 559634f

10 files changed

Lines changed: 102 additions & 41 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* Modified add_readme template
1616
* Fix typo in cron due to remove_tp_reservation changes
1717
* Allow spaces, - and ' in user first/last names
18+
* Fix project deletion process
1819

1920
## 1.4.32 (2025-04-22)
2021

manager2/src/app/admin/project/project.component.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { Group, GroupsService } from 'src/app/admin/groups/groups.service';
66
import { User, UserService } from 'src/app/user/user.service';
77
import { Table } from 'primeng/table';
88

9+
import { forkJoin } from 'rxjs';
10+
911
@Component({
1012
selector: 'app-project',
1113
templateUrl: './project.component.html',
@@ -156,7 +158,7 @@ export class ProjectComponent implements OnInit {
156158
remove_user() {
157159
this.admin_user_msg = '';
158160
this.admin_user_err_msg = '';
159-
this.userService.removeFromProject(this.remove_user_admin, this.project.id).subscribe(
161+
this.userService.removeFromProject(this.remove_user_admin, this.project.id, false).subscribe(
160162
(resp) => {
161163
this.admin_user_msg = resp['message'];
162164
this.show_project_users(this.project.id);
@@ -177,16 +179,23 @@ export class ProjectComponent implements OnInit {
177179

178180
delete_project() {
179181
this.admin_user_err_msg = '';
180-
for (var i = 0; i < this.users.length; i++) {
181-
this.userService.removeFromProject(this.users[i].uid, this.project.id).subscribe(
182-
(resp) => {},
183-
(err) => (this.prj_err_msg = err.error.message)
184-
);
185-
}
186-
this.projectsService.delete(this.project.id).subscribe(
187-
(resp) => this.router.navigate(['/admin/project'], { queryParams: { deleted: 'ok' } }),
188-
(err) => (this.admin_user_err_msg = err.error.message)
182+
this.prj_err_msg = '';
183+
184+
const deleteRequests = this.users.map(user =>
185+
this.userService.removeFromProject(user.uid, this.project.id, true)
189186
);
187+
188+
forkJoin(deleteRequests).subscribe({
189+
next: () => {
190+
this.projectsService.delete(this.project.id).subscribe(
191+
() => this.router.navigate(['/admin/project'], { queryParams: { deleted: 'ok' } }),
192+
(err) => (this.admin_user_err_msg = err.error.message)
193+
);
194+
},
195+
error: (err) => {
196+
this.prj_err_msg = err.error?.message || 'Error removing users from project';
197+
}
198+
});
190199
}
191200

192201
update_project() {

manager2/src/app/project/project.component.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class ProjectComponent implements OnInit {
3939
manager_visible: boolean;
4040
overview_visible: boolean;
4141
members_visible: boolean;
42-
42+
4343
request_err_msg: string;
4444
request_msg: string;
4545
owner_request_err_msg: string;
@@ -151,7 +151,7 @@ export class ProjectComponent implements OnInit {
151151
for (let i = 0; i < resp.length; i++) {
152152
this.users[i].temp = { ...this.users[i].temp, is_manager: this.selectedProject.managers.includes(this.users[i].uid) }
153153
if (
154-
resp[i].group.indexOf(this.selectedProject.group) >= 0 ||
154+
resp[i].group.indexOf(this.selectedProject.group) >= 0 ||
155155
resp[i].secondarygroups.indexOf(this.selectedProject.group) >= 0
156156
) {
157157
this.users[i].temp = { ...this.users[i].temp, access: true };
@@ -216,7 +216,7 @@ export class ProjectComponent implements OnInit {
216216
}
217217
if (request_type === 'remove' && this.session_user.uid === user_id) {
218218
// Self removal
219-
this.userService.removeFromProject(user_id, project.id).subscribe(
219+
this.userService.removeFromProject(user_id, project.id, false).subscribe(
220220
(resp) => {
221221
this.manager_request_msg = resp['message'];
222222
this.project_list();

manager2/src/app/user/projects/projects.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class ProjectsComponent implements OnInit {
5151
}
5252

5353
remove_from_project(project_id) {
54-
this.userService.removeFromProject(this.user.uid, project_id).subscribe(
54+
this.userService.removeFromProject(this.user.uid, project_id, false).subscribe(
5555
(resp) => {
5656
this.remove_from_project_msg = resp['message'];
5757
let tmpproject = [];

manager2/src/app/user/user.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,7 @@ export class UserComponent implements OnInit {
860860
}
861861

862862
remove_from_project(project_id) {
863-
this.userService.removeFromProject(this.user.uid, project_id).subscribe(
863+
this.userService.removeFromProject(this.user.uid, project_id, false).subscribe(
864864
(resp) => {
865865
this.remove_from_project_msg = resp['message'];
866866
var tmp_project: any[] = [];

manager2/src/app/user/user.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,15 +410,15 @@ export class UserService {
410410
}));
411411
}
412412

413-
removeFromProject(userId: string, projectId: string) {
413+
removeFromProject(userId: string, projectId: string, force: boolean) {
414414
//let user = this.authService.profile;
415415
let httpOptions = {
416416
//headers: new HttpHeaders({
417417
// 'x-api-key': user.apikey
418418
//}),
419419
};
420420
return this.http.delete(
421-
environment.apiUrl + '/user/' + userId + '/project/' + projectId,
421+
environment.apiUrl + '/user/' + userId + '/project/' + projectId + '?force=' + force,
422422
httpOptions)
423423
}
424424

routes/auth.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ router.post('/auth/:id', async function (req, res) {
417417
req.connection.socket.remoteAddress;
418418
if ((user.is_admin && GENERAL_CONFIG.admin_ip.indexOf(ip) >= 0) || process.env.gomngr_auth == 'fake') {
419419
// Skip auth
420-
usertoken = jwt.sign({ isLogged: true, u2f: user._id }, CONFIG.general.secret, { expiresIn: '2 days' });
420+
usertoken = jwt.sign({ isLogged: true, u2f: user._id, user: user._id }, CONFIG.general.secret, { expiresIn: '2 days' });
421421
return res.send({ token: usertoken, user: user, message: '', double_auth: need_double_auth });
422422
} else {
423423
try {

routes/projects.js

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,12 @@ router.delete('/project/:id', async function (req, res) {
250250
return res.status(401).send({ message: 'Not authorized' });
251251
}
252252

253+
let users_in_project = await dbsrv.mongo_users().find({ projects: req.params.id }).toArray();
254+
255+
if (users_in_project.length > 0){
256+
return res.status(403).send({ message: 'Project is not empty. Cannot remove' });
257+
}
258+
253259
try {
254260
await prjsrv.remove_project(req.params.id, user.uid);
255261
} catch (e) {
@@ -325,16 +331,26 @@ router.post('/project/:id/request/user', async function (req, res) {
325331
if (!sansrv.sanitizeAll([req.params.id])) {
326332
return res.status(403).send({ message: 'Invalid parameters' });
327333
}
328-
let user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
329-
if (!user) {
334+
335+
let session_user = null;
336+
let isadmin = false;
337+
try {
338+
session_user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
339+
isadmin = await rolsrv.is_admin(session_user);
340+
} catch (e) {
341+
logger.error(e);
342+
return res.status(404).send({ message: 'User session not found' });
343+
}
344+
345+
if (!session_user) {
330346
return res.status(404).send({ message: 'User not found' });
331347
}
332348
let project = await dbsrv.mongo_projects().findOne({ id: req.params.id });
333349
if (!project) {
334350
return res.status(404).send({ message: 'Project ' + req.params.id + ' not found' });
335351
}
336-
if ((!project.managers || !project.managers.includes(user.uid)) && user.uid !== project.owner && !user.is_admin) {
337-
return res.status(401).send({ message: 'User ' + user.uid + ' is not project manager for project ' + project.id });
352+
if ((!project.managers || !project.managers.includes(session_user.uid)) && session_user.uid !== project.owner && !isadmin) {
353+
return res.status(401).send({ message: 'User ' + session_user.uid + ' is not project manager for project ' + project.id });
338354
}
339355
if (req.body.user == project.owner) {
340356
return res.status(403).send({ message: 'User ' + req.body.user + ' is the owner of project ' + project.id });
@@ -349,9 +365,9 @@ router.post('/project/:id/request/user', async function (req, res) {
349365

350366
try {
351367
if (req.body.request === 'add') {
352-
await usrsrv.add_user_to_project(project.id, req.body.user, user.uid);
368+
await usrsrv.add_user_to_project(project.id, req.body.user, session_user.uid);
353369
} else if (req.body.request === 'remove') {
354-
await usrsrv.remove_user_from_project(project.id, req.body.user, user.uid, user.is_admin, false);
370+
await usrsrv.remove_user_from_project(project.id, req.body.user, session_user.uid, isadmin, false);
355371
}
356372
} catch (e) {
357373
logger.error(e);
@@ -369,19 +385,30 @@ router.post('/project/:id/add/manager/:uid', async function(req, res) {
369385
if (!req.locals.logInfo.is_logged) {
370386
return res.status(401).send({ message: 'Not authorized' });
371387
}
372-
if (!sansrv.sanitizeAll([req.params.id])) {
388+
if (!sansrv.sanitizeAll([req.params.id]) || !sansrv.sanitizeAll([req.params.uid])) {
373389
return res.status(403).send({ message: 'Invalid parameters' });
374390
}
375-
let user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
376-
if (!user) {
391+
392+
let session_user = null;
393+
let isadmin = false;
394+
try {
395+
session_user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
396+
isadmin = await rolsrv.is_admin(session_user);
397+
} catch (e) {
398+
logger.error(e);
399+
return res.status(404).send({ message: 'User session not found' });
400+
}
401+
402+
if (!session_user) {
377403
return res.status(404).send({ message: 'User not found' });
378404
}
405+
379406
let project = await dbsrv.mongo_projects().findOne({ 'id': req.params.id });
380407
if (!project) {
381408
return res.status(404).send({ message: 'Project ' + req.params.id + ' not found' });
382409
}
383-
if (user.uid != project.owner && !user.is_admin) {
384-
return res.status(401).send({ message: 'Non-admin user ' + user.uid + ' is not the owner of project ' + project.id });
410+
if (session_user.uid != project.owner && !isadmin) {
411+
return res.status(401).send({ message: 'Non-admin user ' + session_user.uid + ' is not the owner of project ' + project.id });
385412
}
386413
const new_manager = await dbsrv.mongo_users().findOne({ 'uid': req.params.uid });
387414
if (!new_manager) {
@@ -416,19 +443,30 @@ router.post('/project/:id/remove/manager/:uid', async function(req, res) {
416443
if (!req.locals.logInfo.is_logged) {
417444
return res.status(401).send({ message: 'Not authorized' });
418445
}
419-
if (!sansrv.sanitizeAll([req.params.id])) {
446+
if (!sansrv.sanitizeAll([req.params.id]) || !sansrv.sanitizeAll([req.params.uid])) {
420447
return res.status(403).send({ message: 'Invalid parameters' });
421448
}
422-
let user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
423-
if (!user) {
449+
450+
let session_user = null;
451+
let isadmin = false;
452+
try {
453+
session_user = await dbsrv.mongo_users().findOne({ _id: req.locals.logInfo.id });
454+
isadmin = await rolsrv.is_admin(session_user);
455+
} catch (e) {
456+
logger.error(e);
457+
return res.status(404).send({ message: 'User session not found' });
458+
}
459+
460+
if (!session_user) {
424461
return res.status(404).send({ message: 'User not found' });
425462
}
463+
426464
let project = await dbsrv.mongo_projects().findOne({ 'id': req.params.id });
427465
if (!project) {
428466
return res.status(404).send({ message: 'Project ' + req.params.id + ' not found' });
429467
}
430-
if (user.uid != project.owner && !user.is_admin) {
431-
return res.status(401).send({ message: 'Non-admin user ' + user.uid + ' is not the owner of project ' + project.id });
468+
if (session_user.uid != project.owner && !isadmin) {
469+
return res.status(401).send({ message: 'Non-admin user ' + session_user.uid + ' is not the owner of project ' + project.id });
432470
}
433471
const ex_manager = await dbsrv.mongo_users().findOne({ 'uid': req.params.uid });
434472
if (!ex_manager) {

routes/users.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,9 +693,19 @@ router.post('/user/:id', async function (req, res) {
693693
if (req.body.firstname == '' || req.body.firstname === null || req.body.firstname === undefined) {
694694
return res.send({ status: 1, message: 'Missing field: firstname' });
695695
}
696+
697+
if (!req.body.firstname.match(/^[a-zA-Zà-ü -']+$/)) {
698+
return res.send({ status: 1, message: 'Firstname contains unauthorized characters' });
699+
}
700+
696701
if (req.body.lastname == '' || req.body.lastname === null || req.body.lastname === undefined) {
697702
return res.send({ status: 1, message: 'Missing field: lastname' });
698703
}
704+
705+
if (!req.body.lastname.match(/^[a-zA-Zà-ü -']+$/)) {
706+
return res.send({ status: 1, message: 'Lastname contains unauthorized characters' });
707+
}
708+
699709
if (req.body.team == '' || req.body.team === null || req.body.team === undefined) {
700710
return res.send({ status: 1, message: 'Missing field: team' });
701711
}
@@ -1633,7 +1643,7 @@ router.delete('/user/:id/project/:project', async function (req, res) {
16331643
}
16341644
let oldproject = req.params.project;
16351645
let uid = req.params.id;
1636-
let force = req.query.force ? true : false;
1646+
16371647

16381648
let session_user = null;
16391649
let isadmin = false;
@@ -1647,6 +1657,9 @@ router.delete('/user/:id/project/:project', async function (req, res) {
16471657
return res.status(404).send({ message: 'User session not found' });
16481658
}
16491659

1660+
// Force is restricted to admins
1661+
let force = req.query.force && isadmin;
1662+
16501663
if (!session_user) {
16511664
return res.status(404).send({ message: 'User session not found' });
16521665
}

test/my.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ describe('My', () => {
133133
chai.request('http://localhost:3000')
134134
.post('/user/' + test_user_id2)
135135
.send({
136-
'firstname': 'ftest2',
137-
'lastname': 'ltest2',
136+
'firstname': 'ftestt',
137+
'lastname': 'ltestt',
138138
'email': test_user_id2 + '@my.org',
139139
'address': 'test address',
140140
'lab': 'test',
@@ -583,7 +583,7 @@ describe('My', () => {
583583
create: true
584584

585585
};
586-
586+
587587
chai.request('http://localhost:3000')
588588
.post('/database/create/' + test_db_id)
589589
.set('X-Api-Key', token_id)
@@ -594,7 +594,7 @@ describe('My', () => {
594594
.get('/database')
595595
.set('X-Api-Key', token_id)
596596
.end((err, res) => {
597-
597+
598598
expect(res).to.have.status(200);
599599
let found = false;
600600
for(let i=0; i<res.body.length; i++){
@@ -743,7 +743,7 @@ describe('My', () => {
743743
single_user: true,
744744
create: true
745745
};
746-
746+
747747
chai.request('http://localhost:3000')
748748
.post('/database/create/' + db.name)
749749
.set('X-Api-Key', user_token_id)
@@ -754,7 +754,7 @@ describe('My', () => {
754754
});
755755
});
756756

757-
757+
758758
it('User delete database', (done) => {
759759
chai.request('http://localhost:3000')
760760
.delete('/database/' + test_db_id)

0 commit comments

Comments
 (0)