mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-09-05 23:47:50 +08:00
feat: add admin panel (#31)
* feat: add admin panel * feature: update limit
This commit is contained in:
@@ -109,6 +109,8 @@ node_compat = true
|
|||||||
PREFIX = "tmp" # 要处理的邮箱名称前缀
|
PREFIX = "tmp" # 要处理的邮箱名称前缀
|
||||||
# 如果你想要你的网站私有,取消下面的注释,并修改密码
|
# 如果你想要你的网站私有,取消下面的注释,并修改密码
|
||||||
# PASSWORDS = ["123", "456"]
|
# PASSWORDS = ["123", "456"]
|
||||||
|
# admin 控制台密码
|
||||||
|
# ADMIN_PASSWORDS = ["123", "456"]
|
||||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名
|
||||||
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥
|
||||||
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ pnpm install
|
|||||||
# PREFIX = "tmp" - the email create will be like tmp<xxxxx>@DOMAIN
|
# PREFIX = "tmp" - the email create will be like tmp<xxxxx>@DOMAIN
|
||||||
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
||||||
# PASSWORDS = ["123", "456"]
|
# PASSWORDS = ["123", "456"]
|
||||||
|
# For admin panel
|
||||||
|
# ADMIN_PASSWORDS = ["123", "456"]
|
||||||
# DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] you domain name
|
# DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] you domain name
|
||||||
# JWT_SECRET = "xxx"
|
# JWT_SECRET = "xxx"
|
||||||
# BLACK_LIST = ""
|
# BLACK_LIST = ""
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
"naive-ui": "^2.34.3",
|
"naive-ui": "^2.34.3",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-i18n": "9"
|
"vue-i18n": "9",
|
||||||
|
"vue-router": "^4.2.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
|
|||||||
Generated
+12
@@ -20,6 +20,9 @@ dependencies:
|
|||||||
vue-i18n:
|
vue-i18n:
|
||||||
specifier: '9'
|
specifier: '9'
|
||||||
version: 9.3.0(vue@3.3.4)
|
version: 9.3.0(vue@3.3.4)
|
||||||
|
vue-router:
|
||||||
|
specifier: ^4.2.5
|
||||||
|
version: 4.2.5(vue@3.3.4)
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@vitejs/plugin-vue':
|
'@vitejs/plugin-vue':
|
||||||
@@ -735,6 +738,15 @@ packages:
|
|||||||
vue: 3.3.4
|
vue: 3.3.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/vue-router@4.2.5(vue@3.3.4):
|
||||||
|
resolution: {integrity: sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.2.0
|
||||||
|
dependencies:
|
||||||
|
'@vue/devtools-api': 6.5.0
|
||||||
|
vue: 3.3.4
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vue@3.3.4:
|
/vue@3.3.4:
|
||||||
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|||||||
@@ -43,10 +43,7 @@ onMounted(async () => {
|
|||||||
<n-gi span="1"></n-gi>
|
<n-gi span="1"></n-gi>
|
||||||
<n-gi span="6">
|
<n-gi span="6">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<n-space vertical>
|
<router-view></router-view>
|
||||||
<Header />
|
|
||||||
<Content />
|
|
||||||
</n-space>
|
|
||||||
</div>
|
</div>
|
||||||
</n-gi>
|
</n-gi>
|
||||||
<n-gi span="1"></n-gi>
|
<n-gi span="1"></n-gi>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useGlobalState } from '../store'
|
import { useGlobalState } from '../store'
|
||||||
|
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
||||||
const { loading, auth, jwt, openSettings, showAuth } = useGlobalState();
|
const { loading, auth, jwt, openSettings, showAuth, adminAuth, showAdminAuth } = useGlobalState();
|
||||||
|
|
||||||
const apiFetch = async (path, options = {}) => {
|
const apiFetch = async (path, options = {}) => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@@ -10,6 +10,7 @@ const apiFetch = async (path, options = {}) => {
|
|||||||
method: options.method || 'GET',
|
method: options.method || 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'x-custom-auth': auth.value,
|
'x-custom-auth': auth.value,
|
||||||
|
'x-admin-auth': adminAuth.value,
|
||||||
'Authorization': `Bearer ${jwt.value}`,
|
'Authorization': `Bearer ${jwt.value}`,
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
@@ -18,6 +19,10 @@ const apiFetch = async (path, options = {}) => {
|
|||||||
showAuth.value = true;
|
showAuth.value = true;
|
||||||
throw new Error("Unauthorized");
|
throw new Error("Unauthorized");
|
||||||
}
|
}
|
||||||
|
if (response.status === 401 && path.startsWith("/admin")) {
|
||||||
|
showAdminAuth.value = true;
|
||||||
|
throw new Error("Unauthorized");
|
||||||
|
}
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`${response.status} ${await response.text()}` || "error");
|
throw new Error(`${response.status} ${await response.text()}` || "error");
|
||||||
}
|
}
|
||||||
@@ -58,9 +63,39 @@ const getSettings = async () => {
|
|||||||
return res["address"];
|
return res["address"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const adminShowPassword = async (id) => {
|
||||||
|
try {
|
||||||
|
const { password } = await apiFetch(`/admin/show_password/${id}`);
|
||||||
|
return password;
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminDeleteAddress = async (id) => {
|
||||||
|
try {
|
||||||
|
await apiFetch(`/admin/delete_address/${id}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminGetAddress = async () => {
|
||||||
|
try {
|
||||||
|
return await apiFetch("/admin/addresss");
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const api = {
|
export const api = {
|
||||||
fetch: apiFetch,
|
fetch: apiFetch,
|
||||||
getSettings: getSettings,
|
getSettings: getSettings,
|
||||||
getOpenSettings: getOpenSettings,
|
getOpenSettings: getOpenSettings,
|
||||||
|
adminShowPassword: adminShowPassword,
|
||||||
|
adminDeleteAddress: adminDeleteAddress,
|
||||||
|
adminGetAddress: adminGetAddress,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import router from './router'
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
legacy: false, // you must set `false`, to use Composition API
|
legacy: false, // you must set `false`, to use Composition API
|
||||||
@@ -15,4 +16,5 @@ const i18n = createI18n({
|
|||||||
})
|
})
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
|
app.use(router)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import Index from '../views/Index.vue'
|
||||||
|
import Admin from '../views/Admin.vue'
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
component: Index
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/admin',
|
||||||
|
component: Admin
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
||||||
@@ -13,7 +13,9 @@ export const useGlobalState = createGlobalState(
|
|||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
const showAuth = ref(false);
|
const showAuth = ref(false);
|
||||||
|
const showAdminAuth = ref(false);
|
||||||
const auth = useStorage('auth', '');
|
const auth = useStorage('auth', '');
|
||||||
|
const adminAuth = useStorage('adminAuth', '');
|
||||||
const jwt = useStorage('jwt', '');
|
const jwt = useStorage('jwt', '');
|
||||||
const localeCache = useStorage('locale', 'zhCN');
|
const localeCache = useStorage('locale', 'zhCN');
|
||||||
const themeSwitch = useStorage('themeSwitch', false);
|
const themeSwitch = useStorage('themeSwitch', false);
|
||||||
@@ -24,7 +26,9 @@ export const useGlobalState = createGlobalState(
|
|||||||
auth,
|
auth,
|
||||||
jwt,
|
jwt,
|
||||||
localeCache,
|
localeCache,
|
||||||
themeSwitch
|
themeSwitch,
|
||||||
|
adminAuth,
|
||||||
|
showAdminAuth,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
<script setup>
|
||||||
|
import { NSpace, NLayoutHeader, NInput, c } from 'naive-ui'
|
||||||
|
import { NButton, NSelect, NModal } from 'naive-ui'
|
||||||
|
import { NDataTable, NPopconfirm } from 'naive-ui'
|
||||||
|
import { ref, h, onMounted } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
import { useMessage } from 'naive-ui'
|
||||||
|
|
||||||
|
import { useGlobalState } from '../store'
|
||||||
|
import { api } from '../api'
|
||||||
|
|
||||||
|
const { localeCache, adminAuth, showAdminAuth } = useGlobalState()
|
||||||
|
const router = useRouter()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const showEmailPassword = ref(false)
|
||||||
|
const curEmailPassword = ref("")
|
||||||
|
|
||||||
|
const authFunc = async () => {
|
||||||
|
try {
|
||||||
|
location.reload()
|
||||||
|
} catch (error) {
|
||||||
|
message.error(error.message || "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { t } = useI18n({
|
||||||
|
locale: localeCache.value || 'zh',
|
||||||
|
messages: {
|
||||||
|
en: {
|
||||||
|
title: 'Temp Email Admin',
|
||||||
|
auth: 'Admin Auth',
|
||||||
|
home: 'Home',
|
||||||
|
authTip: 'Please enter the correct auth code',
|
||||||
|
name: 'Name',
|
||||||
|
created_at: 'Created At',
|
||||||
|
showPass: 'Show Passwrod',
|
||||||
|
password: 'Password',
|
||||||
|
passwordTip: 'Please copy the password and you can use it to login to your email account.',
|
||||||
|
delete: 'Delete',
|
||||||
|
deleteTip: 'Are you sure to delete this email?',
|
||||||
|
refresh: 'Refresh',
|
||||||
|
},
|
||||||
|
zh: {
|
||||||
|
title: '临时邮件 Admin',
|
||||||
|
auth: 'Admin 授权',
|
||||||
|
home: '首页',
|
||||||
|
authTip: '请输入正确的授权码',
|
||||||
|
name: '名称',
|
||||||
|
created_at: '创建时间',
|
||||||
|
showPass: '显示密码',
|
||||||
|
password: '密码',
|
||||||
|
passwordTip: '请复制密码,你可以使用它登录你的邮箱。',
|
||||||
|
delete: '删除',
|
||||||
|
deleteTip: '确定要删除这个邮箱吗?',
|
||||||
|
refresh: '刷新',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const data = ref([])
|
||||||
|
|
||||||
|
const showPassword = async (id) => {
|
||||||
|
try {
|
||||||
|
curEmailPassword.value = await api.adminShowPassword(id)
|
||||||
|
showEmailPassword.value = true
|
||||||
|
} catch (error) {
|
||||||
|
message.error(error.message || "error");
|
||||||
|
showEmailPassword.value = false
|
||||||
|
curEmailPassword.value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteEmail = async (id) => {
|
||||||
|
try {
|
||||||
|
await api.adminDeleteAddress(id)
|
||||||
|
message.success("success");
|
||||||
|
await fetchData()
|
||||||
|
} catch (error) {
|
||||||
|
message.error(error.message || "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
data.value = await api.adminGetAddress()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
message.error(error.message || "error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: "ID",
|
||||||
|
key: "id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('name'),
|
||||||
|
key: "name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('created_at'),
|
||||||
|
key: "created_at"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Action',
|
||||||
|
key: 'actions',
|
||||||
|
render(row) {
|
||||||
|
return h('div', [
|
||||||
|
h(NButton,
|
||||||
|
{
|
||||||
|
type: 'success',
|
||||||
|
onClick: () => showPassword(row.id)
|
||||||
|
},
|
||||||
|
{ default: () => t('showPass') }
|
||||||
|
),
|
||||||
|
h(NPopconfirm,
|
||||||
|
{
|
||||||
|
onPositiveClick: () => deleteEmail(row.id)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
trigger: () => h(NButton, { type: "error" }, () => t('delete')),
|
||||||
|
default: () => t('deleteTip')
|
||||||
|
}
|
||||||
|
)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (!adminAuth.value) {
|
||||||
|
showAdminAuth.value = true
|
||||||
|
} else {
|
||||||
|
await fetchData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-space vertical>
|
||||||
|
|
||||||
|
<n-layout-header>
|
||||||
|
<div>
|
||||||
|
<h2>{{ t('title') }}</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<n-button tertiary @click="() => router.push('/')" type="primary">
|
||||||
|
{{ t('home') }}
|
||||||
|
</n-button>
|
||||||
|
<n-button tertiary @click="fetchData" type="primary">
|
||||||
|
{{ t('refresh') }}
|
||||||
|
</n-button>
|
||||||
|
</div>
|
||||||
|
<n-modal v-model:show="showAdminAuth" :closable="false" :closeOnEsc="false" :maskClosable="false" preset="dialog"
|
||||||
|
title="Dialog">
|
||||||
|
<template #header>
|
||||||
|
<div>{{ t('auth') }}</div>
|
||||||
|
</template>
|
||||||
|
<p>{{ t('authTip') }}</p>
|
||||||
|
<n-input v-model:value="adminAuth" type="textarea" :autosize="{
|
||||||
|
minRows: 3
|
||||||
|
}" />
|
||||||
|
<template #action>
|
||||||
|
<n-button @click="authFunc" size="small" tertiary round type="primary">
|
||||||
|
{{ t('auth') }}
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
|
<n-modal v-model:show="showEmailPassword" preset="dialog" title="Dialog">
|
||||||
|
<template #header>
|
||||||
|
<div>{{ t("password") }}</div>
|
||||||
|
</template>
|
||||||
|
<span>
|
||||||
|
<p>{{ t("passwordTip") }}</p>
|
||||||
|
</span>
|
||||||
|
<n-card>
|
||||||
|
<b>{{ curEmailPassword }}</b>
|
||||||
|
</n-card>
|
||||||
|
<template #action>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
|
</n-layout-header>
|
||||||
|
<n-data-table :columns="columns" :data="data" :bordered="false" />
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.n-layout-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -13,10 +13,9 @@ const { toClipboard } = useClipboard()
|
|||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
const address = ref("")
|
const address = ref("")
|
||||||
const { jwt, loading, openSettings } = useGlobalState()
|
const { jwt, openSettings } = useGlobalState()
|
||||||
const autoRefresh = ref(false)
|
const autoRefresh = ref(false)
|
||||||
const data = ref([])
|
const data = ref([])
|
||||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
|
||||||
const timer = ref(null)
|
const timer = ref(null)
|
||||||
const showPassword = ref(false)
|
const showPassword = ref(false)
|
||||||
const showNewEmail = ref(false)
|
const showNewEmail = ref(false)
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<script setup>
|
||||||
|
import { NSpace } from 'naive-ui'
|
||||||
|
import Header from './Header.vue';
|
||||||
|
import Content from './Content.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<n-space vertical>
|
||||||
|
<Header />
|
||||||
|
<Content />
|
||||||
|
</n-space>
|
||||||
|
</template>
|
||||||
+39
-1
@@ -9,7 +9,7 @@ api.get('/api/mails', async (c) => {
|
|||||||
return c.json({ "error": "No address" }, 400)
|
return c.json({ "error": "No address" }, 400)
|
||||||
}
|
}
|
||||||
const { results } = await c.env.DB.prepare(
|
const { results } = await c.env.DB.prepare(
|
||||||
`SELECT id, source, subject, message FROM mails where address = ? order by id desc limit 10`
|
`SELECT id, source, subject, message FROM mails where address = ? order by id desc limit 100`
|
||||||
).bind(address).all();
|
).bind(address).all();
|
||||||
return c.json(results);
|
return c.json(results);
|
||||||
})
|
})
|
||||||
@@ -66,4 +66,42 @@ api.get('/api/new_address', async (c) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
api.get('/admin/addresss', async (c) => {
|
||||||
|
const { results } = await c.env.DB.prepare(
|
||||||
|
`SELECT * FROM address order by id desc`
|
||||||
|
).all();
|
||||||
|
return c.json(results.map((r) => {
|
||||||
|
r.name = c.env.PREFIX + r.name;
|
||||||
|
return r;
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
|
||||||
|
api.delete('/admin/delete_address/:id', async (c) => {
|
||||||
|
const { id } = c.req.param();
|
||||||
|
const { success } = await c.env.DB.prepare(
|
||||||
|
`DELETE FROM address WHERE id = ?`
|
||||||
|
).bind(id).run();
|
||||||
|
if (!success) {
|
||||||
|
return c.text("Failed to delete address", 500)
|
||||||
|
}
|
||||||
|
return c.json({
|
||||||
|
success: success
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
api.get('/admin/show_password/:id', async (c) => {
|
||||||
|
const { id } = c.req.param();
|
||||||
|
const name = await c.env.DB.prepare(
|
||||||
|
`SELECT name FROM address WHERE id = ?`
|
||||||
|
).bind(id).first("name");
|
||||||
|
// compute address
|
||||||
|
const emailAddress = c.env.PREFIX + name
|
||||||
|
const jwt = await Jwt.sign({
|
||||||
|
address: emailAddress
|
||||||
|
}, c.env.JWT_SECRET)
|
||||||
|
return c.json({
|
||||||
|
password: jwt
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
export { api }
|
export { api }
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ app.use('/api/*', async (c, next) => {
|
|||||||
return jwt({ secret: c.env.JWT_SECRET })(c, next);
|
return jwt({ secret: c.env.JWT_SECRET })(c, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.use('/admin/*', async (c, next) => {
|
||||||
|
// check header x-admin-auth
|
||||||
|
if (c.env.ADMIN_PASSWORDS && c.env.ADMIN_PASSWORDS.length > 0) {
|
||||||
|
const adminAuth = c.req.headers.get("x-admin-auth");
|
||||||
|
if (adminAuth && c.env.ADMIN_PASSWORDS.includes(adminAuth)) {
|
||||||
|
await next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.text("Need Admin Password", 401)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
app.route('/', api)
|
app.route('/', api)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ node_compat = true
|
|||||||
PREFIX = "tmp"
|
PREFIX = "tmp"
|
||||||
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
# IF YOU WANT TO MAKE YOUR SITE PRIVATE, UNCOMMENT THE FOLLOWING LINES
|
||||||
# PASSWORDS = ["123", "456"]
|
# PASSWORDS = ["123", "456"]
|
||||||
|
# For admin panel
|
||||||
|
# ADMIN_PASSWORDS = ["123", "456"]
|
||||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
||||||
JWT_SECRET = "xxx"
|
JWT_SECRET = "xxx"
|
||||||
BLACK_LIST = ""
|
BLACK_LIST = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user