refactor(server): auth dto (#5593)

* refactor: AuthUserDto => AuthDto

* refactor: reorganize auth-dto

* refactor: AuthUser() => Auth()
This commit is contained in:
Jason Rasmussen
2023-12-09 23:34:12 -05:00
committed by GitHub
parent 8057c375ba
commit 33529d1d9b
60 changed files with 1033 additions and 1065 deletions
+44 -29
View File
@@ -31,7 +31,7 @@ import {
IUserTokenRepository,
} from '../repositories';
import { AuthType } from './auth.constant';
import { AuthUserDto, SignUpDto } from './auth.dto';
import { AuthDto, SignUpDto } from './auth.dto';
import { AuthService } from './auth.service';
// const token = Buffer.from('my-api-key', 'utf8').toString('base64');
@@ -145,7 +145,7 @@ describe('AuthService', () => {
describe('changePassword', () => {
it('should change the password', async () => {
const authUser = { email: 'test@imimch.com' } as UserEntity;
const auth = { user: { email: 'test@imimch.com' } } as AuthDto;
const dto = { password: 'old-password', newPassword: 'new-password' };
userMock.getByEmail.mockResolvedValue({
@@ -153,23 +153,23 @@ describe('AuthService', () => {
password: 'hash-password',
} as UserEntity);
await sut.changePassword(authUser, dto);
await sut.changePassword(auth, dto);
expect(userMock.getByEmail).toHaveBeenCalledWith(authUser.email, true);
expect(userMock.getByEmail).toHaveBeenCalledWith(auth.user.email, true);
expect(cryptoMock.compareBcrypt).toHaveBeenCalledWith('old-password', 'hash-password');
});
it('should throw when auth user email is not found', async () => {
const authUser = { email: 'test@imimch.com' } as UserEntity;
const auth = { user: { email: 'test@imimch.com' } } as AuthDto;
const dto = { password: 'old-password', newPassword: 'new-password' };
userMock.getByEmail.mockResolvedValue(null);
await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(UnauthorizedException);
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(UnauthorizedException);
});
it('should throw when password does not match existing password', async () => {
const authUser = { email: 'test@imimch.com' } as UserEntity;
const auth = { user: { email: 'test@imimch.com' } as UserEntity };
const dto = { password: 'old-password', newPassword: 'new-password' };
cryptoMock.compareBcrypt.mockReturnValue(false);
@@ -179,11 +179,11 @@ describe('AuthService', () => {
password: 'hash-password',
} as UserEntity);
await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
});
it('should throw when user does not have a password', async () => {
const authUser = { email: 'test@imimch.com' } as UserEntity;
const auth = { user: { email: 'test@imimch.com' } } as AuthDto;
const dto = { password: 'old-password', newPassword: 'new-password' };
userMock.getByEmail.mockResolvedValue({
@@ -191,33 +191,33 @@ describe('AuthService', () => {
password: '',
} as UserEntity);
await expect(sut.changePassword(authUser, dto)).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.changePassword(auth, dto)).rejects.toBeInstanceOf(BadRequestException);
});
});
describe('logout', () => {
it('should return the end session endpoint', async () => {
configMock.load.mockResolvedValue(systemConfigStub.enabled);
const authUser = { id: '123' } as AuthUserDto;
await expect(sut.logout(authUser, AuthType.OAUTH)).resolves.toEqual({
const auth = { user: { id: '123' } } as AuthDto;
await expect(sut.logout(auth, AuthType.OAUTH)).resolves.toEqual({
successful: true,
redirectUri: 'http://end-session-endpoint',
});
});
it('should return the default redirect', async () => {
const authUser = { id: '123' } as AuthUserDto;
const auth = { user: { id: '123' } } as AuthDto;
await expect(sut.logout(authUser, AuthType.PASSWORD)).resolves.toEqual({
await expect(sut.logout(auth, AuthType.PASSWORD)).resolves.toEqual({
successful: true,
redirectUri: '/auth/login?autoLaunch=0',
});
});
it('should delete the access token', async () => {
const authUser = { id: '123', accessTokenId: 'token123' } as AuthUserDto;
const auth = { user: { id: '123' }, userToken: { id: 'token123' } } as AuthDto;
await expect(sut.logout(authUser, AuthType.PASSWORD)).resolves.toEqual({
await expect(sut.logout(auth, AuthType.PASSWORD)).resolves.toEqual({
successful: true,
redirectUri: '/auth/login?autoLaunch=0',
});
@@ -226,9 +226,9 @@ describe('AuthService', () => {
});
it('should return the default redirect if auth type is OAUTH but oauth is not enabled', async () => {
const authUser = { id: '123' } as AuthUserDto;
const auth = { user: { id: '123' } } as AuthDto;
await expect(sut.logout(authUser, AuthType.OAUTH)).resolves.toEqual({
await expect(sut.logout(auth, AuthType.OAUTH)).resolves.toEqual({
successful: true,
redirectUri: '/auth/login?autoLaunch=0',
});
@@ -268,7 +268,10 @@ describe('AuthService', () => {
userMock.get.mockResolvedValue(userStub.user1);
userTokenMock.getByToken.mockResolvedValue(userTokenStub.userToken);
const client = { request: { headers: { authorization: 'Bearer auth_token' } } };
await expect(sut.validate((client as Socket).request.headers, {})).resolves.toEqual(userStub.user1);
await expect(sut.validate((client as Socket).request.headers, {})).resolves.toEqual({
user: userStub.user1,
userToken: userTokenStub.userToken,
});
});
});
@@ -296,7 +299,10 @@ describe('AuthService', () => {
shareMock.getByKey.mockResolvedValue(sharedLinkStub.valid);
userMock.get.mockResolvedValue(userStub.admin);
const headers: IncomingHttpHeaders = { 'x-immich-share-key': sharedLinkStub.valid.key.toString('base64url') };
await expect(sut.validate(headers, {})).resolves.toEqual(authStub.adminSharedLink);
await expect(sut.validate(headers, {})).resolves.toEqual({
user: userStub.admin,
sharedLink: sharedLinkStub.valid,
});
expect(shareMock.getByKey).toHaveBeenCalledWith(sharedLinkStub.valid.key);
});
@@ -304,7 +310,10 @@ describe('AuthService', () => {
shareMock.getByKey.mockResolvedValue(sharedLinkStub.valid);
userMock.get.mockResolvedValue(userStub.admin);
const headers: IncomingHttpHeaders = { 'x-immich-share-key': sharedLinkStub.valid.key.toString('hex') };
await expect(sut.validate(headers, {})).resolves.toEqual(authStub.adminSharedLink);
await expect(sut.validate(headers, {})).resolves.toEqual({
user: userStub.admin,
sharedLink: sharedLinkStub.valid,
});
expect(shareMock.getByKey).toHaveBeenCalledWith(sharedLinkStub.valid.key);
});
});
@@ -319,14 +328,20 @@ describe('AuthService', () => {
it('should return an auth dto', async () => {
userTokenMock.getByToken.mockResolvedValue(userTokenStub.userToken);
const headers: IncomingHttpHeaders = { cookie: 'immich_access_token=auth_token' };
await expect(sut.validate(headers, {})).resolves.toEqual(userStub.user1);
await expect(sut.validate(headers, {})).resolves.toEqual({
user: userStub.user1,
userToken: userTokenStub.userToken,
});
});
it('should update when access time exceeds an hour', async () => {
userTokenMock.getByToken.mockResolvedValue(userTokenStub.inactiveToken);
userTokenMock.save.mockResolvedValue(userTokenStub.userToken);
const headers: IncomingHttpHeaders = { cookie: 'immich_access_token=auth_token' };
await expect(sut.validate(headers, {})).resolves.toEqual(userStub.user1);
await expect(sut.validate(headers, {})).resolves.toEqual({
user: userStub.user1,
userToken: userTokenStub.userToken,
});
expect(userTokenMock.save.mock.calls[0][0]).toMatchObject({
id: 'not_active',
token: 'auth_token',
@@ -350,7 +365,7 @@ describe('AuthService', () => {
it('should return an auth dto', async () => {
keyMock.getKey.mockResolvedValue(keyStub.admin);
const headers: IncomingHttpHeaders = { 'x-api-key': 'auth_token' };
await expect(sut.validate(headers, {})).resolves.toEqual(authStub.admin);
await expect(sut.validate(headers, {})).resolves.toEqual({ user: userStub.admin, apiKey: keyStub.admin });
expect(keyMock.getKey).toHaveBeenCalledWith('auth_token (hashed)');
});
});
@@ -377,7 +392,7 @@ describe('AuthService', () => {
},
]);
expect(userTokenMock.getAll).toHaveBeenCalledWith(authStub.user1.id);
expect(userTokenMock.getAll).toHaveBeenCalledWith(authStub.user1.user.id);
});
});
@@ -387,7 +402,7 @@ describe('AuthService', () => {
await sut.logoutDevices(authStub.user1);
expect(userTokenMock.getAll).toHaveBeenCalledWith(authStub.user1.id);
expect(userTokenMock.getAll).toHaveBeenCalledWith(authStub.user1.user.id);
expect(userTokenMock.delete).toHaveBeenCalledWith('not_active');
expect(userTokenMock.delete).not.toHaveBeenCalledWith('token-id');
});
@@ -399,7 +414,7 @@ describe('AuthService', () => {
await sut.logoutDevice(authStub.user1, 'token-1');
expect(accessMock.authDevice.checkOwnerAccess).toHaveBeenCalledWith(authStub.user1.id, new Set(['token-1']));
expect(accessMock.authDevice.checkOwnerAccess).toHaveBeenCalledWith(authStub.user1.user.id, new Set(['token-1']));
expect(userTokenMock.delete).toHaveBeenCalledWith('token-1');
});
});
@@ -506,7 +521,7 @@ describe('AuthService', () => {
await sut.link(authStub.user1, { url: 'http://immich/user-settings?code=abc123' });
expect(userMock.update).toHaveBeenCalledWith(authStub.user1.id, { oauthId: sub });
expect(userMock.update).toHaveBeenCalledWith(authStub.user1.user.id, { oauthId: sub });
});
it('should not link an already linked oauth.sub', async () => {
@@ -528,7 +543,7 @@ describe('AuthService', () => {
await sut.unlink(authStub.user1);
expect(userMock.update).toHaveBeenCalledWith(authStub.user1.id, { oauthId: '' });
expect(userMock.update).toHaveBeenCalledWith(authStub.user1.user.id, { oauthId: '' });
});
});
});