refactor: cleanup now un-used graphql resolvers and services
This commit is contained in:
parent
f6a6b85b60
commit
4609078894
10 changed files with 16 additions and 646 deletions
|
@ -12,7 +12,8 @@
|
|||
"start:pg": "docker run --name test-db -p 5433:5432 -d --rm -e POSTGRES_PASSWORD=postgres postgres",
|
||||
"version": "echo $npm_package_version",
|
||||
"release:rc": "./scripts/deploy/release-rc.sh",
|
||||
"test:build": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t meienberger/runtipi:test ."
|
||||
"test:build": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t meienberger/runtipi:test .",
|
||||
"test:build:arm64": "docker buildx build --platform linux/arm64 -t meienberger/runtipi:test ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.3",
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
"@trpc/next": "^10.7.0",
|
||||
"@trpc/react-query": "^10.7.0",
|
||||
"@trpc/server": "^10.7.0",
|
||||
"argon2": "^0.29.1",
|
||||
"clsx": "^1.1.1",
|
||||
"fs-extra": "^10.1.0",
|
||||
"graphql": "^15.8.0",
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
ROOT_FOLDER=/test
|
||||
ROOT_FOLDER_HOST=/tipi
|
||||
JWT_SECRET=secret
|
||||
POSTGRES_DBNAME=postgres
|
||||
POSTGRES_HOST=localhost
|
||||
POSTGRES_USERNAME=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
APPS_REPO_ID=repo-id
|
||||
APPS_REPO_URL=http://test.com
|
||||
INTERNAL_IP=localhost
|
||||
JWT_SECRET=secret
|
||||
STORAGE_PATH=/tipi/test
|
||||
|
|
|
@ -1,234 +0,0 @@
|
|||
import { faker } from '@faker-js/faker';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { DataSource } from 'typeorm';
|
||||
import TipiCache from '../../../config/TipiCache';
|
||||
import { getConfig } from '../../../core/config/TipiConfig';
|
||||
import { setupConnection, teardownConnection } from '../../../test/connection';
|
||||
import { gcall } from '../../../test/gcall';
|
||||
import { loginMutation, registerMutation } from '../../../test/mutations';
|
||||
import { isConfiguredQuery, MeQuery, refreshTokenQuery } from '../../../test/queries';
|
||||
import { TokenResponse } from '../auth.types';
|
||||
import User from '../user.entity';
|
||||
import { createUser } from './user.factory';
|
||||
|
||||
jest.mock('redis');
|
||||
|
||||
let db: DataSource | null = null;
|
||||
const TEST_SUITE = 'authresolver';
|
||||
|
||||
beforeAll(async () => {
|
||||
db = await setupConnection(TEST_SUITE);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await db?.destroy();
|
||||
await teardownConnection(TEST_SUITE);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.resetModules();
|
||||
jest.resetAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
await User.clear();
|
||||
});
|
||||
|
||||
describe('Test: me', () => {
|
||||
const email = faker.internet.email();
|
||||
let user1: User;
|
||||
|
||||
beforeEach(async () => {
|
||||
user1 = await createUser(email);
|
||||
});
|
||||
|
||||
it('should return null if no user is logged in', async () => {
|
||||
const { data } = await gcall<{ me: User }>({
|
||||
source: MeQuery,
|
||||
});
|
||||
|
||||
expect(data?.me).toBeNull();
|
||||
});
|
||||
|
||||
it('should return the user if a user is logged in', async () => {
|
||||
const { data } = await gcall<{ me: User | null }>({
|
||||
source: MeQuery,
|
||||
userId: user1.id,
|
||||
});
|
||||
|
||||
expect(data?.me?.username).toEqual(user1.username);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: register', () => {
|
||||
const email = faker.internet.email();
|
||||
const password = faker.internet.password();
|
||||
|
||||
it('should register a user', async () => {
|
||||
const { data } = await gcall<{ register: TokenResponse }>({
|
||||
source: registerMutation,
|
||||
variableValues: {
|
||||
input: { username: email, password },
|
||||
},
|
||||
});
|
||||
|
||||
expect(data?.register).toBeDefined();
|
||||
expect(data?.register?.token).toBeDefined();
|
||||
|
||||
const decoded = jwt.verify(data?.register?.token || '', getConfig().jwtSecret) as jwt.JwtPayload;
|
||||
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded).not.toBeNull();
|
||||
expect(decoded).toHaveProperty('id');
|
||||
expect(decoded).toHaveProperty('iat');
|
||||
expect(decoded).toHaveProperty('exp');
|
||||
expect(decoded).toHaveProperty('session');
|
||||
});
|
||||
|
||||
it('should not register a user with an existing username', async () => {
|
||||
await createUser(email);
|
||||
|
||||
const { errors } = await gcall<{ register: TokenResponse }>({
|
||||
source: registerMutation,
|
||||
variableValues: {
|
||||
input: { username: email, password },
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors?.[0].message).toEqual('User already exists');
|
||||
});
|
||||
|
||||
it('should not register a user with a malformed email', async () => {
|
||||
const { errors } = await gcall<{ register: TokenResponse }>({
|
||||
source: registerMutation,
|
||||
variableValues: {
|
||||
input: { username: 'not an email', password },
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors?.[0].message).toEqual('Invalid username');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: login', () => {
|
||||
const email = faker.internet.email();
|
||||
|
||||
beforeEach(async () => {
|
||||
await createUser(email);
|
||||
});
|
||||
|
||||
it('should login a user', async () => {
|
||||
const { data } = await gcall<{ login: TokenResponse }>({
|
||||
source: loginMutation,
|
||||
variableValues: {
|
||||
input: { username: email, password: 'password' },
|
||||
},
|
||||
});
|
||||
|
||||
const token = data?.login.token as string;
|
||||
|
||||
expect(token).toBeDefined();
|
||||
|
||||
const decoded = jwt.verify(token, getConfig().jwtSecret) as { id: string; session: string };
|
||||
|
||||
const user = await User.findOne({ where: { username: email.toLowerCase().trim() } });
|
||||
|
||||
expect(decoded.id).toBeDefined();
|
||||
expect(user?.id).toEqual(decoded.id);
|
||||
});
|
||||
|
||||
it('should not login a user with an incorrect password', async () => {
|
||||
const { errors } = await gcall<{ login: TokenResponse }>({
|
||||
source: loginMutation,
|
||||
variableValues: {
|
||||
input: { username: email, password: 'wrong password' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors?.[0].message).toEqual('Wrong password');
|
||||
});
|
||||
|
||||
it('should not login a user with a malformed email', async () => {
|
||||
const { errors } = await gcall<{ login: TokenResponse }>({
|
||||
source: loginMutation,
|
||||
variableValues: {
|
||||
input: { username: 'not an email', password: 'password' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(errors?.[0].message).toEqual('User not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: logout', () => {
|
||||
const email = faker.internet.email();
|
||||
let user1: User;
|
||||
|
||||
beforeEach(async () => {
|
||||
user1 = await createUser(email);
|
||||
});
|
||||
|
||||
it('should logout a user', async () => {
|
||||
const { data } = await gcall<{ logout: boolean }>({
|
||||
source: 'mutation { logout }',
|
||||
userId: user1.id,
|
||||
session: 'session',
|
||||
});
|
||||
|
||||
expect(data?.logout).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: isConfigured', () => {
|
||||
it('should return false if no users exist', async () => {
|
||||
const { data } = await gcall<{ isConfigured: boolean }>({
|
||||
source: isConfiguredQuery,
|
||||
});
|
||||
|
||||
expect(data?.isConfigured).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should return true if a user exists', async () => {
|
||||
await createUser(faker.internet.email());
|
||||
|
||||
const { data } = await gcall<{ isConfigured: boolean }>({
|
||||
source: isConfiguredQuery,
|
||||
});
|
||||
|
||||
expect(data?.isConfigured).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: refreshToken', () => {
|
||||
const email = faker.internet.email();
|
||||
let user1: User;
|
||||
|
||||
beforeEach(async () => {
|
||||
user1 = await createUser(email);
|
||||
});
|
||||
|
||||
it('should return a new token', async () => {
|
||||
// Arrange
|
||||
const session = faker.datatype.uuid();
|
||||
await TipiCache.set(session, user1.id.toString());
|
||||
|
||||
// Act
|
||||
const { data } = await gcall<{ refreshToken: TokenResponse }>({
|
||||
source: refreshTokenQuery,
|
||||
userId: user1.id,
|
||||
session,
|
||||
});
|
||||
const decoded = jwt.verify(data?.refreshToken?.token || '', getConfig().jwtSecret) as jwt.JwtPayload;
|
||||
|
||||
// Assert
|
||||
expect(data?.refreshToken).toBeDefined();
|
||||
expect(data?.refreshToken?.token).toBeDefined();
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded).not.toBeNull();
|
||||
expect(decoded).toHaveProperty('id');
|
||||
expect(decoded).toHaveProperty('iat');
|
||||
expect(decoded).toHaveProperty('exp');
|
||||
expect(decoded).toHaveProperty('session');
|
||||
|
||||
expect(decoded.id).toEqual(user1.id.toString());
|
||||
expect(decoded.session).not.toEqual(session);
|
||||
});
|
||||
});
|
|
@ -1,234 +0,0 @@
|
|||
import * as argon2 from 'argon2';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { DataSource } from 'typeorm';
|
||||
import AuthService from '../auth.service';
|
||||
import { createUser } from './user.factory';
|
||||
import User from '../user.entity';
|
||||
import { setupConnection, teardownConnection } from '../../../test/connection';
|
||||
import { setConfig } from '../../../core/config/TipiConfig';
|
||||
import TipiCache from '../../../config/TipiCache';
|
||||
|
||||
let db: DataSource | null = null;
|
||||
const TEST_SUITE = 'authservice';
|
||||
|
||||
jest.mock('redis');
|
||||
|
||||
beforeAll(async () => {
|
||||
setConfig('jwtSecret', 'test');
|
||||
db = await setupConnection(TEST_SUITE);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await User.clear();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await db?.destroy();
|
||||
await teardownConnection(TEST_SUITE);
|
||||
});
|
||||
|
||||
describe('Login', () => {
|
||||
it('Should return a valid jsonwebtoken containing a user id', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser(email);
|
||||
|
||||
// Act
|
||||
const { token } = await AuthService.login({ username: email, password: 'password' });
|
||||
const decoded = jwt.verify(token, 'test') as jwt.JwtPayload;
|
||||
|
||||
// Assert
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded).not.toBeNull();
|
||||
expect(decoded).toHaveProperty('id');
|
||||
expect(decoded.id).toBe(user.id);
|
||||
expect(decoded).toHaveProperty('iat');
|
||||
expect(decoded).toHaveProperty('exp');
|
||||
expect(decoded).toHaveProperty('session');
|
||||
});
|
||||
|
||||
it('Should throw if user does not exist', async () => {
|
||||
await expect(AuthService.login({ username: 'test', password: 'test' })).rejects.toThrowError('User not found');
|
||||
});
|
||||
|
||||
it('Should throw if password is incorrect', async () => {
|
||||
const email = faker.internet.email();
|
||||
await createUser(email);
|
||||
await expect(AuthService.login({ username: email, password: 'wrong' })).rejects.toThrowError('Wrong password');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Register', () => {
|
||||
it('Should return valid jsonwebtoken after register', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email();
|
||||
|
||||
// Act
|
||||
const { token } = await AuthService.register({ username: email, password: 'password' });
|
||||
const decoded = jwt.verify(token, 'test') as jwt.JwtPayload;
|
||||
|
||||
// Assert
|
||||
expect(decoded).toBeDefined();
|
||||
expect(decoded).not.toBeNull();
|
||||
expect(decoded).toHaveProperty('id');
|
||||
expect(decoded).toHaveProperty('iat');
|
||||
expect(decoded).toHaveProperty('exp');
|
||||
expect(decoded).toHaveProperty('session');
|
||||
});
|
||||
|
||||
it('Should correctly trim and lowercase email', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email();
|
||||
|
||||
// Act
|
||||
await AuthService.register({ username: email, password: 'test' });
|
||||
const user = await User.findOne({ where: { username: email.toLowerCase().trim() } });
|
||||
|
||||
// Assert
|
||||
expect(user).toBeDefined();
|
||||
expect(user?.username).toBe(email.toLowerCase().trim());
|
||||
});
|
||||
|
||||
it('Should throw if user already exists', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email();
|
||||
|
||||
// Act & Assert
|
||||
await createUser(email);
|
||||
await expect(AuthService.register({ username: email, password: 'test' })).rejects.toThrowError('User already exists');
|
||||
});
|
||||
|
||||
it('Should throw if email is not provided', async () => {
|
||||
await expect(AuthService.register({ username: '', password: 'test' })).rejects.toThrowError('Missing email or password');
|
||||
});
|
||||
|
||||
it('Should throw if password is not provided', async () => {
|
||||
await expect(AuthService.register({ username: faker.internet.email(), password: '' })).rejects.toThrowError('Missing email or password');
|
||||
});
|
||||
|
||||
it('Password is correctly hashed', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email().toLowerCase().trim();
|
||||
|
||||
// Act
|
||||
await AuthService.register({ username: email, password: 'test' });
|
||||
const user = await User.findOne({ where: { username: email } });
|
||||
const isPasswordValid = await argon2.verify(user?.password || '', 'test');
|
||||
|
||||
// Assert
|
||||
expect(isPasswordValid).toBe(true);
|
||||
});
|
||||
|
||||
it('Should throw if email is invalid', async () => {
|
||||
await expect(AuthService.register({ username: 'test', password: 'test' })).rejects.toThrowError('Invalid username');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: logout', () => {
|
||||
it('Should return true if there is no session to delete', async () => {
|
||||
// Act
|
||||
// @ts-ignore
|
||||
const result = await AuthService.logout();
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
it('Should delete session from cache', async () => {
|
||||
// Arrange
|
||||
const session = faker.random.alphaNumeric(32);
|
||||
await TipiCache.set(session, 'test');
|
||||
expect(await TipiCache.get(session)).toBe('test');
|
||||
|
||||
// Act
|
||||
const result = await AuthService.logout(session);
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(true);
|
||||
expect(await TipiCache.get('session')).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: refreshToken', () => {
|
||||
it('Should return null if session is not provided', async () => {
|
||||
// Act
|
||||
const result = await AuthService.refreshToken();
|
||||
|
||||
// Assert
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('Should return null if session is not found in cache', async () => {
|
||||
// Act
|
||||
const result = await AuthService.refreshToken('test');
|
||||
|
||||
// Assert
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('Should return a new token if session is found in cache', async () => {
|
||||
// Arrange
|
||||
const session = faker.random.alphaNumeric(32);
|
||||
await TipiCache.set(session, 'test');
|
||||
|
||||
// Act
|
||||
const result = await AuthService.refreshToken(session);
|
||||
|
||||
// Assert
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveProperty('token');
|
||||
expect(result?.token).not.toBe(session);
|
||||
});
|
||||
|
||||
it('Should put expiration in 6 seconds for old session', async () => {
|
||||
// Arrange
|
||||
const session = faker.random.alphaNumeric(32);
|
||||
await TipiCache.set(session, '1');
|
||||
|
||||
// Act
|
||||
const result = await AuthService.refreshToken(session);
|
||||
const expiration = await TipiCache.ttl(session);
|
||||
|
||||
// Assert
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveProperty('token');
|
||||
expect(result?.token).not.toBe(session);
|
||||
expect(expiration).toMatchObject({ EX: 6 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: me', () => {
|
||||
it('Should return null if userId is not provided', async () => {
|
||||
// Act
|
||||
const result = await AuthService.me();
|
||||
|
||||
// Assert
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('Should return null if user does not exist', async () => {
|
||||
// Act
|
||||
const result = await AuthService.me(1);
|
||||
|
||||
// Assert
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('Should return user if user exists', async () => {
|
||||
// Arrange
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser(email);
|
||||
|
||||
// Act
|
||||
const result = await AuthService.me(user.id);
|
||||
|
||||
// Assert
|
||||
expect(result).not.toBeNull();
|
||||
expect(result).toHaveProperty('id');
|
||||
expect(result).toHaveProperty('username');
|
||||
expect(result).toHaveProperty('createdAt');
|
||||
expect(result).toHaveProperty('updatedAt');
|
||||
});
|
||||
});
|
|
@ -1,54 +0,0 @@
|
|||
import { Arg, Ctx, Mutation, Query, Resolver } from 'type-graphql';
|
||||
import { MyContext } from '../../types';
|
||||
import { TokenResponse, UsernamePasswordInput } from './auth.types';
|
||||
|
||||
import AuthService from './auth.service';
|
||||
import User from './user.entity';
|
||||
|
||||
@Resolver()
|
||||
export default class AuthResolver {
|
||||
@Query(() => User, { nullable: true })
|
||||
async me(@Ctx() ctx: MyContext): Promise<User | null> {
|
||||
return AuthService.me(ctx.req?.session?.userId);
|
||||
}
|
||||
|
||||
@Mutation(() => TokenResponse)
|
||||
async register(@Arg('input', () => UsernamePasswordInput) input: UsernamePasswordInput): Promise<TokenResponse> {
|
||||
const { token } = await AuthService.register(input);
|
||||
|
||||
return { token };
|
||||
}
|
||||
|
||||
@Mutation(() => TokenResponse)
|
||||
async login(@Arg('input', () => UsernamePasswordInput) input: UsernamePasswordInput): Promise<TokenResponse> {
|
||||
const { token } = await AuthService.login(input);
|
||||
|
||||
return { token };
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean)
|
||||
async logout(@Ctx() { req }: MyContext): Promise<boolean> {
|
||||
if (req.session.id) {
|
||||
await AuthService.logout(req.session?.id);
|
||||
}
|
||||
|
||||
req.session.userId = undefined;
|
||||
req.session.id = undefined;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Query(() => Boolean)
|
||||
async isConfigured(): Promise<boolean> {
|
||||
const users = await User.find();
|
||||
|
||||
return users.length > 0;
|
||||
}
|
||||
|
||||
@Query(() => TokenResponse, { nullable: true })
|
||||
async refreshToken(@Ctx() { req }: MyContext): Promise<TokenResponse | null> {
|
||||
const res = await AuthService.refreshToken(req.session?.id);
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
import * as argon2 from 'argon2';
|
||||
import { v4 } from 'uuid';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import validator from 'validator';
|
||||
import { getConfig } from '../../core/config/TipiConfig';
|
||||
import { TokenResponse, UsernamePasswordInput } from './auth.types';
|
||||
import User from './user.entity';
|
||||
import TipiCache from '../../config/TipiCache';
|
||||
|
||||
const login = async (input: UsernamePasswordInput): Promise<TokenResponse> => {
|
||||
const { password, username } = input;
|
||||
|
||||
const user = await User.findOne({ where: { username: username.trim().toLowerCase() } });
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
|
||||
const isPasswordValid = await argon2.verify(user.password, password);
|
||||
|
||||
if (!isPasswordValid) {
|
||||
throw new Error('Wrong password');
|
||||
}
|
||||
|
||||
const session = v4();
|
||||
const token = jwt.sign({ id: user.id, session }, getConfig().jwtSecret, { expiresIn: '7d' });
|
||||
|
||||
await TipiCache.set(session, user.id.toString());
|
||||
|
||||
return { token };
|
||||
};
|
||||
|
||||
const register = async (input: UsernamePasswordInput): Promise<TokenResponse> => {
|
||||
const { password, username } = input;
|
||||
const email = username.trim().toLowerCase();
|
||||
|
||||
if (!username || !password) {
|
||||
throw new Error('Missing email or password');
|
||||
}
|
||||
|
||||
if (username.length < 3 || !validator.isEmail(email)) {
|
||||
throw new Error('Invalid username');
|
||||
}
|
||||
|
||||
const user = await User.findOne({ where: { username: email } });
|
||||
|
||||
if (user) {
|
||||
throw new Error('User already exists');
|
||||
}
|
||||
|
||||
const hash = await argon2.hash(password);
|
||||
const newUser = await User.create({ username: email, password: hash }).save();
|
||||
|
||||
const session = v4();
|
||||
const token = jwt.sign({ id: newUser.id, session }, getConfig().jwtSecret, { expiresIn: '1d' });
|
||||
|
||||
await TipiCache.set(session, newUser.id.toString());
|
||||
|
||||
return { token };
|
||||
};
|
||||
|
||||
const me = async (userId?: number): Promise<User | null> => {
|
||||
if (!userId) return null;
|
||||
|
||||
const user = await User.findOne({ where: { id: userId } });
|
||||
|
||||
if (!user) return null;
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
const logout = async (session: string): Promise<boolean> => {
|
||||
await TipiCache.del(session);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const refreshToken = async (session?: string): Promise<TokenResponse | null> => {
|
||||
if (!session) return null;
|
||||
|
||||
const userId = await TipiCache.get(session);
|
||||
if (!userId) return null;
|
||||
|
||||
// Expire token in 6 seconds
|
||||
await TipiCache.set(session, userId, 6);
|
||||
|
||||
const newSession = v4();
|
||||
const token = jwt.sign({ id: userId, session: newSession }, getConfig().jwtSecret, { expiresIn: '1d' });
|
||||
await TipiCache.set(newSession, userId);
|
||||
|
||||
return { token };
|
||||
};
|
||||
|
||||
const AuthService = {
|
||||
login,
|
||||
register,
|
||||
me,
|
||||
logout,
|
||||
refreshToken,
|
||||
};
|
||||
|
||||
export default AuthService;
|
|
@ -1,18 +0,0 @@
|
|||
import { Field, InputType, ObjectType } from 'type-graphql';
|
||||
|
||||
@InputType()
|
||||
class UsernamePasswordInput {
|
||||
@Field(() => String)
|
||||
username!: string;
|
||||
|
||||
@Field(() => String)
|
||||
password!: string;
|
||||
}
|
||||
|
||||
@ObjectType()
|
||||
class TokenResponse {
|
||||
@Field(() => String, { nullable: false })
|
||||
token!: string;
|
||||
}
|
||||
|
||||
export { UsernamePasswordInput, TokenResponse };
|
|
@ -2,11 +2,10 @@ import { GraphQLSchema } from 'graphql';
|
|||
import { buildSchema } from 'type-graphql';
|
||||
import { customAuthChecker } from './core/middlewares/authChecker';
|
||||
import AppsResolver from './modules/apps/apps.resolver';
|
||||
import AuthResolver from './modules/auth/auth.resolver';
|
||||
|
||||
const createSchema = (): Promise<GraphQLSchema> =>
|
||||
buildSchema({
|
||||
resolvers: [AppsResolver, AuthResolver],
|
||||
resolvers: [AppsResolver],
|
||||
validate: true,
|
||||
authChecker: customAuthChecker,
|
||||
});
|
||||
|
|
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
|
@ -51,6 +51,7 @@ importers:
|
|||
'@types/validator': ^13.7.2
|
||||
'@typescript-eslint/eslint-plugin': ^5.47.1
|
||||
'@typescript-eslint/parser': ^5.47.1
|
||||
argon2: ^0.29.1
|
||||
clsx: ^1.1.1
|
||||
dotenv-cli: ^6.0.0
|
||||
eslint: 8.30.0
|
||||
|
@ -91,6 +92,7 @@ importers:
|
|||
ts-node: ^10.9.1
|
||||
tslib: ^2.4.0
|
||||
typescript: 4.9.4
|
||||
uuid: ^9.0.0
|
||||
validator: ^13.7.0
|
||||
whatwg-fetch: ^3.6.2
|
||||
winston: ^3.7.2
|
||||
|
@ -107,6 +109,7 @@ importers:
|
|||
'@trpc/next': 10.7.0_gmaturtqmtlrknaw65ek5pmv2i
|
||||
'@trpc/react-query': 10.7.0_x4ie6nhblo2vtx2aafrgzlfqy4
|
||||
'@trpc/server': 10.7.0
|
||||
argon2: 0.29.1
|
||||
clsx: 1.1.1
|
||||
fs-extra: 10.1.0
|
||||
graphql: 15.8.0
|
||||
|
|
Loading…
Add table
Reference in a new issue