feat(server): use base64 shared links (#2633)
* feat(server): use base64 shared links * fix: handle array values
This commit is contained in:
parent
76a1629e75
commit
4350f9363d
6 changed files with 33 additions and 16 deletions
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -82,8 +82,11 @@ export class ShareCore {
|
|||
}
|
||||
}
|
||||
|
||||
async validate(key: string): Promise<AuthUserDto | null> {
|
||||
const link = await this.repository.getByKey(key);
|
||||
async validate(key: string | string[]): Promise<AuthUserDto | null> {
|
||||
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;
|
||||
|
|
|
@ -5,7 +5,7 @@ export const ISharedLinkRepository = 'ISharedLinkRepository';
|
|||
export interface ISharedLinkRepository {
|
||||
getAll(userId: string): Promise<SharedLinkEntity[]>;
|
||||
get(userId: string, id: string): Promise<SharedLinkEntity | null>;
|
||||
getByKey(key: string): Promise<SharedLinkEntity | null>;
|
||||
getByKey(key: Buffer): Promise<SharedLinkEntity | null>;
|
||||
create(entity: Omit<SharedLinkEntity, 'id' | 'user'>): Promise<SharedLinkEntity>;
|
||||
remove(entity: SharedLinkEntity): Promise<void>;
|
||||
save(entity: Partial<SharedLinkEntity>): Promise<SharedLinkEntity>;
|
||||
|
|
|
@ -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<AuthUserDto>({
|
||||
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<SharedLinkResponseDto>({
|
||||
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<SharedLinkResponseDto>({
|
||||
id: '123',
|
||||
userId: 'admin_id',
|
||||
key: '7365637265742d6b6579',
|
||||
key: sharedLinkBytes.toString('base64url'),
|
||||
type: SharedLinkType.ALBUM,
|
||||
createdAt: today,
|
||||
expiresAt: tomorrow,
|
||||
|
|
|
@ -60,10 +60,10 @@ export class SharedLinkRepository implements ISharedLinkRepository {
|
|||
});
|
||||
}
|
||||
|
||||
async getByKey(key: string): Promise<SharedLinkEntity | null> {
|
||||
async getByKey(key: Buffer): Promise<SharedLinkEntity | null> {
|
||||
return await this.repository.findOne({
|
||||
where: {
|
||||
key: Buffer.from(key, 'hex'),
|
||||
key,
|
||||
},
|
||||
relations: {
|
||||
assets: true,
|
||||
|
|
Loading…
Reference in a new issue