2023-09-15 10:34:14 +03:00
|
|
|
/// <reference types="../src/global.d.ts" />
|
2023-08-29 13:07:05 +03:00
|
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
2023-04-28 06:49:44 +03:00
|
|
|
import { PrismaClient } from '@prisma/client';
|
2023-09-01 22:41:29 +03:00
|
|
|
import test from 'ava';
|
2023-04-28 06:49:44 +03:00
|
|
|
|
2023-09-15 10:34:14 +03:00
|
|
|
import { ConfigModule } from '../src/config';
|
|
|
|
import { GqlModule } from '../src/graphql.module';
|
|
|
|
import { MetricsModule } from '../src/metrics';
|
|
|
|
import { AuthModule } from '../src/modules/auth';
|
|
|
|
import { AuthResolver } from '../src/modules/auth/resolver';
|
|
|
|
import { AuthService } from '../src/modules/auth/service';
|
|
|
|
import { PrismaModule } from '../src/prisma';
|
2023-10-18 11:06:07 +03:00
|
|
|
import { mintChallengeResponse, verifyChallengeResponse } from '../src/storage';
|
2023-09-15 10:34:14 +03:00
|
|
|
import { RateLimiterModule } from '../src/throttler';
|
2023-04-28 06:49:44 +03:00
|
|
|
|
2023-09-12 08:31:58 +03:00
|
|
|
let authService: AuthService;
|
|
|
|
let authResolver: AuthResolver;
|
2023-08-29 13:07:05 +03:00
|
|
|
let module: TestingModule;
|
2023-04-28 06:49:44 +03:00
|
|
|
|
|
|
|
// cleanup database before each test
|
2023-09-01 22:41:29 +03:00
|
|
|
test.beforeEach(async () => {
|
2023-04-28 06:49:44 +03:00
|
|
|
const client = new PrismaClient();
|
|
|
|
await client.$connect();
|
|
|
|
await client.user.deleteMany({});
|
2023-09-07 23:55:04 +03:00
|
|
|
await client.$disconnect();
|
2023-04-28 06:49:44 +03:00
|
|
|
});
|
|
|
|
|
2023-09-01 22:41:29 +03:00
|
|
|
test.beforeEach(async () => {
|
2023-08-29 13:07:05 +03:00
|
|
|
module = await Test.createTestingModule({
|
2023-04-28 06:49:44 +03:00
|
|
|
imports: [
|
|
|
|
ConfigModule.forRoot({
|
|
|
|
auth: {
|
2023-06-21 09:08:32 +03:00
|
|
|
accessTokenExpiresIn: 1,
|
|
|
|
refreshTokenExpiresIn: 1,
|
|
|
|
leeway: 1,
|
2023-04-28 06:49:44 +03:00
|
|
|
},
|
2023-09-12 08:31:58 +03:00
|
|
|
host: 'example.org',
|
|
|
|
https: true,
|
2023-04-28 06:49:44 +03:00
|
|
|
}),
|
|
|
|
PrismaModule,
|
|
|
|
GqlModule,
|
|
|
|
AuthModule,
|
2023-08-29 13:07:05 +03:00
|
|
|
MetricsModule,
|
2023-08-31 15:29:25 +03:00
|
|
|
RateLimiterModule,
|
2023-04-28 06:49:44 +03:00
|
|
|
],
|
|
|
|
}).compile();
|
2023-09-12 08:31:58 +03:00
|
|
|
authService = module.get(AuthService);
|
|
|
|
authResolver = module.get(AuthResolver);
|
2023-04-28 06:49:44 +03:00
|
|
|
});
|
|
|
|
|
2023-09-11 12:30:39 +03:00
|
|
|
test.afterEach.always(async () => {
|
2023-08-29 13:07:05 +03:00
|
|
|
await module.close();
|
|
|
|
});
|
|
|
|
|
2023-09-01 22:41:29 +03:00
|
|
|
test('should be able to register and signIn', async t => {
|
2023-09-12 08:31:58 +03:00
|
|
|
await authService.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
|
|
|
await authService.signIn('alexyang@example.org', '123456');
|
2023-09-01 22:41:29 +03:00
|
|
|
t.pass();
|
2023-04-28 06:49:44 +03:00
|
|
|
});
|
|
|
|
|
2023-09-01 22:41:29 +03:00
|
|
|
test('should be able to verify', async t => {
|
2023-09-12 08:31:58 +03:00
|
|
|
await authService.signUp('Alex Yang', 'alexyang@example.org', '123456');
|
|
|
|
await authService.signIn('alexyang@example.org', '123456');
|
2023-08-29 13:07:05 +03:00
|
|
|
const date = new Date();
|
|
|
|
|
2023-04-28 06:49:44 +03:00
|
|
|
const user = {
|
|
|
|
id: '1',
|
|
|
|
name: 'Alex Yang',
|
|
|
|
email: 'alexyang@example.org',
|
2023-08-29 13:07:05 +03:00
|
|
|
emailVerified: date,
|
|
|
|
createdAt: date,
|
|
|
|
avatarUrl: '',
|
2023-04-28 06:49:44 +03:00
|
|
|
};
|
|
|
|
{
|
2023-09-12 08:31:58 +03:00
|
|
|
const token = await authService.sign(user);
|
|
|
|
const claim = await authService.verify(token);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(claim.id, '1');
|
|
|
|
t.is(claim.name, 'Alex Yang');
|
|
|
|
t.is(claim.email, 'alexyang@example.org');
|
|
|
|
t.is(claim.emailVerified?.toISOString(), date.toISOString());
|
|
|
|
t.is(claim.createdAt.toISOString(), date.toISOString());
|
2023-04-28 06:49:44 +03:00
|
|
|
}
|
|
|
|
{
|
2023-09-12 08:31:58 +03:00
|
|
|
const token = await authService.refresh(user);
|
|
|
|
const claim = await authService.verify(token);
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(claim.id, '1');
|
|
|
|
t.is(claim.name, 'Alex Yang');
|
|
|
|
t.is(claim.email, 'alexyang@example.org');
|
|
|
|
t.is(claim.emailVerified?.toISOString(), date.toISOString());
|
|
|
|
t.is(claim.createdAt.toISOString(), date.toISOString());
|
2023-04-28 06:49:44 +03:00
|
|
|
}
|
|
|
|
});
|
2023-09-12 08:31:58 +03:00
|
|
|
|
|
|
|
test('should not be able to return token if user is invalid', async t => {
|
|
|
|
const date = new Date();
|
|
|
|
const user = {
|
|
|
|
id: '1',
|
|
|
|
name: 'Alex Yang',
|
|
|
|
email: 'alexyang@example.org',
|
|
|
|
emailVerified: date,
|
|
|
|
createdAt: date,
|
|
|
|
avatarUrl: '',
|
|
|
|
};
|
|
|
|
const anotherUser = {
|
|
|
|
id: '2',
|
|
|
|
name: 'Alex Yang 2',
|
|
|
|
email: 'alexyang@example.org',
|
|
|
|
emailVerified: date,
|
|
|
|
createdAt: date,
|
|
|
|
avatarUrl: '',
|
|
|
|
};
|
|
|
|
await t.throwsAsync(
|
|
|
|
authResolver.token(
|
|
|
|
{
|
|
|
|
req: {
|
|
|
|
headers: {
|
|
|
|
referer: 'https://example.org',
|
|
|
|
host: 'example.org',
|
|
|
|
},
|
|
|
|
} as any,
|
|
|
|
},
|
|
|
|
user,
|
|
|
|
anotherUser
|
|
|
|
),
|
|
|
|
{
|
|
|
|
message: 'Invalid user',
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should not return sessionToken if request headers is invalid', async t => {
|
|
|
|
const date = new Date();
|
|
|
|
const user = {
|
|
|
|
id: '1',
|
|
|
|
name: 'Alex Yang',
|
|
|
|
email: 'alexyang@example.org',
|
|
|
|
emailVerified: date,
|
|
|
|
createdAt: date,
|
|
|
|
avatarUrl: '',
|
|
|
|
};
|
|
|
|
const result = await authResolver.token(
|
|
|
|
{
|
|
|
|
req: {
|
|
|
|
headers: {},
|
|
|
|
} as any,
|
|
|
|
},
|
|
|
|
user,
|
|
|
|
user
|
|
|
|
);
|
|
|
|
t.is(result.sessionToken, undefined);
|
|
|
|
});
|
|
|
|
|
|
|
|
test('should return valid sessionToken if request headers valid', async t => {
|
|
|
|
const date = new Date();
|
|
|
|
const user = {
|
|
|
|
id: '1',
|
|
|
|
name: 'Alex Yang',
|
|
|
|
email: 'alexyang@example.org',
|
|
|
|
emailVerified: date,
|
|
|
|
createdAt: date,
|
|
|
|
avatarUrl: '',
|
|
|
|
};
|
|
|
|
const result = await authResolver.token(
|
|
|
|
{
|
|
|
|
req: {
|
|
|
|
headers: {
|
|
|
|
referer: 'https://example.org/open-app/test',
|
|
|
|
host: 'example.org',
|
|
|
|
},
|
|
|
|
cookies: {
|
|
|
|
'next-auth.session-token': '123456',
|
|
|
|
},
|
|
|
|
} as any,
|
|
|
|
},
|
|
|
|
user,
|
|
|
|
user
|
|
|
|
);
|
|
|
|
t.is(result.sessionToken, '123456');
|
|
|
|
});
|
2023-10-18 11:06:07 +03:00
|
|
|
|
|
|
|
test('verify challenge', async t => {
|
|
|
|
const resource = 'xp8D3rcXV9bMhWrb6abxl';
|
|
|
|
const response = await mintChallengeResponse(resource, 20);
|
|
|
|
const success = await verifyChallengeResponse(response, 20, resource);
|
|
|
|
t.true(success);
|
|
|
|
});
|