Skip to content

Instantly share code, notes, and snippets.

@chenxuan520
Last active June 24, 2025 17:40
Show Gist options
  • Select an option

  • Save chenxuan520/7f6c0017b774955726eaca2a20d6b5ba to your computer and use it in GitHub Desktop.

Select an option

Save chenxuan520/7f6c0017b774955726eaca2a20d6b5ba to your computer and use it in GitHub Desktop.
'use strict'
/**
* this file from https://github.com/hunshcn/gh-proxy
*/
// index.html interface
async function indexInterface() {
const text = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>github clone/文件下载</title>
<!-- Tailwind CSS v3 -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Font Awesome -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- Tailwind配置 -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#0D1117',
secondary: '#58A6FF',
accent: '#238636',
neutral: '#161B22',
'neutral-dark': '#30363D',
'text-light': '#C9D1D9',
'text-muted': '#8B949E',
},
fontFamily: {
inter: ['Inter', 'system-ui', 'sans-serif'],
},
}
}
}
</script>
<!-- 自定义工具类 -->
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.shadow-github {
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.25);
}
.border-glow {
box-shadow: 0 0 0 3px rgba(56, 139, 253, 0.3);
}
}
</style>
</head>
<body class="bg-primary text-text-light min-h-screen flex flex-col">
<!-- 顶部导航 -->
<header class="bg-neutral text-text-light py-4 px-6 shadow-md border-b border-neutral-dark">
<div class="container mx-auto flex justify-between items-center">
<div class="flex items-center space-x-2">
<i class="fa fa-github text-2xl text-white"></i>
<span class="font-bold text-xl">011203.xyz</span>
</div>
<nav>
<ul class="flex space-x-6">
</ul>
</nav>
</div>
</header>
<!-- 主要内容 -->
<main class="flex-grow flex items-center justify-center p-6">
<div class="container mx-auto max-w-3xl">
<div class="text-center mb-10">
<h1 class="text-[clamp(2rem,5vw,3.5rem)] font-bold text-white mb-4">clone.011203.xyz</h1>
<p class="text-text-muted text-lg max-w-2xl mx-auto">github 文件下载</p>
</div>
<div class="bg-neutral rounded-xl shadow-github p-8 border border-neutral-dark">
<!-- 内容输入框 -->
<div class="mb-6">
<label for="content" class="block text-sm font-medium text-text-light mb-2">请输入github文件或仓库链接</label>
<textarea
id="content"
class="w-full p-4 bg-primary border border-neutral-dark rounded-lg text-text-light focus:ring-2 focus:ring-secondary focus:border-secondary transition-all duration-200 h-24 resize-none"
placeholder="请输入要添加到URL的内容..."
></textarea>
</div>
<!-- 链接显示区域 -->
<div class="space-y-4 mb-6">
<!-- 文件下载链接 -->
<div>
<label class="block text-sm font-medium text-text-light mb-2">文件下载链接</label>
<div class="flex items-center">
<input
id="downloadUrl"
type="text"
class="flex-grow p-2 bg-primary border border-neutral-dark rounded-l-lg text-text-light focus:ring-2 focus:ring-secondary focus:border-secondary transition-all duration-200"
readonly
placeholder="生成的链接将显示在这里"
>
<button
id="copyDownloadBtn"
class="bg-neutral-dark hover:bg-neutral-dark/80 text-text-light px-3 py-2 rounded-r-lg transition-colors duration-200"
>
<i class="fa fa-copy"></i>
</button>
</div>
</div>
<!-- Clone链接 -->
<div>
<label class="block text-sm font-medium text-text-light mb-2">Clone链接</label>
<div class="flex items-center">
<input
id="cloneUrl"
type="text"
class="flex-grow p-2 bg-primary border border-neutral-dark rounded-l-lg text-text-light focus:ring-2 focus:ring-secondary focus:border-secondary transition-all duration-200"
readonly
placeholder="生成的链接将显示在这里"
>
<button
id="copyCloneBtn"
class="bg-neutral-dark hover:bg-neutral-dark/80 text-text-light px-3 py-2 rounded-r-lg transition-colors duration-200"
>
<i class="fa fa-copy"></i>
</button>
</div>
</div>
</div>
<!-- 生成按钮 -->
<div class="flex justify-center">
<button
id="generateBtn"
class="bg-accent hover:bg-accent/90 text-white font-medium py-3 px-8 rounded-lg transition-all duration-200 flex items-center shadow-md hover:shadow-lg transform hover:-translate-y-0.5"
>
<i class="fa fa-link mr-2"></i>
生成链接
</button>
</div>
</div>
</div>
</main>
<!-- 页脚 -->
<footer class="bg-neutral text-text-muted py-6 px-6 border-t border-neutral-dark">
<div class="container mx-auto text-center">
<p>仅供学习, 请勿用于任何其他用途</p>
<div class="mt-4 flex justify-center space-x-4">
<a href="https://gist.github.com/chenxuan520/7f6c0017b774955726eaca2a20d6b5ba" class="hover:text-secondary transition-colors duration-200"><i class="fa fa-github"></i></a>
</div>
</div>
</footer>
<!-- JavaScript -->
<script>
// 获取元素
const contentTextarea = document.getElementById('content');
const generateBtn = document.getElementById('generateBtn');
const downloadUrl = document.getElementById('downloadUrl');
const cloneUrl = document.getElementById('cloneUrl');
const copyDownloadBtn = document.getElementById('copyDownloadBtn');
const copyCloneBtn = document.getElementById('copyCloneBtn');
// 生成按钮点击事件
generateBtn.addEventListener('click', () => {
const content = contentTextarea.value.trim();
if (content === '') {
alert('请输入内容后再生成链接!');
return;
}
// 使用更健壮的URL构建方法
const baseUrl = new URL(window.location.href).origin;
const contentPath = content;
const fullDownloadUrl = baseUrl+'/'+contentPath;
const fullCloneUrl = \`git clone \${fullDownloadUrl}\`;
// 填充到输入框
downloadUrl.value = fullDownloadUrl;
cloneUrl.value = fullCloneUrl;
// 显示成功消息
showNotification('链接生成成功!');
// 滚动到链接区域
downloadUrl.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
});
// 复制下载链接
copyDownloadBtn.addEventListener('click', () => {
copyToClipboard(downloadUrl, copyDownloadBtn);
});
// 复制Clone链接
copyCloneBtn.addEventListener('click', () => {
copyToClipboard(cloneUrl, copyCloneBtn);
});
// 复制到剪贴板的辅助函数
function copyToClipboard(inputElement, buttonElement) {
if (!inputElement.value) {
alert('没有可复制的链接!');
return;
}
inputElement.select();
document.execCommand('copy');
// 显示复制成功图标
const originalHTML = buttonElement.innerHTML;
buttonElement.innerHTML = '<i class="fa fa-check"></i>';
setTimeout(() => {
buttonElement.innerHTML = originalHTML;
}, 2000);
}
// 显示通知消息
function showNotification(message) {
// 创建通知元素
const notification = document.createElement('div');
notification.className = 'fixed bottom-4 right-4 bg-accent text-white px-4 py-2 rounded-lg shadow-lg z-50 transform transition-all duration-300 opacity-0 translate-y-4';
notification.textContent = message;
// 添加到页面
document.body.appendChild(notification);
// 显示通知
setTimeout(() => {
notification.classList.remove('opacity-0', 'translate-y-4');
}, 10);
// 3秒后隐藏
setTimeout(() => {
notification.classList.add('opacity-0', 'translate-y-4');
setTimeout(() => {
document.body.removeChild(notification);
}, 300);
}, 3000);
}
// 文本框输入事件 - 自动调整高度
contentTextarea.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = (this.scrollHeight) + 'px';
});
</script>
</body>
</html>`;
return text;
}
// 前缀,如果自定义路由为example.com/gh/*,将PREFIX改为 '/gh/',注意,少一个杠都会错!
const PREFIX = '/'
// 分支文件使用jsDelivr镜像的开关,0为关闭,默认关闭
const Config = {
jsdelivr: 0
}
const whiteList = [] // 白名单,路径里面有包含字符的才会通过,e.g. ['/username/']
/** @type {ResponseInit} */
const PREFLIGHT_INIT = {
status: 204,
headers: new Headers({
'access-control-allow-origin': '*',
'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age': '1728000',
}),
}
const exp1 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i
const exp2 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob|raw)\/.*$/i
const exp3 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:info|git-).*$/i
const exp4 = /^(?:https?:\/\/)?raw\.(?:githubusercontent|github)\.com\/.+?\/.+?\/.+?\/.+$/i
const exp5 = /^(?:https?:\/\/)?gist\.(?:githubusercontent|github)\.com\/.+?\/.+?\/.+$/i
const exp6 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/tags.*$/i
/**
* @param {any} body
* @param {number} status
* @param {Object<string, string>} headers
*/
function makeRes(body, status = 200, headers = {}) {
headers['access-control-allow-origin'] = '*'
return new Response(body, {status, headers})
}
/**
* @param {string} urlStr
*/
function newUrl(urlStr) {
try {
return new URL(urlStr)
} catch (err) {
return null
}
}
addEventListener('fetch', e => {
const ret = fetchHandler(e)
.catch(err => makeRes('cfworker error:\n' + err.stack, 502))
e.respondWith(ret)
})
function checkUrl(u) {
for (let i of [exp1, exp2, exp3, exp4, exp5, exp6]) {
if (u.search(i) === 0) {
return true
}
}
return false
}
/**
* @param {FetchEvent} e
*/
async function fetchHandler(e) {
const req = e.request
const urlStr = req.url
const urlObj = new URL(urlStr)
let path = urlObj.searchParams.get('q')
if (path) {
return Response.redirect('https://' + urlObj.host + PREFIX + path, 301)
}
// cfworker 会把路径中的 `//` 合并成 `/`
path = urlObj.href.substr(urlObj.origin.length + PREFIX.length).replace(/^https?:\/+/, 'https://')
if (path.search(exp1) === 0 || path.search(exp5) === 0 || path.search(exp6) === 0 || path.search(exp3) === 0 || path.search(exp4) === 0) {
return httpHandler(req, path)
} else if (path.search(exp2) === 0) {
if (Config.jsdelivr) {
const newUrl = path.replace('/blob/', '@').replace(/^(?:https?:\/\/)?github\.com/, 'https://cdn.jsdelivr.net/gh')
return Response.redirect(newUrl, 302)
} else {
path = path.replace('/blob/', '/raw/')
return httpHandler(req, path)
}
} else if (path.search(exp4) === 0) {
const newUrl = path.replace(/(?<=com\/.+?\/.+?)\/(.+?\/)/, '@$1').replace(/^(?:https?:\/\/)?raw\.(?:githubusercontent|github)\.com/, 'https://cdn.jsdelivr.net/gh')
return Response.redirect(newUrl, 302)
} else {
return new Response(await indexInterface(), {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
},
});
}
}
/**
* @param {Request} req
* @param {string} pathname
*/
function httpHandler(req, pathname) {
const reqHdrRaw = req.headers
// preflight
if (req.method === 'OPTIONS' &&
reqHdrRaw.has('access-control-request-headers')
) {
return new Response(null, PREFLIGHT_INIT)
}
const reqHdrNew = new Headers(reqHdrRaw)
let urlStr = pathname
let flag = !Boolean(whiteList.length)
for (let i of whiteList) {
if (urlStr.includes(i)) {
flag = true
break
}
}
if (!flag) {
return new Response("blocked", {status: 403})
}
if (urlStr.search(/^https?:\/\//) !== 0) {
urlStr = 'https://' + urlStr
}
const urlObj = newUrl(urlStr)
/** @type {RequestInit} */
const reqInit = {
method: req.method,
headers: reqHdrNew,
redirect: 'manual',
body: req.body
}
return proxy(urlObj, reqInit)
}
/**
*
* @param {URL} urlObj
* @param {RequestInit} reqInit
*/
async function proxy(urlObj, reqInit) {
const res = await fetch(urlObj.href, reqInit)
const resHdrOld = res.headers
const resHdrNew = new Headers(resHdrOld)
const status = res.status
if (resHdrNew.has('location')) {
let _location = resHdrNew.get('location')
if (checkUrl(_location))
resHdrNew.set('location', PREFIX + _location)
else {
reqInit.redirect = 'follow'
return proxy(newUrl(_location), reqInit)
}
}
resHdrNew.set('access-control-expose-headers', '*')
resHdrNew.set('access-control-allow-origin', '*')
resHdrNew.delete('content-security-policy')
resHdrNew.delete('content-security-policy-report-only')
resHdrNew.delete('clear-site-data')
return new Response(res.body, {
status,
headers: resHdrNew,
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment