Files
24kycj 88c6ce8ccc 重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构
- 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐
- 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作
- 新增管理后台、支付与云端文件 API,更新 README 与项目规范

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 18:17:39 +08:00

74 lines
2.7 KiB
JavaScript

(function () {
'use strict';
var ALLOWED = /^(index\.web\.html|member\.web\.html|login\.web\.html|register\.web\.html|admin\/(?:index|login)\.html|index\.html|login\.html|design[12]\.web\.html)(\?.*)?$/i;
function soonEscapeHtml(s) {
if (s == null) return '';
return String(s)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
function soonSafeRedirect(urlParam, fallback) {
fallback = fallback || 'index.web.html';
if (!urlParam || typeof urlParam !== 'string') return fallback;
var raw = urlParam.trim();
if (!raw) return fallback;
try {
raw = decodeURIComponent(raw);
} catch (e) {
return fallback;
}
var lower = raw.toLowerCase();
if (lower.indexOf('//') === 0 || lower.indexOf('http:') === 0 || lower.indexOf('https:') === 0 ||
lower.indexOf('javascript:') === 0 || raw.indexOf('..') !== -1 || raw.indexOf('\\') !== -1) {
return fallback;
}
var pathOnly = raw.split(/[#?]/)[0];
if (ALLOWED.test(pathOnly)) return raw;
try {
var resolved = new URL(raw, window.location.href);
if (resolved.origin !== window.location.origin) return fallback;
var path = resolved.pathname.replace(/^.*\/pages\//, '').replace(/^\//, '');
if (!ALLOWED.test(path.split(/[#?]/)[0])) return fallback;
return path + resolved.search + resolved.hash;
} catch (e) {
return fallback;
}
}
function soonSafeImageUrl(url, fallback) {
if (!url || typeof url !== 'string') return fallback || '';
var raw = url.trim();
if (!raw) return fallback || '';
var lower = raw.toLowerCase();
if (lower.indexOf('javascript:') === 0 || lower.indexOf('data:text/html') === 0 ||
lower.indexOf('vbscript:') === 0 || lower.indexOf('//') === 0) {
return fallback || '';
}
if (lower.indexOf('data:image/') === 0) return raw;
if (lower.indexOf('blob:') === 0) return raw;
if (lower.indexOf('https:') === 0) return raw;
if (lower.indexOf('http:') === 0) {
try {
var apiBase = (typeof window !== 'undefined' && window.SOON_DEPLOY_CONFIG && window.SOON_DEPLOY_CONFIG.api_v1_base);
if (apiBase && new URL(raw).origin === new URL(apiBase).origin) return raw;
} catch (e) { /* fall through */ }
}
if (raw.indexOf('../') === 0 || raw.indexOf('./') === 0 || raw.indexOf('/') === 0) {
try {
var resolved = new URL(raw, window.location.href);
if (resolved.origin === window.location.origin) return raw;
} catch (e) { /* fall through */ }
}
return fallback || '';
}
window.soonEscapeHtml = soonEscapeHtml;
window.soonSafeRedirect = soonSafeRedirect;
window.soonSafeImageUrl = soonSafeImageUrl;
})();