Skip to content

Commit

Permalink
refactor(server): narrow auth types (#16066)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrasm91 authored Feb 12, 2025
1 parent 7c821dd commit 2d7c333
Show file tree
Hide file tree
Showing 25 changed files with 264 additions and 238 deletions.
6 changes: 3 additions & 3 deletions server/src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class UserController {

@Get('me')
@Authenticated()
getMyUser(@Auth() auth: AuthDto): UserAdminResponseDto {
getMyUser(@Auth() auth: AuthDto): Promise<UserAdminResponseDto> {
return this.service.getMe(auth);
}

Expand All @@ -56,7 +56,7 @@ export class UserController {

@Get('me/preferences')
@Authenticated()
getMyPreferences(@Auth() auth: AuthDto): UserPreferencesResponseDto {
getMyPreferences(@Auth() auth: AuthDto): Promise<UserPreferencesResponseDto> {
return this.service.getMyPreferences(auth);
}

Expand All @@ -71,7 +71,7 @@ export class UserController {

@Get('me/license')
@Authenticated()
getUserLicense(@Auth() auth: AuthDto): LicenseResponseDto {
getUserLicense(@Auth() auth: AuthDto): Promise<LicenseResponseDto> {
return this.service.getLicense(auth);
}

Expand Down
50 changes: 50 additions & 0 deletions server/src/database.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,53 @@
import { Permission } from 'src/enum';

export type AuthUser = {
id: string;
isAdmin: boolean;
name: string;
email: string;
quotaUsageInBytes: number;
quotaSizeInBytes: number | null;
};

export type AuthApiKey = {
id: string;
permissions: Permission[];
};

export type AuthSharedLink = {
id: string;
expiresAt: Date | null;
userId: string;
showExif: boolean;
allowUpload: boolean;
allowDownload: boolean;
password: string | null;
};

export type AuthSession = {
id: string;
};

export const columns = {
authUser: [
'users.id',
'users.name',
'users.email',
'users.isAdmin',
'users.quotaUsageInBytes',
'users.quotaSizeInBytes',
],
authApiKey: ['api_keys.id', 'api_keys.permissions'],
authSession: ['sessions.id', 'sessions.updatedAt'],
authSharedLink: [
'shared_links.id',
'shared_links.userId',
'shared_links.expiresAt',
'shared_links.showExif',
'shared_links.allowUpload',
'shared_links.allowDownload',
'shared_links.password',
],
userDto: ['id', 'name', 'email', 'profileImagePath', 'profileChangedAt'],
apiKey: ['id', 'name', 'userId', 'createdAt', 'updatedAt', 'permissions'],
} as const;
26 changes: 11 additions & 15 deletions server/src/db.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,19 @@
* Please do not edit it manually.
*/

import type { ColumnType } from "kysely";
import type { ColumnType } from 'kysely';
import { Permission } from 'src/enum';

export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[]
? U[]
: ArrayTypeImpl<T>;
export type ArrayType<T> = ArrayTypeImpl<T> extends (infer U)[] ? U[] : ArrayTypeImpl<T>;

export type ArrayTypeImpl<T> = T extends ColumnType<infer S, infer I, infer U>
? ColumnType<S[], I[], U[]>
: T[];
export type ArrayTypeImpl<T> = T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S[], I[], U[]> : T[];

export type AssetsStatusEnum = "active" | "deleted" | "trashed";
export type AssetsStatusEnum = 'active' | 'deleted' | 'trashed';

export type Generated<T> = T extends ColumnType<infer S, infer I, infer U>
? ColumnType<S, I | undefined, U>
: ColumnType<T, T | undefined, T>;
export type Generated<T> =
T extends ColumnType<infer S, infer I, infer U> ? ColumnType<S, I | undefined, U> : ColumnType<T, T | undefined, T>;

export type Int8 = ColumnType<string, bigint | number | string, bigint | number | string>;
export type Int8 = ColumnType<number>;

export type Json = JsonValue;

Expand All @@ -33,7 +29,7 @@ export type JsonPrimitive = boolean | number | string | null;

export type JsonValue = JsonArray | JsonObject | JsonPrimitive;

export type Sourcetype = "exif" | "machine-learning";
export type Sourcetype = 'exif' | 'machine-learning';

export type Timestamp = ColumnType<Date, Date | string, Date | string>;

Expand Down Expand Up @@ -81,7 +77,7 @@ export interface ApiKeys {
id: Generated<string>;
key: string;
name: string;
permissions: string[];
permissions: Permission[];
updatedAt: Generated<Timestamp>;
userId: string;
}
Expand Down Expand Up @@ -444,6 +440,6 @@ export interface DB {
typeorm_metadata: TypeormMetadata;
user_metadata: UserMetadata;
users: Users;
"vectors.pg_vector_index_stat": VectorsPgVectorIndexStat;
'vectors.pg_vector_index_stat': VectorsPgVectorIndexStat;
version_history: VersionHistory;
}
10 changes: 4 additions & 6 deletions server/src/dtos/auth.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { IsEmail, IsNotEmpty, IsString, MinLength } from 'class-validator';
import { SessionEntity } from 'src/entities/session.entity';
import { SharedLinkEntity } from 'src/entities/shared-link.entity';
import { AuthApiKey, AuthSession, AuthSharedLink, AuthUser } from 'src/database';
import { UserEntity } from 'src/entities/user.entity';
import { ImmichCookie } from 'src/enum';
import { AuthApiKey } from 'src/types';
import { toEmail } from 'src/validation';

export type CookieResponse = {
Expand All @@ -14,11 +12,11 @@ export type CookieResponse = {
};

export class AuthDto {
user!: UserEntity;
user!: AuthUser;

apiKey?: AuthApiKey;
sharedLink?: SharedLinkEntity;
session?: SessionEntity;
sharedLink?: AuthSharedLink;
session?: AuthSession;
}

export class LoginCredentialDto {
Expand Down
2 changes: 1 addition & 1 deletion server/src/dtos/user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const mapUser = (entity: UserEntity): UserResponseDto => {
email: entity.email,
name: entity.name,
profileImagePath: entity.profileImagePath,
avatarColor: getPreferences(entity).avatar.color,
avatarColor: getPreferences(entity.email, entity.metadata || []).avatar.color,
profileChangedAt: entity.profileChangedAt,
};
};
Expand Down
9 changes: 7 additions & 2 deletions server/src/entities/user-metadata.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { DeepPartial } from 'src/types';
import { HumanReadableSize } from 'src/utils/bytes';
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';

export type UserMetadataItem<T extends keyof UserMetadata = UserMetadataKey> = {
key: T;
value: UserMetadata[T];
};

@Entity('user_metadata')
export class UserMetadataEntity<T extends keyof UserMetadata = UserMetadataKey> {
export class UserMetadataEntity<T extends keyof UserMetadata = UserMetadataKey> implements UserMetadataItem<T> {
@PrimaryColumn({ type: 'uuid' })
userId!: string;

@ManyToOne(() => UserEntity, (user) => user.metadata, { onUpdate: 'CASCADE', onDelete: 'CASCADE' })
user!: UserEntity;
user?: UserEntity;

@PrimaryColumn({ type: 'varchar' })
key!: T;
Expand Down
33 changes: 16 additions & 17 deletions server/src/queries/api.key.repository.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,28 @@
-- ApiKeyRepository.getKey
select
"api_keys"."id",
"api_keys"."key",
"api_keys"."userId",
"api_keys"."permissions",
to_json("user") as "user"
from
"api_keys"
inner join lateral (
(
select
"users".*,
to_json(obj)
from
(
select
array_agg("user_metadata") as "metadata"
"users"."id",
"users"."name",
"users"."email",
"users"."isAdmin",
"users"."quotaUsageInBytes",
"users"."quotaSizeInBytes"
from
"user_metadata"
"users"
where
"users"."id" = "user_metadata"."userId"
) as "metadata"
from
"users"
where
"users"."id" = "api_keys"."userId"
and "users"."deletedAt" is null
) as "user" on true
"users"."id" = "api_keys"."userId"
and "users"."deletedAt" is null
) as obj
) as "user"
from
"api_keys"
where
"api_keys"."key" = $1

Expand Down
48 changes: 18 additions & 30 deletions server/src/queries/session.repository.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,29 @@ where

-- SessionRepository.getByToken
select
"sessions".*,
to_json("user") as "user"
from
"sessions"
inner join lateral (
"sessions"."id",
"sessions"."updatedAt",
(
select
"id",
"email",
"createdAt",
"profileImagePath",
"isAdmin",
"shouldChangePassword",
"deletedAt",
"oauthId",
"updatedAt",
"storageLabel",
"name",
"quotaSizeInBytes",
"quotaUsageInBytes",
"status",
"profileChangedAt",
to_json(obj)
from
(
select
array_agg("user_metadata") as "metadata"
"users"."id",
"users"."name",
"users"."email",
"users"."isAdmin",
"users"."quotaUsageInBytes",
"users"."quotaSizeInBytes"
from
"user_metadata"
"users"
where
"users"."id" = "user_metadata"."userId"
) as "metadata"
from
"users"
where
"users"."id" = "sessions"."userId"
and "users"."deletedAt" is null
) as "user" on true
"users"."id" = "sessions"."userId"
and "users"."deletedAt" is null
) as obj
) as "user"
from
"sessions"
where
"sessions"."token" = $1

Expand Down
22 changes: 10 additions & 12 deletions server/src/queries/shared.link.repository.sql
Original file line number Diff line number Diff line change
Expand Up @@ -153,33 +153,31 @@ where
"shared_links"."type" = $2
or "album"."id" is not null
)
and "shared_links"."albumId" = $3
order by
"shared_links"."createdAt" desc

-- SharedLinkRepository.getByKey
select
"shared_links".*,
"shared_links"."id",
"shared_links"."userId",
"shared_links"."expiresAt",
"shared_links"."showExif",
"shared_links"."allowUpload",
"shared_links"."allowDownload",
"shared_links"."password",
(
select
to_json(obj)
from
(
select
"users"."id",
"users"."name",
"users"."email",
"users"."createdAt",
"users"."profileImagePath",
"users"."isAdmin",
"users"."shouldChangePassword",
"users"."deletedAt",
"users"."oauthId",
"users"."updatedAt",
"users"."storageLabel",
"users"."name",
"users"."quotaSizeInBytes",
"users"."quotaUsageInBytes",
"users"."status",
"users"."profileChangedAt"
"users"."quotaSizeInBytes"
from
"users"
where
Expand Down
Loading

0 comments on commit 2d7c333

Please sign in to comment.