Files
bbq/src/app/shared/components/captcha/dun.ts
2021-11-26 16:34:35 +08:00

354 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable no-undef */
let errorCallbackCount: any = 0;
// 常量
const DEFAULT_VALIDATE =
'QjGAuvoHrcpuxlbw7cp4WnIbbjzG4rtSlpc7EDovNHQS._ujzPZpeCInSxIT4WunuDDh8dRZYF2GbBGWyHlC6q5uEi9x-TXT9j7J705vSsBXyTar7aqFYyUltKYJ7f4Y2TXm_1Mn6HFkb4M7URQ_rWtpxQ5D6hCgNJYC0HpRE7.2sttqYKLoi7yP1KHzK-PptdHHkVwb77cwS2EJW7Mj_PsOtnPBubTmTZLpnRECJR99dWTVC11xYG0sx8dJNLUxUFxEyzTfX4nSmQz_T5sXATRKHtVAz7nmV0De5unmflfAlUwMGKlCT1khBtewlgN5nHvyxeD8Z1_fPVzi9oznl-sbegj6lKfCWezmLcwft8.4yaVh6SlzXJq-FnSK.euq9OBd5jYc82ge2_hEca1fGU--SkPRzgwkzew4O4qjdS2utdPwFONnhKAIMJRPUmCV4lPHG1OeRDvyNV8sCnuFMw7leasxIhPoycl4pm5bNy70Z1laozEGJgItVNr3'; // 默认validate
const FALLBACK_LANG: any = {
'zh-CN': '前方拥堵,已自动跳过验证',
en: 'captcha errorVerified automatically',
};
const CACHE_MIN = 1000 * 60; // 缓存时长单位1分钟
const REQUEST_SCRIPT_ERROR = 502;
const RESOURCE_CACHE: any = {};
// 工具函数
function loadScript(src: any, cb: any) {
const head: any = document.head || document.getElementsByTagName('head')[0];
const script: any = document.createElement('script');
cb = cb || function () {};
script.type = 'text/javascript';
script.charset = 'utf8';
script.async = true;
script.src = src;
if (!('onload' in script)) {
script.onreadystatechange = function () {
if (this.readyState !== 'complete' && this.readyState !== 'loaded') {
return;
}
this.onreadystatechange = null;
cb(null, script); // there is no way to catch loading errors in IE8
};
}
script.onload = function () {
this.onerror = this.onload = null;
cb(null, script);
};
script.onerror = function () {
// because even IE9 works not like others
this.onerror = this.onload = null;
cb(new Error('Failed to load ' + this.src), script);
};
head.appendChild(script);
}
function joinUrl(protocol: any, host: any, path: any) {
protocol = protocol || '';
host = host || '';
path = path || '';
if (protocol) {
protocol = protocol.replace(/:?\/{0,2}$/, '://');
}
if (host) {
const matched = host.match(/^([-0-9a-zA-Z.:]*)(\/.*)?/);
host = matched[1];
path = (matched[2] || '') + '/' + path;
}
!host && (protocol = '');
return protocol + host + path;
}
function setDomText(el: any, value: any) {
if (value === undefined) {
return;
}
const nodeType = el.nodeType;
if (nodeType === 1 || nodeType === 11 || nodeType === 9) {
if (typeof el.textContent === 'string') {
el.textContent = value;
} else {
el.innerText = value;
}
}
}
function queryAllByClassName(selector: any, node: any) {
node = node || document;
if (node.querySelectorAll) {
return node.querySelectorAll(selector);
}
if (!/^\.[^.]+$/.test(selector)) {
return [];
}
if (node.getElementsByClassName) {
return node.getElementsByClassName(selector);
}
const children = node.getElementsByTagName('*');
let current;
const result = [];
const className = selector.slice(1);
for (let i = 0, l = children.length; i < l; i++) {
current = children[i];
if (~(' ' + current.className + ' ').indexOf(' ' + className + ' ')) {
result.push(current);
}
}
return result;
}
function assert(condition: any, msg: any) {
if (!condition) {
throw new Error('[NECaptcha] ' + msg);
}
}
function isInteger(val: any) {
if (Number.isInteger) {
return Number.isInteger(val);
}
return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
}
function isArray(val: any) {
if (Array.isArray) {
return Array.isArray(val);
}
return Object.prototype.toString.call(val) === '[object Array]';
}
function ObjectAssign(a: any, b: any, c: any) {
if (Object.assign) {
// return Object.assign.apply(null, arguments);
return Object.assign.apply(null, arguments as any);
}
const target: any = {};
for (let index = 1; index < arguments.length; index++) {
const source = arguments[index];
if (source != null) {
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
}
return target;
}
function getTimestamp(msec: any) {
msec = !msec && msec !== 0 ? msec : 1;
return parseInt((new Date().valueOf() / msec).toString(), 10);
}
// 降级方案
function normalizeFallbackConfig(customConfig: any) {
const siteProtocol = window.location.protocol.replace(':', '');
const defaultConf: any = {
protocol: siteProtocol === 'http' ? 'http' : 'https',
lang: 'zh-CN',
errorFallbackCount: 3,
};
const config: any = ObjectAssign({}, defaultConf, customConfig);
const errorFallbackCount: any = config.errorFallbackCount;
assert(
errorFallbackCount === undefined || (isInteger(errorFallbackCount) && errorFallbackCount >= 1),
"errorFallbackCount must be an integer, and it's value greater than or equal one",
);
return config;
}
function loadResource(config: any, cb: any) {
if ((window as any).initNECaptcha) {
return cb(null);
}
function genUrl(server: any) {
const path = 'load.min.js';
let _urls = [];
if (isArray(server)) {
for (let i = 0, len = server.length; i < len; i++) {
_urls.push(joinUrl(config.protocol, server[i], path));
}
} else {
const url = joinUrl(config.protocol, server, path);
_urls = [url, url];
}
return _urls;
}
const urls = genUrl(config.staticServer || ['cstaticdun.126.net', 'cstaticdun1.126.net', 'cstatic.dun.163yun.com']);
function step(i: any) {
const url = urls[i] + '?v=' + getTimestamp(CACHE_MIN);
loadScript(url, function (err: any) {
if (err || !(window as any).initNECaptcha) {
// loadjs的全局变量
i = i + 1;
if (i === urls.length) {
return cb(new Error('Failed to load script(' + url + ').' + (err ? err.message : 'unreliable script')));
}
return step(i);
}
return cb(null);
});
}
step(0);
}
/*
* entry: initNECaptchaWithFallback
* options:
* errorFallbackCount: 触发降级的错误次数,默认第三次错误降级
* defaultFallback: 是否开启默认降级
* onFallback: 自定义降级方案参数为默认validate
*/
export function initNECaptchaWithFallback(options: any, onload: any, onerror: any) {
let captchaIns: any = null;
const config = normalizeFallbackConfig(options);
const defaultFallback = config.defaultFallback !== false;
const langPkg = FALLBACK_LANG[config.lang === 'zh-CN' ? config.lang : 'en'];
const storeKey = window.location.pathname + '_' + config.captchaId + '_NECAPTCHA_ERROR_COUNTS';
try {
errorCallbackCount = parseInt(localStorage.getItem(storeKey)?.toString() || '0', 10);
} catch (error) {}
const fallbackFn = !defaultFallback
? config.onFallback || function () {}
: (validate: any) => {
function setFallbackTip(instance: any) {
if (!instance) {
return;
}
setFallbackTip(instance._captchaIns);
if (!instance.$el) {
return;
}
const tipEles = queryAllByClassName('.yidun-fallback__tip', instance.$el);
if (!tipEles.length) {
return;
}
// 确保在队列的最后
setTimeout(() => {
for (let i = 0, l = tipEles.length; i < l; i++) {
setDomText(tipEles[i], langPkg);
}
}, 0);
}
setFallbackTip(captchaIns);
config.onVerify && config.onVerify(null, { validate: validate });
};
const noFallback = !defaultFallback && !config.onFallback;
const proxyOnError = (error: any) => {
errorCallbackCount++;
if (errorCallbackCount < config.errorFallbackCount) {
try {
localStorage.setItem(storeKey, errorCallbackCount);
} catch (err) {}
onerror(error);
} else {
fallbackFn(DEFAULT_VALIDATE);
proxyRefresh();
noFallback && onerror(error);
}
};
const proxyRefresh = () => {
errorCallbackCount = 0;
try {
localStorage.setItem(storeKey, '0');
} catch (err) {}
};
const triggerInitError = (error: any) => {
if (initialTimer && initialTimer.isError()) {
initialTimer.resetError();
return;
}
initialTimer && initialTimer.resetTimer();
noFallback ? onerror(error) : proxyOnError(error);
};
config.onError = (error: any) => {
if (initialTimer && initialTimer.isError()) {
initialTimer.resetError();
}
proxyOnError(error);
};
config.onDidRefresh = () => {
if (initialTimer && initialTimer.isError()) {
initialTimer.resetError();
}
proxyRefresh();
};
const initialTimer = options.initTimeoutError ? options.initTimeoutError(proxyOnError) : null; // initialTimer is only for mobile.html
const loadResolve = () => {
(window as any).initNECaptcha(
config,
(instance: any) => {
if (initialTimer && initialTimer.isError()) {
return;
}
initialTimer && initialTimer.resetTimer();
captchaIns = instance;
onload && onload(instance);
},
triggerInitError,
);
};
const cacheId = 'load-queue';
if (!RESOURCE_CACHE[cacheId]) {
RESOURCE_CACHE[cacheId] = {
rejects: [],
resolves: [],
status: 'error',
};
}
if (RESOURCE_CACHE[cacheId].status === 'error') {
RESOURCE_CACHE[cacheId].status = 'pending';
loadResource(config, (error: any) => {
if (error) {
const err: any = new Error();
err.code = REQUEST_SCRIPT_ERROR;
err.message = config.staticServer + '/load.min.js error';
const rejects = RESOURCE_CACHE[cacheId].rejects;
for (let i = 0, iLen = rejects.length; i < iLen; i++) {
rejects.pop()(err);
}
RESOURCE_CACHE[cacheId].status = 'error';
} else {
RESOURCE_CACHE[cacheId].status = 'done';
const resolves = RESOURCE_CACHE[cacheId].resolves;
for (let j = 0, jLen = resolves.length; j < jLen; j++) {
resolves.pop()();
}
}
});
} else if (RESOURCE_CACHE[cacheId].status === 'done') {
loadResolve();
}
if (RESOURCE_CACHE[cacheId].status === 'pending') {
RESOURCE_CACHE[cacheId].rejects.push(function loadReject(err: any) {
triggerInitError(err);
});
RESOURCE_CACHE[cacheId].resolves.push(loadResolve);
}
}