Point hotlink viewer links at the viewer page path.
Hotlink share links were using the zero-knowledge viewer URL. The direct image URL stays separate for embeds.
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { buildHotlinkViewerPath } from '@/utils/share/buildHotlinkViewerPath';
|
||||
|
||||
describe('buildHotlinkViewerPath', () => {
|
||||
it('places upload id and secret in the viewer path', () => {
|
||||
expect(buildHotlinkViewerPath('upload-uuid', 'url-safe-secret')).toBe('/h/upload-uuid/url-safe-secret');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
export const buildHotlinkViewerPath = (uploadId: string, secret: string): string => `/h/${uploadId}/${secret}`;
|
||||
@@ -0,0 +1,78 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { config } from '@/config';
|
||||
import type { UploadQueueEntry } from '@/types/upload/UploadQueueEntry';
|
||||
import { buildUploadedShareUrls } from '@/utils/share/buildUploadedShareUrls';
|
||||
|
||||
const { clearnet, onion } = config.shareOrigins;
|
||||
|
||||
const uploaded = (
|
||||
mode: 'zk' | 'hotlink',
|
||||
overrides: Partial<Extract<UploadQueueEntry, { status: 'uploaded' }>> = {}
|
||||
): UploadQueueEntry => ({
|
||||
status: 'uploaded',
|
||||
message: 'Uploaded',
|
||||
uploadId: 'upload-id',
|
||||
deleteToken: 'delete-token',
|
||||
urlSecret: 'url-secret',
|
||||
mode,
|
||||
...overrides
|
||||
});
|
||||
|
||||
describe('buildUploadedShareUrls', () => {
|
||||
it('returns null unless the upload succeeded', () => {
|
||||
const statuses = ['idle', 'queued', 'preparing', 'uploading', 'failed', 'skipped'] as const;
|
||||
|
||||
for (const status of statuses) {
|
||||
expect(buildUploadedShareUrls({ status, message: status }, 'photo.jpg')).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('builds zero-knowledge viewer, delete, and clearnet text embeds', () => {
|
||||
const urls = buildUploadedShareUrls(
|
||||
uploaded('zk', { deleteToken: 'a+b/c', urlSecret: 'fragment_key' }),
|
||||
'a <photo> & "shot"'
|
||||
);
|
||||
|
||||
expect(urls).toEqual({
|
||||
mode: 'zk',
|
||||
viewer: {
|
||||
clearnet: `${clearnet}/v/upload-id#fragment_key`,
|
||||
onion: `${onion}/v/upload-id#fragment_key`
|
||||
},
|
||||
delete: {
|
||||
clearnet: `${clearnet}/d/upload-id?token=a%2Bb%2Fc`,
|
||||
onion: `${onion}/d/upload-id?token=a%2Bb%2Fc`
|
||||
},
|
||||
markdownLink: `[a <photo> & "shot"](${clearnet}/v/upload-id#fragment_key)`,
|
||||
htmlLink: `<a href="${clearnet}/v/upload-id#fragment_key">a <photo> & "shot"</a>`
|
||||
});
|
||||
});
|
||||
|
||||
it('builds hotlink viewer, direct image, delete, and clearnet image embeds', () => {
|
||||
const urls = buildUploadedShareUrls(
|
||||
uploaded('hotlink', { deleteToken: 'a+b/c', urlSecret: 'path_secret' }),
|
||||
'a <photo> & "shot"'
|
||||
);
|
||||
|
||||
const directClearnet = `${clearnet}/i/upload-id/path_secret`;
|
||||
|
||||
expect(urls).toEqual({
|
||||
mode: 'hotlink',
|
||||
viewer: {
|
||||
clearnet: `${clearnet}/h/upload-id/path_secret`,
|
||||
onion: `${onion}/h/upload-id/path_secret`
|
||||
},
|
||||
direct: {
|
||||
clearnet: directClearnet,
|
||||
onion: `${onion}/i/upload-id/path_secret`
|
||||
},
|
||||
delete: {
|
||||
clearnet: `${clearnet}/d/upload-id?token=a%2Bb%2Fc`,
|
||||
onion: `${onion}/d/upload-id?token=a%2Bb%2Fc`
|
||||
},
|
||||
bbcode: `[img]${directClearnet}[/img]`,
|
||||
markdownImage: ``,
|
||||
htmlImage: `<img src="${directClearnet}" alt="a <photo> & "shot"" />`
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,7 @@ import { buildMarkdownLink } from '@/utils/share/buildMarkdownLink';
|
||||
import { config } from '@/config';
|
||||
import { buildDeletePath } from '@/utils/share/buildDeletePath';
|
||||
import { buildHotlinkImagePath } from '@/utils/share/buildHotlinkImagePath';
|
||||
import { buildHotlinkViewerPath } from '@/utils/share/buildHotlinkViewerPath';
|
||||
import { buildSiteShareUrl } from '@/utils/share/buildSiteShareUrl';
|
||||
import { buildZkViewerPath } from '@/utils/share/buildZkViewerPath';
|
||||
|
||||
@@ -22,23 +23,21 @@ export const buildUploadedShareUrls = (
|
||||
}
|
||||
|
||||
const deletePath = buildDeletePath(upload.uploadId, upload.deleteToken);
|
||||
const viewerPath = buildZkViewerPath(upload.uploadId, upload.urlSecret);
|
||||
|
||||
const viewer = {
|
||||
clearnet: buildSiteShareUrl(clearnet, viewerPath),
|
||||
onion: buildSiteShareUrl(onion, viewerPath)
|
||||
};
|
||||
|
||||
const deleteUrls = {
|
||||
clearnet: buildSiteShareUrl(clearnet, deletePath),
|
||||
onion: buildSiteShareUrl(onion, deletePath)
|
||||
};
|
||||
|
||||
const core = { viewer, delete: deleteUrls };
|
||||
|
||||
if (upload.mode === 'hotlink') {
|
||||
const viewerPath = buildHotlinkViewerPath(upload.uploadId, upload.urlSecret);
|
||||
const directPath = buildHotlinkImagePath(upload.uploadId, upload.urlSecret);
|
||||
|
||||
const viewer = {
|
||||
clearnet: buildSiteShareUrl(clearnet, viewerPath),
|
||||
onion: buildSiteShareUrl(onion, viewerPath)
|
||||
};
|
||||
|
||||
const direct = {
|
||||
clearnet: buildSiteShareUrl(clearnet, directPath),
|
||||
onion: buildSiteShareUrl(onion, directPath)
|
||||
@@ -46,7 +45,8 @@ export const buildUploadedShareUrls = (
|
||||
|
||||
return {
|
||||
mode: 'hotlink',
|
||||
...core,
|
||||
delete: deleteUrls,
|
||||
viewer,
|
||||
direct,
|
||||
bbcode: buildBbcodeImage(direct.clearnet),
|
||||
markdownImage: buildMarkdownImage(direct.clearnet, fileLabel),
|
||||
@@ -54,9 +54,17 @@ export const buildUploadedShareUrls = (
|
||||
};
|
||||
}
|
||||
|
||||
const viewerPath = buildZkViewerPath(upload.uploadId, upload.urlSecret);
|
||||
|
||||
const viewer = {
|
||||
clearnet: buildSiteShareUrl(clearnet, viewerPath),
|
||||
onion: buildSiteShareUrl(onion, viewerPath)
|
||||
};
|
||||
|
||||
return {
|
||||
mode: 'zk',
|
||||
...core,
|
||||
delete: deleteUrls,
|
||||
viewer,
|
||||
markdownLink: buildMarkdownLink(fileLabel, viewer.clearnet),
|
||||
htmlLink: buildHtmlLink(fileLabel, viewer.clearnet)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user