mirror of
https://github.com/immich-app/immich.git
synced 2025-12-20 01:11:46 +03:00
feat: shared links custom URL (#19999)
* feat: custom url for shared links * feat: use a separate route and query param --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
This commit is contained in:
@@ -6,7 +6,7 @@ import { IncomingHttpHeaders } from 'node:http';
|
||||
import { join } from 'node:path';
|
||||
import { LOGIN_URL, MOBILE_REDIRECT, SALT_ROUNDS } from 'src/constants';
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { UserAdmin } from 'src/database';
|
||||
import { AuthSharedLink, AuthUser, UserAdmin } from 'src/database';
|
||||
import {
|
||||
AuthDto,
|
||||
AuthStatusResponseDto,
|
||||
@@ -196,6 +196,7 @@ export class AuthService extends BaseService {
|
||||
|
||||
private async validate({ headers, queryParams }: Omit<ValidateRequest, 'metadata'>): Promise<AuthDto> {
|
||||
const shareKey = (headers[ImmichHeader.SharedLinkKey] || queryParams[ImmichQuery.SharedLinkKey]) as string;
|
||||
const shareSlug = (headers[ImmichHeader.SharedLinkSlug] || queryParams[ImmichQuery.SharedLinkSlug]) as string;
|
||||
const session = (headers[ImmichHeader.UserToken] ||
|
||||
headers[ImmichHeader.SessionToken] ||
|
||||
queryParams[ImmichQuery.SessionKey] ||
|
||||
@@ -204,7 +205,11 @@ export class AuthService extends BaseService {
|
||||
const apiKey = (headers[ImmichHeader.ApiKey] || queryParams[ImmichQuery.ApiKey]) as string;
|
||||
|
||||
if (shareKey) {
|
||||
return this.validateSharedLink(shareKey);
|
||||
return this.validateSharedLinkKey(shareKey);
|
||||
}
|
||||
|
||||
if (shareSlug) {
|
||||
return this.validateSharedLinkSlug(shareSlug);
|
||||
}
|
||||
|
||||
if (session) {
|
||||
@@ -403,18 +408,33 @@ export class AuthService extends BaseService {
|
||||
return cookies[ImmichCookie.OAuthCodeVerifier] || null;
|
||||
}
|
||||
|
||||
async validateSharedLink(key: string | string[]): Promise<AuthDto> {
|
||||
async validateSharedLinkKey(key: string | string[]): Promise<AuthDto> {
|
||||
key = Array.isArray(key) ? key[0] : key;
|
||||
|
||||
const bytes = Buffer.from(key, key.length === 100 ? 'hex' : 'base64url');
|
||||
const sharedLink = await this.sharedLinkRepository.getByKey(bytes);
|
||||
if (sharedLink?.user && (!sharedLink.expiresAt || new Date(sharedLink.expiresAt) > new Date())) {
|
||||
return {
|
||||
user: sharedLink.user,
|
||||
sharedLink,
|
||||
};
|
||||
if (!this.isValidSharedLink(sharedLink)) {
|
||||
throw new UnauthorizedException('Invalid share key');
|
||||
}
|
||||
throw new UnauthorizedException('Invalid share key');
|
||||
|
||||
return { user: sharedLink.user, sharedLink };
|
||||
}
|
||||
|
||||
async validateSharedLinkSlug(slug: string | string[]): Promise<AuthDto> {
|
||||
slug = Array.isArray(slug) ? slug[0] : slug;
|
||||
|
||||
const sharedLink = await this.sharedLinkRepository.getBySlug(slug);
|
||||
if (!this.isValidSharedLink(sharedLink)) {
|
||||
throw new UnauthorizedException('Invalid share slug');
|
||||
}
|
||||
|
||||
return { user: sharedLink.user, sharedLink };
|
||||
}
|
||||
|
||||
private isValidSharedLink(
|
||||
sharedLink?: AuthSharedLink & { user: AuthUser | null },
|
||||
): sharedLink is AuthSharedLink & { user: AuthUser } {
|
||||
return !!sharedLink?.user && (!sharedLink.expiresAt || new Date(sharedLink.expiresAt) > new Date());
|
||||
}
|
||||
|
||||
private async validateApiKey(key: string): Promise<AuthDto> {
|
||||
|
||||
Reference in New Issue
Block a user