mirror of
https://github.com/dreamhunter2333/cloudflare_temp_email.git
synced 2026-05-12 02:20:12 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0ccc3ded1 | ||
|
|
163d9451f7 | ||
|
|
60dda7e3fe | ||
|
|
384eb9b041 | ||
|
|
38816cbf0f | ||
|
|
d7d1ba6b64 | ||
|
|
14725e9e9f | ||
|
|
2c1e63b8bc | ||
|
|
f3a1d980c5 | ||
|
|
75c48beb3b | ||
|
|
26ccfdd6e0 | ||
|
|
aa8f3b4d46 | ||
|
|
a749c829d2 | ||
|
|
4b2caf1a4b | ||
|
|
80a8848ed8 | ||
|
|
dcfc1b3721 | ||
|
|
b0a0a6a1ef | ||
|
|
00c671cf14 |
39
.github/workflows/frontend_pagefunction_deploy.yaml
vendored
Normal file
39
.github/workflows/frontend_pagefunction_deploy.yaml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Deploy Frontend with page function
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
name: Install pnpm
|
||||
id: pnpm-install
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Deploy Frontend for ${{ github.ref_name }}
|
||||
run: |
|
||||
cd frontend/
|
||||
pnpm install --no-frozen-lockfile
|
||||
pnpm build:pages
|
||||
cd ../pages/
|
||||
echo '${{ secrets.PAGE_TOML }}' > wrangler.toml
|
||||
pnpm install --no-frozen-lockfile
|
||||
pnpm run deploy
|
||||
echo "Deploying prodcution for ${{ github.ref_name }}"
|
||||
env:
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,6 +1,34 @@
|
||||
<!-- markdownlint-disable-file MD004 MD024 MD034 MD036 -->
|
||||
# CHANGE LOG
|
||||
|
||||
## v0.6.1
|
||||
|
||||
- pages github actions && 修复清理邮件天数为 0 不生效 by @tqjason (#355)
|
||||
- fix: imap proxy server 不支持 密码 by @dreamhunter2333 (#356)
|
||||
- worker 新增 `ANNOUNCEMENT` 配置, 用于配置公告信息 by @dreamhunter2333 (#357)
|
||||
- fix: telegram bot 新建地址默认选择第一个域名 by @dreamhunter2333 (#358)
|
||||
|
||||
## v0.6.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
DB changes: 增加用户角色表, 需要执行 `db/2024-07-14-patch.sql` 更新 `D1` 数据库
|
||||
|
||||
### Changes
|
||||
|
||||
worker 配置文件新增 `DEFAULT_DOMAINS`, `USER_ROLES`, `USER_DEFAULT_ROLE`, 具体查看文档 [worker配置](https://temp-mail-docs.awsl.uk/zh/guide/cli/worker.html#%E4%BF%AE%E6%94%B9-wrangler-toml-%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6)
|
||||
|
||||
- 移除 `apiV1` 相关代码和相关的数据库表
|
||||
- 更新 `admin/statistics` api, 添加用户统计信息
|
||||
- 更新地址的规则,只允许小写+数字,对于历史的地址在查询邮件时会进行 `lowercase` 处理
|
||||
- 增加用户角色功能,`admin` 可以设置用户角色(目前可配置每个角色域名和前缀)
|
||||
- admin 页面搜索优化, 回车自动搜索, 输入内容自动 trim
|
||||
|
||||
## v0.5.4
|
||||
|
||||
- 点击 logo 5 次进入 admin 页面
|
||||
- 修复 401 时无法跳转登录页面(admin 和 网站认证)
|
||||
|
||||
## v0.5.3
|
||||
|
||||
- 修复 smtp imap proxy sever 的一些 bug
|
||||
@@ -292,7 +320,7 @@ The `mails` table will be discarded, and the `raw` text of the new `mail` will b
|
||||
```bash
|
||||
git checkout v0.2.0
|
||||
cd worker
|
||||
wrangler d1 execute dev --file=../db/2024-04-09-patch.sql
|
||||
wrangler d1 execute dev --file=../db/2024-04-09-patch.sql --remote
|
||||
pnpm run deploy
|
||||
cd ../frontend
|
||||
pnpm run deploy
|
||||
|
||||
9
db/2024-07-14-patch.sql
Normal file
9
db/2024-07-14-patch.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
CREATE TABLE IF NOT EXISTS user_roles (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER UNIQUE NOT NULL,
|
||||
role_text TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
|
||||
@@ -1,15 +1,3 @@
|
||||
CREATE TABLE IF NOT EXISTS mails (
|
||||
id INTEGER PRIMARY KEY,
|
||||
message_id TEXT,
|
||||
source TEXT,
|
||||
address TEXT,
|
||||
subject TEXT,
|
||||
message TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_mails_address ON mails(address);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS raw_mails (
|
||||
id INTEGER PRIMARY KEY,
|
||||
message_id TEXT,
|
||||
@@ -43,15 +31,6 @@ CREATE TABLE IF NOT EXISTS auto_reply_mails (
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_auto_reply_mails_address ON auto_reply_mails(address);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS attachments (
|
||||
id INTEGER PRIMARY KEY,
|
||||
source TEXT,
|
||||
address TEXT,
|
||||
message_id TEXT,
|
||||
data TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS address_sender (
|
||||
id INTEGER PRIMARY KEY,
|
||||
address TEXT UNIQUE,
|
||||
@@ -99,3 +78,13 @@ CREATE TABLE IF NOT EXISTS users_address (
|
||||
CREATE INDEX IF NOT EXISTS idx_users_address_user_id ON users_address(user_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_users_address_address_id ON users_address(address_id);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_roles (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER UNIQUE NOT NULL,
|
||||
role_text TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_roles_user_id ON user_roles(user_id);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cloudflare_temp_email",
|
||||
"version": "0.5.3",
|
||||
"version": "0.6.1",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -17,7 +17,7 @@
|
||||
"deploy:actions": "npm run build && wrangler pages deploy ./dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@unhead/vue": "^1.9.14",
|
||||
"@unhead/vue": "^1.9.15",
|
||||
"@vicons/material": "^0.12.0",
|
||||
"@vueuse/core": "^10.11.0",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
@@ -38,11 +38,11 @@
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"unplugin-auto-import": "^0.17.6",
|
||||
"unplugin-vue-components": "^0.27.2",
|
||||
"vite": "^5.3.2",
|
||||
"vite": "^5.3.3",
|
||||
"vite-plugin-pwa": "^0.19.8",
|
||||
"vite-plugin-top-level-await": "^1.4.1",
|
||||
"vite-plugin-wasm": "^3.3.0",
|
||||
"workbox-window": "^7.1.0",
|
||||
"wrangler": "^3.62.0"
|
||||
"wrangler": "^3.63.1"
|
||||
}
|
||||
}
|
||||
|
||||
354
frontend/pnpm-lock.yaml
generated
354
frontend/pnpm-lock.yaml
generated
@@ -9,8 +9,8 @@ importers:
|
||||
.:
|
||||
dependencies:
|
||||
'@unhead/vue':
|
||||
specifier: ^1.9.14
|
||||
version: 1.9.14(vue@3.4.31(typescript@5.4.5))
|
||||
specifier: ^1.9.15
|
||||
version: 1.9.15(vue@3.4.31(typescript@5.4.5))
|
||||
'@vicons/material':
|
||||
specifier: ^0.12.0
|
||||
version: 0.12.0
|
||||
@@ -59,7 +59,7 @@ importers:
|
||||
version: 0.12.0
|
||||
'@vitejs/plugin-vue':
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.5(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))(vue@3.4.31(typescript@5.4.5))
|
||||
version: 5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))(vue@3.4.31(typescript@5.4.5))
|
||||
unplugin-auto-import:
|
||||
specifier: ^0.17.6
|
||||
version: 0.17.6(@vueuse/core@10.11.0(vue@3.4.31(typescript@5.4.5)))(rollup@2.79.1)
|
||||
@@ -67,23 +67,23 @@ importers:
|
||||
specifier: ^0.27.2
|
||||
version: 0.27.2(@babel/parser@7.24.7)(rollup@2.79.1)(vue@3.4.31(typescript@5.4.5))
|
||||
vite:
|
||||
specifier: ^5.3.2
|
||||
version: 5.3.2(@types/node@20.14.9)(terser@5.31.1)
|
||||
specifier: ^5.3.3
|
||||
version: 5.3.3(@types/node@20.14.10)(terser@5.31.1)
|
||||
vite-plugin-pwa:
|
||||
specifier: ^0.19.8
|
||||
version: 0.19.8(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))(workbox-build@7.0.0)(workbox-window@7.1.0)
|
||||
version: 0.19.8(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))(workbox-build@7.0.0)(workbox-window@7.1.0)
|
||||
vite-plugin-top-level-await:
|
||||
specifier: ^1.4.1
|
||||
version: 1.4.1(rollup@2.79.1)(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))
|
||||
version: 1.4.1(rollup@2.79.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))
|
||||
vite-plugin-wasm:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))
|
||||
version: 3.3.0(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))
|
||||
workbox-window:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0
|
||||
wrangler:
|
||||
specifier: ^3.62.0
|
||||
version: 3.62.0
|
||||
specifier: ^3.63.1
|
||||
version: 3.63.1
|
||||
|
||||
packages:
|
||||
|
||||
@@ -680,32 +680,32 @@ packages:
|
||||
resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
|
||||
engines: {node: '>=16.13'}
|
||||
|
||||
'@cloudflare/workerd-darwin-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-YWeS2aE8jAzDefuus/3GmZcFGu3Ef94uCAoxsQuaEXNsiGM9NeAhPpKC1BJAlcv168U/Q1J+6hckcGtipf6ZcQ==}
|
||||
'@cloudflare/workerd-darwin-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-XAZa4ZP+qyTn6JQQACCPH09hGZXP2lTnWKkmg5mPwT8EyRzCKLkczAf98vPP5bq7JZD/zORdFWRY0dOTap8zTQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240620.1':
|
||||
resolution: {integrity: sha512-3rdND+EHpmCrwYX6hvxIBSBJ0f40tRNxond1Vfw7GiR1MJVi3gragiBx75UDFHCxfRw3J0GZ1qVlkRce2/Xbsg==}
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240701.0':
|
||||
resolution: {integrity: sha512-w80ZVAgfH4UwTz7fXZtk7KmS2FzlXniuQm4ku4+cIgRTilBAuKqjpOjwUCbx5g13Gqcm9NuiHce+IDGtobRTIQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@cloudflare/workerd-linux-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-tURcTrXGeSbYqeM5ISVcofY20StKbVIcdxjJvNYNZ+qmSV9Fvn+zr7rRE+q64pEloVZfhsEPAlUCnFso5VV4XQ==}
|
||||
'@cloudflare/workerd-linux-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-UWLr/Anxwwe/25nGv451MNd2jhREmPt/ws17DJJqTLAx6JxwGWA15MeitAIzl0dbxRFAJa+0+R8ag2WR3F/D6g==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@cloudflare/workerd-linux-arm64@1.20240620.1':
|
||||
resolution: {integrity: sha512-TThvkwNxaZFKhHZnNjOGqIYCOk05DDWgO+wYMuXg15ymN/KZPnCicRAkuyqiM+R1Fgc4kwe/pehjP8pbmcf6sg==}
|
||||
'@cloudflare/workerd-linux-arm64@1.20240701.0':
|
||||
resolution: {integrity: sha512-3kCnF9kYgov1ggpuWbgpXt4stPOIYtVmPCa7MO2xhhA0TWP6JDUHRUOsnmIgKrvDjXuXqlK16cdg3v+EWsaPJg==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@cloudflare/workerd-windows-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-Y/BA9Yj0r7Al1HK3nDHcfISgFllw6NR3XMMPChev57vrVT9C9D4erBL3sUBfofHU+2U9L+ShLsl6obBpe3vvUw==}
|
||||
'@cloudflare/workerd-windows-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-6IPGITRAeS67j3BH1rN4iwYWDt47SqJG7KlZJ5bB4UaNAia4mvMBSy/p2p4vA89bbXoDRjMtEvRu7Robu6O7hQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -1191,68 +1191,68 @@ packages:
|
||||
'@surma/rollup-plugin-off-main-thread@2.2.3':
|
||||
resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==}
|
||||
|
||||
'@swc/core-darwin-arm64@1.6.5':
|
||||
resolution: {integrity: sha512-RGQhMdni2v1/ANQ/2K+F+QYdzaucekYBewZcX1ogqJ8G5sbPaBdYdDN1qQ4kHLCIkPtGP6qC7c71qPEqL2RidQ==}
|
||||
'@swc/core-darwin-arm64@1.6.13':
|
||||
resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-darwin-x64@1.6.5':
|
||||
resolution: {integrity: sha512-/pSN0/Jtcbbb9+ovS9rKxR3qertpFAM3OEJr/+Dh/8yy7jK5G5EFPIrfsw/7Q5987ERPIJIH6BspK2CBB2tgcg==}
|
||||
'@swc/core-darwin-x64@1.6.13':
|
||||
resolution: {integrity: sha512-AW8akFSC+tmPE6YQQvK9S2A1B8pjnXEINg+gGgw0KRUUXunvu1/OEOeC5L2Co1wAwhD7bhnaefi06Qi9AiwOag==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.5':
|
||||
resolution: {integrity: sha512-B0g/dROCE747RRegs/jPHuKJgwXLracDhnqQa80kFdgWEMjlcb7OMCgs5OX86yJGRS4qcYbiMGD0Pp7Kbqn3yw==}
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.13':
|
||||
resolution: {integrity: sha512-f4gxxvDXVUm2HLYXRd311mSrmbpQF2MZ4Ja6XCQz1hWAxXdhRl1gpnZ+LH/xIfGSwQChrtLLVrkxdYUCVuIjFg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.6.5':
|
||||
resolution: {integrity: sha512-W8meapgXTq8AOtSvDG4yKR8ant2WWD++yOjgzAleB5VAC+oC+aa8YJROGxj8HepurU8kurqzcialwoMeq5SZZQ==}
|
||||
'@swc/core-linux-arm64-gnu@1.6.13':
|
||||
resolution: {integrity: sha512-Nf/eoW2CbG8s+9JoLtjl9FByBXyQ5cjdBsA4efO7Zw4p+YSuXDgc8HRPC+E2+ns0praDpKNZtLvDtmF2lL+2Gg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.6.5':
|
||||
resolution: {integrity: sha512-jyCKqoX50Fg8rJUQqh4u5PqnE7nqYKXHjVH2WcYr114/MU21zlsI+YL6aOQU1XP8bJQ2gPQ1rnlnGJdEHiKS/w==}
|
||||
'@swc/core-linux-arm64-musl@1.6.13':
|
||||
resolution: {integrity: sha512-2OysYSYtdw79prJYuKIiux/Gj0iaGEbpS2QZWCIY4X9sGoETJ5iMg+lY+YCrIxdkkNYd7OhIbXdYFyGs/w5LDg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.6.5':
|
||||
resolution: {integrity: sha512-G6HmUn/RRIlXC0YYFfBz2qh6OZkHS/KUPkhoG4X9ADcgWXXjOFh6JrefwsYj8VBAJEnr5iewzjNfj+nztwHaeA==}
|
||||
'@swc/core-linux-x64-gnu@1.6.13':
|
||||
resolution: {integrity: sha512-PkR4CZYJNk5hcd2+tMWBpnisnmYsUzazI1O5X7VkIGFcGePTqJ/bWlfUIVVExWxvAI33PQFzLbzmN5scyIUyGQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-linux-x64-musl@1.6.5':
|
||||
resolution: {integrity: sha512-AQpBjBnelQDSbeTJA50AXdS6+CP66LsXIMNTwhPSgUfE7Bx1ggZV11Fsi4Q5SGcs6a8Qw1cuYKN57ZfZC5QOuA==}
|
||||
'@swc/core-linux-x64-musl@1.6.13':
|
||||
resolution: {integrity: sha512-OdsY7wryTxCKwGQcwW9jwWg3cxaHBkTTHi91+5nm7hFPpmZMz1HivJrWAMwVE7iXFw+M4l6ugB/wCvpYrUAAjA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.6.5':
|
||||
resolution: {integrity: sha512-MZTWM8kUwS30pVrtbzSGEXtek46aXNb/mT9D6rsS7NvOuv2w+qZhjR1rzf4LNbbn5f8VnR4Nac1WIOYZmfC5ng==}
|
||||
'@swc/core-win32-arm64-msvc@1.6.13':
|
||||
resolution: {integrity: sha512-ap6uNmYjwk9M/+bFEuWRNl3hq4VqgQ/Lk+ID/F5WGqczNr0L7vEf+pOsRAn0F6EV+o/nyb3ePt8rLhE/wjHpPg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.6.5':
|
||||
resolution: {integrity: sha512-WZdu4gISAr3yOm1fVwKhhk6+MrP7kVX0KMP7+ZQFTN5zXQEiDSDunEJKVgjMVj3vlR+6mnAqa/L0V9Qa8+zKlQ==}
|
||||
'@swc/core-win32-ia32-msvc@1.6.13':
|
||||
resolution: {integrity: sha512-IJ8KH4yIUHTnS/U1jwQmtbfQals7zWPG0a9hbEfIr4zI0yKzjd83lmtS09lm2Q24QBWOCFGEEbuZxR4tIlvfzA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.6.5':
|
||||
resolution: {integrity: sha512-ezXgucnMTzlFIxQZw7ls/5r2hseFaRoDL04cuXUOs97E8r+nJSmFsRQm/ygH5jBeXNo59nyZCalrjJAjwfgACA==}
|
||||
'@swc/core-win32-x64-msvc@1.6.13':
|
||||
resolution: {integrity: sha512-f6/sx6LMuEnbuxtiSL/EkR0Y6qUHFw1XVrh6rwzKXptTipUdOY+nXpKoh+1UsBm/r7H0/5DtOdrn3q5ZHbFZjQ==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@swc/core@1.6.5':
|
||||
resolution: {integrity: sha512-tyVvUK/HDOUUsK6/GmWvnqUtD9oDpPUA4f7f7JCOV8hXxtfjMtAZeBKf93yrB1XZet69TDR7EN0hFC6i4MF0Ig==}
|
||||
'@swc/core@1.6.13':
|
||||
resolution: {integrity: sha512-eailUYex6fkfaQTev4Oa3mwn0/e3mQU4H8y1WPuImYQESOQDtVrowwUGDSc19evpBbHpKtwM+hw8nLlhIsF+Tw==}
|
||||
engines: {node: '>=10'}
|
||||
peerDependencies:
|
||||
'@swc/helpers': '*'
|
||||
@@ -1290,8 +1290,8 @@ packages:
|
||||
'@types/node-forge@1.3.11':
|
||||
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
|
||||
|
||||
'@types/node@20.14.9':
|
||||
resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==}
|
||||
'@types/node@20.14.10':
|
||||
resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==}
|
||||
|
||||
'@types/resolve@1.17.1':
|
||||
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
|
||||
@@ -1302,17 +1302,17 @@ packages:
|
||||
'@types/web-bluetooth@0.0.20':
|
||||
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
||||
|
||||
'@unhead/dom@1.9.14':
|
||||
resolution: {integrity: sha512-XZSZ2Wmm1Sv7k9scSFGrarbteSIl3p3I3oOUprKPDboBTvuG5q81Qz8O99NKUGKGJ8BKUkxCqE982eH3S8DKJA==}
|
||||
'@unhead/dom@1.9.15':
|
||||
resolution: {integrity: sha512-4sdP/2Unt4zFRO8pBZVXvebidGmrLEvnDU6ZpasZfInjiiuuaQOVTJaiKnEnug3cmW2YjglPG2d1c2xAsHr3NQ==}
|
||||
|
||||
'@unhead/schema@1.9.14':
|
||||
resolution: {integrity: sha512-60NYSM6QjfK/wx4/QfaYyZ3XnNtwxS9a1oij2abEkGHPmA2/fqBOXeuHtnBo4eD42/Eg+owcS5s3mClPL8AkXw==}
|
||||
'@unhead/schema@1.9.15':
|
||||
resolution: {integrity: sha512-9ADZuXOH+tOKHIjXsgg+SPINnh/YJEBMCjpg+8VLGgE2r5med3jAnOU8g7ALfuVEBRBrbFgs1qVKoKm1NkTXJQ==}
|
||||
|
||||
'@unhead/shared@1.9.14':
|
||||
resolution: {integrity: sha512-7ZIC7uDV8gp3KHm5JxJ/NXMENQgkh+SCyTcsILSpOhkAGeszMHABrB6vjeZDGM4J9mRUxwyPn24KI2zG/R+XiQ==}
|
||||
'@unhead/shared@1.9.15':
|
||||
resolution: {integrity: sha512-+U5r04eRtCNcniWjzNPRtwVuF9rW/6EXxhGvuohJBDaIE57J6BHWo5cEp7Pqts7DlTFs7LiDtH8ONNDv4QqRaw==}
|
||||
|
||||
'@unhead/vue@1.9.14':
|
||||
resolution: {integrity: sha512-Yc7Qv0ze+iLte4urHiA+ghkF7y+svrawrT+ZrCuGXkZ/eRTF/AY2SKex+rJQJZsP+fKEQ2pGb72IsI5kHFZT3A==}
|
||||
'@unhead/vue@1.9.15':
|
||||
resolution: {integrity: sha512-h866wYOs6Q6+lc0av4EU0CPTtTvaz9UWwwsiNoulzJa95QyUN/gDPI/NiDuKweHswY+a0SSzEqe9Nhg+LlmHew==}
|
||||
peerDependencies:
|
||||
vue: '>=2.7 || >=3'
|
||||
|
||||
@@ -1478,8 +1478,8 @@ packages:
|
||||
resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
acorn@8.12.0:
|
||||
resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==}
|
||||
acorn@8.12.1:
|
||||
resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1580,8 +1580,8 @@ packages:
|
||||
resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
caniuse-lite@1.0.30001638:
|
||||
resolution: {integrity: sha512-5SuJUJ7cZnhPpeLHaH0c/HPAnAHZvS6ElWyHK9GSIbVOQABLzowiI2pjmpvZ1WEbkyz46iFd4UXlOHR5SqgfMQ==}
|
||||
caniuse-lite@1.0.30001640:
|
||||
resolution: {integrity: sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==}
|
||||
|
||||
capnp-ts@0.7.0:
|
||||
resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==}
|
||||
@@ -1734,8 +1734,8 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
hasBin: true
|
||||
|
||||
electron-to-chromium@1.4.814:
|
||||
resolution: {integrity: sha512-GVulpHjFu1Y9ZvikvbArHmAhZXtm3wHlpjTMcXNGKl4IQ4jMQjlnz8yMQYYqdLHKi/jEL2+CBC2akWVCoIGUdw==}
|
||||
electron-to-chromium@1.4.818:
|
||||
resolution: {integrity: sha512-eGvIk2V0dGImV9gWLq8fDfTTsCAeMDwZqEPMr+jMInxZdnp9Us8UpovYpRCf9NQ7VOFgrN2doNSgvISbsbNpxA==}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
@@ -1969,8 +1969,8 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
highlight.js@11.9.0:
|
||||
resolution: {integrity: sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==}
|
||||
highlight.js@11.10.0:
|
||||
resolution: {integrity: sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
hookable@5.5.3:
|
||||
@@ -2232,8 +2232,8 @@ packages:
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
miniflare@3.20240620.0:
|
||||
resolution: {integrity: sha512-NBMzqUE2mMlh/hIdt6U5MP+aFhEjKDq3l8CAajXAQa1WkndJdciWvzB2mfLETwoVFhMl/lphaVzyEN2AgwJpbQ==}
|
||||
miniflare@3.20240701.0:
|
||||
resolution: {integrity: sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==}
|
||||
engines: {node: '>=16.13'}
|
||||
hasBin: true
|
||||
|
||||
@@ -2326,8 +2326,8 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
pkg-types@1.1.1:
|
||||
resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==}
|
||||
pkg-types@1.1.3:
|
||||
resolution: {integrity: sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==}
|
||||
|
||||
possible-typed-array-names@1.0.0:
|
||||
resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==}
|
||||
@@ -2336,12 +2336,12 @@ packages:
|
||||
postal-mime@2.2.5:
|
||||
resolution: {integrity: sha512-6eTJf+B47JMdDuLF/4MBiGpTinxl0W8bA9CzrSoiQrNVRqK8Vhe59VrS6sXh2lG/lgo0bxpZFcWOF4Dv1FaSfg==}
|
||||
|
||||
postcss@8.4.38:
|
||||
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
|
||||
postcss@8.4.39:
|
||||
resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
preact@10.22.0:
|
||||
resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==}
|
||||
preact@10.22.1:
|
||||
resolution: {integrity: sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==}
|
||||
|
||||
pretty-bytes@5.6.0:
|
||||
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
|
||||
@@ -2665,8 +2665,8 @@ packages:
|
||||
unenv-nightly@1.10.0-1717606461.a117952:
|
||||
resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==}
|
||||
|
||||
unhead@1.9.14:
|
||||
resolution: {integrity: sha512-npdYu6CfasX/IhB8OO27e3u4A1zhAY77T1FwWDIIUaJvugYTte5hjsolPX0/fG5jmjnWTFTuIkmbCSfj7bfIkg==}
|
||||
unhead@1.9.15:
|
||||
resolution: {integrity: sha512-/99Wft1CT0fxsWzmBeOwuH/k4HdMeyfDGyB4wFNVZVNTffRHDOqaqQ6RS+LHPsIiCKmm9FP7Vq7Rz09Zs/fQJQ==}
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.0:
|
||||
resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
|
||||
@@ -2720,16 +2720,16 @@ packages:
|
||||
'@nuxt/kit':
|
||||
optional: true
|
||||
|
||||
unplugin@1.10.1:
|
||||
resolution: {integrity: sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==}
|
||||
unplugin@1.11.0:
|
||||
resolution: {integrity: sha512-3r7VWZ/webh0SGgJScpWl2/MRCZK5d3ZYFcNaeci/GQ7Teop7zf0Nl2pUuz7G21BwPd9pcUPOC5KmJ2L3WgC5g==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
upath@1.2.0:
|
||||
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
update-browserslist-db@1.0.16:
|
||||
resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==}
|
||||
update-browserslist-db@1.1.0:
|
||||
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
@@ -2771,8 +2771,8 @@ packages:
|
||||
peerDependencies:
|
||||
vite: ^2 || ^3 || ^4 || ^5
|
||||
|
||||
vite@5.3.2:
|
||||
resolution: {integrity: sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==}
|
||||
vite@5.3.3:
|
||||
resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2921,13 +2921,13 @@ packages:
|
||||
workbox-window@7.1.0:
|
||||
resolution: {integrity: sha512-ZHeROyqR+AS5UPzholQRDttLFqGMwP0Np8MKWAdyxsDETxq3qOAyXvqessc3GniohG6e0mAqSQyKOHmT8zPF7g==}
|
||||
|
||||
workerd@1.20240620.1:
|
||||
resolution: {integrity: sha512-Qoq+RrFNk4pvEO+kpJVn8uJ5TRE9YJx5jX5pC5LjdKlw1XeD8EdXt5k0TbByvWunZ4qgYIcF9lnVxhcDFo203g==}
|
||||
workerd@1.20240701.0:
|
||||
resolution: {integrity: sha512-qSgNVqauqzNCij9MaJLF2c2ko3AnFioVSIxMSryGbRK+LvtGr9BKBt6JOxCb24DoJASoJDx3pe3DJHBVydUiBg==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
|
||||
wrangler@3.62.0:
|
||||
resolution: {integrity: sha512-TM1Bd8+GzxFw/JzwsC3i/Oss4LTWvIEWXXo1vZhx+7PHcsxdbnQGBBwPurHNJDSu2Pw22+2pCZiUGKexmgJksw==}
|
||||
wrangler@3.63.1:
|
||||
resolution: {integrity: sha512-fxMPNEyDc9pZNtQOuYqRikzv6lL5eP4S1zv7L/kw24uu1cCEmJ39j8bfJGzrAEqKDNsiFXVjEka0RjlpgEVWPg==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -2939,8 +2939,8 @@ packages:
|
||||
wrappy@1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
|
||||
ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
ws@8.18.0:
|
||||
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
@@ -3754,19 +3754,19 @@ snapshots:
|
||||
dependencies:
|
||||
mime: 3.0.0
|
||||
|
||||
'@cloudflare/workerd-darwin-64@1.20240620.1':
|
||||
'@cloudflare/workerd-darwin-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240620.1':
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-linux-64@1.20240620.1':
|
||||
'@cloudflare/workerd-linux-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-linux-arm64@1.20240620.1':
|
||||
'@cloudflare/workerd-linux-arm64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-windows-64@1.20240620.1':
|
||||
'@cloudflare/workerd-windows-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cspotcode/source-map-support@0.8.1':
|
||||
@@ -4082,51 +4082,51 @@ snapshots:
|
||||
magic-string: 0.25.9
|
||||
string.prototype.matchall: 4.0.11
|
||||
|
||||
'@swc/core-darwin-arm64@1.6.5':
|
||||
'@swc/core-darwin-arm64@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-darwin-x64@1.6.5':
|
||||
'@swc/core-darwin-x64@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.5':
|
||||
'@swc/core-linux-arm-gnueabihf@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-gnu@1.6.5':
|
||||
'@swc/core-linux-arm64-gnu@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-arm64-musl@1.6.5':
|
||||
'@swc/core-linux-arm64-musl@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-gnu@1.6.5':
|
||||
'@swc/core-linux-x64-gnu@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-linux-x64-musl@1.6.5':
|
||||
'@swc/core-linux-x64-musl@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-arm64-msvc@1.6.5':
|
||||
'@swc/core-win32-arm64-msvc@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-ia32-msvc@1.6.5':
|
||||
'@swc/core-win32-ia32-msvc@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core-win32-x64-msvc@1.6.5':
|
||||
'@swc/core-win32-x64-msvc@1.6.13':
|
||||
optional: true
|
||||
|
||||
'@swc/core@1.6.5':
|
||||
'@swc/core@1.6.13':
|
||||
dependencies:
|
||||
'@swc/counter': 0.1.3
|
||||
'@swc/types': 0.1.9
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.6.5
|
||||
'@swc/core-darwin-x64': 1.6.5
|
||||
'@swc/core-linux-arm-gnueabihf': 1.6.5
|
||||
'@swc/core-linux-arm64-gnu': 1.6.5
|
||||
'@swc/core-linux-arm64-musl': 1.6.5
|
||||
'@swc/core-linux-x64-gnu': 1.6.5
|
||||
'@swc/core-linux-x64-musl': 1.6.5
|
||||
'@swc/core-win32-arm64-msvc': 1.6.5
|
||||
'@swc/core-win32-ia32-msvc': 1.6.5
|
||||
'@swc/core-win32-x64-msvc': 1.6.5
|
||||
'@swc/core-darwin-arm64': 1.6.13
|
||||
'@swc/core-darwin-x64': 1.6.13
|
||||
'@swc/core-linux-arm-gnueabihf': 1.6.13
|
||||
'@swc/core-linux-arm64-gnu': 1.6.13
|
||||
'@swc/core-linux-arm64-musl': 1.6.13
|
||||
'@swc/core-linux-x64-gnu': 1.6.13
|
||||
'@swc/core-linux-x64-musl': 1.6.13
|
||||
'@swc/core-win32-arm64-msvc': 1.6.13
|
||||
'@swc/core-win32-ia32-msvc': 1.6.13
|
||||
'@swc/core-win32-x64-msvc': 1.6.13
|
||||
|
||||
'@swc/counter@0.1.3': {}
|
||||
|
||||
@@ -4152,40 +4152,40 @@ snapshots:
|
||||
|
||||
'@types/node-forge@1.3.11':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/node@20.14.9':
|
||||
'@types/node@20.14.10':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/resolve@1.17.1':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/trusted-types@2.0.7': {}
|
||||
|
||||
'@types/web-bluetooth@0.0.20': {}
|
||||
|
||||
'@unhead/dom@1.9.14':
|
||||
'@unhead/dom@1.9.15':
|
||||
dependencies:
|
||||
'@unhead/schema': 1.9.14
|
||||
'@unhead/shared': 1.9.14
|
||||
'@unhead/schema': 1.9.15
|
||||
'@unhead/shared': 1.9.15
|
||||
|
||||
'@unhead/schema@1.9.14':
|
||||
'@unhead/schema@1.9.15':
|
||||
dependencies:
|
||||
hookable: 5.5.3
|
||||
zhead: 2.2.4
|
||||
|
||||
'@unhead/shared@1.9.14':
|
||||
'@unhead/shared@1.9.15':
|
||||
dependencies:
|
||||
'@unhead/schema': 1.9.14
|
||||
'@unhead/schema': 1.9.15
|
||||
|
||||
'@unhead/vue@1.9.14(vue@3.4.31(typescript@5.4.5))':
|
||||
'@unhead/vue@1.9.15(vue@3.4.31(typescript@5.4.5))':
|
||||
dependencies:
|
||||
'@unhead/schema': 1.9.14
|
||||
'@unhead/shared': 1.9.14
|
||||
'@unhead/schema': 1.9.15
|
||||
'@unhead/shared': 1.9.15
|
||||
hookable: 5.5.3
|
||||
unhead: 1.9.14
|
||||
unhead: 1.9.15
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
|
||||
'@uppy/companion-client@2.2.2':
|
||||
@@ -4202,7 +4202,7 @@ snapshots:
|
||||
mime-match: 1.0.2
|
||||
namespace-emitter: 2.0.1
|
||||
nanoid: 3.3.7
|
||||
preact: 10.22.0
|
||||
preact: 10.22.1
|
||||
|
||||
'@uppy/store-default@2.1.1': {}
|
||||
|
||||
@@ -4221,9 +4221,9 @@ snapshots:
|
||||
|
||||
'@vicons/material@0.12.0': {}
|
||||
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))(vue@3.4.31(typescript@5.4.5))':
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))(vue@3.4.31(typescript@5.4.5))':
|
||||
dependencies:
|
||||
vite: 5.3.2(@types/node@20.14.9)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(terser@5.31.1)
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
|
||||
'@vue/compiler-core@3.4.31':
|
||||
@@ -4248,7 +4248,7 @@ snapshots:
|
||||
'@vue/shared': 3.4.31
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.10
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.39
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-ssr@3.4.31':
|
||||
@@ -4411,9 +4411,9 @@ snapshots:
|
||||
|
||||
acorn-walk@8.3.3:
|
||||
dependencies:
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
|
||||
acorn@8.12.0: {}
|
||||
acorn@8.12.1: {}
|
||||
|
||||
ajv@8.16.0:
|
||||
dependencies:
|
||||
@@ -4520,10 +4520,10 @@ snapshots:
|
||||
|
||||
browserslist@4.23.1:
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001638
|
||||
electron-to-chromium: 1.4.814
|
||||
caniuse-lite: 1.0.30001640
|
||||
electron-to-chromium: 1.4.818
|
||||
node-releases: 2.0.14
|
||||
update-browserslist-db: 1.0.16(browserslist@4.23.1)
|
||||
update-browserslist-db: 1.1.0(browserslist@4.23.1)
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
@@ -4537,7 +4537,7 @@ snapshots:
|
||||
get-intrinsic: 1.2.4
|
||||
set-function-length: 1.2.2
|
||||
|
||||
caniuse-lite@1.0.30001638: {}
|
||||
caniuse-lite@1.0.30001640: {}
|
||||
|
||||
capnp-ts@0.7.0:
|
||||
dependencies:
|
||||
@@ -4691,7 +4691,7 @@ snapshots:
|
||||
dependencies:
|
||||
jake: 10.9.1
|
||||
|
||||
electron-to-chromium@1.4.814: {}
|
||||
electron-to-chromium@1.4.818: {}
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
@@ -5011,7 +5011,7 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
highlight.js@11.9.0: {}
|
||||
highlight.js@11.10.0: {}
|
||||
|
||||
hookable@5.5.3: {}
|
||||
|
||||
@@ -5138,7 +5138,7 @@ snapshots:
|
||||
|
||||
jest-worker@26.6.2:
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 7.2.0
|
||||
|
||||
@@ -5180,7 +5180,7 @@ snapshots:
|
||||
local-pkg@0.5.0:
|
||||
dependencies:
|
||||
mlly: 1.7.1
|
||||
pkg-types: 1.1.1
|
||||
pkg-types: 1.1.3
|
||||
|
||||
lodash-es@4.17.21: {}
|
||||
|
||||
@@ -5237,18 +5237,18 @@ snapshots:
|
||||
|
||||
mime@3.0.0: {}
|
||||
|
||||
miniflare@3.20240620.0:
|
||||
miniflare@3.20240701.0:
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
acorn-walk: 8.3.3
|
||||
capnp-ts: 0.7.0
|
||||
exit-hook: 2.2.1
|
||||
glob-to-regexp: 0.4.1
|
||||
stoppable: 1.1.0
|
||||
undici: 5.28.4
|
||||
workerd: 1.20240620.1
|
||||
ws: 8.17.1
|
||||
workerd: 1.20240701.0
|
||||
ws: 8.18.0
|
||||
youch: 3.3.3
|
||||
zod: 3.23.8
|
||||
transitivePeerDependencies:
|
||||
@@ -5270,9 +5270,9 @@ snapshots:
|
||||
|
||||
mlly@1.7.1:
|
||||
dependencies:
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.1.1
|
||||
pkg-types: 1.1.3
|
||||
ufo: 1.5.3
|
||||
|
||||
ms@2.1.2: {}
|
||||
@@ -5292,7 +5292,7 @@ snapshots:
|
||||
date-fns: 2.30.0
|
||||
date-fns-tz: 2.0.1(date-fns@2.30.0)
|
||||
evtd: 0.2.4
|
||||
highlight.js: 11.9.0
|
||||
highlight.js: 11.10.0
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
seemly: 0.3.8
|
||||
@@ -5345,7 +5345,7 @@ snapshots:
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
pkg-types@1.1.1:
|
||||
pkg-types@1.1.3:
|
||||
dependencies:
|
||||
confbox: 0.1.7
|
||||
mlly: 1.7.1
|
||||
@@ -5355,13 +5355,13 @@ snapshots:
|
||||
|
||||
postal-mime@2.2.5: {}
|
||||
|
||||
postcss@8.4.38:
|
||||
postcss@8.4.39:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
preact@10.22.0: {}
|
||||
preact@10.22.1: {}
|
||||
|
||||
pretty-bytes@5.6.0: {}
|
||||
|
||||
@@ -5665,7 +5665,7 @@ snapshots:
|
||||
terser@5.31.1:
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.6
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
|
||||
@@ -5750,11 +5750,11 @@ snapshots:
|
||||
pathe: 1.1.2
|
||||
ufo: 1.5.3
|
||||
|
||||
unhead@1.9.14:
|
||||
unhead@1.9.15:
|
||||
dependencies:
|
||||
'@unhead/dom': 1.9.14
|
||||
'@unhead/schema': 1.9.14
|
||||
'@unhead/shared': 1.9.14
|
||||
'@unhead/dom': 1.9.15
|
||||
'@unhead/schema': 1.9.15
|
||||
'@unhead/shared': 1.9.15
|
||||
hookable: 5.5.3
|
||||
|
||||
unicode-canonical-property-names-ecmascript@2.0.0: {}
|
||||
@@ -5771,7 +5771,7 @@ snapshots:
|
||||
unimport@3.7.2(rollup@2.79.1):
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.0(rollup@2.79.1)
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
escape-string-regexp: 5.0.0
|
||||
estree-walker: 3.0.3
|
||||
fast-glob: 3.3.2
|
||||
@@ -5779,10 +5779,10 @@ snapshots:
|
||||
magic-string: 0.30.10
|
||||
mlly: 1.7.1
|
||||
pathe: 1.1.2
|
||||
pkg-types: 1.1.1
|
||||
pkg-types: 1.1.3
|
||||
scule: 1.3.0
|
||||
strip-literal: 2.1.0
|
||||
unplugin: 1.10.1
|
||||
unplugin: 1.11.0
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
|
||||
@@ -5801,7 +5801,7 @@ snapshots:
|
||||
magic-string: 0.30.10
|
||||
minimatch: 9.0.5
|
||||
unimport: 3.7.2(rollup@2.79.1)
|
||||
unplugin: 1.10.1
|
||||
unplugin: 1.11.0
|
||||
optionalDependencies:
|
||||
'@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.4.5))
|
||||
transitivePeerDependencies:
|
||||
@@ -5818,7 +5818,7 @@ snapshots:
|
||||
magic-string: 0.30.10
|
||||
minimatch: 9.0.5
|
||||
mlly: 1.7.1
|
||||
unplugin: 1.10.1
|
||||
unplugin: 1.11.0
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
optionalDependencies:
|
||||
'@babel/parser': 7.24.7
|
||||
@@ -5826,16 +5826,16 @@ snapshots:
|
||||
- rollup
|
||||
- supports-color
|
||||
|
||||
unplugin@1.10.1:
|
||||
unplugin@1.11.0:
|
||||
dependencies:
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
chokidar: 3.6.0
|
||||
webpack-sources: 3.2.3
|
||||
webpack-virtual-modules: 0.6.2
|
||||
|
||||
upath@1.2.0: {}
|
||||
|
||||
update-browserslist-db@1.0.16(browserslist@4.23.1):
|
||||
update-browserslist-db@1.1.0(browserslist@4.23.1):
|
||||
dependencies:
|
||||
browserslist: 4.23.1
|
||||
escalade: 3.1.2
|
||||
@@ -5854,38 +5854,38 @@ snapshots:
|
||||
evtd: 0.2.4
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
|
||||
vite-plugin-pwa@0.19.8(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1))(workbox-build@7.0.0)(workbox-window@7.1.0):
|
||||
vite-plugin-pwa@0.19.8(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1))(workbox-build@7.0.0)(workbox-window@7.1.0):
|
||||
dependencies:
|
||||
debug: 4.3.5
|
||||
fast-glob: 3.3.2
|
||||
pretty-bytes: 6.1.1
|
||||
vite: 5.3.2(@types/node@20.14.9)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(terser@5.31.1)
|
||||
workbox-build: 7.0.0
|
||||
workbox-window: 7.1.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite-plugin-top-level-await@1.4.1(rollup@2.79.1)(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1)):
|
||||
vite-plugin-top-level-await@1.4.1(rollup@2.79.1)(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1)):
|
||||
dependencies:
|
||||
'@rollup/plugin-virtual': 3.0.2(rollup@2.79.1)
|
||||
'@swc/core': 1.6.5
|
||||
'@swc/core': 1.6.13
|
||||
uuid: 9.0.1
|
||||
vite: 5.3.2(@types/node@20.14.9)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(terser@5.31.1)
|
||||
transitivePeerDependencies:
|
||||
- '@swc/helpers'
|
||||
- rollup
|
||||
|
||||
vite-plugin-wasm@3.3.0(vite@5.3.2(@types/node@20.14.9)(terser@5.31.1)):
|
||||
vite-plugin-wasm@3.3.0(vite@5.3.3(@types/node@20.14.10)(terser@5.31.1)):
|
||||
dependencies:
|
||||
vite: 5.3.2(@types/node@20.14.9)(terser@5.31.1)
|
||||
vite: 5.3.3(@types/node@20.14.10)(terser@5.31.1)
|
||||
|
||||
vite@5.3.2(@types/node@20.14.9)(terser@5.31.1):
|
||||
vite@5.3.3(@types/node@20.14.10)(terser@5.31.1):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.39
|
||||
rollup: 4.18.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
fsevents: 2.3.3
|
||||
terser: 5.31.1
|
||||
|
||||
@@ -6085,15 +6085,15 @@ snapshots:
|
||||
'@types/trusted-types': 2.0.7
|
||||
workbox-core: 7.1.0
|
||||
|
||||
workerd@1.20240620.1:
|
||||
workerd@1.20240701.0:
|
||||
optionalDependencies:
|
||||
'@cloudflare/workerd-darwin-64': 1.20240620.1
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20240620.1
|
||||
'@cloudflare/workerd-linux-64': 1.20240620.1
|
||||
'@cloudflare/workerd-linux-arm64': 1.20240620.1
|
||||
'@cloudflare/workerd-windows-64': 1.20240620.1
|
||||
'@cloudflare/workerd-darwin-64': 1.20240701.0
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20240701.0
|
||||
'@cloudflare/workerd-linux-64': 1.20240701.0
|
||||
'@cloudflare/workerd-linux-arm64': 1.20240701.0
|
||||
'@cloudflare/workerd-windows-64': 1.20240701.0
|
||||
|
||||
wrangler@3.62.0:
|
||||
wrangler@3.63.1:
|
||||
dependencies:
|
||||
'@cloudflare/kv-asset-handler': 0.3.4
|
||||
'@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19)
|
||||
@@ -6102,7 +6102,7 @@ snapshots:
|
||||
chokidar: 3.6.0
|
||||
date-fns: 3.6.0
|
||||
esbuild: 0.17.19
|
||||
miniflare: 3.20240620.0
|
||||
miniflare: 3.20240701.0
|
||||
nanoid: 3.3.7
|
||||
path-to-regexp: 6.2.2
|
||||
resolve: 1.22.8
|
||||
@@ -6120,7 +6120,7 @@ snapshots:
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
ws@8.17.1: {}
|
||||
ws@8.18.0: {}
|
||||
|
||||
xxhash-wasm@1.0.2: {}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ onMounted(async () => {
|
||||
<n-config-provider :locale="localeConfig" :theme="theme">
|
||||
<n-global-style />
|
||||
<n-spin description="loading..." :show="loading">
|
||||
<n-message-provider>
|
||||
<n-message-provider container-style="margin-top: 20px;">
|
||||
<n-grid x-gap="12" :cols="12">
|
||||
<n-gi v-if="showSideMargin" span="1"></n-gi>
|
||||
<n-gi :span="!showSideMargin ? 12 : 10">
|
||||
|
||||
@@ -4,13 +4,14 @@ import axios from 'axios'
|
||||
const API_BASE = import.meta.env.VITE_API_BASE || "";
|
||||
const {
|
||||
loading, auth, jwt, settings, openSettings,
|
||||
userOpenSettings, userSettings,
|
||||
userOpenSettings, userSettings, announcement,
|
||||
showAuth, adminAuth, showAdminAuth, userJwt
|
||||
} = useGlobalState();
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: API_BASE,
|
||||
timeout: 30000
|
||||
timeout: 30000,
|
||||
validateStatus: (status) => status >= 200 && status <= 500
|
||||
});
|
||||
|
||||
const apiFetch = async (path, options = {}) => {
|
||||
@@ -27,14 +28,14 @@ const apiFetch = async (path, options = {}) => {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (response.status === 401 && openSettings.value.auth) {
|
||||
showAuth.value = true;
|
||||
throw new Error("Unauthorized, you access password is wrong")
|
||||
}
|
||||
if (response.status === 401 && path.startsWith("/admin")) {
|
||||
showAdminAuth.value = true;
|
||||
throw new Error("Unauthorized, your admin password is wrong")
|
||||
}
|
||||
if (response.status === 401 && openSettings.value.auth) {
|
||||
showAuth.value = true;
|
||||
throw new Error("Unauthorized, you access password is wrong")
|
||||
}
|
||||
if (response.status >= 300) {
|
||||
throw new Error(`${response.status} ${response.data}` || "error");
|
||||
}
|
||||
@@ -55,11 +56,13 @@ const getOpenSettings = async (message) => {
|
||||
const res = await api.fetch("/open_api/settings");
|
||||
const domainLabels = res["domainLabels"] || [];
|
||||
Object.assign(openSettings.value, {
|
||||
...res,
|
||||
title: res["title"] || "",
|
||||
prefix: res["prefix"] || "",
|
||||
minAddressLen: res["minAddressLen"] || 1,
|
||||
maxAddressLen: res["maxAddressLen"] || 30,
|
||||
needAuth: res["needAuth"] || false,
|
||||
defaultDomains: res["defaultDomains"] || [],
|
||||
domains: res["domains"].map((domain, index) => {
|
||||
return {
|
||||
label: domainLabels.length > index ? domainLabels[index] : domain,
|
||||
@@ -79,6 +82,14 @@ const getOpenSettings = async (message) => {
|
||||
if (openSettings.value.needAuth) {
|
||||
showAuth.value = true;
|
||||
}
|
||||
if (openSettings.value.announcement && openSettings.value.announcement != announcement.value) {
|
||||
announcement.value = openSettings.value.announcement;
|
||||
message.info(announcement.value, {
|
||||
showIcon: false,
|
||||
duration: 0,
|
||||
closable: true
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
message.error(error.message || "error");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref, watch, defineModel, onMounted } from "vue";
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGlobalState } from '../store'
|
||||
const { openSettings, isDark } = useGlobalState()
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { ref } from "vue";
|
||||
import { createGlobalState, useStorage, useDark, useToggle } from '@vueuse/core'
|
||||
import { createGlobalState, useStorage, useDark, useToggle, useLocalStorage } from '@vueuse/core'
|
||||
|
||||
export const useGlobalState = createGlobalState(
|
||||
() => {
|
||||
const isDark = useDark()
|
||||
const toggleDark = useToggle(isDark)
|
||||
const loading = ref(false);
|
||||
const announcement = useLocalStorage('announcement', '');
|
||||
const openSettings = ref({
|
||||
title: '',
|
||||
announcement: '',
|
||||
prefix: '',
|
||||
needAuth: false,
|
||||
adminContact: '',
|
||||
@@ -15,6 +17,8 @@ export const useGlobalState = createGlobalState(
|
||||
enableUserDeleteEmail: false,
|
||||
enableAutoReply: false,
|
||||
enableIndexAbout: false,
|
||||
/** @type {string[]} */
|
||||
defaultDomains: [],
|
||||
/** @type {Array<{label: string, value: string}>} */
|
||||
domains: [],
|
||||
copyright: 'Dream Hunter',
|
||||
@@ -70,6 +74,8 @@ export const useGlobalState = createGlobalState(
|
||||
user_email: '',
|
||||
/** @type {number} */
|
||||
user_id: 0,
|
||||
/** @type {null | {domains: string[] | undefined | null, role: string, prefix: string | undefined | null}} */
|
||||
user_role: null,
|
||||
});
|
||||
const telegramApp = ref(window.Telegram?.WebApp || {});
|
||||
const isTelegram = ref(!!window.Telegram?.WebApp?.initData);
|
||||
@@ -79,6 +85,7 @@ export const useGlobalState = createGlobalState(
|
||||
loading,
|
||||
settings,
|
||||
sendMailModel,
|
||||
announcement,
|
||||
openSettings,
|
||||
showAuth,
|
||||
showAddressCredential,
|
||||
|
||||
@@ -203,6 +203,24 @@ useHead({
|
||||
]
|
||||
});
|
||||
|
||||
const logoClickCount = ref(0);
|
||||
const logoClick = async () => {
|
||||
if (route.path.includes("admin")) {
|
||||
logoClickCount.value = 0;
|
||||
return;
|
||||
}
|
||||
if (logoClickCount.value >= 5) {
|
||||
logoClickCount.value = 0;
|
||||
message.info("Change to admin Page");
|
||||
await router.push(getRouterPathWithLang('/admin', locale.value));
|
||||
} else {
|
||||
logoClickCount.value++;
|
||||
}
|
||||
if (logoClickCount.value > 0) {
|
||||
message.info(`Click ${5 - logoClickCount.value + 1} times to enter the admin page`);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await api.getOpenSettings(message);
|
||||
});
|
||||
@@ -215,7 +233,9 @@ onMounted(async () => {
|
||||
<h3>{{ openSettings.title || t('title') }}</h3>
|
||||
</template>
|
||||
<template #avatar>
|
||||
<n-avatar style="margin-left: 10px;" src="/logo.png" />
|
||||
<div @click="logoClick">
|
||||
<n-avatar style="margin-left: 10px;" src="/logo.png" />
|
||||
</div>
|
||||
</template>
|
||||
<template #extra>
|
||||
<n-space>
|
||||
|
||||
@@ -94,6 +94,7 @@ const deleteEmail = async () => {
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
addressQuery.value = addressQuery.value.trim()
|
||||
const { results, count: addressCount } = await api.fetch(
|
||||
`/admin/address`
|
||||
+ `?limit=${pageSize.value}`
|
||||
@@ -283,7 +284,8 @@ onMounted(async () => {
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="addressQuery" clearable :placeholder="t('addressQueryTip')" />
|
||||
<n-input v-model:value="addressQuery" clearable :placeholder="t('addressQueryTip')"
|
||||
@keydown.enter="fetchData" />
|
||||
<n-button @click="fetchData" type="primary" tertiary>
|
||||
{{ t('query') }}
|
||||
</n-button>
|
||||
|
||||
@@ -29,12 +29,9 @@ const { t } = useI18n({
|
||||
const mailBoxKey = ref("")
|
||||
const mailKeyword = ref("")
|
||||
|
||||
watch([adminMailTabAddress, mailKeyword], () => {
|
||||
const queryMail = () => {
|
||||
adminMailTabAddress.value = adminMailTabAddress.value.trim();
|
||||
mailKeyword.value = mailKeyword.value.trim();
|
||||
});
|
||||
|
||||
const queryMail = () => {
|
||||
mailBoxKey.value = Date.now();
|
||||
}
|
||||
|
||||
@@ -63,8 +60,9 @@ onMounted(async () => {
|
||||
<template>
|
||||
<div style="margin-top: 10px;">
|
||||
<n-input-group>
|
||||
<n-input v-model:value="adminMailTabAddress" :placeholder="t('addressQueryTip')" />
|
||||
<n-input v-model:value="mailKeyword" :placeholder="t('keywordQueryTip')" />
|
||||
<n-input v-model:value="adminMailTabAddress" :placeholder="t('addressQueryTip')"
|
||||
@keydown.enter="queryMail" />
|
||||
<n-input v-model:value="mailKeyword" :placeholder="t('keywordQueryTip')" @keydown.enter="queryMail" />
|
||||
<n-button @click="queryMail" type="primary" tertiary>
|
||||
{{ t('query') }}
|
||||
</n-button>
|
||||
|
||||
@@ -22,10 +22,10 @@ const cleanupModel = ref({
|
||||
const { t } = useI18n({
|
||||
messages: {
|
||||
en: {
|
||||
tip: 'Please input the cleanup days',
|
||||
mailBoxLabel: 'Clean up days for mailbox',
|
||||
mailUnknowLabel: "Clean up days for unknow receiver",
|
||||
sendBoxLabel: "Clean up days for sendbox",
|
||||
tip: 'Please input the days',
|
||||
mailBoxLabel: 'Cleanup the inbox before n days',
|
||||
mailUnknowLabel: "Cleanup the unknow mail before n days",
|
||||
sendBoxLabel: "Cleanup the sendbox before n days",
|
||||
cleanupNow: "Cleanup now",
|
||||
autoCleanup: "Auto cleanup",
|
||||
cleanupSuccess: "Cleanup success",
|
||||
@@ -33,10 +33,10 @@ const { t } = useI18n({
|
||||
cronTip: "Enable cron cleanup, need to configure [crons] in worker, please refer to the document",
|
||||
},
|
||||
zh: {
|
||||
tip: '请输入清理天数',
|
||||
mailBoxLabel: '收件箱清理天数',
|
||||
mailUnknowLabel: "无收件人邮件清理天数",
|
||||
sendBoxLabel: "发件箱清理天数",
|
||||
tip: '请输入天数',
|
||||
mailBoxLabel: '清理 n 天前的收件箱',
|
||||
mailUnknowLabel: "清理 n 天前的无收件人邮件",
|
||||
sendBoxLabel: "清理 n 天前的发件箱",
|
||||
autoCleanup: "自动清理",
|
||||
cleanupSuccess: "清理成功",
|
||||
cleanupNow: "立即清理",
|
||||
|
||||
@@ -21,6 +21,7 @@ const { t } = useI18n({
|
||||
});
|
||||
|
||||
const fetchData = async (limit, offset) => {
|
||||
adminSendBoxTabAddress.value = adminSendBoxTabAddress.value.trim();
|
||||
return await api.fetch(
|
||||
`/admin/sendbox?limit=${limit}&offset=${offset}`
|
||||
+ (adminSendBoxTabAddress.value ? `&address=${adminSendBoxTabAddress.value}` : '')
|
||||
@@ -35,7 +36,7 @@ const deleteSenboxMail = async (curMailId) => {
|
||||
<template>
|
||||
<div>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="adminSendBoxTabAddress" :placeholder="t('queryTip')" />
|
||||
<n-input v-model:value="adminSendBoxTabAddress" :placeholder="t('queryTip')" @keydown.enter="fetchData" />
|
||||
<n-button @click="fetchData" type="primary" tertiary>
|
||||
{{ t('query') }}
|
||||
</n-button>
|
||||
|
||||
@@ -79,6 +79,7 @@ const updateData = async () => {
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
addressQuery.value = addressQuery.value.trim();
|
||||
const { results, count: addressCount } = await api.fetch(
|
||||
`/admin/address_sender`
|
||||
+ `?limit=${pageSize.value}`
|
||||
@@ -192,7 +193,7 @@ onMounted(async () => {
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="addressQuery" />
|
||||
<n-input v-model:value="addressQuery" @keydown.enter="fetchData" />
|
||||
<n-button @click="fetchData" type="primary" tertiary>
|
||||
{{ t('query') }}
|
||||
</n-button>
|
||||
|
||||
@@ -13,14 +13,18 @@ const message = useMessage()
|
||||
const { t } = useI18n({
|
||||
messages: {
|
||||
en: {
|
||||
userCount: 'Account Count',
|
||||
activeUser: '7 days Active Mail Account',
|
||||
userCount: 'User Count',
|
||||
addressCount: 'Address Count',
|
||||
activeAddressCount7days: '7 days Active Address Count',
|
||||
activeAddressCount30days: '30 days Active Address Count',
|
||||
mailCount: 'Mail Count',
|
||||
sendMailCount: 'Send Mail Count'
|
||||
},
|
||||
zh: {
|
||||
userCount: '地址总数',
|
||||
activeUser: '周活跃邮箱地址',
|
||||
userCount: '用户总数',
|
||||
addressCount: '邮箱地址总数',
|
||||
activeAddressCount7days: '7天活跃邮箱地址总数',
|
||||
activeAddressCount30days: '30天活跃邮箱地址总数',
|
||||
mailCount: '邮件总数',
|
||||
sendMailCount: '发送邮件总数'
|
||||
}
|
||||
@@ -28,21 +32,27 @@ const { t } = useI18n({
|
||||
});
|
||||
|
||||
const statistics = ref({
|
||||
addressCount: 0,
|
||||
userCount: 0,
|
||||
mailCount: 0,
|
||||
activeUserCount7days: 0,
|
||||
activeAddressCount7days: 0,
|
||||
activeAddressCount30days: 0,
|
||||
sendMailCount: 0,
|
||||
})
|
||||
|
||||
const fetchStatistics = async () => {
|
||||
try {
|
||||
const {
|
||||
userCount, activeUserCount7days, mailCount, sendMailCount
|
||||
userCount, mailCount, sendMailCount,
|
||||
addressCount, activeAddressCount7days,
|
||||
activeAddressCount30days,
|
||||
} = await api.fetch(`/admin/statistics`);
|
||||
statistics.value.mailCount = mailCount || 0;
|
||||
statistics.value.userCount = userCount || 0;
|
||||
statistics.value.activeUserCount7days = activeUserCount7days || 0;
|
||||
statistics.value.sendMailCount = sendMailCount || 0;
|
||||
statistics.value.userCount = userCount || 0;
|
||||
statistics.value.addressCount = addressCount || 0;
|
||||
statistics.value.activeAddressCount7days = activeAddressCount7days || 0;
|
||||
statistics.value.activeAddressCount30days = activeAddressCount30days || 0;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
message.error(error.message || "error");
|
||||
@@ -58,36 +68,63 @@ onMounted(async () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-card :bordered="false" embedded>
|
||||
<n-row>
|
||||
<n-col :span="6">
|
||||
<n-statistic :label="t('userCount')" :value="statistics.userCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="User" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-statistic :label="t('activeUser')" :value="statistics.activeUserCount7days">
|
||||
<template #prefix>
|
||||
<n-icon :component="UserCheck" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-statistic :label="t('mailCount')" :value="statistics.mailCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="MailBulk" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="6">
|
||||
<n-statistic :label="t('sendMailCount')" :value="statistics.sendMailCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="SendOutlined" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-card>
|
||||
<div>
|
||||
<n-card :bordered="false" embedded>
|
||||
<n-row>
|
||||
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('addressCount')" :value="statistics.addressCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="User" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('activeAddressCount7days')" :value="statistics.activeAddressCount7days">
|
||||
<template #prefix>
|
||||
<n-icon :component="UserCheck" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('activeAddressCount30days')" :value="statistics.activeAddressCount30days">
|
||||
<template #prefix>
|
||||
<n-icon :component="UserCheck" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-card>
|
||||
<n-card :bordered="false" embedded>
|
||||
<n-row>
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('userCount')" :value="statistics.userCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="User" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('mailCount')" :value="statistics.mailCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="MailBulk" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
<n-col :span="8">
|
||||
<n-statistic :label="t('sendMailCount')" :value="statistics.sendMailCount">
|
||||
<template #prefix>
|
||||
<n-icon :component="SendOutlined" />
|
||||
</template>
|
||||
</n-statistic>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.n-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script setup>
|
||||
import { ref, h, onMounted, watch } from 'vue';
|
||||
import { ref, h, onMounted, watch, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { NMenu, NButton, NBadge } from 'naive-ui';
|
||||
import { NMenu, NButton, NBadge, NTag } from 'naive-ui';
|
||||
import { MenuFilled } from '@vicons/material'
|
||||
|
||||
import { useGlobalState } from '../../store'
|
||||
import { api } from '../../api'
|
||||
import { hashPassword } from '../../utils';
|
||||
|
||||
const { loading } = useGlobalState()
|
||||
const { loading, openSettings } = useGlobalState()
|
||||
const message = useMessage()
|
||||
|
||||
const { t } = useI18n({
|
||||
@@ -16,6 +16,7 @@ const { t } = useI18n({
|
||||
en: {
|
||||
success: 'Success',
|
||||
user_email: 'User Email',
|
||||
role: 'Role',
|
||||
address_count: 'Address Count',
|
||||
created_at: 'Created At',
|
||||
actions: 'Actions',
|
||||
@@ -29,10 +30,15 @@ const { t } = useI18n({
|
||||
createUser: 'Create User',
|
||||
email: 'Email',
|
||||
password: 'Password',
|
||||
changeRole: 'Change Role',
|
||||
prefix: 'Prefix',
|
||||
domains: 'Domains',
|
||||
roleDonotExist: 'Current Role does not exist',
|
||||
},
|
||||
zh: {
|
||||
success: '成功',
|
||||
user_email: '用户邮箱',
|
||||
role: '角色',
|
||||
address_count: '地址数量',
|
||||
created_at: '创建时间',
|
||||
actions: '操作',
|
||||
@@ -46,6 +52,10 @@ const { t } = useI18n({
|
||||
createUser: '创建用户',
|
||||
email: '邮箱',
|
||||
password: '密码',
|
||||
changeRole: '更改角色',
|
||||
prefix: '前缀',
|
||||
domains: '域名',
|
||||
roleDonotExist: '当前角色不存在',
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -64,9 +74,31 @@ const user = ref({
|
||||
email: "",
|
||||
password: ""
|
||||
})
|
||||
const showChangeRole = ref(false)
|
||||
const userRoles = ref([])
|
||||
const curUserRole = ref('')
|
||||
const userRolesOptions = computed(() => {
|
||||
return userRoles.value.map(role => {
|
||||
return {
|
||||
label: role.role,
|
||||
value: role.role
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
const fetchUserRoles = async () => {
|
||||
try {
|
||||
const results = await api.fetch(`/admin/user_roles`);
|
||||
userRoles.value = results;
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
message.error(error.message || "error");
|
||||
}
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
userQuery.value = userQuery.value.trim()
|
||||
const { results, count: userCount } = await api.fetch(
|
||||
`/admin/users`
|
||||
+ `?limit=${pageSize.value}`
|
||||
@@ -138,6 +170,24 @@ const deleteUser = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const changeRole = async () => {
|
||||
try {
|
||||
await api.fetch(`/admin/user_roles`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
user_id: curUserId.value,
|
||||
role_text: curUserRole.value
|
||||
})
|
||||
});
|
||||
message.success(t('success'));
|
||||
showChangeRole.value = false;
|
||||
await fetchData();
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
message.error(error.message || "error");
|
||||
}
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "ID",
|
||||
@@ -147,6 +197,19 @@ const columns = [
|
||||
title: t('user_email'),
|
||||
key: "user_email"
|
||||
},
|
||||
{
|
||||
title: t('role'),
|
||||
key: "role_text",
|
||||
render(row) {
|
||||
if (!row.role_text) return null;
|
||||
return h(NTag, {
|
||||
bordered: false,
|
||||
type: "info"
|
||||
}, {
|
||||
default: () => row.role_text
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t('address_count'),
|
||||
key: "address_count",
|
||||
@@ -176,6 +239,19 @@ const columns = [
|
||||
icon: () => h(MenuFilled),
|
||||
key: "action",
|
||||
children: [
|
||||
{
|
||||
label: () => h(NButton,
|
||||
{
|
||||
text: true,
|
||||
onClick: () => {
|
||||
curUserId.value = row.id;
|
||||
curUserRole.value = row.role_text;
|
||||
showChangeRole.value = true;
|
||||
}
|
||||
},
|
||||
{ default: () => t('changeRole') }
|
||||
),
|
||||
},
|
||||
{
|
||||
label: () => h(NButton,
|
||||
{
|
||||
@@ -212,12 +288,29 @@ const columns = [
|
||||
}
|
||||
]
|
||||
|
||||
const getRolePrefix = (role) => {
|
||||
const res = userRoles.value.find(r => r.role === role)?.prefix;
|
||||
if (res === undefined || res === null) return openSettings.value.prefix;
|
||||
return res;
|
||||
}
|
||||
|
||||
const getRoleDomains = (role) => {
|
||||
const res = userRoles.value.find(r => r.role === role)?.domains;
|
||||
if (res === undefined || res === null || res.length == 0) return openSettings.value.defaultDomains;
|
||||
return res;
|
||||
}
|
||||
|
||||
const roleDonotExist = computed(() => {
|
||||
return curUserRole.value && !userRoles.value.some(r => r.role === curUserRole.value);
|
||||
})
|
||||
|
||||
watch([page, pageSize], async () => {
|
||||
await fetchData()
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await fetchData()
|
||||
await fetchUserRoles();
|
||||
await fetchData();
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -256,8 +349,21 @@ onMounted(async () => {
|
||||
</n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-modal v-model:show="showChangeRole" preset="dialog" :title="t('changeRole')">
|
||||
<n-alert type="error" :bordered="false" v-if="roleDonotExist">
|
||||
<span>{{ t('roleDonotExist') }}</span>
|
||||
</n-alert>
|
||||
<p>{{ t('prefix') + ": " + getRolePrefix(curUserRole) }}</p>
|
||||
<p>{{ t('domains') + ": " + JSON.stringify(getRoleDomains(curUserRole)) }}</p>
|
||||
<n-select clearable v-model:value="curUserRole" :options="userRolesOptions" />
|
||||
<template #action>
|
||||
<n-button :loading="loading" @click="changeRole" size="small" tertiary type="primary">
|
||||
{{ t('changeRole') }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-modal>
|
||||
<n-input-group>
|
||||
<n-input v-model:value="userQuery" />
|
||||
<n-input v-model:value="userQuery" @keydown.enter="fetchData" />
|
||||
<n-button @click="fetchData" type="primary" tertiary>
|
||||
{{ t('query') }}
|
||||
</n-button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { NewLabelOutlined, EmailOutlined } from '@vicons/material'
|
||||
@@ -72,7 +72,7 @@ const { locale, t } = useI18n({
|
||||
login: 'Login',
|
||||
pleaseGetNewEmail: 'Please login or click "Get New Email" button to get a new email address',
|
||||
getNewEmail: 'Create New Email',
|
||||
getNewEmailTip1: 'Please input the email you want to use. only allow ., a-z, A-Z and 0-9',
|
||||
getNewEmailTip1: 'Please input the email you want to use. only allow a-z and 0-9',
|
||||
getNewEmailTip2: 'Levaing it blank will generate a random email address.',
|
||||
getNewEmailTip3: 'You can choose a domain from the dropdown list.',
|
||||
credential: 'Email Address Credential',
|
||||
@@ -87,7 +87,7 @@ const { locale, t } = useI18n({
|
||||
login: '登录',
|
||||
pleaseGetNewEmail: '请"登录"或点击 "注册新邮箱" 按钮来获取一个新的邮箱地址',
|
||||
getNewEmail: '创建新邮箱',
|
||||
getNewEmailTip1: '请输入你想要使用的邮箱地址, 只允许 ., a-z, A-Z, 0-9',
|
||||
getNewEmailTip1: '请输入你想要使用的邮箱地址, 只允许 a-z, 0-9',
|
||||
getNewEmailTip2: '留空将会生成一个随机的邮箱地址。',
|
||||
getNewEmailTip3: '你可以从下拉列表中选择一个域名。',
|
||||
credential: '邮箱地址凭据',
|
||||
@@ -110,7 +110,7 @@ const generateName = async () => {
|
||||
.split('@')[0]
|
||||
.replace(/\s+/g, '.')
|
||||
.replace(/\.{2,}/g, '.')
|
||||
.replace(/[^a-zA-Z0-9.]/g, '')
|
||||
.replace(/[^a-z0-9]/g, '')
|
||||
.toLowerCase();
|
||||
} catch (error) {
|
||||
message.error(error.message || "error");
|
||||
@@ -140,11 +140,39 @@ const newEmail = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const addressPrefix = computed(() => {
|
||||
// if user has role, return role prefix
|
||||
if (userSettings.value?.user_role) {
|
||||
return userSettings.value.user_role.prefix || "";
|
||||
}
|
||||
// if user has no role, return default prefix
|
||||
return openSettings.value.prefix;
|
||||
});
|
||||
|
||||
const domainsOptions = computed(() => {
|
||||
// if user has role, return role domains
|
||||
if (userSettings.value.user_role) {
|
||||
const allDomains = userSettings.value.user_role.domains;
|
||||
if (!allDomains) return openSettings.value.domains;
|
||||
return openSettings.value.domains.filter((domain) => {
|
||||
return allDomains.includes(domain.value);
|
||||
});
|
||||
}
|
||||
// if user has no role, return default domains
|
||||
if (!openSettings.value.defaultDomains) {
|
||||
return openSettings.value.domains;
|
||||
}
|
||||
// if user has no role and no default domains, return all domains
|
||||
return openSettings.value.domains.filter((domain) => {
|
||||
return openSettings.value.defaultDomains.includes(domain.value);
|
||||
});
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
if (!openSettings.value.domains || openSettings.value.domains.length === 0) {
|
||||
await api.getOpenSettings();
|
||||
}
|
||||
emailDomain.value = openSettings.value.domains ? openSettings.value.domains[0]?.value : "";
|
||||
emailDomain.value = domainsOptions.value ? domainsOptions.value[0]?.value : "";
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -186,14 +214,14 @@ onMounted(async () => {
|
||||
{{ t('generateName') }}
|
||||
</n-button>
|
||||
<n-input-group>
|
||||
<n-input-group-label v-if="openSettings.prefix">
|
||||
{{ openSettings.prefix }}
|
||||
<n-input-group-label v-if="addressPrefix">
|
||||
{{ addressPrefix }}
|
||||
</n-input-group-label>
|
||||
<n-input v-model:value="emailName" show-count :minlength="openSettings.minAddressLen"
|
||||
:maxlength="openSettings.maxAddressLen" />
|
||||
<n-input-group-label>@</n-input-group-label>
|
||||
<n-select v-model:value="emailDomain" :consistent-menu-width="false"
|
||||
:options="openSettings.domains" />
|
||||
:options="domainsOptions" />
|
||||
</n-input-group>
|
||||
<Turnstile v-model:value="cfToken" />
|
||||
<n-button type="primary" block secondary strong @click="newEmail" :loading="loading">
|
||||
|
||||
@@ -13,6 +13,7 @@ class Settings(BaseSettings):
|
||||
proxy_url: str = "http://localhost:8787"
|
||||
port: int = 8025
|
||||
imap_port: int = 11143
|
||||
basic_password: str = ""
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
|
||||
@@ -121,6 +121,7 @@ class SimpleMailbox:
|
||||
f"{settings.proxy_url}/api/mails?limit={limit}&offset={start - 1}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.password}",
|
||||
"x-custom-auth": f"{settings.basic_password}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
@@ -147,6 +148,7 @@ class SimpleMailbox:
|
||||
f"{settings.proxy_url}/api/sendbox?limit={limit}&offset={start - 1}",
|
||||
headers={
|
||||
"Authorization": f"Bearer {self.password}",
|
||||
"x-custom-auth": f"{settings.basic_password}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
|
||||
@@ -31,6 +31,16 @@ export default defineConfig({
|
||||
logo: { src: '/logo.png', width: 24, height: 24 },
|
||||
search: { provider: 'local' },
|
||||
socialLinks: [
|
||||
{
|
||||
icon: 'discord',
|
||||
link: 'https://discord.gg/dQEwTWhA6Q'
|
||||
},
|
||||
{
|
||||
icon: {
|
||||
svg: '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 448 512"><path d="M446.7 98.6l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9l-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9l190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1L117.8 284L16.2 252.2c-22.1-6.9-22.5-22.1 4.6-32.7L418.2 66.4c18.4-6.9 34.5 4.1 28.5 32.2z" fill="currentColor"></path></svg>'
|
||||
},
|
||||
link: 'https://t.me/cloudflare_temp_email'
|
||||
},
|
||||
{
|
||||
icon: 'github',
|
||||
link: 'https://github.com/dreamhunter2333/cloudflare_temp_email'
|
||||
|
||||
@@ -34,10 +34,10 @@ git clone https://github.com/dreamhunter2333/cloudflare_temp_email.git
|
||||
```bash
|
||||
# create a database, and copy the output to wrangler.toml in the next step
|
||||
wrangler d1 create dev
|
||||
wrangler d1 execute dev --file=db/schema.sql
|
||||
wrangler d1 execute dev --file=db/schema.sql --remote
|
||||
# schema update, if you have initialized the database before this date, you can execute this command to update
|
||||
# wrangler d1 execute dev --file=db/2024-01-13-patch.sql
|
||||
# wrangler d1 execute dev --file=db/2024-04-03-patch.sql
|
||||
# wrangler d1 execute dev --file=db/2024-01-13-patch.sql --remote
|
||||
# wrangler d1 execute dev --file=db/2024-04-03-patch.sql --remote
|
||||
# create a namespace, and copy the output to wrangler.toml in the next step
|
||||
wrangler kv:namespace create DEV
|
||||
```
|
||||
@@ -77,6 +77,7 @@ node_compat = true
|
||||
# TITLE = "Custom Title" # The title of the site
|
||||
PREFIX = "tmp" # The mailbox name prefix to be processed
|
||||
# (min, max) length of the adderss, if not set, the default is (1, 30)
|
||||
# ANNOUNCEMENT = "Custom Announcement"
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# If you want your site to be private, uncomment below and change your password
|
||||
@@ -85,9 +86,16 @@ PREFIX = "tmp" # The mailbox name prefix to be processed
|
||||
# ADMIN_PASSWORDS = ["123", "456"]
|
||||
# admin contact information. If not configured, it will not be displayed. Any string can be configured.
|
||||
# ADMIN_CONTACT = "xx@xx.xxx"
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # your domain name
|
||||
DEFAULT_DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # domain name for no role users
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # all your domain name
|
||||
# For chinese domain name, you can use DOMAIN_LABELS to show chinese domain name
|
||||
# DOMAIN_LABELS = ["中文.xxx", "xxx.xxx2"]
|
||||
# USER_DEFAULT_ROLE = "vip" # default role for new users(only when enable mail verification)
|
||||
# User roles configuration, if domains is empty will use default_domains, if prefix is null will use default prefix, if prefix is empty string will not use prefix
|
||||
# USER_ROLES = [
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "vip", prefix = "vip" },
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "admin", prefix = "" },
|
||||
# ]
|
||||
JWT_SECRET = "xxx" # Key used to generate jwt
|
||||
BLACK_LIST = "" # Blacklist, used to filter senders, comma separated
|
||||
# Allow users to create email addresses
|
||||
|
||||
@@ -8,7 +8,7 @@ hero:
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Try it now
|
||||
link: https://mail.awsl.uk/
|
||||
link: https://mail.awsl.uk/en
|
||||
- theme: alt
|
||||
text: command line deployment
|
||||
link: /en/cli
|
||||
|
||||
@@ -9,7 +9,7 @@ cd worker
|
||||
cp wrangler.toml.template wrangler.toml
|
||||
# 创建 D1 并执行 schema.sql
|
||||
wrangler d1 create dev
|
||||
wrangler d1 execute dev --file=../db/schema.sql
|
||||
wrangler d1 execute dev --file=../db/schema.sql --remote
|
||||
```
|
||||
|
||||
创建完成后,我们在 cloudflare 的控制台可以看到 D1 数据库
|
||||
@@ -25,6 +25,6 @@ wrangler d1 execute dev --file=../db/schema.sql
|
||||
|
||||
```bash
|
||||
cd worker
|
||||
wrangler d1 execute dev --file=../db/2024-01-13-patch.sql
|
||||
wrangler d1 execute dev --file=../db/2024-04-03-patch.sql
|
||||
wrangler d1 execute dev --file=../db/2024-01-13-patch.sql --remote
|
||||
wrangler d1 execute dev --file=../db/2024-04-03-patch.sql --remote
|
||||
```
|
||||
|
||||
@@ -45,6 +45,7 @@ node_compat = true
|
||||
# TITLE = "Custom Title" # 自定义网站标题
|
||||
PREFIX = "tmp" # 要处理的邮箱名称前缀,不需要后缀可配置为空字符串
|
||||
# (min, max) adderss的长度,如果不设置,默认为(1, 30)
|
||||
# ANNOUNCEMENT = "Custom Announcement" # 自定义公告
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
# MAX_ADDRESS_LEN = 30
|
||||
# 如果你想要你的网站私有,取消下面的注释,并修改密码
|
||||
@@ -53,9 +54,18 @@ PREFIX = "tmp" # 要处理的邮箱名称前缀,不需要后缀可配置为空
|
||||
# ADMIN_PASSWORDS = ["123", "456"]
|
||||
# admin 联系方式,不配置则不显示,可配置任意字符串
|
||||
# ADMIN_CONTACT = "xx@xx.xxx"
|
||||
# DEFAULT_DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 默认用户可用的域名(未登录或未分配角色的用户)
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # 你的域名, 支持多个域名
|
||||
# 对于中文域名,可以使用 DOMAIN_LABELS 显示域名的中文展示名称
|
||||
# DOMAIN_LABELS = ["中文.xxx", "xxx.xxx2"]
|
||||
# 新用户默认角色, 仅在启用邮件验证时有效
|
||||
# USER_DEFAULT_ROLE = "vip"
|
||||
# 用户角色配置, 如果 domains 为空将使用 default_domains
|
||||
# 如果 prefix 为 null 将使用默认前缀, 如果 prefix 为空字符串将不使用前缀
|
||||
# USER_ROLES = [
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "vip", prefix = "vip" },
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "admin", prefix = "" },
|
||||
# ]
|
||||
JWT_SECRET = "xxx" # 用于生成 jwt 的密钥, jwt 用于给用户登录以及鉴权
|
||||
BLACK_LIST = "" # 黑名单,用于过滤发件人,逗号分隔
|
||||
# 是否允许用户创建邮件, 不配置则不允许
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"version": "0.2.6",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.14.9",
|
||||
"@types/node": "^20.14.10",
|
||||
"vitepress": "^1.2.3",
|
||||
"wrangler": "^3.62.0"
|
||||
"wrangler": "^3.63.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vitepress dev docs",
|
||||
|
||||
188
vitepress-docs/pnpm-lock.yaml
generated
188
vitepress-docs/pnpm-lock.yaml
generated
@@ -13,14 +13,14 @@ importers:
|
||||
version: 3.10.1
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^20.14.9
|
||||
version: 20.14.9
|
||||
specifier: ^20.14.10
|
||||
version: 20.14.10
|
||||
vitepress:
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3(@algolia/client-search@4.24.0)(@types/node@20.14.9)(postcss@8.4.38)(search-insights@2.13.0)(typescript@5.4.5)
|
||||
version: 1.2.3(@algolia/client-search@4.24.0)(@types/node@20.14.10)(postcss@8.4.39)(search-insights@2.13.0)(typescript@5.4.5)
|
||||
wrangler:
|
||||
specifier: ^3.62.0
|
||||
version: 3.62.0
|
||||
specifier: ^3.63.1
|
||||
version: 3.63.1
|
||||
|
||||
packages:
|
||||
|
||||
@@ -110,32 +110,32 @@ packages:
|
||||
resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==}
|
||||
engines: {node: '>=16.13'}
|
||||
|
||||
'@cloudflare/workerd-darwin-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-YWeS2aE8jAzDefuus/3GmZcFGu3Ef94uCAoxsQuaEXNsiGM9NeAhPpKC1BJAlcv168U/Q1J+6hckcGtipf6ZcQ==}
|
||||
'@cloudflare/workerd-darwin-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-XAZa4ZP+qyTn6JQQACCPH09hGZXP2lTnWKkmg5mPwT8EyRzCKLkczAf98vPP5bq7JZD/zORdFWRY0dOTap8zTQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240620.1':
|
||||
resolution: {integrity: sha512-3rdND+EHpmCrwYX6hvxIBSBJ0f40tRNxond1Vfw7GiR1MJVi3gragiBx75UDFHCxfRw3J0GZ1qVlkRce2/Xbsg==}
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240701.0':
|
||||
resolution: {integrity: sha512-w80ZVAgfH4UwTz7fXZtk7KmS2FzlXniuQm4ku4+cIgRTilBAuKqjpOjwUCbx5g13Gqcm9NuiHce+IDGtobRTIQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@cloudflare/workerd-linux-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-tURcTrXGeSbYqeM5ISVcofY20StKbVIcdxjJvNYNZ+qmSV9Fvn+zr7rRE+q64pEloVZfhsEPAlUCnFso5VV4XQ==}
|
||||
'@cloudflare/workerd-linux-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-UWLr/Anxwwe/25nGv451MNd2jhREmPt/ws17DJJqTLAx6JxwGWA15MeitAIzl0dbxRFAJa+0+R8ag2WR3F/D6g==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@cloudflare/workerd-linux-arm64@1.20240620.1':
|
||||
resolution: {integrity: sha512-TThvkwNxaZFKhHZnNjOGqIYCOk05DDWgO+wYMuXg15ymN/KZPnCicRAkuyqiM+R1Fgc4kwe/pehjP8pbmcf6sg==}
|
||||
'@cloudflare/workerd-linux-arm64@1.20240701.0':
|
||||
resolution: {integrity: sha512-3kCnF9kYgov1ggpuWbgpXt4stPOIYtVmPCa7MO2xhhA0TWP6JDUHRUOsnmIgKrvDjXuXqlK16cdg3v+EWsaPJg==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@cloudflare/workerd-windows-64@1.20240620.1':
|
||||
resolution: {integrity: sha512-Y/BA9Yj0r7Al1HK3nDHcfISgFllw6NR3XMMPChev57vrVT9C9D4erBL3sUBfofHU+2U9L+ShLsl6obBpe3vvUw==}
|
||||
'@cloudflare/workerd-windows-64@1.20240701.0':
|
||||
resolution: {integrity: sha512-6IPGITRAeS67j3BH1rN4iwYWDt47SqJG7KlZJ5bB4UaNAia4mvMBSy/p2p4vA89bbXoDRjMtEvRu7Robu6O7hQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -541,11 +541,11 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@shikijs/core@1.10.0':
|
||||
resolution: {integrity: sha512-BZcr6FCmPfP6TXaekvujZcnkFmJHZ/Yglu97r/9VjzVndQA56/F4WjUKtJRQUnK59Wi7p/UTAOekMfCJv7jnYg==}
|
||||
'@shikijs/core@1.10.1':
|
||||
resolution: {integrity: sha512-qdiJS5a/QGCff7VUFIqd0hDdWly9rDp8lhVmXVrS11aazX8LOTRLHAXkkEeONNsS43EcCd7gax9LLoOz4vlFQA==}
|
||||
|
||||
'@shikijs/transformers@1.10.0':
|
||||
resolution: {integrity: sha512-5Eu/kuJu7/CzAjFlTJkyyPoLTLSVQZ31Ps81cjIeR/3PDJ2RUuX1/R8d0qFziBKToym1LXbNiXoJQq0mg5+Cwg==}
|
||||
'@shikijs/transformers@1.10.1':
|
||||
resolution: {integrity: sha512-0gLtcFyi6R6zcUkFajUEp1Qiv7lHBSFgOz4tQvS8nFsYCQSLI1/9pM+Me8jEIPXv7XLKAoUjw6InL+Sv+BHw/A==}
|
||||
|
||||
'@types/estree@1.0.5':
|
||||
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
|
||||
@@ -562,8 +562,8 @@ packages:
|
||||
'@types/node-forge@1.3.11':
|
||||
resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==}
|
||||
|
||||
'@types/node@20.14.9':
|
||||
resolution: {integrity: sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==}
|
||||
'@types/node@20.14.10':
|
||||
resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==}
|
||||
|
||||
'@types/web-bluetooth@0.0.20':
|
||||
resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
|
||||
@@ -587,14 +587,14 @@ packages:
|
||||
'@vue/compiler-ssr@3.4.31':
|
||||
resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==}
|
||||
|
||||
'@vue/devtools-api@7.3.4':
|
||||
resolution: {integrity: sha512-E5dJlLW+NgGb+WS33y99ioOJL2OXpVhje6VwXGJ/q5fNizJDpe67Ml0GBSrlYOKNSjZs2mwcZd7B3e12th3Q0g==}
|
||||
'@vue/devtools-api@7.3.5':
|
||||
resolution: {integrity: sha512-BSdBBu5hOIv+gBJC9jzYMh5bC27FQwjWLSb8fVAniqlL9gvsqvK27xTgczMf+hgctlszMYQnRm3bpY/j8vhPqw==}
|
||||
|
||||
'@vue/devtools-kit@7.3.4':
|
||||
resolution: {integrity: sha512-DalQZWaFLRyA4qfKT0WT7e+q2AwvYoTwd0pWqswHqcpviXw+oU6FlSJHMrEACB3lBHjN1KBS9Kh527sWIe1vcg==}
|
||||
'@vue/devtools-kit@7.3.5':
|
||||
resolution: {integrity: sha512-wwfi10gJ1HMtjzcd8aIOnzBHlIRqsYDgcDyrKvkeyc0Gbcoe7UrkXRVHZUOtcxxoplHA0PwpT6wFg0uUCmi8Ww==}
|
||||
|
||||
'@vue/devtools-shared@7.3.4':
|
||||
resolution: {integrity: sha512-5S5cHh7oWLZdboujnLteR3rT8UGfKHfA34aGLyFRB/B5TqBxmeLW1Rq32xW6TCDEy4isoYsYHGwJVp6DQcpiDA==}
|
||||
'@vue/devtools-shared@7.3.5':
|
||||
resolution: {integrity: sha512-Rqii3VazmWTi67a86rYopi61n5Ved05EybJCwyrfoO9Ok3MaS/4yRFl706ouoISMlyrASJFEzM0/AiDA6w4f9A==}
|
||||
|
||||
'@vue/reactivity@3.4.31':
|
||||
resolution: {integrity: sha512-VGkTani8SOoVkZNds1PfJ/T1SlAIOf8E58PGAhIOUDYPC4GAmFA2u/E14TDAFcf3vVDKunc4QqCe/SHr8xC65Q==}
|
||||
@@ -667,8 +667,8 @@ packages:
|
||||
resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
acorn@8.12.0:
|
||||
resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==}
|
||||
acorn@8.12.1:
|
||||
resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
@@ -852,8 +852,8 @@ packages:
|
||||
engines: {node: '>=10.0.0'}
|
||||
hasBin: true
|
||||
|
||||
miniflare@3.20240620.0:
|
||||
resolution: {integrity: sha512-NBMzqUE2mMlh/hIdt6U5MP+aFhEjKDq3l8CAajXAQa1WkndJdciWvzB2mfLETwoVFhMl/lphaVzyEN2AgwJpbQ==}
|
||||
miniflare@3.20240701.0:
|
||||
resolution: {integrity: sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==}
|
||||
engines: {node: '>=16.13'}
|
||||
hasBin: true
|
||||
|
||||
@@ -908,12 +908,12 @@ packages:
|
||||
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
|
||||
engines: {node: '>=8.6'}
|
||||
|
||||
postcss@8.4.38:
|
||||
resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
|
||||
postcss@8.4.39:
|
||||
resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
|
||||
preact@10.22.0:
|
||||
resolution: {integrity: sha512-RRurnSjJPj4rp5K6XoP45Ui33ncb7e4H7WiOHVpjbkvqvA3U+N8Z6Qbo0AE6leGYBV66n8EhEaFixvIu3SkxFw==}
|
||||
preact@10.22.1:
|
||||
resolution: {integrity: sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==}
|
||||
|
||||
printable-characters@1.0.42:
|
||||
resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==}
|
||||
@@ -967,8 +967,8 @@ packages:
|
||||
setimmediate@1.0.5:
|
||||
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
|
||||
|
||||
shiki@1.10.0:
|
||||
resolution: {integrity: sha512-YD2sXQ+TMD/F9BimV9Jn0wj35pqOvywvOG/3PB6hGHyGKlM7TJ9tyJ02jOb2kF8F0HfJwKNYrh3sW7jEcuRlXA==}
|
||||
shiki@1.10.1:
|
||||
resolution: {integrity: sha512-uafV7WCgN4YYrccH6yxpnps6k38sSTlFRrwc4jycWmhWxJIm9dPrk+XkY1hZ2t0I7jmacMNb15Lf2fspa/Y3lg==}
|
||||
|
||||
source-map-js@1.2.0:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
@@ -1039,8 +1039,8 @@ packages:
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
vite@5.3.2:
|
||||
resolution: {integrity: sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==}
|
||||
vite@5.3.3:
|
||||
resolution: {integrity: sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1098,13 +1098,13 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
workerd@1.20240620.1:
|
||||
resolution: {integrity: sha512-Qoq+RrFNk4pvEO+kpJVn8uJ5TRE9YJx5jX5pC5LjdKlw1XeD8EdXt5k0TbByvWunZ4qgYIcF9lnVxhcDFo203g==}
|
||||
workerd@1.20240701.0:
|
||||
resolution: {integrity: sha512-qSgNVqauqzNCij9MaJLF2c2ko3AnFioVSIxMSryGbRK+LvtGr9BKBt6JOxCb24DoJASoJDx3pe3DJHBVydUiBg==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
|
||||
wrangler@3.62.0:
|
||||
resolution: {integrity: sha512-TM1Bd8+GzxFw/JzwsC3i/Oss4LTWvIEWXXo1vZhx+7PHcsxdbnQGBBwPurHNJDSu2Pw22+2pCZiUGKexmgJksw==}
|
||||
wrangler@3.63.1:
|
||||
resolution: {integrity: sha512-fxMPNEyDc9pZNtQOuYqRikzv6lL5eP4S1zv7L/kw24uu1cCEmJ39j8bfJGzrAEqKDNsiFXVjEka0RjlpgEVWPg==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1113,8 +1113,8 @@ packages:
|
||||
'@cloudflare/workers-types':
|
||||
optional: true
|
||||
|
||||
ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
ws@8.18.0:
|
||||
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
@@ -1258,19 +1258,19 @@ snapshots:
|
||||
dependencies:
|
||||
mime: 3.0.0
|
||||
|
||||
'@cloudflare/workerd-darwin-64@1.20240620.1':
|
||||
'@cloudflare/workerd-darwin-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240620.1':
|
||||
'@cloudflare/workerd-darwin-arm64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-linux-64@1.20240620.1':
|
||||
'@cloudflare/workerd-linux-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-linux-arm64@1.20240620.1':
|
||||
'@cloudflare/workerd-linux-arm64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cloudflare/workerd-windows-64@1.20240620.1':
|
||||
'@cloudflare/workerd-windows-64@1.20240701.0':
|
||||
optional: true
|
||||
|
||||
'@cspotcode/source-map-support@0.8.1':
|
||||
@@ -1282,7 +1282,7 @@ snapshots:
|
||||
'@docsearch/js@3.6.0(@algolia/client-search@4.24.0)(search-insights@2.13.0)':
|
||||
dependencies:
|
||||
'@docsearch/react': 3.6.0(@algolia/client-search@4.24.0)(search-insights@2.13.0)
|
||||
preact: 10.22.0
|
||||
preact: 10.22.1
|
||||
transitivePeerDependencies:
|
||||
- '@algolia/client-search'
|
||||
- '@types/react'
|
||||
@@ -1505,11 +1505,11 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@shikijs/core@1.10.0': {}
|
||||
'@shikijs/core@1.10.1': {}
|
||||
|
||||
'@shikijs/transformers@1.10.0':
|
||||
'@shikijs/transformers@1.10.1':
|
||||
dependencies:
|
||||
shiki: 1.10.0
|
||||
shiki: 1.10.1
|
||||
|
||||
'@types/estree@1.0.5': {}
|
||||
|
||||
@@ -1524,17 +1524,17 @@ snapshots:
|
||||
|
||||
'@types/node-forge@1.3.11':
|
||||
dependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
|
||||
'@types/node@20.14.9':
|
||||
'@types/node@20.14.10':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/web-bluetooth@0.0.20': {}
|
||||
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.3.2(@types/node@20.14.9))(vue@3.4.31(typescript@5.4.5))':
|
||||
'@vitejs/plugin-vue@5.0.5(vite@5.3.3(@types/node@20.14.10))(vue@3.4.31(typescript@5.4.5))':
|
||||
dependencies:
|
||||
vite: 5.3.2(@types/node@20.14.9)
|
||||
vite: 5.3.3(@types/node@20.14.10)
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
|
||||
'@vue/compiler-core@3.4.31':
|
||||
@@ -1559,7 +1559,7 @@ snapshots:
|
||||
'@vue/shared': 3.4.31
|
||||
estree-walker: 2.0.2
|
||||
magic-string: 0.30.10
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.39
|
||||
source-map-js: 1.2.0
|
||||
|
||||
'@vue/compiler-ssr@3.4.31':
|
||||
@@ -1567,13 +1567,13 @@ snapshots:
|
||||
'@vue/compiler-dom': 3.4.31
|
||||
'@vue/shared': 3.4.31
|
||||
|
||||
'@vue/devtools-api@7.3.4':
|
||||
'@vue/devtools-api@7.3.5':
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.3.4
|
||||
'@vue/devtools-kit': 7.3.5
|
||||
|
||||
'@vue/devtools-kit@7.3.4':
|
||||
'@vue/devtools-kit@7.3.5':
|
||||
dependencies:
|
||||
'@vue/devtools-shared': 7.3.4
|
||||
'@vue/devtools-shared': 7.3.5
|
||||
birpc: 0.2.17
|
||||
hookable: 5.5.3
|
||||
mitt: 3.0.1
|
||||
@@ -1581,7 +1581,7 @@ snapshots:
|
||||
speakingurl: 14.0.1
|
||||
superjson: 2.2.1
|
||||
|
||||
'@vue/devtools-shared@7.3.4':
|
||||
'@vue/devtools-shared@7.3.5':
|
||||
dependencies:
|
||||
rfdc: 1.4.1
|
||||
|
||||
@@ -1641,9 +1641,9 @@ snapshots:
|
||||
|
||||
acorn-walk@8.3.3:
|
||||
dependencies:
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
|
||||
acorn@8.12.0: {}
|
||||
acorn@8.12.1: {}
|
||||
|
||||
algoliasearch@4.24.0:
|
||||
dependencies:
|
||||
@@ -1861,18 +1861,18 @@ snapshots:
|
||||
|
||||
mime@3.0.0: {}
|
||||
|
||||
miniflare@3.20240620.0:
|
||||
miniflare@3.20240701.0:
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
acorn: 8.12.0
|
||||
acorn: 8.12.1
|
||||
acorn-walk: 8.3.3
|
||||
capnp-ts: 0.7.0
|
||||
exit-hook: 2.2.1
|
||||
glob-to-regexp: 0.4.1
|
||||
stoppable: 1.1.0
|
||||
undici: 5.28.4
|
||||
workerd: 1.20240620.1
|
||||
ws: 8.17.1
|
||||
workerd: 1.20240701.0
|
||||
ws: 8.18.0
|
||||
youch: 3.3.3
|
||||
zod: 3.23.8
|
||||
transitivePeerDependencies:
|
||||
@@ -1910,13 +1910,13 @@ snapshots:
|
||||
|
||||
picomatch@2.3.1: {}
|
||||
|
||||
postcss@8.4.38:
|
||||
postcss@8.4.39:
|
||||
dependencies:
|
||||
nanoid: 3.3.7
|
||||
picocolors: 1.0.1
|
||||
source-map-js: 1.2.0
|
||||
|
||||
preact@10.22.0: {}
|
||||
preact@10.22.1: {}
|
||||
|
||||
printable-characters@1.0.42: {}
|
||||
|
||||
@@ -1993,9 +1993,9 @@ snapshots:
|
||||
|
||||
setimmediate@1.0.5: {}
|
||||
|
||||
shiki@1.10.0:
|
||||
shiki@1.10.1:
|
||||
dependencies:
|
||||
'@shikijs/core': 1.10.0
|
||||
'@shikijs/core': 1.10.1
|
||||
|
||||
source-map-js@1.2.0: {}
|
||||
|
||||
@@ -2054,35 +2054,35 @@ snapshots:
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
vite@5.3.2(@types/node@20.14.9):
|
||||
vite@5.3.3(@types/node@20.14.10):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.39
|
||||
rollup: 4.18.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.9
|
||||
'@types/node': 20.14.10
|
||||
fsevents: 2.3.3
|
||||
|
||||
vitepress@1.2.3(@algolia/client-search@4.24.0)(@types/node@20.14.9)(postcss@8.4.38)(search-insights@2.13.0)(typescript@5.4.5):
|
||||
vitepress@1.2.3(@algolia/client-search@4.24.0)(@types/node@20.14.10)(postcss@8.4.39)(search-insights@2.13.0)(typescript@5.4.5):
|
||||
dependencies:
|
||||
'@docsearch/css': 3.6.0
|
||||
'@docsearch/js': 3.6.0(@algolia/client-search@4.24.0)(search-insights@2.13.0)
|
||||
'@shikijs/core': 1.10.0
|
||||
'@shikijs/transformers': 1.10.0
|
||||
'@shikijs/core': 1.10.1
|
||||
'@shikijs/transformers': 1.10.1
|
||||
'@types/markdown-it': 14.1.1
|
||||
'@vitejs/plugin-vue': 5.0.5(vite@5.3.2(@types/node@20.14.9))(vue@3.4.31(typescript@5.4.5))
|
||||
'@vue/devtools-api': 7.3.4
|
||||
'@vitejs/plugin-vue': 5.0.5(vite@5.3.3(@types/node@20.14.10))(vue@3.4.31(typescript@5.4.5))
|
||||
'@vue/devtools-api': 7.3.5
|
||||
'@vue/shared': 3.4.31
|
||||
'@vueuse/core': 10.11.0(vue@3.4.31(typescript@5.4.5))
|
||||
'@vueuse/integrations': 10.11.0(focus-trap@7.5.4)(vue@3.4.31(typescript@5.4.5))
|
||||
focus-trap: 7.5.4
|
||||
mark.js: 8.11.1
|
||||
minisearch: 6.3.0
|
||||
shiki: 1.10.0
|
||||
vite: 5.3.2(@types/node@20.14.9)
|
||||
shiki: 1.10.1
|
||||
vite: 5.3.3(@types/node@20.14.10)
|
||||
vue: 3.4.31(typescript@5.4.5)
|
||||
optionalDependencies:
|
||||
postcss: 8.4.38
|
||||
postcss: 8.4.39
|
||||
transitivePeerDependencies:
|
||||
- '@algolia/client-search'
|
||||
- '@types/node'
|
||||
@@ -2124,15 +2124,15 @@ snapshots:
|
||||
optionalDependencies:
|
||||
typescript: 5.4.5
|
||||
|
||||
workerd@1.20240620.1:
|
||||
workerd@1.20240701.0:
|
||||
optionalDependencies:
|
||||
'@cloudflare/workerd-darwin-64': 1.20240620.1
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20240620.1
|
||||
'@cloudflare/workerd-linux-64': 1.20240620.1
|
||||
'@cloudflare/workerd-linux-arm64': 1.20240620.1
|
||||
'@cloudflare/workerd-windows-64': 1.20240620.1
|
||||
'@cloudflare/workerd-darwin-64': 1.20240701.0
|
||||
'@cloudflare/workerd-darwin-arm64': 1.20240701.0
|
||||
'@cloudflare/workerd-linux-64': 1.20240701.0
|
||||
'@cloudflare/workerd-linux-arm64': 1.20240701.0
|
||||
'@cloudflare/workerd-windows-64': 1.20240701.0
|
||||
|
||||
wrangler@3.62.0:
|
||||
wrangler@3.63.1:
|
||||
dependencies:
|
||||
'@cloudflare/kv-asset-handler': 0.3.4
|
||||
'@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19)
|
||||
@@ -2141,7 +2141,7 @@ snapshots:
|
||||
chokidar: 3.6.0
|
||||
date-fns: 3.6.0
|
||||
esbuild: 0.17.19
|
||||
miniflare: 3.20240620.0
|
||||
miniflare: 3.20240701.0
|
||||
nanoid: 3.3.7
|
||||
path-to-regexp: 6.2.2
|
||||
resolve: 1.22.8
|
||||
@@ -2157,7 +2157,7 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
ws@8.17.1: {}
|
||||
ws@8.18.0: {}
|
||||
|
||||
xxhash-wasm@1.0.2: {}
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
"@cloudflare/workers-types": "^4.20240620.0",
|
||||
"@eslint/js": "8.56.0",
|
||||
"eslint": "8.56.0",
|
||||
"globals": "^15.6.0",
|
||||
"typescript-eslint": "^7.14.1",
|
||||
"wrangler": "^3.62.0"
|
||||
"globals": "^15.8.0",
|
||||
"typescript-eslint": "^7.15.0",
|
||||
"wrangler": "^3.63.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.600.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.600.0",
|
||||
"hono": "^4.4.9",
|
||||
"@aws-sdk/client-s3": "^3.609.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.609.0",
|
||||
"hono": "^4.4.12",
|
||||
"mimetext": "^3.0.24",
|
||||
"postal-mime": "^2.2.5",
|
||||
"resend": "^3.4.0",
|
||||
|
||||
751
worker/pnpm-lock.yaml
generated
751
worker/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
import { Context } from 'hono';
|
||||
|
||||
import { CONSTANTS } from '../constants';
|
||||
import { getJsonSetting, saveSetting, checkUserPassword, getDomains } from '../utils';
|
||||
import { getJsonSetting, saveSetting, checkUserPassword, getDomains, getUserRoles } from '../utils';
|
||||
import { UserSettings, GeoData, UserInfo } from "../models";
|
||||
import { handleListQuery } from '../common'
|
||||
import { HonoCustomType } from '../types';
|
||||
@@ -38,18 +38,22 @@ export default {
|
||||
const { limit, offset, query } = c.req.query();
|
||||
if (query) {
|
||||
return await handleListQuery(c,
|
||||
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
||||
`SELECT u.id as id, u.user_email, u.created_at, u.updated_at,`
|
||||
+ ` ur.role_text as role_text,`
|
||||
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
||||
+ ` FROM users u`
|
||||
+ ` LEFT JOIN user_roles ur ON u.id = ur.user_id`
|
||||
+ ` where u.user_email like ?`,
|
||||
`SELECT count(*) as count FROM users where user_email like ?`,
|
||||
[`%${query}%`], limit, offset
|
||||
);
|
||||
}
|
||||
return await handleListQuery(c,
|
||||
`SELECT u.id, u.user_email, u.created_at, u.updated_at,`
|
||||
`SELECT u.id as id, u.user_email, u.created_at, u.updated_at,`
|
||||
+ ` ur.role_text as role_text,`
|
||||
+ ` (SELECT COUNT(*) FROM users_address WHERE user_id = u.id) AS address_count`
|
||||
+ ` FROM users u`,
|
||||
+ ` FROM users u`
|
||||
+ ` LEFT JOIN user_roles ur ON u.id = ur.user_id`,
|
||||
`SELECT count(*) as count FROM users`,
|
||||
[], limit, offset
|
||||
);
|
||||
@@ -114,4 +118,30 @@ export default {
|
||||
}
|
||||
return c.json({ success: true });
|
||||
},
|
||||
updateUserRoles: async (c: Context<HonoCustomType>) => {
|
||||
const { user_id, role_text } = await c.req.json();
|
||||
if (!user_id) return c.text("Invalid user_id", 400);
|
||||
if (!role_text) {
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`DELETE FROM user_roles WHERE user_id = ?`
|
||||
).bind(user_id).run();
|
||||
if (!success) {
|
||||
return c.text("Failed to update user roles", 500)
|
||||
}
|
||||
return c.json({ success: true })
|
||||
}
|
||||
const user_roles = getUserRoles(c);
|
||||
if (!user_roles.find((r) => r.role === role_text)) {
|
||||
return c.text("Invalid role_text", 400)
|
||||
}
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`INSERT INTO user_roles (user_id, role_text)`
|
||||
+ ` VALUES (?, ?)`
|
||||
+ ` ON CONFLICT(user_id) DO UPDATE SET role_text = ?, updated_at = datetime('now')`
|
||||
).bind(user_id, role_text, role_text).run();
|
||||
if (!success) {
|
||||
return c.text("Failed to update user roles", 500)
|
||||
}
|
||||
return c.json({ success: true })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Hono } from 'hono'
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
|
||||
import { HonoCustomType } from '../types'
|
||||
import { sendAdminInternalMail, getJsonSetting, saveSetting } from '../utils'
|
||||
import { sendAdminInternalMail, getJsonSetting, saveSetting, getUserRoles } from '../utils'
|
||||
import { newAddress, handleListQuery } from '../common'
|
||||
import { CONSTANTS } from '../constants'
|
||||
import cleanup_api from './cleanup_api'
|
||||
@@ -40,7 +40,7 @@ api.post('/admin/new_address', async (c) => {
|
||||
return c.text("Please provide a name", 400)
|
||||
}
|
||||
try {
|
||||
const res = await newAddress(c, name, domain, enablePrefix, false);
|
||||
const res = await newAddress(c, name, domain, enablePrefix, false, null, false);
|
||||
return c.json(res);
|
||||
} catch (e) {
|
||||
return c.text(`Failed create address: ${(e as Error).message}`, 400)
|
||||
@@ -219,16 +219,24 @@ api.get('/admin/statistics', async (c) => {
|
||||
const { count: addressCount } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM address`
|
||||
).first<{ count: number }>() || {};
|
||||
const { count: activeUserCount7days } = await c.env.DB.prepare(
|
||||
const { count: activeAddressCount7days } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM address where updated_at > datetime('now', '-7 day')`
|
||||
).first<{ count: number }>() || {};
|
||||
const { count: activeAddressCount30days } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM address where updated_at > datetime('now', '-30 day')`
|
||||
).first<{ count: number }>() || {};
|
||||
const { count: sendMailCount } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM sendbox`
|
||||
).first<{ count: number }>() || {};
|
||||
const { count: userCount } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM users`
|
||||
).first<{ count: number }>() || {};
|
||||
return c.json({
|
||||
mailCount: mailCount,
|
||||
userCount: addressCount,
|
||||
activeUserCount7days: activeUserCount7days,
|
||||
addressCount: addressCount,
|
||||
activeAddressCount7days: activeAddressCount7days,
|
||||
activeAddressCount30days: activeAddressCount30days,
|
||||
userCount: userCount,
|
||||
sendMailCount: sendMailCount
|
||||
})
|
||||
});
|
||||
@@ -284,5 +292,7 @@ api.get('/admin/users', admin_user_api.getUsers)
|
||||
api.delete('/admin/users/:user_id', admin_user_api.deleteUser)
|
||||
api.post('/admin/users', admin_user_api.createUser)
|
||||
api.post('/admin/users/:user_id/reset_password', admin_user_api.resetPassword)
|
||||
api.get('/admin/user_roles', async (c) => c.json(getUserRoles(c)))
|
||||
api.post('/admin/user_roles', admin_user_api.updateUserRoles)
|
||||
api.get("/admin/webhook/settings", webhook_settings.getWebhookSettings);
|
||||
api.post("/admin/webhook/settings", webhook_settings.saveWebhookSettings);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Hono } from 'hono'
|
||||
|
||||
import { getDomains, getPasswords, getBooleanValue, getIntValue, getStringArray } from './utils';
|
||||
import { getDomains, getPasswords, getBooleanValue, getIntValue, getStringArray, getDefaultDomains, getStringValue } from './utils';
|
||||
import { CONSTANTS } from './constants';
|
||||
import { HonoCustomType } from './types';
|
||||
import { isS3Enabled } from './mails_api/s3_attachment';
|
||||
@@ -17,9 +17,11 @@ api.get('/open_api/settings', async (c) => {
|
||||
}
|
||||
return c.json({
|
||||
"title": c.env.TITLE,
|
||||
"announcement": getStringValue(c.env.ANNOUNCEMENT),
|
||||
"prefix": c.env.PREFIX,
|
||||
"minAddressLen": getIntValue(c.env.MIN_ADDRESS_LEN, 1),
|
||||
"maxAddressLen": getIntValue(c.env.MAX_ADDRESS_LEN, 30),
|
||||
"defaultDomains": getDefaultDomains(c),
|
||||
"domains": getDomains(c),
|
||||
"domainLabels": getStringArray(c.env.DOMAIN_LABELS),
|
||||
"needAuth": needAuth,
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { Context } from 'hono';
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
|
||||
import { getBooleanValue, getDomains, getStringValue, getIntValue } from './utils';
|
||||
import { HonoCustomType } from './types';
|
||||
import { getBooleanValue, getDomains, getStringValue, getIntValue, getUserRoles, getDefaultDomains } from './utils';
|
||||
import { HonoCustomType, UserRole } from './types';
|
||||
import { unbindTelegramByAddress } from './telegram_api/common';
|
||||
|
||||
export const newAddress = async (
|
||||
c: Context<HonoCustomType>,
|
||||
name: string, domain: string | undefined | null,
|
||||
enablePrefix: boolean,
|
||||
checkLengthByConfig: boolean = true
|
||||
checkLengthByConfig: boolean = true,
|
||||
addressPrefix: string | undefined | null = null,
|
||||
checkAllowDomains: boolean = true
|
||||
): Promise<{ address: string, jwt: string }> => {
|
||||
// remove special characters
|
||||
name = name.replace(/[^a-zA-Z0-9.]/g, '')
|
||||
name = name.replace(/[^a-z0-9]/g, '')
|
||||
// name min length min 1
|
||||
const minAddressLength = Math.max(
|
||||
checkLengthByConfig ? getIntValue(c.env.MIN_ADDRESS_LEN, 1) : 1,
|
||||
@@ -30,14 +32,21 @@ export const newAddress = async (
|
||||
if (name.length > maxAddressLength) {
|
||||
throw new Error(`Name too long (max ${maxAddressLength})`);
|
||||
}
|
||||
// create address
|
||||
if (enablePrefix) {
|
||||
// create address with prefix
|
||||
if (typeof addressPrefix === "string") {
|
||||
name = addressPrefix + name;
|
||||
} else if (enablePrefix) {
|
||||
name = getStringValue(c.env.PREFIX) + name;
|
||||
}
|
||||
// check domain, generate random domain
|
||||
const domains = getDomains(c);
|
||||
if (!domain || !domains.includes(domain)) {
|
||||
domain = domains[Math.floor(Math.random() * domains.length)];
|
||||
// check domain
|
||||
const allowDomains = checkAllowDomains ? await getAllowDomains(c) : getDomains(c);
|
||||
// if domain is not set, use the first domain
|
||||
if (!domain && allowDomains.length > 0) {
|
||||
domain = allowDomains[0];
|
||||
}
|
||||
// check domain is valid
|
||||
if (!domain || !allowDomains.includes(domain)) {
|
||||
throw new Error("Invalid domain")
|
||||
}
|
||||
// create address
|
||||
name = name + "@" + domain;
|
||||
@@ -74,7 +83,7 @@ export const cleanup = async (
|
||||
cleanType: string | undefined | null,
|
||||
cleanDays: number | undefined | null
|
||||
): Promise<boolean> => {
|
||||
if (!cleanType || !cleanDays || cleanDays < 0 || cleanDays > 30) {
|
||||
if (!cleanType || typeof cleanDays !== 'number' || cleanDays < 0 || cleanDays > 30) {
|
||||
throw new Error("Invalid cleanType or cleanDays")
|
||||
}
|
||||
console.log(`Cleanup ${cleanType} before ${cleanDays} days`);
|
||||
@@ -217,3 +226,34 @@ export const commonParseMail = async (raw_mail: string | undefined | null): Prom
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export const commonGetUserRole = async (
|
||||
c: Context<HonoCustomType>, user_id: number
|
||||
): Promise<UserRole | undefined | null> => {
|
||||
const user_roles = getUserRoles(c);
|
||||
const role_text = await c.env.DB.prepare(
|
||||
`SELECT role_text FROM user_roles where user_id = ?`
|
||||
).bind(user_id).first<string | undefined | null>("role_text");
|
||||
return role_text ? user_roles.find((r) => r.role === role_text) : null;
|
||||
}
|
||||
|
||||
export const getAddressPrefix = async (c: Context<HonoCustomType>): Promise<string | undefined> => {
|
||||
const user = c.get("userPayload");
|
||||
if (!user) {
|
||||
return c.env.PREFIX;
|
||||
}
|
||||
const user_role = await commonGetUserRole(c, user.user_id);
|
||||
if (typeof user_role?.prefix === "string") {
|
||||
return user_role.prefix;
|
||||
}
|
||||
return c.env.PREFIX;
|
||||
}
|
||||
|
||||
export const getAllowDomains = async (c: Context<HonoCustomType>): Promise<string[]> => {
|
||||
const user = c.get("userPayload");
|
||||
if (!user) {
|
||||
return getDefaultDomains(c);
|
||||
}
|
||||
const user_role = await commonGetUserRole(c, user.user_id);
|
||||
return user_role?.domains || getDefaultDomains(c);;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const CONSTANTS = {
|
||||
VERSION: 'v0.5.3',
|
||||
VERSION: 'v0.6.1',
|
||||
|
||||
// DB settings
|
||||
ADDRESS_BLOCK_LIST_KEY: 'address_block_list',
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
import { Hono } from 'hono'
|
||||
|
||||
// api v1 is deprecated
|
||||
const api = new Hono()
|
||||
|
||||
api.get('/admin/v1/mails', async (c) => {
|
||||
const { address, limit, offset } = c.req.query();
|
||||
if (!limit || limit < 0 || limit > 100) {
|
||||
return c.text("Invalid limit", 400)
|
||||
}
|
||||
if (!offset || offset < 0) {
|
||||
return c.text("Invalid offset", 400)
|
||||
}
|
||||
const { results } = await c.env.DB.prepare(
|
||||
`SELECT id, source, subject, message FROM mails where address = ? order by id desc limit ? offset ? `
|
||||
).bind(address, limit, offset).all();
|
||||
let count = 0;
|
||||
if (offset == 0) {
|
||||
const { count: mailCount } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM mails where address = ? `
|
||||
).bind(address).first();
|
||||
count = mailCount;
|
||||
}
|
||||
return c.json({
|
||||
results: results,
|
||||
count: count
|
||||
})
|
||||
});
|
||||
|
||||
api.get('/admin/v1/mails_unknow', async (c) => {
|
||||
const { limit, offset } = c.req.query();
|
||||
if (!limit || limit < 0 || limit > 100) {
|
||||
return c.text("Invalid limit", 400)
|
||||
}
|
||||
if (!offset || offset < 0) {
|
||||
return c.text("Invalid offset", 400)
|
||||
}
|
||||
const { results } = await c.env.DB.prepare(`
|
||||
SELECT id, source, subject, message FROM mails
|
||||
where address NOT IN(select name from address)
|
||||
order by id desc limit ? offset ? `
|
||||
).bind(limit, offset).all();
|
||||
let count = 0;
|
||||
if (offset == 0) {
|
||||
const { count: mailCount } = await c.env.DB.prepare(`
|
||||
SELECT count(*) as count FROM mails
|
||||
where address NOT IN (select name from address)`
|
||||
).first();
|
||||
count = mailCount;
|
||||
}
|
||||
return c.json({
|
||||
results: results,
|
||||
count: count
|
||||
})
|
||||
});
|
||||
|
||||
api.get('/api/v1/mails', async (c) => {
|
||||
const { address } = c.get("jwtPayload")
|
||||
if (!address) {
|
||||
return c.json({ "error": "No address" }, 400)
|
||||
}
|
||||
const { limit, offset } = c.req.query();
|
||||
if (!limit || limit < 0 || limit > 100) {
|
||||
return c.text("Invalid limit", 400)
|
||||
}
|
||||
if (!offset || offset < 0) {
|
||||
return c.text("Invalid offset", 400)
|
||||
}
|
||||
const { results } = await c.env.DB.prepare(
|
||||
`SELECT id, source, subject, message, message_id, created_at FROM mails where address = ? order by id desc limit ? offset ?`
|
||||
).bind(address, limit, offset).all();
|
||||
let count = 0;
|
||||
if (offset == 0) {
|
||||
const { count: mailCount } = await c.env.DB.prepare(
|
||||
`SELECT count(*) as count FROM mails where address = ?`
|
||||
).bind(address).first();
|
||||
count = mailCount;
|
||||
}
|
||||
// add attachments
|
||||
let attachmentResults = [];
|
||||
const message_ids = results.map((r) => r.message_id).filter((r) => r);
|
||||
if (message_ids && message_ids.length > 0) {
|
||||
const { results: innerAttachmentResults } = await c.env.DB.prepare(
|
||||
`SELECT id, message_id FROM attachments where message_id in (${message_ids.map((id) => `'${id}'`).join(",")})`
|
||||
).all();
|
||||
attachmentResults = innerAttachmentResults || [];
|
||||
}
|
||||
results.forEach((r) => {
|
||||
const attachment_id = attachmentResults.filter((ar) => ar.message_id == r.message_id).map((ar) => ar.id);
|
||||
if (attachment_id && attachment_id.length > 0) {
|
||||
r.attachment_id = attachment_id[0];
|
||||
}
|
||||
delete r.message_id;
|
||||
})
|
||||
return c.json({
|
||||
results: results,
|
||||
count: count
|
||||
})
|
||||
})
|
||||
|
||||
// attachments
|
||||
api.get("/api/v1/attachment/:attachment_id", async (c) => {
|
||||
const { attachment_id } = c.req.param();
|
||||
const { data } = await c.env.DB.prepare(
|
||||
`SELECT data FROM attachments where id = ? `
|
||||
).bind(attachment_id).first();
|
||||
if (!data) {
|
||||
return c.text("Not found", 404)
|
||||
}
|
||||
return c.json(JSON.parse(data))
|
||||
})
|
||||
|
||||
export { api }
|
||||
@@ -2,7 +2,7 @@ import { Hono } from 'hono'
|
||||
|
||||
import { HonoCustomType } from "../types";
|
||||
import { getBooleanValue, getJsonSetting, checkCfTurnstile } from '../utils';
|
||||
import { newAddress, handleListQuery, deleteAddressWithData } from '../common'
|
||||
import { newAddress, handleListQuery, deleteAddressWithData, getAddressPrefix, getAllowDomains } from '../common'
|
||||
import { CONSTANTS } from '../constants'
|
||||
import auto_reply from './auto_reply'
|
||||
import webhook_settings from './webhook_settings';
|
||||
@@ -38,9 +38,10 @@ api.delete('/api/mails/:id', async (c) => {
|
||||
}
|
||||
const { address } = c.get("jwtPayload")
|
||||
const { id } = c.req.param();
|
||||
// TODO: add toLowerCase() to handle old data
|
||||
const { success } = await c.env.DB.prepare(
|
||||
`DELETE FROM raw_mails WHERE address = ? and id = ? `
|
||||
).bind(address, id).run();
|
||||
).bind(address.toLowerCase(), id).run();
|
||||
return c.json({
|
||||
success: success
|
||||
})
|
||||
@@ -117,7 +118,8 @@ api.post('/api/new_address', async (c) => {
|
||||
console.error(error);
|
||||
}
|
||||
try {
|
||||
const res = await newAddress(c, name, domain, true);
|
||||
const addressPrefix = await getAddressPrefix(c);
|
||||
const res = await newAddress(c, name, domain, true, true, addressPrefix);
|
||||
return c.json(res);
|
||||
} catch (e) {
|
||||
return c.text(`Failed create address: ${(e as Error).message}`, 400)
|
||||
|
||||
@@ -18,7 +18,7 @@ const COMMANDS = [
|
||||
},
|
||||
{
|
||||
command: "new",
|
||||
description: "新建邮箱地址, 如果要自定义邮箱地址, 请输入 /new <name>@<domain>, name [a-zA-Z0-9.] 有效"
|
||||
description: "新建邮箱地址, 如果要自定义邮箱地址, 请输入 /new <name>@<domain>, name [a-z0-9] 有效"
|
||||
},
|
||||
{
|
||||
command: "address",
|
||||
|
||||
10
worker/src/types.d.ts
vendored
10
worker/src/types.d.ts
vendored
@@ -1,3 +1,9 @@
|
||||
export type UserRole = {
|
||||
domains: string[] | undefined | null,
|
||||
role: string,
|
||||
prefix: string | undefined | null
|
||||
}
|
||||
|
||||
export type Bindings = {
|
||||
// bindings
|
||||
DB: D1Database
|
||||
@@ -7,10 +13,14 @@ export type Bindings = {
|
||||
|
||||
// config
|
||||
TITLE: string | undefined
|
||||
ANNOUNCEMENT: string | undefined | null
|
||||
PREFIX: string | undefined
|
||||
MIN_ADDRESS_LEN: string | number | undefined
|
||||
MAX_ADDRESS_LEN: string | number | undefined
|
||||
DEFAULT_DOMAINS: string | string[] | undefined
|
||||
DOMAINS: string | string[] | undefined
|
||||
USER_DEFAULT_ROLE: string | UserRole | undefined
|
||||
USER_ROLES: string | UserRole[] | undefined
|
||||
DOMAIN_LABELS: string | string[] | undefined
|
||||
PASSWORDS: string | string[] | undefined
|
||||
ADMIN_PASSWORDS: string | string[] | undefined
|
||||
|
||||
@@ -2,8 +2,9 @@ import { Context } from "hono";
|
||||
|
||||
import { HonoCustomType } from "../types";
|
||||
import { UserSettings } from "../models";
|
||||
import { getJsonSetting } from "../utils"
|
||||
import { getJsonSetting, getUserRoles } from "../utils"
|
||||
import { CONSTANTS } from "../constants";
|
||||
import { commonGetUserRole } from "../common";
|
||||
|
||||
export default {
|
||||
openSettings: async (c: Context<HonoCustomType>) => {
|
||||
@@ -19,10 +20,14 @@ export default {
|
||||
// check if user exists
|
||||
const db_user_id = await c.env.DB.prepare(
|
||||
`SELECT id FROM users where id = ?`
|
||||
).bind(user.user_id).first("id");
|
||||
).bind(user.user_id).first<number | undefined | null>("id");
|
||||
if (!db_user_id) {
|
||||
return c.text("User not found", 400);
|
||||
}
|
||||
return c.json(user);
|
||||
const user_role = await commonGetUserRole(c, db_user_id);
|
||||
return c.json({
|
||||
...user,
|
||||
user_role: user_role
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Context } from 'hono';
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
|
||||
import { HonoCustomType } from '../types';
|
||||
import { checkCfTurnstile, getJsonSetting, checkUserPassword } from "../utils"
|
||||
import { checkCfTurnstile, getJsonSetting, checkUserPassword, getUserRoles, getStringValue } from "../utils"
|
||||
import { CONSTANTS } from "../constants";
|
||||
import { GeoData, UserInfo, UserSettings } from "../models";
|
||||
import { sendMail } from "../mails_api/send_mail_api";
|
||||
@@ -124,6 +124,28 @@ export default {
|
||||
if (!success) {
|
||||
return c.text("Failed to register", 500)
|
||||
}
|
||||
const defaultRole = getStringValue(c.env.USER_DEFAULT_ROLE);
|
||||
if (!defaultRole) return c.json({ success: true })
|
||||
const user_roles = getUserRoles(c);
|
||||
if (!user_roles.find((r) => r.role === defaultRole)) {
|
||||
return c.text("Invalid role_text", 400)
|
||||
}
|
||||
// find user_id
|
||||
const user_id = await c.env.DB.prepare(
|
||||
`SELECT id FROM users where user_email = ?`
|
||||
).bind(email).first<number | undefined | null>("id");
|
||||
if (!user_id) {
|
||||
return c.text("User not found", 400)
|
||||
}
|
||||
// update user roles
|
||||
const { success: success2 } = await c.env.DB.prepare(
|
||||
`INSERT INTO user_roles (user_id, role_text)`
|
||||
+ ` VALUES (?, ?)`
|
||||
+ ` ON CONFLICT(user_id) DO NOTHING`
|
||||
).bind(user_id, defaultRole).run();
|
||||
if (!success2) {
|
||||
return c.text("Failed to update user roles", 500)
|
||||
}
|
||||
return c.json({ success: true })
|
||||
},
|
||||
login: async (c: Context<HonoCustomType>) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Context } from "hono";
|
||||
import { createMimeMessage } from "mimetext";
|
||||
import { HonoCustomType } from "./types";
|
||||
import { HonoCustomType, UserRole } from "./types";
|
||||
import { User } from "telegraf/types";
|
||||
|
||||
export const getJsonSetting = async (
|
||||
c: Context<HonoCustomType>, key: string
|
||||
@@ -97,6 +98,12 @@ export const getStringArray = (
|
||||
return value;
|
||||
}
|
||||
|
||||
export const getDefaultDomains = (c: Context<HonoCustomType>): string[] => {
|
||||
const domains = getStringArray(c.env.DEFAULT_DOMAINS);
|
||||
if (domains && domains.length > 0) return domains;
|
||||
return getDomains(c);
|
||||
}
|
||||
|
||||
export const getDomains = (c: Context<HonoCustomType>): string[] => {
|
||||
if (!c.env.DOMAINS) {
|
||||
return [];
|
||||
@@ -113,6 +120,22 @@ export const getDomains = (c: Context<HonoCustomType>): string[] => {
|
||||
return c.env.DOMAINS;
|
||||
}
|
||||
|
||||
export const getUserRoles = (c: Context<HonoCustomType>): UserRole[] => {
|
||||
if (!c.env.USER_ROLES) {
|
||||
return [];
|
||||
}
|
||||
// check if USER_ROLES is an array, if not use json.parse
|
||||
if (!Array.isArray(c.env.USER_ROLES)) {
|
||||
try {
|
||||
return JSON.parse(c.env.USER_ROLES);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse USER_ROLES", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
return c.env.USER_ROLES;
|
||||
}
|
||||
|
||||
export const getPasswords = (c: Context<HonoCustomType>): string[] => {
|
||||
if (!c.env.PASSWORDS) {
|
||||
return [];
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { Hono } from 'hono'
|
||||
import { Context, Hono } from 'hono'
|
||||
import { cors } from 'hono/cors';
|
||||
import { jwt } from 'hono/jwt'
|
||||
import { Jwt } from 'hono/utils/jwt'
|
||||
|
||||
// @ts-ignore
|
||||
import { api as apiV1 } from './deprecated';
|
||||
|
||||
import { api as commonApi } from './commom_api';
|
||||
import { api as mailsApi } from './mails_api'
|
||||
import { api as userApi } from './user_api';
|
||||
@@ -16,11 +13,16 @@ import { api as telegramApi } from './telegram_api'
|
||||
import { email } from './email';
|
||||
import { scheduled } from './scheduled';
|
||||
import { getAdminPasswords, getPasswords, getBooleanValue } from './utils';
|
||||
import { HonoCustomType } from './types';
|
||||
import { HonoCustomType, UserPayload } from './types';
|
||||
|
||||
const app = new Hono<HonoCustomType>()
|
||||
//cors
|
||||
app.use('/*', cors());
|
||||
// error handler
|
||||
app.onError((err, c) => {
|
||||
console.error(err)
|
||||
return c.text(`${err.name} ${err.message}`, 500)
|
||||
})
|
||||
// rate limit
|
||||
app.use('/*', async (c, next) => {
|
||||
if (
|
||||
@@ -53,6 +55,26 @@ app.use('/*', async (c, next) => {
|
||||
}
|
||||
await next()
|
||||
});
|
||||
|
||||
const checkUserPayload = async (
|
||||
c: Context<HonoCustomType>
|
||||
): Promise<void> => {
|
||||
try {
|
||||
const token = c.req.raw.headers.get("x-user-token");
|
||||
if (!token) return;
|
||||
const payload = await Jwt.verify(token, c.env.JWT_SECRET, "HS256");
|
||||
// check expired
|
||||
if (!payload.exp) return;
|
||||
// exp is in seconds
|
||||
if (payload.exp < Math.floor(Date.now() / 1000)) {
|
||||
return;
|
||||
}
|
||||
c.set("userPayload", payload as UserPayload);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// api auth
|
||||
app.use('/api/*', async (c, next) => {
|
||||
// check header x-custom-auth
|
||||
@@ -64,6 +86,7 @@ app.use('/api/*', async (c, next) => {
|
||||
}
|
||||
}
|
||||
if (c.req.path.startsWith("/api/new_address")) {
|
||||
await checkUserPayload(c);
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
@@ -90,7 +113,7 @@ app.use('/user_api/*', async (c, next) => {
|
||||
if (payload.exp < Math.floor(Date.now() / 1000)) {
|
||||
return c.text("Token Expired", 401)
|
||||
}
|
||||
c.set("userPayload", payload);
|
||||
c.set("userPayload", payload as UserPayload);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return c.text("Need User Token", 401)
|
||||
@@ -121,7 +144,6 @@ app.route('/', commonApi)
|
||||
app.route('/', mailsApi)
|
||||
app.route('/', userApi)
|
||||
app.route('/', adminApi)
|
||||
app.route('/', apiV1)
|
||||
app.route('/', apiSendMail)
|
||||
app.route('/', telegramApi)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ node_compat = true
|
||||
|
||||
[vars]
|
||||
# TITLE = "Custom Title" # custom title
|
||||
# ANNOUNCEMENT = "Custom Announcement"
|
||||
PREFIX = "tmp"
|
||||
# (min, max) length of the adderss, if not set, the default is (1, 30)
|
||||
# MIN_ADDRESS_LEN = 1
|
||||
@@ -27,9 +28,16 @@ PREFIX = "tmp"
|
||||
# ADMIN_PASSWORDS = ["123", "456"]
|
||||
# ADMIN CONTACT, CAN BE ANY STRING
|
||||
# ADMIN_CONTACT = "xx@xx.xxx"
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"]
|
||||
DEFAULT_DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # domain name for no role users
|
||||
DOMAINS = ["xxx.xxx1" , "xxx.xxx2"] # all domain names
|
||||
# For chinese domain name, you can use DOMAIN_LABELS to show chinese domain name
|
||||
# DOMAIN_LABELS = ["中文.xxx", "xxx.xxx2"]
|
||||
# USER_DEFAULT_ROLE = "vip" # default role for new users(only when enable mail verification)
|
||||
# User roles configuration, if domains is empty will use default_domains, if prefix is null will use default prefix, if prefix is empty string will not use prefix
|
||||
# USER_ROLES = [
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "vip", prefix = "vip" },
|
||||
# { domains = ["xxx.xxx1" , "xxx.xxx2"], role = "admin", prefix = "" },
|
||||
# ]
|
||||
JWT_SECRET = "xxx"
|
||||
BLACK_LIST = ""
|
||||
# Allow users to create email addresses
|
||||
|
||||
Reference in New Issue
Block a user