fix: serve MindSpace public assets as same-origin relative URLs

Rewrite absolute tkmind asset download links to /api/... at delivery time
and strip base tags that violate public page CSP, so images load on any host.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-03 23:02:47 +08:00
parent f543a91cc4
commit c3c487a8fb
3 changed files with 65 additions and 13 deletions
+27 -11
View File
@@ -26,15 +26,31 @@ export function verifyPublicAssetToken(assetId, token, secret) {
);
}
export function appendPublicAssetTokens(html, secret) {
const source = String(html ?? '');
if (!source || !source.includes('/api/mindspace/v1/assets/')) return source;
return source.replace(
/((?:https?:\/\/[^"'<>\\\s]+)?\/api\/mindspace\/v1\/assets\/([a-z0-9-]+)\/download)(\?[^"'<>\\\s)]*)?/gi,
(value, base, assetId, query = '') => {
if (/(?:\?|&|&amp;)public_token=/.test(query)) return value;
const separator = query ? (query.includes('&amp;') ? '&amp;' : '&') : '?';
return `${base}${query}${separator}public_token=${publicAssetToken(assetId, secret)}`;
},
);
const PUBLIC_ASSET_DOWNLOAD_PATTERN =
/((?:https?:\/\/[^"'<>\\\s]+)?\/api\/mindspace\/v1\/assets\/([a-z0-9-]+)\/download)(\?[^"'<>\\\s)]*)?/gi;
export function stripPublicHtmlBaseTag(html) {
return String(html ?? '').replace(/<base\b[^>]*>/gi, '');
}
export function normalizePublicAssetReferences(html) {
const source = String(html ?? '');
if (!source.includes('/api/mindspace/v1/assets/')) return source;
return source.replace(PUBLIC_ASSET_DOWNLOAD_PATTERN, (_value, _base, assetId, query = '') => {
return `/api/mindspace/v1/assets/${assetId}/download${query ?? ''}`;
});
}
export function appendPublicAssetTokens(html, secret) {
const source = normalizePublicAssetReferences(html);
if (!source || !source.includes('/api/mindspace/v1/assets/')) return source;
return source.replace(PUBLIC_ASSET_DOWNLOAD_PATTERN, (value, _base, assetId, query = '') => {
if (/(?:\?|&|&amp;)public_token=/.test(query)) return value;
const separator = query ? (query.includes('&amp;') ? '&amp;' : '&') : '?';
return `/api/mindspace/v1/assets/${assetId}/download${query}${separator}public_token=${publicAssetToken(assetId, secret)}`;
});
}
export function preparePublicHtmlAssetDelivery(html, secret) {
return appendPublicAssetTokens(stripPublicHtmlBaseTag(html), secret);
}