mirror of
https://github.com/WJQSERVER-STUDIO/ghproxy.git
synced 2026-02-03 00:01:10 +08:00
24w21d
This commit is contained in:
parent
e32adadaff
commit
267dfafcb9
10 changed files with 154 additions and 35 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,5 +1,15 @@
|
|||
# 更新日志
|
||||
|
||||
24w21d
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||
- ADD: 新增`ratePerMinute` API可供查询
|
||||
- ADD: 前端新增 version 标识
|
||||
- ADD: 前端新增 `重定向` 按钮,用于重定向到代理后的链接
|
||||
- CHANGE: 优化输出代码块,使样式更加美观
|
||||
- CHANGE: 更新相关依赖库
|
||||
- CHANGE: 对黑名单模块进行实验性功能优化,提升性能
|
||||
|
||||
24w21c
|
||||
---
|
||||
- PRE-RELEASE: 此版本是v1.7.0的预发布版本,请勿在生产环境中使用
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
24w21c
|
||||
24w21d
|
||||
11
api/api.go
11
api/api.go
|
|
@ -44,6 +44,9 @@ func InitHandleRouter(cfg *config.Config, router *gin.Engine, version string) {
|
|||
apiRouter.GET("/rate_limit/status", func(c *gin.Context) {
|
||||
RateLimitStatusHandler(c, cfg)
|
||||
})
|
||||
apiRouter.GET("/rate_limit/limit", func(c *gin.Context) {
|
||||
RateLimitLimitHandler(c, cfg)
|
||||
})
|
||||
}
|
||||
logInfo("API router Init success")
|
||||
}
|
||||
|
|
@ -104,3 +107,11 @@ func RateLimitStatusHandler(c *gin.Context, cfg *config.Config) {
|
|||
"RateLimit": cfg.RateLimit.Enabled,
|
||||
})
|
||||
}
|
||||
|
||||
func RateLimitLimitHandler(c *gin.Context, cfg *config.Config) {
|
||||
logInfo("%s %s %s %s %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto)
|
||||
c.Writer.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(c.Writer).Encode(map[string]interface{}{
|
||||
"RatePerMinute": cfg.RateLimit.RatePerMinute,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 日志模块
|
||||
var (
|
||||
logw = logger.Logw
|
||||
logInfo = logger.LogInfo
|
||||
|
|
@ -16,7 +15,6 @@ var (
|
|||
logError = logger.LogError
|
||||
)
|
||||
|
||||
// Auth Init
|
||||
func Init(cfg *config.Config) {
|
||||
if cfg.Blacklist.Enabled {
|
||||
LoadBlacklist(cfg)
|
||||
|
|
@ -28,17 +26,13 @@ func Init(cfg *config.Config) {
|
|||
}
|
||||
|
||||
func AuthHandler(c *gin.Context, cfg *config.Config) (isValid bool, err string) {
|
||||
// 如果身份验证未启用,直接返回 true
|
||||
if !cfg.Auth.Enabled {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
// 获取 auth_token 参数
|
||||
authToken := c.Query("auth_token")
|
||||
// IP METHOD URL USERAGENT PROTO TOKEN
|
||||
logInfo("%s %s %s %s %s AUTH_TOKEN: %s", c.ClientIP(), c.Request.Method, c.Request.URL.Path, c.Request.UserAgent(), c.Request.Proto, authToken)
|
||||
|
||||
// 验证 token
|
||||
if authToken == "" {
|
||||
err := "Auth token == nil"
|
||||
return false, err
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ func LoadBlacklist(cfg *config.Config) {
|
|||
}
|
||||
|
||||
// fullrepo: "owner/repo" or "owner/*"
|
||||
func CheckBlacklist(fullrepo string) bool {
|
||||
return forRangeCheckBlacklist(blacklist.Blacklist, fullrepo)
|
||||
func CheckBlacklist(repouser string, user string, repo string) bool {
|
||||
return forRangeCheckBlacklist(blacklist.Blacklist, repouser, user)
|
||||
}
|
||||
|
||||
func sliceRepoName_Blacklist(fullrepo string) (string, string) {
|
||||
|
|
@ -45,12 +45,29 @@ func sliceRepoName_Blacklist(fullrepo string) (string, string) {
|
|||
return s[0], s[1]
|
||||
}
|
||||
|
||||
func forRangeCheckBlacklist(blist []string, fullrepo string) bool {
|
||||
repoUser, _ := sliceRepoName_Blacklist(fullrepo)
|
||||
func forRangeCheckBlacklist(blist []string, fullrepo string, user string) bool {
|
||||
// 先匹配user,再匹配user/*,最后匹配完整repo
|
||||
for _, blocked := range blist {
|
||||
if blocked == fullrepo || (strings.HasSuffix(blocked, "/*") && strings.HasPrefix(repoUser, blocked[:len(blocked)-2])) {
|
||||
// 切片
|
||||
users, _ := sliceRepoName_Blacklist(blocked)
|
||||
logw("users:%s, blocked:%s", users, blocked)
|
||||
// 匹配 user
|
||||
if user == users {
|
||||
// 匹配 user/*
|
||||
if strings.HasSuffix(blocked, "/*") {
|
||||
return true
|
||||
}
|
||||
// 匹配完整repo
|
||||
if fullrepo == blocked {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* for _, blocked := range blist {
|
||||
if blocked == fullrepo || (strings.HasSuffix(blocked, "/*") && strings.HasPrefix(repoUser, blocked[:len(blocked)-2])) {
|
||||
return true
|
||||
}
|
||||
} */
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -6,6 +6,7 @@ require (
|
|||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/imroc/req/v3 v3.48.0
|
||||
golang.org/x/time v0.7.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -22,7 +23,7 @@ require (
|
|||
github.com/go-playground/validator/v10 v10.22.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
|
|
@ -48,7 +49,6 @@ require (
|
|||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/time v0.7.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -52,6 +52,8 @@ github.com/google/pprof v0.0.0-20241023014458-598669927662 h1:SKMkD83p7FwUqKmBsP
|
|||
github.com/google/pprof v0.0.0-20241023014458-598669927662/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142 h1:sAGdeJj0bnMgUNVeUpp6AYlVdCt3/GdI3pGRqsNSQLs=
|
||||
github.com/google/pprof v0.0.0-20241101162523-b92577c0c142/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ func Log(customMessage string) {
|
|||
logChannel <- customMessage
|
||||
}
|
||||
|
||||
// 格式化日志记录
|
||||
func Logw(format string, args ...interface{}) {
|
||||
message := fmt.Sprintf(format, args...)
|
||||
Log(message)
|
||||
|
|
@ -82,7 +81,6 @@ func LogError(format string, args ...interface{}) {
|
|||
Log(message)
|
||||
}
|
||||
|
||||
// 关闭日志文件
|
||||
func Close() {
|
||||
logFileMutex.Lock()
|
||||
defer logFileMutex.Unlock()
|
||||
|
|
|
|||
109
pages/index.html
109
pages/index.html
|
|
@ -11,7 +11,6 @@
|
|||
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://font.sec.miui.com/font/css?family=MiSans:400,700:MiSans">
|
||||
<style>
|
||||
|
||||
:root {
|
||||
--color: #dadada;
|
||||
--fontcolor: #333;
|
||||
|
|
@ -41,6 +40,35 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.version {
|
||||
width: 12.5%;
|
||||
height: 2%;
|
||||
background-color: #39c5bb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 0.5rem;
|
||||
position: fixed;
|
||||
bottom: 0%;
|
||||
right: 0%;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
height: 10px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: #39c5bb;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 80%;
|
||||
text-align: center;
|
||||
|
|
@ -89,9 +117,9 @@
|
|||
pre {
|
||||
background: #012333;
|
||||
color: #39c5bc;
|
||||
padding: 20px 20px;
|
||||
margin: 10px 0;
|
||||
border-radius: 8px;
|
||||
padding: 15px 20px 15px 20px;
|
||||
margin: 0px 0;
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
}
|
||||
|
|
@ -100,10 +128,10 @@
|
|||
content: " ";
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #bd3c35;
|
||||
border-radius: 50%;
|
||||
box-shadow: 20px 0 0 #d69f27, 40px 0 0 #39c5bb;
|
||||
|
|
@ -111,7 +139,8 @@
|
|||
|
||||
code {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 1em;
|
||||
font-size: 0.9em;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
|
@ -158,9 +187,14 @@
|
|||
.status-container {
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 10%;
|
||||
}
|
||||
|
||||
.version {
|
||||
width: 7.5%;
|
||||
}
|
||||
}
|
||||
|
||||
.form-group {
|
||||
|
|
@ -201,7 +235,7 @@
|
|||
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background: rgba(0, 217, 224, 0.822);
|
||||
color: white;
|
||||
|
|
@ -211,6 +245,24 @@
|
|||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
z-index: 1;
|
||||
font-size: 0.85rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.redir-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 65px;
|
||||
background: rgba(0, 217, 224, 0.822);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.3s;
|
||||
z-index: 1;
|
||||
font-size: 0.85rem;
|
||||
display: none;
|
||||
}
|
||||
|
||||
pre:hover .copy-button {
|
||||
|
|
@ -239,6 +291,9 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="version">
|
||||
<p id="version"></p>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1>Github文件加速</h1>
|
||||
<div class="form-group">
|
||||
|
|
@ -248,6 +303,7 @@
|
|||
|
||||
<div class="code" id="outputBlock">
|
||||
<button class="copy-button" id="copyButton">复制</button>
|
||||
<button class="redir-button" id="redirButton">打开</button>
|
||||
<pre id="formattedLinkOutput"></pre>
|
||||
</div>
|
||||
<div class="tips">
|
||||
|
|
@ -274,16 +330,22 @@
|
|||
|
||||
if (githubLinkInput.value.startsWith("https://github.com/") || githubLinkInput.value.startsWith("http://github.com/")) {
|
||||
formattedLink = "https://" + currentHost + "/github.com" + githubLinkInput.value.substring(githubLinkInput.value.indexOf("/", 8));
|
||||
displayButton();
|
||||
} else if (githubLinkInput.value.startsWith("github.com/")) {
|
||||
formattedLink = "https://" + currentHost + "/" + githubLinkInput.value;
|
||||
displayButton();
|
||||
} else if (githubLinkInput.value.startsWith("https://raw.githubusercontent.com/") || githubLinkInput.value.startsWith("http://raw.githubusercontent.com/")) {
|
||||
formattedLink = "https://" + currentHost + githubLinkInput.value.substring(githubLinkInput.value.indexOf("/", 7));
|
||||
displayButton();
|
||||
} else if (githubLinkInput.value.startsWith("raw.githubusercontent.com/")) {
|
||||
formattedLink = "https://" + currentHost + "/" + githubLinkInput.value;
|
||||
displayButton();
|
||||
} else if (githubLinkInput.value.startsWith("https://gist.githubusercontent.com/") || githubLinkInput.value.startsWith("http://gist.githubusercontent.com/")) {
|
||||
formattedLink = "https://" + currentHost + "/gist.github.com" + githubLinkInput.value.substring(githubLinkInput.value.indexOf("/", 18));
|
||||
displayButton();
|
||||
} else if (githubLinkInput.value.startsWith("gist.githubusercontent.com/")) {
|
||||
formattedLink = "https://" + currentHost + "/" + githubLinkInput.value;
|
||||
displayButton();
|
||||
} else {
|
||||
showToast('请输入有效的GitHub链接');
|
||||
}
|
||||
|
|
@ -291,6 +353,19 @@
|
|||
formattedLinkOutput.textContent = formattedLink;
|
||||
}
|
||||
|
||||
function displayButton() {
|
||||
var copyButton = document.getElementById('copyButton');
|
||||
var redirButton = document.getElementById('redirButton');
|
||||
copyButton.style.display = 'block';
|
||||
redirButton.style.display = 'block';
|
||||
}
|
||||
|
||||
function redirToFormattedLink() {
|
||||
var formattedLinkOutput = document.getElementById('formattedLinkOutput');
|
||||
console.log(formattedLinkOutput.textContent);
|
||||
window.open(formattedLinkOutput.textContent);
|
||||
}
|
||||
|
||||
document.getElementById('formatButton').addEventListener('click', formatGithubLink);
|
||||
document.getElementById('copyButton').addEventListener('click', function () {
|
||||
const output = document.getElementById('formattedLinkOutput');
|
||||
|
|
@ -300,9 +375,9 @@
|
|||
window.getSelection().addRange(range);
|
||||
document.execCommand('copy');
|
||||
window.getSelection().removeAllRanges();
|
||||
//alert('链接已复制到剪贴板');
|
||||
showToast('链接已复制到剪贴板');
|
||||
});
|
||||
document.getElementById('redirButton').addEventListener('click', redirToFormattedLink);
|
||||
|
||||
function showToast(message) {
|
||||
const toast = document.getElementById('toast');
|
||||
|
|
@ -360,10 +435,22 @@
|
|||
console.error('Error fetching API:', error);
|
||||
});
|
||||
}
|
||||
function fetchVersion() {
|
||||
fetch(window.location.origin + '/api/version')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const version = document.getElementById('version');
|
||||
version.textContent = `${data.Version}`;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching API:', error);
|
||||
});
|
||||
}
|
||||
function fetchAPI() {
|
||||
fetchSizeLimit();
|
||||
fetchWhiteList();
|
||||
fetchBlackList();
|
||||
fetchVersion();
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', fetchAPI);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -60,14 +60,14 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFu
|
|||
username, repo := MatchUserRepo(rawPath, cfg, c, matches)
|
||||
|
||||
logInfo("%s %s %s %s %s Matched-Username: %s, Matched-Repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, username, repo)
|
||||
fullrepo := fmt.Sprintf("%s/%s", username, repo)
|
||||
repouser := fmt.Sprintf("%s/%s", username, repo)
|
||||
|
||||
// 白名单检查
|
||||
if cfg.Whitelist.Enabled {
|
||||
whitelist := auth.CheckWhitelist(fullrepo)
|
||||
whitelist := auth.CheckWhitelist(repouser)
|
||||
if !whitelist {
|
||||
logErrMsg := fmt.Sprintf("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, fullrepo)
|
||||
errMsg := fmt.Sprintf("Whitelist Blocked repo: %s", fullrepo)
|
||||
logErrMsg := fmt.Sprintf("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, repouser)
|
||||
errMsg := fmt.Sprintf("Whitelist Blocked repo: %s", repouser)
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": errMsg})
|
||||
logWarning(logErrMsg)
|
||||
return
|
||||
|
|
@ -76,10 +76,10 @@ func NoRouteHandler(cfg *config.Config, limiter *rate.RateLimiter) gin.HandlerFu
|
|||
|
||||
// 黑名单检查
|
||||
if cfg.Blacklist.Enabled {
|
||||
blacklist := auth.CheckBlacklist(fullrepo)
|
||||
blacklist := auth.CheckBlacklist(repouser, username, repo)
|
||||
if blacklist {
|
||||
logErrMsg := fmt.Sprintf("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, fullrepo)
|
||||
errMsg := fmt.Sprintf("Blacklist Blocked repo: %s", fullrepo)
|
||||
logErrMsg := fmt.Sprintf("%s %s %s %s %s Whitelist Blocked repo: %s", c.ClientIP(), c.Request.Method, rawPath, c.Request.Header.Get("User-Agent"), c.Request.Proto, repouser)
|
||||
errMsg := fmt.Sprintf("Blacklist Blocked repo: %s", repouser)
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": errMsg})
|
||||
logWarning(logErrMsg)
|
||||
return
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue