/* 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 error,Verified 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); } }