const config = { no_ref: "off", //Control the HTTP referrer header, if you want to create an anonymous link that will hide the HTTP Referer header, please set to "on" . theme:"theme/captcha",//Homepage theme, use the empty value for default theme. To use urlcool theme, please fill with "theme/urlcool" . If you need captcha feature, you need to use captcha theme. cors: "on",//Allow Cross-origin resource sharing for API requests. unique_link:true,//If it is true, the same long url will be shorten into the same short url custom_link:false,//Allow users to customize the short url. safe_browsing_api_key: "", //Enter Google Safe Browsing API Key to enable url safety check before redirect. // CAPTCHA Configuration captcha: { enabled: true, // Master switch for CAPTCHA service api_endpoint: "https://captcha.gurl.eu.org/api", // CAP Worker API endpoint require_on_create: true, // Require CAPTCHA when creating short links require_on_access: true, // Require CAPTCHA when accessing short links timeout: 5000, // API request timeout in milliseconds fallback_on_error: true, // Allow operations when CAPTCHA service is down max_retries: 2, // Maximum retry attempts for CAPTCHA API calls } } const html404 = `
The url you visit is not found.
Fork me on GitHub ` let response_header={ "content-type": "text/html;charset=UTF-8", } if (config.cors=="on"){ response_header={ "content-type": "text/html;charset=UTF-8", "Access-Control-Allow-Origin":"*", "Access-Control-Allow-Methods": "POST", } } async function randomString(len) { len = len || 6; let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ let maxPos = $chars.length; let result = ''; for (let i = 0; i < len; i++) { result += $chars.charAt(Math.floor(Math.random() * maxPos)); } return result; } async function sha512(url){ url = new TextEncoder().encode(url) const url_digest = await crypto.subtle.digest( { name: "SHA-512", }, url, // The data you want to hash as an ArrayBuffer ) const hashArray = Array.from(new Uint8Array(url_digest)); // convert buffer to byte array const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); //console.log(hashHex) return hashHex } async function checkURL(URL){ let str=URL; let Expression=/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/; let objExp=new RegExp(Expression); if(objExp.test(str)==true){ if (str[0] == 'h') return true; else return false; }else{ return false; } } async function save_url(URL){ let random_key=await randomString() let is_exist=await LINKS.get(random_key) console.log(is_exist) if (is_exist == null) return await LINKS.put(random_key, URL),random_key else return save_url(URL) } async function is_url_exist(url_sha512){ let is_exist = await LINKS.get(url_sha512) console.log(is_exist) if (is_exist == null) { return false }else{ return is_exist } } async function is_url_safe(url){ let raw = JSON.stringify({"client":{"clientId":"Url-Shorten-Worker","clientVersion":"1.0.7"},"threatInfo":{"threatTypes":["MALWARE","SOCIAL_ENGINEERING","POTENTIALLY_HARMFUL_APPLICATION","UNWANTED_SOFTWARE"],"platformTypes":["ANY_PLATFORM"],"threatEntryTypes":["URL"],"threatEntries":[{"url":url}]}}); let requestOptions = { method: 'POST', body: raw, redirect: 'follow' }; let result = await fetch("https://safebrowsing.googleapis.com/v4/threatMatches:find?key="+config.safe_browsing_api_key, requestOptions) result = await result.json() console.log(result) if (Object.keys(result).length === 0){ return true }else{ return false } } // ============ CAPTCHA Service Integration ============ /** * Validates CAPTCHA token with retry and fallback mechanism * @param {string} token - The CAPTCHA token to validate * @param {boolean} keepToken - Whether to keep the token for reuse * @returns {Promise<{success: boolean, error?: string, degraded?: boolean}>} */ async function validateCaptchaToken(token, keepToken = false) { // If CAPTCHA is disabled, always return success if (!config.captcha.enabled) { return { success: true, degraded: false }; } // Validate token format if (!token || typeof token !== 'string' || token.length < 10) { return { success: false, error: 'Invalid token format' }; } let lastError = null; const maxRetries = config.captcha.max_retries || 2; // Retry mechanism for resilience for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), config.captcha.timeout); const response = await fetch(`${config.captcha.api_endpoint}/validate`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'User-Agent': 'Url-Shorten-Worker/1.0.7', }, body: JSON.stringify({ token, keepToken }), signal: controller.signal, }); clearTimeout(timeoutId); // Handle various HTTP status codes if (response.ok) { const result = await response.json(); return { success: result.success === true, degraded: false }; } // Handle specific error codes if (response.status === 400 || response.status === 410 || response.status === 404 || response.status === 409) { // Client error, no need to retry return { success: false, error: 'Invalid or expired token' }; } lastError = `HTTP ${response.status}`; } catch (error) { lastError = error.name === 'AbortError' ? 'Timeout' : error.message; console.error(`CAPTCHA validation attempt ${attempt + 1} failed:`, lastError); // Exponential backoff before retry (except on last attempt) if (attempt < maxRetries) { await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 100)); } } } // Service degradation: if fallback is enabled, allow operation if (config.captcha.fallback_on_error) { console.warn(`CAPTCHA service degraded: ${lastError}. Allowing operation due to fallback policy.`); return { success: true, degraded: true }; } return { success: false, error: lastError || 'CAPTCHA service unavailable' }; } /** * Checks if CAPTCHA is required for the current operation * @param {string} operation - 'create' or 'access' * @returns {boolean} */ function isCaptchaRequired(operation) { if (!config.captcha.enabled) { return false; } switch (operation) { case 'create': return config.captcha.require_on_create; case 'access': return config.captcha.require_on_access; default: return false; } } /** * Extracts CAPTCHA token from request * @param {Request} request - The incoming request * @returns {PromisePlease complete the CAPTCHA below to access this link.
${validation.error || 'CAPTCHA verification failed'}
Try again `, { headers: { "content-type": "text/html;charset=UTF-8", }, status: 403 }) } if (validation.degraded) { console.warn("Access granted under CAPTCHA service degradation") } } // Safe browsing check if (config.safe_browsing_api_key) { if (!(await is_url_safe(location))) { let warning_page = await fetch("https://xytom.github.io/Url-Shorten-Worker/safe-browsing.html") warning_page = await warning_page.text() warning_page = warning_page.replace(/{Replace}/gm, location) return new Response(warning_page, { headers: { "content-type": "text/html;charset=UTF-8", }, }) } } // Redirect to target URL if (config.no_ref == "on") { let no_ref = await fetch("https://xytom.github.io/Url-Shorten-Worker/no-ref.html") no_ref = await no_ref.text() no_ref = no_ref.replace(/{Replace}/gm, location) return new Response(no_ref, { headers: { "content-type": "text/html;charset=UTF-8", }, }) } else { return Response.redirect(location, 302) } } // If request not in kv, return 404 return new Response(html404, { headers: { "content-type": "text/html;charset=UTF-8", }, status: 404 }) } addEventListener("fetch", async event => { event.respondWith(handleRequest(event.request)) })