forked from cf-pages/Telegraph-Image
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
625 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<!-- import CSS --> | ||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/lib/theme-chalk/index.css" integrity="sha256-ghr1zmXTODLKl1HULQd6fq1MIe7m3FJiNTOCT8sddLM=" crossorigin="anonymous"> | ||
</head> | ||
<body> | ||
<div id="app"> | ||
<el-container> | ||
<el-header> | ||
<div style=" | ||
margin: auto; | ||
line-height: 60px; | ||
font-size: xx-large; | ||
position: relative; | ||
">Dashboard | ||
|
||
|
||
<span style=" | ||
position: absolute; | ||
right: 0px; | ||
" v-if="showLogoutButton"><el-button | ||
size="mini" | ||
type="info" | ||
@click="handleLogout()">退出登录</el-button></span></div> | ||
</el-header> | ||
<el-main><el-row :gutter="12"> | ||
<el-col :span="24"> | ||
<el-card shadow="always"> | ||
记录总数量: | ||
{{ Number }} | ||
</el-card> | ||
</el-col> | ||
<!--<el-col :span="8"> | ||
<el-card shadow="hover"> | ||
<el-tooltip class="item" effect="dark" content="白名单数量" placement="top-start"> | ||
</el-tooltip> | ||
白名单数量:{{ WhiteList }} | ||
</el-card> | ||
</el-col> | ||
<el-col :span="8"> | ||
<el-card shadow="hover"> | ||
<el-tooltip class="item" effect="dark" content="黑名单数量" placement="top-start"> | ||
</el-tooltip> | ||
黑名单数量:{{ BlackList }} | ||
</el-card> | ||
</el-col>--> | ||
</el-row> | ||
<template> | ||
<el-table | ||
:data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))" | ||
style="width: 100%"> | ||
<el-table-column | ||
label="name" | ||
prop="name"> | ||
</el-table-column> | ||
<el-table-column | ||
label="preview" | ||
prop="preview"> | ||
<template slot-scope="scope"> | ||
<el-image | ||
style="width: 100%; height: 100%;" | ||
:src="'/file/'+scope.row.name" | ||
:zoom-rate="1.2" | ||
:preview-src-list="['/file/'+scope.row.name]" | ||
fit="cover" | ||
lazy | ||
/> | ||
|
||
</template> | ||
</el-table-column> | ||
<el-table-column | ||
label="data" | ||
prop="data"> | ||
<template slot-scope="scope"> | ||
<el-popover trigger="hover" placement="top"> | ||
<p>{{ scope.row.metadata }}</p> | ||
<div slot="reference" class="name-wrapper"> | ||
<el-tag size="medium">{{ scope.row.metadata }}</el-tag> | ||
</div> | ||
</el-popover> | ||
</template> | ||
</el-table-column> | ||
<el-table-column | ||
align="right"> | ||
<template slot="header" slot-scope="scope"> | ||
<el-input | ||
v-model="search" | ||
size="mini" | ||
placeholder="输入关键字搜索"/> | ||
</template> | ||
<template slot-scope="scope"> | ||
<el-button | ||
size="mini" | ||
type="primary" | ||
@click="handleWhite(scope.$index,scope.row.name)">白名单</el-button> | ||
<el-button | ||
size="mini" | ||
type="info" | ||
@click="handleBlock(scope.$index,scope.row.name)">黑名单</el-button> | ||
<el-button | ||
size="mini" | ||
type="danger" | ||
@click="handleDelete(scope.$index,scope.row.name)">删除</el-button> | ||
</template> | ||
</el-table-column> | ||
</el-table> | ||
</template> | ||
</el-main> | ||
</el-container> | ||
</div> | ||
</body> | ||
<!-- import Vue before Element --> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js" integrity="sha256-kXTEJcRFN330VirZFl6gj9+UM6gIKW195fYZeR3xDhc=" crossorigin="anonymous"></script> | ||
<!-- import JavaScript --> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/index.js" integrity="sha256-OFVFYfqhQ9nDnKh+NfIsefpy/fnjTwkK909ZYgo45nw=" crossorigin="anonymous"></script> | ||
<script> | ||
var app=new Vue({ | ||
el: '#app', | ||
data: { | ||
Number:0, | ||
WhiteList:0, | ||
BlackList:0, | ||
showLogoutButton:false, | ||
tableData: [], | ||
dialogFormVisible: false, | ||
formLabelWidth: '120px', | ||
form: { | ||
name: '', | ||
id: '' | ||
}, | ||
search: '', | ||
password:'123456' | ||
}, | ||
methods: { | ||
handleBlock(index,key) { | ||
console.log(key); | ||
if (confirm("确认加入黑名单吗?")) { | ||
console.log("Yes") | ||
var requestOptions = { | ||
method: 'GET', | ||
redirect: 'follow', | ||
//include authorization credientials | ||
credentials: 'include' | ||
}; | ||
|
||
fetch("./api/manage/block/"+key, requestOptions) | ||
.then(response => response.text()) | ||
.then(result => {console.log(result); | ||
this.tableData[index].metadata=result;}) | ||
.catch(error => {alert("An error occurred while synchronizing data with the server, please check the network connection");console.log('error', error)}); | ||
|
||
} else { | ||
console.log("No") | ||
} | ||
}, | ||
handleDelete(index,key) { | ||
console.log(key); | ||
if (confirm("确认删除该条记录吗?")) { | ||
console.log("Yes") | ||
var requestOptions = { | ||
method: 'GET', | ||
redirect: 'follow', | ||
//include authorization credientials | ||
credentials: 'include' | ||
}; | ||
|
||
fetch("./api/manage/delete/"+key, requestOptions) | ||
.then(response => response.text()) | ||
.then(result => {console.log(result);this.tableData.remove(index);}) | ||
.catch(error => {alert("An error occurred while synchronizing data with the server, please check the network connection");console.log('error', error)}); | ||
|
||
} else { | ||
console.log("No") | ||
} | ||
}, | ||
handleWhite(index,key) { | ||
console.log(key); | ||
if (confirm("确认加入白名单吗?")) { | ||
console.log("Yes") | ||
var requestOptions = { | ||
method: 'GET', | ||
redirect: 'follow', | ||
//include authorization credientials | ||
credentials: 'include' | ||
}; | ||
fetch("./api/manage/white/"+key, requestOptions) | ||
.then(response => response.text()) | ||
.then(result => {console.log(result);this.tableData[index].metadata=result;}) | ||
.catch(error => {alert("An error occurred while synchronizing data with the server, please check the network connection");console.log('error', error)}); | ||
|
||
} else { | ||
console.log("No") | ||
} | ||
|
||
}, | ||
handleLogout(){ | ||
window.location.href="./api/manage/logout"; | ||
} | ||
}, | ||
|
||
mounted () { | ||
//check if the user is logged in | ||
//read the basic auth credientials from the browser | ||
var requestOptions = { | ||
method: 'GET', | ||
redirect: 'follow', | ||
//include authorization credientials | ||
credentials: 'include' | ||
}; | ||
fetch("./api/manage/check", requestOptions) | ||
.then(response => response.text()) | ||
.then(result => {console.log(result); | ||
if(result=="true"){ | ||
this.showLogoutButton=true; | ||
}else if(result=="Not using basic auth."){ | ||
|
||
} | ||
else{ | ||
window.location.href="./api/manage/login"; | ||
} | ||
}) | ||
.catch(error => {alert("An error occurred while synchronizing data with the server, please check the network connection");console.log('error', error)}); | ||
|
||
|
||
|
||
Array.prototype.remove = function(from, to) { | ||
var rest = this.slice((to || from) + 1 || this.length); | ||
this.length = from < 0 ? this.length + from : from; | ||
return this.push.apply(this, rest); | ||
}; | ||
var requestOptions = { | ||
method: 'GET', | ||
redirect: 'follow', | ||
//include authorization credientials | ||
credentials: 'include' | ||
|
||
}; | ||
|
||
|
||
fetch("./api/manage/list", requestOptions) | ||
//判断是否需要登录 | ||
.then(response => { | ||
if(response.status==401){ | ||
alert("请先登录"); | ||
window.location.href="./api/manage/login"; | ||
} | ||
else{ | ||
return response; | ||
} | ||
}) | ||
.then(response => response.text()) | ||
.then(result => {this.tableData=JSON.parse(result);console.log(result);this.Number=this.tableData.length}) | ||
.catch(error => {alert("An error occurred while synchronizing data with the server, please check the network connection");console.log('error', error)}); | ||
|
||
} | ||
}) | ||
|
||
</script><!-- Hotjar Tracking Code --> | ||
<script> | ||
(function(h,o,t,j,a,r){ | ||
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)}; | ||
h._hjSettings={hjid:2531461,hjsv:6}; | ||
a=o.getElementsByTagName('head')[0]; | ||
r=o.createElement('script');r.async=1; | ||
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv; | ||
a.appendChild(r); | ||
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); | ||
</script> | ||
<script type="text/javascript"> | ||
(function(c,l,a,r,i,t,y){ | ||
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; | ||
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; | ||
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); | ||
})(window, document, "clarity", "script", "7t5ai7agat"); | ||
</script> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
async function errorHandling(context) { | ||
try { | ||
return await context.next(); | ||
} catch (err) { | ||
return new Response(`${err.message}\n${err.stack}`, { status: 500 }); | ||
} | ||
} | ||
|
||
function basicAuthentication(request) { | ||
const Authorization = request.headers.get('Authorization'); | ||
|
||
const [scheme, encoded] = Authorization.split(' '); | ||
|
||
// The Authorization header must start with Basic, followed by a space. | ||
if (!encoded || scheme !== 'Basic') { | ||
throw new BadRequestException('Malformed authorization header.'); | ||
} | ||
|
||
// Decodes the base64 value and performs unicode normalization. | ||
// @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (and #section-4.2.2) | ||
// @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize | ||
const buffer = Uint8Array.from(atob(encoded), character => character.charCodeAt(0)); | ||
const decoded = new TextDecoder().decode(buffer).normalize(); | ||
|
||
// The username & password are split by the first colon. | ||
//=> example: "username:password" | ||
const index = decoded.indexOf(':'); | ||
|
||
// The user & password are split by the first colon and MUST NOT contain control characters. | ||
// @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F") | ||
if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) { | ||
throw new BadRequestException('Invalid authorization value.'); | ||
} | ||
|
||
return { | ||
user: decoded.substring(0, index), | ||
pass: decoded.substring(index + 1), | ||
}; | ||
} | ||
|
||
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, | ||
}, | ||
}); | ||
} | ||
|
||
function BadRequestException(reason) { | ||
return new Response(reason, { | ||
status: 400, | ||
statusText: 'Bad Request', | ||
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, | ||
}, | ||
}); | ||
} | ||
|
||
|
||
function authentication(context) { | ||
//context.env.BASIC_USER="admin" | ||
//context.env.BASIC_PASS="admin" | ||
//check if the env variables Disable_Dashboard are set | ||
if (context.env.DISABLE_DASHBOARD == "true") { | ||
return new Response('Dashboard is disabled. Please enable to use this feature.', { status: 200 }); | ||
} | ||
|
||
console.log(context.env.BASIC_USER) | ||
if(typeof context.env.BASIC_USER == "undefined" || context.env.BASIC_USER == null || context.env.BASIC_USER == ""){ | ||
return context.next(); | ||
}else{ | ||
if (context.request.headers.has('Authorization')) { | ||
// Throws exception when authorization fails. | ||
const { user, pass } = basicAuthentication(context.request); | ||
|
||
|
||
if (context.env.BASIC_USER !== user || context.env.BASIC_PASS !== pass) { | ||
return UnauthorizedException('Invalid credentials.'); | ||
}else{ | ||
return context.next(); | ||
} | ||
|
||
} else { | ||
return new Response('You need to login.', { | ||
status: 401, | ||
headers: { | ||
// Prompts the user for credentials. | ||
'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"', | ||
}, | ||
}); | ||
} | ||
} | ||
|
||
} | ||
|
||
export const onRequest = [errorHandling, authentication]; |
Oops, something went wrong.