mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-31 11:59:10 +00:00
refactor(cuesheet): images are referenced by link only
A path to a local file resolves on the machine running ontime, but not for the clients we serve the cuesheet to, so we no longer accept it. Validation now parses the value as a URL and checks the protocol, which also rejects malformed values that the previous prefix check let through. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CKXcDrZoQXbJpaXiLi1aff
This commit is contained in:
@@ -3,20 +3,22 @@ import { describe, expect, test } from 'vitest';
|
|||||||
import { isValidImageSource } from '../cuesheet-table/cuesheet-table-elements/EditableImage';
|
import { isValidImageSource } from '../cuesheet-table/cuesheet-table-elements/EditableImage';
|
||||||
|
|
||||||
describe('isValidImageSource()', () => {
|
describe('isValidImageSource()', () => {
|
||||||
test('accepts images hosted elsewhere', () => {
|
test('accepts links to a hosted image', () => {
|
||||||
expect(isValidImageSource('https://example.com/image.png')).toBe(true);
|
expect(isValidImageSource('https://example.com/image.png')).toBe(true);
|
||||||
expect(isValidImageSource('http://example.com/image.png')).toBe(true);
|
expect(isValidImageSource('http://example.com/image.png')).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('accepts images served by ontime', () => {
|
test('rejects references to a local file, they would not resolve for our clients', () => {
|
||||||
expect(isValidImageSource('/user/image.png')).toBe(true);
|
expect(isValidImageSource('/user/image.png')).toBe(false);
|
||||||
expect(isValidImageSource('/external/image.png')).toBe(true);
|
expect(isValidImageSource('user/image.png')).toBe(false);
|
||||||
|
expect(isValidImageSource('file:///Users/me/image.png')).toBe(false);
|
||||||
|
expect(isValidImageSource('C:\\images\\image.png')).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('rejects values which would not resolve to an image', () => {
|
test('rejects values which would not resolve to an image', () => {
|
||||||
expect(isValidImageSource('www.example.com/image.png')).toBe(false);
|
expect(isValidImageSource('www.example.com/image.png')).toBe(false);
|
||||||
expect(isValidImageSource('example.com/image.png')).toBe(false);
|
expect(isValidImageSource('example.com/image.png')).toBe(false);
|
||||||
expect(isValidImageSource('user/image.png')).toBe(false);
|
expect(isValidImageSource('https://')).toBe(false);
|
||||||
expect(isValidImageSource('some text')).toBe(false);
|
expect(isValidImageSource('some text')).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+9
-4
@@ -16,11 +16,16 @@ interface EditableImageProps {
|
|||||||
export default memo(EditableImage);
|
export default memo(EditableImage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An image is either hosted somewhere else
|
* Images are referenced by link: anything local to the machine running ontime
|
||||||
* or served by ontime itself (eg. a file placed in the user folder)
|
* would not resolve for the clients we serve the cuesheet to
|
||||||
*/
|
*/
|
||||||
export function isValidImageSource(value: string): boolean {
|
export function isValidImageSource(value: string): boolean {
|
||||||
return value.startsWith('http://') || value.startsWith('https://') || value.startsWith('/');
|
try {
|
||||||
|
const url = new URL(value);
|
||||||
|
return url.protocol === 'http:' || url.protocol === 'https:';
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditableImage({ initialValue, fieldLabel, readOnly, updateValue }: EditableImageProps) {
|
function EditableImage({ initialValue, fieldLabel, readOnly, updateValue }: EditableImageProps) {
|
||||||
@@ -73,7 +78,7 @@ function EditableImage({ initialValue, fieldLabel, readOnly, updateValue }: Edit
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isRejected && <span className={style.message}>Use a link (https://...) or a file in ontime (/user/...)</span>}
|
{isRejected && <span className={style.message}>Images are referenced by link (https://...)</span>}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user