Skip to content

Commit 29dc9b5

Browse files
Implemented API endpoint to return current users info (#4872)
* Implemented API endpoint to return current users info * Added tests for login/whoami endpoint * Added another test case for additional requested fields * Fixed a security hole * Removed the req.query.additionalFields test case as well as the allowedFields feature * Added 2 more test cases as requested to test out whoamiFields --------- Co-authored-by: Robert Means <robert@apostrophecms.com>
1 parent 6b8637e commit 29dc9b5

4 files changed

Lines changed: 99 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
### Adds
66

7+
* Implemented GET /api/v1/@apostrophecms/login/whoami route such that it returns the details of the currently logged in user; added the route to the login module.
78
* Adds keyboard shortcuts for manipulating widgets in areas. Includes Cut, Copy, Paste, Delete, and Duplicate.
89
* Adds dynamic choices working with piece manager filters.
910
* Allow `import.imageTags` (array of image tag IDs) to be passed to the rich text widget when importing (see https://docs.apostrophecms.org/reference/api/rich-text.html#importing-inline-images).

modules/@apostrophecms/login/index.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ module.exports = {
6969
allowedAttempts: 3,
7070
perMinutes: 1,
7171
lockoutMinutes: 1
72-
}
72+
},
73+
minimumWhoamiFields: [ '_id', 'username', 'title', 'email' ],
74+
whoamiFields: []
7375
},
7476
async init(self) {
7577
self.passport = new Passport();
@@ -351,6 +353,22 @@ module.exports = {
351353
// it should be accessed via POST because the result
352354
// may differ by individual user session and should not
353355
// be cached
356+
async whoami (req) {
357+
if (!req.user) {
358+
throw self.apos.error('notfound');
359+
}
360+
361+
const fields = new Set([ ...self.options.minimumWhoamiFields, ...self.options.whoamiFields ]);
362+
const user = {};
363+
364+
for (const field of fields) {
365+
if (req.user[field] !== undefined) {
366+
user[field] = req.user[field];
367+
}
368+
}
369+
370+
return user;
371+
},
354372
async context(req) {
355373
return self.getContext(req);
356374
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
"@apostrophecms/vue-material-design-icons": "^1.0.0",
3737
"@ctrl/tinycolor": "^4.1.0",
3838
"@floating-ui/dom": "^1.5.3",
39-
"@opentelemetry/api": "^1.0.4",
39+
"@opentelemetry/api": "^1.9.0",
4040
"@opentelemetry/semantic-conventions": "^1.0.1",
4141
"@paralleldrive/cuid2": "^2.2.2",
4242
"@tiptap/extension-color": "^2.4.0",

test/login.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,4 +867,82 @@ describe('Login', function() {
867867
}
868868
);
869869
});
870+
871+
it('should return an error with code 404 at GET login/whoami when user is not logged in', async function() {
872+
try {
873+
await apos.http.get('/api/v1/@apostrophecms/login/whoami');
874+
assert.fail('Expected error but got success');
875+
} catch (err) {
876+
assert.strictEqual(err.status, 404);
877+
assert(err.message.includes('notfound'));
878+
}
879+
});
880+
881+
it('should return user data at GET login/whoami when user is logged in', async function() {
882+
883+
const jar = apos.http.jar();
884+
885+
await apos.http.post(
886+
'/api/v1/@apostrophecms/login/login',
887+
{
888+
method: 'POST',
889+
body: {
890+
username: 'HarryPutter',
891+
password: 'crookshanks',
892+
session: true
893+
},
894+
jar
895+
}
896+
);
897+
898+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
899+
assert.ok(whoamiResponse._id);
900+
assert.strictEqual(whoamiResponse.username, 'HarryPutter');
901+
assert.strictEqual(whoamiResponse.title, 'Harry Putter');
902+
assert.strictEqual(whoamiResponse.email, 'hputter@aol.com');
903+
});
904+
905+
it('should return user data with additional whoamiFields if explicitly added at GET login/whoami when user is logged in', async function() {
906+
907+
const jar = apos.http.jar();
908+
909+
apos.modules['@apostrophecms/login'].options.whoamiFields = [ 'role' ];
910+
911+
await apos.http.post(
912+
'/api/v1/@apostrophecms/login/login',
913+
{
914+
method: 'POST',
915+
body: {
916+
username: 'HarryPutter',
917+
password: 'crookshanks',
918+
session: true
919+
},
920+
jar
921+
}
922+
);
923+
924+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
925+
assert.strictEqual(whoamiResponse.role, 'admin');
926+
});
927+
928+
it('should not return user data with additional whoamiFields if not explicitly added at GET login/whoami when user is logged in', async function() {
929+
930+
const jar = apos.http.jar();
931+
932+
await apos.http.post(
933+
'/api/v1/@apostrophecms/login/login',
934+
{
935+
method: 'POST',
936+
body: {
937+
username: 'HarryPutter',
938+
password: 'crookshanks',
939+
session: true
940+
},
941+
jar
942+
}
943+
);
944+
945+
const whoamiResponse = await apos.http.get('/api/v1/@apostrophecms/login/whoami', { jar });
946+
assert.ok(!('role' in whoamiResponse));
947+
});
870948
});

0 commit comments

Comments
 (0)