0%

免费图床Telegraph-Image

AI导读:本文讨论了在部署个人博客时使用图床的重要性,并介绍了基于Telegraph-Image项目的部署过程。虽然原项目缺乏上传限制,可能被不法分子滥用,但作者参考了多个解决方案,对上传增加了认证功能,并加入了防盗链限制。最终,作者在遵循必要修改的基础上,保证了与官方版本的同步,并提供了更新的项目地址和相关预览链接,以供他人参考。

前提

部署了博客少不了要用到图片的时候,没有一个合适的图床肯定是不行的,看了一圈还是决定再嫖一次大善人.

部署效果

预览图片

部署过程


按项目文档一步一步走即可.项目Telegraph-Image

部署后的问题

问题

原始项目没有对上传加以限制,导致会出现一个问题只有有人知道你部署的就可以使用你的图床,一般人使用到也没有什么问题,万一碰见不法分子就要遭殃了

解决

翻阅项目的issues,这个问题已经有很多人提出,同样的也有很多解决方法被研究出来,如issues#97,其中有两个解决方案很不错@MicroMatrixOrg提出的增加防盗链,和@maytom2016修改的增加认证版本Telegraph-Image-auth很符合我的期望,不过Telegraph-Image-auth复刻版本有些老,我还是想要新版本的,而且还能同步官方最好.最后决定自己动手,好在修改难度不高.
于是基于这两个方案来修改我的

上传增加认证

对上传文件functions/upload.js进行修改,代码参考Telegraph-Image-auth,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { errorHandling, telemetryData } from "./utils/middleware";

function UnauthorizedException(reason) {
return new Response(reason, {
status: 401,
statusText: "Unauthorized",
headers: {
"Content-Type": "text/plain;charset=UTF-8",
// Disables caching by default.
"Cache-Control": "no-store",
// Returns the "Content-Length" header for HTTP HEAD requests.
"Content-Length": reason.length,
},
});
}

export async function onRequestPost(context) { // Contents of context object
const {
request, // same as existing Worker API
env, // same as existing Worker API
params, // if filename includes [id] or [[path]]
waitUntil, // same as ctx.waitUntil in existing Worker API
next, // used for middleware or to fetch assets
data, // arbitrary space for passing data between middlewares
} = context;
const ref=request.headers.get('Referer');
const url1= new URL(ref)
const refparam = new URLSearchParams(url1.search);
const autcode=refparam.get('authcode');
if(autcode==env.AUTH_CODE){
const url2 = new URL(request.url)
const url = new URL(url2.protocol + '//' + url2.host + '/upload' + url2.search);

const clonedRequest = request.clone();
await errorHandling(context);
telemetryData(context);
const response = fetch('https://telegra.ph/' + url.pathname + url.search, {
method: clonedRequest.method,
headers: clonedRequest.headers,
body: clonedRequest.body,
});
return response;
}
return new UnauthorizedException("error");
}

增加防盗链

对文件读取functions/file/[id].js增加防盗链限制,参考增加防盗链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
export async function onRequest(context) {  // Contents of context object  
const {
request, // same as existing Worker API
env, // same as existing Worker API
params, // if filename includes [id] or [[path]]
waitUntil, // same as ctx.waitUntil in existing Worker API
next, // used for middleware or to fetch assets
data, // arbitrary space for passing data between middlewares
} = context;

const url = new URL(request.url);
let Referer = request.headers.get('Referer')
if (Referer) {
try {
let refererUrl = new URL(Referer)
let allowedDomains = env.ALLOWED_DOMAINS.split(',');
let isAllowed = allowedDomains.some(domain => {
let domainPattern = new RegExp(`(^|\\.)${domain}$`);
return domainPattern.test(refererUrl.hostname);
});
if (!isAllowed) {
return Response.redirect(url.origin + "/block-img.html", 302);
}
} catch (e) {
return Response.redirect(url.origin + "/block-img.html", 302);
}
}

const response = fetch('https://telegra.ph/' + url.pathname + url.search, {
method: request.method,
headers: request.headers,
body: request.body,
}).then(async (response) => {
console.log(response.ok); // true if the response status is 2xx
console.log(response.status); // 200
if (response.ok) {
// Referer header equal to the admin page
console.log(url.origin + "/admin")
if (request.headers.get('Referer') == url.origin + "/admin") {
//show the image
return response;
}

if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == "") { } else {
//check the record from kv
const record = await env.img_url.getWithMetadata(params.id);
console.log("record")
console.log(record)
if (record.metadata === null) {

} else {

//if the record is not null, redirect to the image
if (record.metadata.ListType == "White") {
return response;
} else if (record.metadata.ListType == "Block") {
console.log("Referer")
console.log(request.headers.get('Referer'))
if (typeof request.headers.get('Referer') == "undefined" || request.headers.get('Referer') == null || request.headers.get('Referer') == "") {
return Response.redirect(url.origin + "/block-img.html", 302)
} else {
return Response.redirect("https://static-res.pages.dev/teleimage/img-block-compressed.png", 302)
}

} else if (record.metadata.Label == "adult") {
if (typeof request.headers.get('Referer') == "undefined" || request.headers.get('Referer') == null || request.headers.get('Referer') == "") {
return Response.redirect(url.origin + "/block-img.html", 302)
} else {
return Response.redirect("https://static-res.pages.dev/teleimage/img-block-compressed.png", 302)
}
}
//check if the env variables WhiteList_Mode are set
console.log("env.WhiteList_Mode:", env.WhiteList_Mode)
if (env.WhiteList_Mode == "true") {
//if the env variables WhiteList_Mode are set, redirect to the image
return Response.redirect(url.origin + "/whitelist-on.html", 302);
} else {
//if the env variables WhiteList_Mode are not set, redirect to the image
return response;
}
}

}

//get time
let time = new Date().getTime();

let apikey = env.ModerateContentApiKey

if (typeof apikey == "undefined" || apikey == null || apikey == "") {

if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == "") {
console.log("Not enbaled KV")

} else {
//add image to kv
await env.img_url.put(params.id, "", {
metadata: { ListType: "None", Label: "None", TimeStamp: time },
});

}
} else {
await fetch(`https://api.moderatecontent.com/moderate/?key=` + apikey + `&url=https://telegra.ph/` + url.pathname + url.search).
then(async (response) => {
let moderate_data = await response.json();
console.log(moderate_data)
console.log("---env.img_url---")
console.log(env.img_url == "true")
if (typeof env.img_url == "undefined" || env.img_url == null || env.img_url == "") { } else {
//add image to kv
await env.img_url.put(params.id, "", {
metadata: { ListType: "None", Label: moderate_data.rating_label, TimeStamp: time },
});
}
if (moderate_data.rating_label == "adult") {
return Response.redirect(url.origin + "/block-img.html", 302)
}
});

}
}
return response;
});

return response;

}

说明

修改之后相比于原项目增加了两个环境变量
AUTH_CODE:上传时认证密码
ALLOWED_DOMAINS访问时允许的域名,我对空进行的放行
由于还打算同步上游项目所以只对必要部分修改,文档什么的没有修改

项目地址

https://github.com/hl128k/Telegraph-Image

更新 2024/8/14

推荐一个分支仓库,ui优化重制版CloudFlare-ImgBed
预览

欢迎关注我的其它发布渠道