Просмотр исходного кода

add tests for access token parsing from query and body; validate user assignment

reiji-h 1 год назад
Родитель
Сommit
2647c8945e

+ 60 - 0
apps/app/src/server/middlewares/access-token-parser/access-token-parser.integ.ts

@@ -72,6 +72,66 @@ describe('access-token-parser middleware', () => {
     expect(nextMock).toHaveBeenCalled();
   });
 
+  it('should set req.user with a valid api token in query', async() => {
+    // arrange
+    const reqMock = mock<AccessTokenParserReq>({
+      user: undefined,
+    });
+    const resMock = mock<Response>();
+    const nextMock = vi.fn();
+
+    expect(reqMock.user).toBeUndefined();
+
+    // prepare a user with an access token
+    const targetUser = await User.create({
+      name: faker.person.fullName(),
+      username: faker.string.uuid(),
+      password: faker.internet.password(),
+      lang: 'en_US',
+      apiToken: faker.internet.password(),
+    });
+
+    // act
+    reqMock.query.access_token = targetUser.apiToken;
+    await accessTokenParser(reqMock, resMock, nextMock);
+
+    // assert
+    expect(reqMock.user).toBeDefined();
+    expect(reqMock.user?._id).toStrictEqual(targetUser._id);
+    expect(serializeUserSecurely).toHaveBeenCalledOnce();
+    expect(nextMock).toHaveBeenCalled();
+  });
+
+  it('should set req.user with a valid api token in body', async() => {
+    // arrange
+    const reqMock = mock<AccessTokenParserReq>({
+      user: undefined,
+    });
+    const resMock = mock<Response>();
+    const nextMock = vi.fn();
+
+    expect(reqMock.user).toBeUndefined();
+
+    // prepare a user with an access token
+    const targetUser = await User.create({
+      name: faker.person.fullName(),
+      username: faker.string.uuid(),
+      password: faker.internet.password(),
+      lang: 'en_US',
+      apiToken: faker.internet.password(),
+    });
+
+    // act
+    reqMock.body.access_token = targetUser.apiToken;
+    await accessTokenParser(reqMock, resMock, nextMock);
+
+    // assert
+    expect(reqMock.user).toBeDefined();
+    expect(reqMock.user?._id).toStrictEqual(targetUser._id);
+    expect(serializeUserSecurely).toHaveBeenCalledOnce();
+    expect(nextMock).toHaveBeenCalled();
+  });
+
   it('should set req.user with a valid access token in query', async() => {
     // arrange
     const reqMock = mock<AccessTokenParserReq>({

+ 12 - 1
apps/app/src/server/middlewares/access-token-parser/access-token-parser.ts

@@ -1,6 +1,8 @@
-import type { IUserHasId } from '@growi/core/dist/interfaces';
+import type { IUser, IUserHasId } from '@growi/core/dist/interfaces';
 import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
 import type { NextFunction, Response } from 'express';
+import type { HydratedDocument } from 'mongoose';
+import mongoose from 'mongoose';
 
 import { AccessToken } from '~/server/models/access-token';
 import loggerFactory from '~/utils/logger';
@@ -19,6 +21,15 @@ export const accessTokenParser = async(req: AccessTokenParserReq, res: Response,
 
   logger.debug('accessToken is', accessToken);
 
+  // check the api token is valid
+  const User = mongoose.model<HydratedDocument<IUser>, { findUserByApiToken }>('User');
+  const userByApiToken: IUserHasId = await User.findUserByApiToken(accessToken);
+  if (userByApiToken != null) {
+    req.user = serializeUserSecurely(userByApiToken);
+    logger.debug('API token parsed.');
+    return next();
+  }
+
   // check the access token is valid
   const userId = await AccessToken.findUserIdByToken(accessToken);
   if (userId == null) {