Skip to content

Commit 96398e5

Browse files
authored
Merge pull request #17 from which-ecosystem/security
Prepare release-level backend security
2 parents da76bb1 + 1c2f3c9 commit 96398e5

File tree

7 files changed

+57
-13
lines changed

7 files changed

+57
-13
lines changed

config/default.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"local": {
1111
"usernameField": "\\username",
1212
"passwordField": "password"
13+
},
14+
"jwtOptions": {
15+
"expiresIn": "10 days"
1316
}
1417
}
1518
}

hooks/tryAuthenticate.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { authenticate } from '@feathersjs/authentication';
33

44

55
export default async (context: HookContext): Promise<HookContext> => {
6-
return authenticate('jwt')(context).catch(() => context);
6+
if (context.params?.headers?.authorization && context.path !== 'authentication') {
7+
return authenticate('jwt')(context);
8+
}
9+
return context;
710
};
811

populateDb.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@ const createPoll = (authorId: string): Promise<Poll> => {
5656
contents: {
5757
left: generateImageData(),
5858
right: generateImageData()
59-
},
60-
authorId
61-
});
59+
}
60+
}, { user: { _id: authorId }, authenticated: true });
6261
};
6362

6463
const createUser = (username: string): Promise<User> => {
@@ -69,18 +68,18 @@ const createUser = (username: string): Promise<User> => {
6968
});
7069
};
7170

72-
const createVote = (userId: string, pollId: string): Promise<Vote> => {
71+
const createVote = (authorId: string, pollId: string): Promise<Vote> => {
7372
return app.service('votes').create({
7473
pollId,
7574
which: _.sample(choices)
76-
}, { user: { _id: userId }, authenticated: true });
75+
}, { user: { _id: authorId }, authenticated: true });
7776
};
7877

7978
const createFeedback = (userId: string): Promise<Feedback> => {
8079
return app.service('feedback').create({
8180
version: 'v1.0.0',
8281
score: _.sample([1, 2, 3, 4, 5]),
83-
content: 'Absolutely amazing!'
82+
contents: 'Absolutely amazing!'
8483
}, { user: { _id: userId }, authenticated: true });
8584
};
8685

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
1+
import { populate, discard, disallow } from 'feathers-hooks-common';
12
import requireAuth from '../../hooks/requireAuth';
23
import signAuthority from '../../hooks/signAuthority';
4+
import sortByDate from '../../hooks/sortByDate';
5+
6+
7+
const populateAuthor = populate({
8+
schema: {
9+
include: {
10+
service: 'users',
11+
nameAs: 'author',
12+
parentField: 'authorId',
13+
childField: '_id'
14+
}
15+
}
16+
});
317

418
export default {
519
before: {
6-
create: [requireAuth, signAuthority]
20+
create: [requireAuth, signAuthority],
21+
find: sortByDate,
22+
remove: disallow('external'),
23+
patch: disallow('external'),
24+
update: disallow('external')
25+
},
26+
after: {
27+
all: [populateAuthor, discard('authorId')]
728
}
829
};
930

services/polls/polls.hooks.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { HookContext } from '@feathersjs/feathers';
2+
import { disallow } from 'feathers-hooks-common';
23
import { Types } from 'mongoose';
34
import bluebird from 'bluebird'; import _ from 'lodash';
45
import { Poll } from 'which-types';
@@ -46,7 +47,10 @@ const convertPoll = async (context: HookContext): Promise<HookContext> => {
4647
export default {
4748
before: {
4849
find: sortByDate,
49-
create: signAuthority
50+
create: signAuthority,
51+
remove: disallow('external'),
52+
update: disallow('external'),
53+
patch: disallow('external')
5054
},
5155
after: {
5256
all: convertPoll

services/users/users.hooks.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import _ from 'lodash';
22
import { hooks } from '@feathersjs/authentication-local';
3-
import { discard } from 'feathers-hooks-common';
3+
import { discard, disallow } from 'feathers-hooks-common';
44
import { HookContext } from '@feathersjs/feathers';
5+
import { NotAuthenticated } from '@feathersjs/errors';
6+
import requireAuth from '../../hooks/requireAuth';
57

68
const hashPassword = hooks.hashPassword('password');
79

@@ -12,6 +14,13 @@ const ignoreCaseRegex = async (context: HookContext): Promise<HookContext> => {
1214
return context;
1315
};
1416

17+
const compareUser = async (context: HookContext): Promise<HookContext> => {
18+
if (context.arguments[0] !== context.params.user._id) {
19+
throw new NotAuthenticated('You can only PATCH/UPDATE your own user!');
20+
}
21+
return context;
22+
};
23+
1524
export default {
1625
after: {
1726
all: hooks.protect('password'),
@@ -20,8 +29,9 @@ export default {
2029
before: {
2130
find: ignoreCaseRegex,
2231
create: hashPassword,
23-
patch: hashPassword,
24-
update: hashPassword
32+
patch: [hashPassword, requireAuth, compareUser],
33+
update: [hashPassword, requireAuth, compareUser],
34+
remove: disallow('external')
2535
}
2636
};
2737

services/votes/votes.hooks.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { disallow } from 'feathers-hooks-common';
12
import requireAuth from '../../hooks/requireAuth';
23
import signAuthority from '../../hooks/signAuthority';
34

45
export default {
56
before: {
6-
create: [requireAuth, signAuthority]
7+
create: [requireAuth, signAuthority],
8+
remove: disallow('external'),
9+
update: disallow('external'),
10+
patch: disallow('external')
711
}
812
};
913

0 commit comments

Comments
 (0)