Files
immich/server/libs/domain/src/share/share.service.ts
T
Zack Pollard 3f2513a717 feat(server): move authentication to tokens stored in the database (#1381)
* chore: add typeorm commands to npm and set default database config values

* feat: move to server side authentication tokens

* fix: websocket should emit error and disconnect on error thrown by the server

* refactor: rename cookie-auth-strategy to user-auth-strategy

* feat: user tokens and API keys now use SHA256 hash for performance improvements

* test: album e2e test remove unneeded module import

* infra: truncate api key table as old keys will no longer work with new hash algorithm

* fix(server): e2e tests (#1435)

* fix: root module paths

* chore: linting

* chore: rename user-auth to strategy.ts and make validate return AuthUserDto

* fix: we should always send HttpOnly for our auth cookies

* chore: remove now unused crypto functions and jwt dependencies

* fix: return the extra fields for AuthUserDto in auth service validate

---------

Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
2023-01-27 14:50:07 -06:00

101 lines
3.1 KiB
TypeScript

import {
BadRequestException,
ForbiddenException,
Inject,
Injectable,
Logger,
UnauthorizedException,
} from '@nestjs/common';
import { AuthUserDto, ICryptoRepository } from '../auth';
import { IUserRepository, UserCore } from '../user';
import { EditSharedLinkDto } from './dto';
import { mapSharedLink, mapSharedLinkWithNoExif, SharedLinkResponseDto } from './response-dto';
import { ShareCore } from './share.core';
import { ISharedLinkRepository } from './shared-link.repository';
@Injectable()
export class ShareService {
readonly logger = new Logger(ShareService.name);
private shareCore: ShareCore;
private userCore: UserCore;
constructor(
@Inject(ICryptoRepository) cryptoRepository: ICryptoRepository,
@Inject(ISharedLinkRepository) sharedLinkRepository: ISharedLinkRepository,
@Inject(IUserRepository) userRepository: IUserRepository,
) {
this.shareCore = new ShareCore(sharedLinkRepository, cryptoRepository);
this.userCore = new UserCore(userRepository, cryptoRepository);
}
async validate(key: string): Promise<AuthUserDto> {
const link = await this.shareCore.getByKey(key);
if (link) {
if (!link.expiresAt || new Date(link.expiresAt) > new Date()) {
const user = await this.userCore.get(link.userId);
if (user) {
return {
id: user.id,
email: user.email,
isAdmin: user.isAdmin,
isPublicUser: true,
sharedLinkId: link.id,
isAllowUpload: link.allowUpload,
isAllowDownload: link.allowDownload,
isShowExif: link.showExif,
};
}
}
}
throw new UnauthorizedException();
}
async getAll(authUser: AuthUserDto): Promise<SharedLinkResponseDto[]> {
const links = await this.shareCore.getAll(authUser.id);
return links.map(mapSharedLink);
}
async getMine(authUser: AuthUserDto): Promise<SharedLinkResponseDto> {
if (!authUser.isPublicUser || !authUser.sharedLinkId) {
throw new ForbiddenException();
}
let allowExif = true;
if (authUser.isShowExif != undefined) {
allowExif = authUser.isShowExif;
}
return this.getById(authUser, authUser.sharedLinkId, allowExif);
}
async getById(authUser: AuthUserDto, id: string, allowExif: boolean): Promise<SharedLinkResponseDto> {
const link = await this.shareCore.get(authUser.id, id);
if (!link) {
throw new BadRequestException('Shared link not found');
}
if (allowExif) {
return mapSharedLink(link);
} else {
return mapSharedLinkWithNoExif(link);
}
}
async getByKey(key: string): Promise<SharedLinkResponseDto> {
const link = await this.shareCore.getByKey(key);
if (!link) {
throw new BadRequestException('Shared link not found');
}
return mapSharedLink(link);
}
async remove(authUser: AuthUserDto, id: string): Promise<void> {
await this.shareCore.remove(authUser.id, id);
}
async edit(authUser: AuthUserDto, id: string, dto: EditSharedLinkDto) {
const link = await this.shareCore.save(authUser.id, id, dto);
return mapSharedLink(link);
}
}