diff --git a/server/libs/domain/src/auth/auth.service.spec.ts b/server/libs/domain/src/auth/auth.service.spec.ts index 3a3d73415..4cde79dcc 100644 --- a/server/libs/domain/src/auth/auth.service.spec.ts +++ b/server/libs/domain/src/auth/auth.service.spec.ts @@ -277,11 +277,20 @@ describe('AuthService', () => { await expect(sut.validate(headers, {})).rejects.toBeInstanceOf(UnauthorizedException); }); - it('should accept a valid key', async () => { + it('should accept a base64url key', async () => { shareMock.getByKey.mockResolvedValue(sharedLinkStub.valid); userMock.get.mockResolvedValue(userEntityStub.admin); - const headers: IncomingHttpHeaders = { 'x-immich-share-key': 'key' }; + const headers: IncomingHttpHeaders = { 'x-immich-share-key': sharedLinkStub.valid.key.toString('base64url') }; await expect(sut.validate(headers, {})).resolves.toEqual(authStub.adminSharedLink); + expect(shareMock.getByKey).toHaveBeenCalledWith(sharedLinkStub.valid.key); + }); + + it('should accept a hex key', async () => { + shareMock.getByKey.mockResolvedValue(sharedLinkStub.valid); + userMock.get.mockResolvedValue(userEntityStub.admin); + const headers: IncomingHttpHeaders = { 'x-immich-share-key': sharedLinkStub.valid.key.toString('hex') }; + await expect(sut.validate(headers, {})).resolves.toEqual(authStub.adminSharedLink); + expect(shareMock.getByKey).toHaveBeenCalledWith(sharedLinkStub.valid.key); }); }); diff --git a/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts b/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts index bb7656789..f4ccabcfe 100644 --- a/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts +++ b/server/libs/domain/src/share/response-dto/shared-link-response.dto.ts @@ -31,7 +31,7 @@ export function mapSharedLink(sharedLink: SharedLinkEntity): SharedLinkResponseD id: sharedLink.id, description: sharedLink.description, userId: sharedLink.userId, - key: sharedLink.key.toString('hex'), + key: sharedLink.key.toString('base64url'), type: sharedLink.type, createdAt: sharedLink.createdAt, expiresAt: sharedLink.expiresAt, @@ -53,7 +53,7 @@ export function mapSharedLinkWithNoExif(sharedLink: SharedLinkEntity): SharedLin id: sharedLink.id, description: sharedLink.description, userId: sharedLink.userId, - key: sharedLink.key.toString('hex'), + key: sharedLink.key.toString('base64url'), type: sharedLink.type, createdAt: sharedLink.createdAt, expiresAt: sharedLink.expiresAt, diff --git a/server/libs/domain/src/share/share.core.ts b/server/libs/domain/src/share/share.core.ts index 706650a7b..f925b597c 100644 --- a/server/libs/domain/src/share/share.core.ts +++ b/server/libs/domain/src/share/share.core.ts @@ -82,8 +82,11 @@ export class ShareCore { } } - async validate(key: string): Promise { - const link = await this.repository.getByKey(key); + async validate(key: string | string[]): Promise { + key = Array.isArray(key) ? key[0] : key; + + const bytes = Buffer.from(key, key.length === 100 ? 'hex' : 'base64url'); + const link = await this.repository.getByKey(bytes); if (link) { if (!link.expiresAt || new Date(link.expiresAt) > new Date()) { const user = link.user; diff --git a/server/libs/domain/src/share/shared-link.repository.ts b/server/libs/domain/src/share/shared-link.repository.ts index 1eca52403..4b8b24c28 100644 --- a/server/libs/domain/src/share/shared-link.repository.ts +++ b/server/libs/domain/src/share/shared-link.repository.ts @@ -5,7 +5,7 @@ export const ISharedLinkRepository = 'ISharedLinkRepository'; export interface ISharedLinkRepository { getAll(userId: string): Promise; get(userId: string, id: string): Promise; - getByKey(key: string): Promise; + getByKey(key: Buffer): Promise; create(entity: Omit): Promise; remove(entity: SharedLinkEntity): Promise; save(entity: Partial): Promise; diff --git a/server/libs/domain/test/fixtures.ts b/server/libs/domain/test/fixtures.ts index 11abf265c..411e62a38 100644 --- a/server/libs/domain/test/fixtures.ts +++ b/server/libs/domain/test/fixtures.ts @@ -38,6 +38,11 @@ const yesterday = new Date(); tomorrow.setDate(today.getDate() + 1); yesterday.setDate(yesterday.getDate() - 1); +const sharedLinkBytes = Buffer.from( + '2c2b646895f84753bff43fb696ad124f3b0faf2a0bd547406f26fa4a76b5c71990092baa536275654b2ab7a191fb21a6d6cd', + 'hex', +); + export const authStub = { admin: Object.freeze({ id: 'admin_id', @@ -662,7 +667,7 @@ export const sharedLinkStub = { id: '123', userId: authStub.admin.id, user: userEntityStub.admin, - key: Buffer.from('secret-key', 'utf8'), + key: sharedLinkBytes, type: SharedLinkType.ALBUM, createdAt: today, expiresAt: tomorrow, @@ -676,7 +681,7 @@ export const sharedLinkStub = { id: '123', userId: authStub.admin.id, user: userEntityStub.admin, - key: Buffer.from('secret-key', 'utf8'), + key: sharedLinkBytes, type: SharedLinkType.ALBUM, createdAt: today, expiresAt: yesterday, @@ -689,7 +694,7 @@ export const sharedLinkStub = { id: '123', userId: authStub.admin.id, user: userEntityStub.admin, - key: Buffer.from('secret-key', 'utf8'), + key: sharedLinkBytes, type: SharedLinkType.ALBUM, createdAt: today, expiresAt: tomorrow, @@ -786,7 +791,7 @@ export const sharedLinkResponseStub = { description: undefined, expiresAt: tomorrow, id: '123', - key: '7365637265742d6b6579', + key: sharedLinkBytes.toString('base64url'), showExif: true, type: SharedLinkType.ALBUM, userId: 'admin_id', @@ -800,7 +805,7 @@ export const sharedLinkResponseStub = { description: undefined, expiresAt: yesterday, id: '123', - key: '7365637265742d6b6579', + key: sharedLinkBytes.toString('base64url'), showExif: true, type: SharedLinkType.ALBUM, userId: 'admin_id', @@ -808,7 +813,7 @@ export const sharedLinkResponseStub = { readonly: Object.freeze({ id: '123', userId: 'admin_id', - key: '7365637265742d6b6579', + key: sharedLinkBytes.toString('base64url'), type: SharedLinkType.ALBUM, createdAt: today, expiresAt: tomorrow, @@ -822,7 +827,7 @@ export const sharedLinkResponseStub = { readonlyNoExif: Object.freeze({ id: '123', userId: 'admin_id', - key: '7365637265742d6b6579', + key: sharedLinkBytes.toString('base64url'), type: SharedLinkType.ALBUM, createdAt: today, expiresAt: tomorrow, diff --git a/server/libs/infra/src/repositories/shared-link.repository.ts b/server/libs/infra/src/repositories/shared-link.repository.ts index 4cd13e324..0975d95df 100644 --- a/server/libs/infra/src/repositories/shared-link.repository.ts +++ b/server/libs/infra/src/repositories/shared-link.repository.ts @@ -60,10 +60,10 @@ export class SharedLinkRepository implements ISharedLinkRepository { }); } - async getByKey(key: string): Promise { + async getByKey(key: Buffer): Promise { return await this.repository.findOne({ where: { - key: Buffer.from(key, 'hex'), + key, }, relations: { assets: true,