|
@@ -1,9 +1,9 @@
|
|
|
import { faker } from '@faker-js/faker';
|
|
import { faker } from '@faker-js/faker';
|
|
|
|
|
+import { SCOPE } from '@growi/core/dist/interfaces';
|
|
|
import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
|
|
import { serializeUserSecurely } from '@growi/core/dist/models/serializers';
|
|
|
import type { Response } from 'express';
|
|
import type { Response } from 'express';
|
|
|
import { mock } from 'vitest-mock-extended';
|
|
import { mock } from 'vitest-mock-extended';
|
|
|
|
|
|
|
|
-import { SCOPE } from '@growi/core/dist/interfaces';
|
|
|
|
|
import type Crowi from '~/server/crowi';
|
|
import type Crowi from '~/server/crowi';
|
|
|
import type UserEvent from '~/server/events/user';
|
|
import type UserEvent from '~/server/events/user';
|
|
|
import { AccessToken } from '~/server/models/access-token';
|
|
import { AccessToken } from '~/server/models/access-token';
|
|
@@ -13,12 +13,11 @@ import type { AccessTokenParserReq } from './interfaces';
|
|
|
|
|
|
|
|
vi.mock('@growi/core/dist/models/serializers', { spy: true });
|
|
vi.mock('@growi/core/dist/models/serializers', { spy: true });
|
|
|
|
|
|
|
|
-
|
|
|
|
|
describe('access-token-parser middleware for access token with scopes', () => {
|
|
describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
-
|
|
|
|
|
|
|
+ // biome-ignore lint/suspicious/noImplicitAnyLet: ignore
|
|
|
let User;
|
|
let User;
|
|
|
|
|
|
|
|
- beforeAll(async() => {
|
|
|
|
|
|
|
+ beforeAll(async () => {
|
|
|
const crowiMock = mock<Crowi>({
|
|
const crowiMock = mock<Crowi>({
|
|
|
event: vi.fn().mockImplementation((eventName) => {
|
|
event: vi.fn().mockImplementation((eventName) => {
|
|
|
if (eventName === 'user') {
|
|
if (eventName === 'user') {
|
|
@@ -32,7 +31,7 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
User = userModelFactory(crowiMock);
|
|
User = userModelFactory(crowiMock);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should call next if no access token is provided', async() => {
|
|
|
|
|
|
|
+ it('should call next if no access token is provided', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -44,7 +43,7 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
expect(reqMock.user).toBeUndefined();
|
|
expect(reqMock.user).toBeUndefined();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should not authenticate with no scopes', async() => {
|
|
|
|
|
|
|
+ it('should not authenticate with no scopes', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -76,7 +75,7 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
expect(serializeUserSecurely).not.toHaveBeenCalled();
|
|
expect(serializeUserSecurely).not.toHaveBeenCalled();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should authenticate with specific scope', async() => {
|
|
|
|
|
|
|
+ it('should authenticate with specific scope', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -102,7 +101,10 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
|
|
|
|
|
// act
|
|
// act
|
|
|
reqMock.query.access_token = token;
|
|
reqMock.query.access_token = token;
|
|
|
- await parserForAccessToken([SCOPE.READ.USER_SETTINGS.INFO])(reqMock, resMock);
|
|
|
|
|
|
|
+ await parserForAccessToken([SCOPE.READ.USER_SETTINGS.INFO])(
|
|
|
|
|
+ reqMock,
|
|
|
|
|
+ resMock,
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
// assert
|
|
// assert
|
|
|
expect(reqMock.user).toBeDefined();
|
|
expect(reqMock.user).toBeDefined();
|
|
@@ -110,7 +112,7 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should reject with insufficient scopes', async() => {
|
|
|
|
|
|
|
+ it('should reject with insufficient scopes', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -119,7 +121,6 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
|
|
|
|
|
expect(reqMock.user).toBeUndefined();
|
|
expect(reqMock.user).toBeUndefined();
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// prepare a user
|
|
// prepare a user
|
|
|
const targetUser = await User.create({
|
|
const targetUser = await User.create({
|
|
|
name: faker.person.fullName(),
|
|
name: faker.person.fullName(),
|
|
@@ -137,14 +138,17 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
|
|
|
|
|
// act - try to access with write:user:info scope
|
|
// act - try to access with write:user:info scope
|
|
|
reqMock.query.access_token = token;
|
|
reqMock.query.access_token = token;
|
|
|
- await parserForAccessToken([SCOPE.WRITE.USER_SETTINGS.INFO])(reqMock, resMock);
|
|
|
|
|
|
|
+ await parserForAccessToken([SCOPE.WRITE.USER_SETTINGS.INFO])(
|
|
|
|
|
+ reqMock,
|
|
|
|
|
+ resMock,
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
// // assert
|
|
// // assert
|
|
|
expect(reqMock.user).toBeUndefined();
|
|
expect(reqMock.user).toBeUndefined();
|
|
|
expect(serializeUserSecurely).not.toHaveBeenCalled();
|
|
expect(serializeUserSecurely).not.toHaveBeenCalled();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should authenticate with write scope implying read scope', async() => {
|
|
|
|
|
|
|
+ it('should authenticate with write scope implying read scope', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -170,7 +174,10 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
|
|
|
|
|
// act - try to access with read:user:info scope
|
|
// act - try to access with read:user:info scope
|
|
|
reqMock.query.access_token = token;
|
|
reqMock.query.access_token = token;
|
|
|
- await parserForAccessToken([SCOPE.READ.USER_SETTINGS.INFO])(reqMock, resMock);
|
|
|
|
|
|
|
+ await parserForAccessToken([SCOPE.READ.USER_SETTINGS.INFO])(
|
|
|
|
|
+ reqMock,
|
|
|
|
|
+ resMock,
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
// assert
|
|
// assert
|
|
|
expect(reqMock.user).toBeDefined();
|
|
expect(reqMock.user).toBeDefined();
|
|
@@ -178,7 +185,7 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- it('should authenticate with wildcard scope', async() => {
|
|
|
|
|
|
|
+ it('should authenticate with wildcard scope', async () => {
|
|
|
// arrange
|
|
// arrange
|
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
const reqMock = mock<AccessTokenParserReq>({
|
|
|
user: undefined,
|
|
user: undefined,
|
|
@@ -202,12 +209,14 @@ describe('access-token-parser middleware for access token with scopes', () => {
|
|
|
|
|
|
|
|
// act - try to access with read:user:info scope
|
|
// act - try to access with read:user:info scope
|
|
|
reqMock.query.access_token = token;
|
|
reqMock.query.access_token = token;
|
|
|
- await parserForAccessToken([SCOPE.READ.USER_SETTINGS.INFO, SCOPE.READ.USER_SETTINGS.API.ACCESS_TOKEN])(reqMock, resMock);
|
|
|
|
|
|
|
+ await parserForAccessToken([
|
|
|
|
|
+ SCOPE.READ.USER_SETTINGS.INFO,
|
|
|
|
|
+ SCOPE.READ.USER_SETTINGS.API.ACCESS_TOKEN,
|
|
|
|
|
+ ])(reqMock, resMock);
|
|
|
|
|
|
|
|
// assert
|
|
// assert
|
|
|
expect(reqMock.user).toBeDefined();
|
|
expect(reqMock.user).toBeDefined();
|
|
|
expect(reqMock.user?._id).toStrictEqual(targetUser._id);
|
|
expect(reqMock.user?._id).toStrictEqual(targetUser._id);
|
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
expect(serializeUserSecurely).toHaveBeenCalledOnce();
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
});
|
|
});
|