Fix public url getter & update tests
This commit is contained in:
parent
78c76a50ad
commit
da25451f75
|
@ -1,19 +0,0 @@
|
|||
import { render, screen } from "@testing-library/react"
|
||||
import { ProtectedImage } from "./ProtectedMedia"
|
||||
|
||||
const mockPublicUrl = 'http://localhost:9876';
|
||||
vi.mock('../../helpers/utils', () => ({getPublicUrl: () => mockPublicUrl}));
|
||||
|
||||
describe('ProtectedImage', () => {
|
||||
test.each([
|
||||
{label: 'relative', src: '/image.jpg', expected: `${mockPublicUrl}/image.jpg`},
|
||||
{label: 'absolute', src: 'http://localhost:4040/image.jpg', expected: 'http://localhost:4040/image.jpg'}
|
||||
])('loads image correctly given $label url', ({src, expected}) => {
|
||||
|
||||
render(<ProtectedImage alt={'alt_text'} src={src}/>);
|
||||
|
||||
const image = screen.getByAltText('alt_text');
|
||||
|
||||
expect(image).toHaveAttribute('src', expected);
|
||||
})
|
||||
})
|
|
@ -4,26 +4,12 @@ import { useRef } from 'react'
|
|||
import { useState } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { BlurhashCanvas } from 'react-blurhash'
|
||||
import { getPublicUrl, isNil } from '../../helpers/utils'
|
||||
import { getProtectedUrl, isNil } from '../../helpers/utils'
|
||||
|
||||
const isNativeLazyLoadSupported = 'loading' in document.createElement('img')
|
||||
const placeholder =
|
||||
'data:image/gif;base64,R0lGODlhAQABAPAAAAAAAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='
|
||||
|
||||
const getProtectedUrl = (url?: string) => {
|
||||
if (url == undefined) return undefined
|
||||
|
||||
const imgUrl = new URL(url, getPublicUrl())
|
||||
|
||||
const tokenRegex = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/)
|
||||
if (tokenRegex) {
|
||||
const token = tokenRegex[1]
|
||||
imgUrl.searchParams.set('token', token)
|
||||
}
|
||||
|
||||
return imgUrl.href
|
||||
}
|
||||
|
||||
export interface ProtectedImageProps
|
||||
extends Omit<
|
||||
DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement>,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { gql, useLazyQuery } from '@apollo/client'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { NotificationType } from '../../__generated__/globalTypes'
|
||||
import { authToken } from '../../helpers/authentication'
|
||||
import { TranslationFn } from '../../localization'
|
||||
import { MessageState } from '../messages/Messages'
|
||||
import { MediaSidebarMedia } from './MediaSidebar/MediaSidebar'
|
||||
|
@ -13,7 +12,7 @@ import {
|
|||
sidebarDownloadQueryVariables,
|
||||
sidebarDownloadQuery_media_downloads,
|
||||
} from './__generated__/sidebarDownloadQuery'
|
||||
import { getPublicUrl } from '../../helpers/utils'
|
||||
import { getProtectedUrl } from '../../helpers/utils'
|
||||
|
||||
export const SIDEBAR_DOWNLOAD_QUERY = gql`
|
||||
query sidebarDownloadQuery($mediaId: ID!) {
|
||||
|
@ -57,17 +56,9 @@ const formatBytes = (t: TranslationFn) => (bytes: number) => {
|
|||
}
|
||||
|
||||
const downloadMedia = (t: TranslationFn) => async (url: string) => {
|
||||
const imgUrl = new URL(url, getPublicUrl())
|
||||
const imgUrl = getProtectedUrl(url);
|
||||
|
||||
if (authToken() == null) {
|
||||
// Get share token if not authorized
|
||||
const token = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/)
|
||||
if (token) {
|
||||
imgUrl.searchParams.set('token', token[1])
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch(imgUrl.href, {
|
||||
const response = await fetch(imgUrl, {
|
||||
credentials: 'include',
|
||||
})
|
||||
|
||||
|
|
|
@ -1,19 +1,55 @@
|
|||
import { getPublicUrl } from "./utils";
|
||||
import { getProtectedUrl, getPublicUrl } from "./utils";
|
||||
|
||||
describe('getPublicUrl', () => {
|
||||
describe('Url helper', () => {
|
||||
const mockOrigin = 'http://localhost:9876';
|
||||
Object.defineProperty(window, 'location', {
|
||||
get() {
|
||||
return { origin: mockOrigin };
|
||||
}
|
||||
const mockBaseUrl = '/base_url/';
|
||||
const mockShareToken = 'nm42';
|
||||
const mockSharePath = `/share/${mockShareToken}`;
|
||||
|
||||
beforeEach(()=>{
|
||||
import.meta.env.BASE_URL = mockBaseUrl;
|
||||
Object.defineProperties(window,
|
||||
{
|
||||
location: {
|
||||
get() {
|
||||
return { origin: mockOrigin, pathname: mockSharePath };
|
||||
}
|
||||
},
|
||||
document: {
|
||||
get() {
|
||||
return { cookie: 'auth-token=abc' };
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test.each([
|
||||
{label:'relative', baseUrl: '/my_public/', expected: `${mockOrigin}/my_public/`},
|
||||
{label:'absolute', baseUrl: 'http://my_origin', expected: 'http://my_origin/'}
|
||||
])('returns currect url for $label base', ({baseUrl, expected}) => {
|
||||
{url:'', baseUrl: '', expected: `${mockOrigin}/`},
|
||||
{url:'', baseUrl: '/public_path/', expected: `${mockOrigin}/public_path/`},
|
||||
{url:'/image.jpg', baseUrl: '/public_path/', expected: `${mockOrigin}/public_path/image.jpg`},
|
||||
{url:'/image.jpg', baseUrl: 'http://other_host/', expected: 'http://other_host/image.jpg'},
|
||||
{url:'http://other_host2/image.jpg', baseUrl: 'http://other_host/', expected: 'http://other_host2/image.jpg'}
|
||||
])('returns currect public url for base $baseUrl and url $url', ({url, baseUrl, expected}) => {
|
||||
import.meta.env.BASE_URL = baseUrl;
|
||||
const url = getPublicUrl();
|
||||
expect(url.href).toBe(expected);
|
||||
const publicUrl = getPublicUrl(url);
|
||||
expect(publicUrl.href).toBe(expected);
|
||||
})
|
||||
})
|
||||
|
||||
test('returns undefined protected url', () => {
|
||||
expect(getProtectedUrl(undefined)).toBeUndefined();
|
||||
})
|
||||
|
||||
test('returns protected url without token', () => {
|
||||
expect(getProtectedUrl('image.jpg')).toBe(`${mockOrigin}${mockBaseUrl}image.jpg`);
|
||||
})
|
||||
|
||||
test('returns protected url with token', () => {
|
||||
Object.defineProperty(window, 'document', {
|
||||
get() {
|
||||
return { cookie: '' };
|
||||
}
|
||||
});
|
||||
expect(getProtectedUrl('image.jpg')).toBe(`${mockOrigin}${mockBaseUrl}image.jpg?token=${mockShareToken}`);
|
||||
})
|
||||
})
|
|
@ -1,5 +1,6 @@
|
|||
import classNames, { Argument as ClassNamesArg } from 'classnames'
|
||||
import { overrideTailwindClasses } from 'tailwind-override'
|
||||
import { authToken } from './authentication'
|
||||
|
||||
export interface DebouncedFn<F extends (...args: unknown[]) => unknown> {
|
||||
(...args: Parameters<F>): void
|
||||
|
@ -49,6 +50,29 @@ export function tailwindClassNames(...args: ClassNamesArg[]) {
|
|||
// return classNames(args)
|
||||
}
|
||||
|
||||
export function getPublicUrl() {
|
||||
return new URL(import.meta.env.BASE_URL, location.origin);
|
||||
export function getPublicUrl(url: string = '') {
|
||||
try {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch {
|
||||
return new URL(url, import.meta.env.BASE_URL);
|
||||
}
|
||||
} catch {
|
||||
return new URL(`${import.meta.env.BASE_URL}${url}`.replace(/\/\//g, '/'), location.origin);
|
||||
}
|
||||
}
|
||||
|
||||
export function getProtectedUrl<S extends string | undefined>(url: S) {
|
||||
if (url == undefined) return undefined as S
|
||||
|
||||
const publicUrl = getPublicUrl(url);
|
||||
|
||||
if (authToken() == null) {
|
||||
const tokenRegex = location.pathname.match(/^\/share\/([\d\w]+)(\/?.*)$/)
|
||||
if (tokenRegex) {
|
||||
publicUrl.searchParams.set('token', tokenRegex[1])
|
||||
}
|
||||
}
|
||||
|
||||
return publicUrl.href
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue