Refactor code structure for improved readability and maintainability

This commit is contained in:
shuaiplus
2026-02-15 02:21:55 +08:00
parent 719024d0fd
commit c5d3052080
11 changed files with 3791 additions and 619 deletions
+28
View File
@@ -0,0 +1,28 @@
name: Sync upstream
on:
schedule:
- cron: "0 3 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: |
git remote add upstream https://github.com/shuaiplus/nodewarden.git || true
git fetch upstream
# 强制让当前分支完全等于 upstream
git reset --hard upstream/main
# 强制推送
git push origin main --force
+45 -77
View File
@@ -1,69 +1,47 @@
# NodeWarden # NodeWarden
中文文档[`README_ZH.md`](./README_ZH.md) English[`README_ZH.md`](./README_EN.md)
A **Bitwarden-compatible** server that runs on **Cloudflare Workers**. 运行在 **Cloudflare Workers** 上的 **Bitwarden 第三方服务端**
- Simple deploy (no VPS) > **免责声明**
- Focused feature set > 本项目仅供学习交流使用。我们不对任何数据丢失负责,强烈建议定期备份您的密码库。
- Low maintenance > 本项目与 Bitwarden 官方无关,请勿向 Bitwarden 官方反馈问题。
> Disclaimer
> - This project is **not affiliated** with Bitwarden.
> - Use at your own risk. Keep regular backups of your vault.
--- ---
## Features ## 特性
-**完全免费,不需要在服务器上部署,再次感谢大善人!**
- ✅ 数据存储基于 Cloudflare D1SQLite
- ✅ 完整的密码、笔记、卡片、身份信息管理
- ✅ 文件夹和收藏功能
- ✅ 文件附件支持(基于 R2 存储)
- ✅ 导入/导出功能
- ✅ 网站图标获取
- ✅ 端到端加密(服务器无法查看明文)
- ✅ 兼容常见的 Bitwarden 官方客户端
-**Free to use. No server to manage.** ## 测试情况:
-Full support for logins, notes, cards, and identities -Windows 客户端(v2026.1.0
-Folders and favorites -Android Appv2026.1.0
-Attachments (Cloudflare R2) -浏览器扩展(v2026.1.0
- ✅ Import / export - ⬜ macOS 客户端(未测试)
- ✅ Website icons - ⬜ Linux 客户端(未测试)
- ✅ End-to-end encryption (the server cant see plaintext) ---
- ✅ Compatible with common Bitwarden official clients
## Tested clients / platforms # 快速开始
- ✅ Windows desktop client (v2026.1.0) ### 一键部署
- ✅ Android app (v2026.1.0)
- ✅ Browser extension (v2026.1.0) **部署步骤:**
- ⬜ macOS desktop client (not tested)
- ⬜ Linux desktop client (not tested) 1. [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shuaiplus/nodewarden)
2. 打开部署后生成的链接,并根据网页提示完成后续操作。
--- ---
# Quick start ## 本地开发
### One-click deploy 这是一个 Cloudflare Workers 的 TypeScript 项目(Wrangler)。
[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shuaiplus/nodewarden)
**Deploy steps:**
1. Sign in with GitHub and authorize
2. Sign in to Cloudflare
3. **Important**: set `JWT_SECRET` to a strong random string (recommended: `openssl rand -hex 32`)
4. D1 database and R2 bucket will be created automatically
5. Click **Deploy** and wait for it to finish
6. After deploy, open the Cloudflare-provided Workers URL (your service URL), and register on the web page
> ⚠️ **Reminder**: always use a strong random `JWT_SECRET`. Weak secrets may put your account at risk.
### Configure your client
In any Bitwarden client:
1. Open **Settings**
2. Choose **Self-hosted environment**
3. Set **Server URL** to your Worker URL (for example: `https://your-project.your-subdomain.workers.dev`)
4. Save, then go back to the login screen
## 🧑‍💻 Local development
This repo is a Cloudflare Workers TypeScript project (Wrangler).
```bash ```bash
npm install npm install
@@ -72,37 +50,27 @@ npm run dev
--- ---
## Tech stack ## 常见问题
- **Runtime**: Cloudflare Workers **Q: 如何备份数据?**
- **Data storage**: Cloudflare D1 (SQLite) A: 在客户端中选择「导出密码库」,保存 JSON 文件。
- **File storage**: Cloudflare R2
- **Language**: TypeScript **Q: 忘记主密码怎么办?**
- **Crypto**: Client-side AES-256-CBC, JWT uses HS256 A: 无法恢复,这是端到端加密的特性。建议妥善保管主密码。
**Q: 可以多人使用吗?**
A: 不建议。本项目为单用户设计,多人使用请选择 Vaultwarden。
--- ---
## FAQ ## 开源协议
**Q: How do I back up my data?**
A: Use **Export vault** in your client and save the JSON file.
**Q: What if I forget the master password?**
A: It cant be recovered (end-to-end encryption). Keep it safe.
**Q: Can multiple people use it?**
A: Not recommended. This project is designed for single-user usage.
---
## License
LGPL-3.0 License LGPL-3.0 License
--- ---
## Credits ## 致谢
- [Bitwarden](https://bitwarden.com/) - original design and clients - [Bitwarden](https://bitwarden.com/) - 原始设计和客户端
- [Vaultwarden](https://github.com/dani-garcia/vaultwarden) - server implementation reference - [Vaultwarden](https://github.com/dani-garcia/vaultwarden) - 服务器实现参考
- [Cloudflare Workers](https://workers.cloudflare.com/) - serverless platform - [Cloudflare Workers](https://workers.cloudflare.com/) - 无服务器平台
+79
View File
@@ -0,0 +1,79 @@
# NodeWarden
中文文档:[`README.md`](./README.md)
A **Bitwarden-compatible** server that runs on **Cloudflare Workers**.
> Disclaimer
> - This project is for learning and communication only.
> - We are not responsible for any data loss. Regular vault backups are strongly recommended.
> - This project is not affiliated with Bitwarden. Please do not report issues to the official Bitwarden team.
---
## Features
-**Completely free, no server deployment needed. Thanks again to the generous sponsor!**
- ✅ Data storage on Cloudflare D1 (SQLite)
- ✅ Full support for logins, notes, cards, and identities
- ✅ Folders and favorites
- ✅ Attachments (Cloudflare R2)
- ✅ Import / export
- ✅ Website icons
- ✅ End-to-end encryption (the server cant see plaintext)
- ✅ Compatible with common Bitwarden official clients
## Tested clients / platforms
- ✅ Windows desktop client (v2026.1.0)
- ✅ Android app (v2026.1.0)
- ✅ Browser extension (v2026.1.0)
- ⬜ macOS desktop client (not tested)
- ⬜ Linux desktop client (not tested)
---
# Quick start
### One-click deploy
**Deploy steps:**
1. [![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shuaiplus/nodewarden)
2. Open the generated service URL and follow the on-page instructions.
## Local development
This repo is a Cloudflare Workers TypeScript project (Wrangler).
```bash
npm install
npm run dev
```
---
## FAQ
**Q: How do I back up my data?**
A: Use **Export vault** in your client and save the JSON file.
**Q: What if I forget the master password?**
A: It cant be recovered (end-to-end encryption). Keep it safe.
**Q: Can multiple people use it?**
A: Not recommended. This project is designed for single-user usage. For multi-user usage, choose Vaultwarden.
---
## License
LGPL-3.0 License
---
## Credits
- [Bitwarden](https://bitwarden.com/) - original design and clients
- [Vaultwarden](https://github.com/dani-garcia/vaultwarden) - server implementation reference
- [Cloudflare Workers](https://workers.cloudflare.com/) - serverless platform
-114
View File
@@ -1,114 +0,0 @@
# NodeWarden
English[`README.md`](./README.md)
一个运行在 **Cloudflare Workers** 上的 **Bitwarden 兼容**服务端实现。
- 部署简单(不需要 VPS
- 功能聚焦
- 维护成本低
> **免责声明**
> 本项目仅供学习交流使用。我们不对任何数据丢失负责,强烈建议定期备份您的密码库。
> 本项目与 Bitwarden 官方无关,请勿向 Bitwarden 官方反馈问题。
---
## 特性
-**完全免费,不需要在服务器上部署,再次感谢大善人!**
- ✅ 完整的密码、笔记、卡片、身份信息管理
- ✅ 文件夹和收藏功能
- ✅ 文件附件支持(基于 R2 存储)
- ✅ 导入/导出功能
- ✅ 网站图标获取
- ✅ 端到端加密(服务器无法查看明文)
- ✅ 兼容常见的 Bitwarden 官方客户端
## 测试情况:
- ✅ Windows 客户端(v2026.1.0
- ✅ Android Appv2026.1.0
- ✅ 浏览器扩展(v2026.1.0
- ⬜ macOS 客户端(未测试)
- ⬜ Linux 客户端(未测试)
---
# 快速开始
### 一键部署
点击下方按钮部署到 Cloudflare Workers
[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shuaiplus/nodewarden)
**部署步骤:**
1. 使用 GitHub 登录并授权
2. 登录 Cloudflare 账户
3. **重要**:设置 `JWT_SECRET` 为强随机字符串(推荐使用 `openssl rand -hex 32` 生成)
4. D1 数据库和 R2 存储桶将自动创建
5. 点击 Deploy 等待部署完成
6. 部署完成后,先打开 Cloudflare 给你的 Workers 链接(也就是你的服务地址),在网页上填写信息完成注册。
> ⚠️ **再次提醒**:请务必使用强随机的 `JWT_SECRET`,使用默认或弱密钥可能导致账户被入侵,**后果自负!**
### 配置客户端
部署完成后,在任意 Bitwarden 客户端中:
1. 打开设置(⚙️
2. 选择「自托管环境」
3. 服务器 URL 填入:`https://你的项目名`
4. 保存并返回登录页面
---
## 本地开发
这是一个 Cloudflare Workers 的 TypeScript 项目(Wrangler)。
```bash
npm install
npm run dev
```
---
## 技术栈
- **运行环境**Cloudflare Workers
- **数据存储**Cloudflare D1SQLite
- **文件存储**Cloudflare R2
- **开发语言**TypeScript
- **加密算法**:客户端 AES-256-CBCJWT 使用 HS256
---
## 常见问题
**Q: 如何备份数据?**
A: 在客户端中选择「导出密码库」,保存 JSON 文件。
**Q: 忘记主密码怎么办?**
A: 无法恢复,这是端到端加密的特性。建议妥善保管主密码。
**Q: 可以多人使用吗?**
A: 不建议。本项目为单用户设计,多人使用请选择 Vaultwarden。
---
## 开源协议
LGPL-3.0 License
---
## 致谢
- [Bitwarden](https://bitwarden.com/) - 原始设计和客户端
- [Vaultwarden](https://github.com/dani-garcia/vaultwarden) - 服务器实现参考
- [Cloudflare Workers](https://workers.cloudflare.com/) - 无服务器平台
+64 -2
View File
@@ -1,15 +1,17 @@
{ {
"name": "nodewarden", "name": "nodewarden",
"version": "0.1.0", "version": "0.2.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "nodewarden", "name": "nodewarden",
"version": "0.1.0", "version": "0.2.0",
"license": "LGPL-3.0", "license": "LGPL-3.0",
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^4.20260131.0", "@cloudflare/workers-types": "^4.20260131.0",
"@types/node": "^25.2.3",
"tsx": "^4.21.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"wrangler": "^4.61.1" "wrangler": "^4.61.1"
} }
@@ -1166,6 +1168,16 @@
"dev": true, "dev": true,
"license": "CC0-1.0" "license": "CC0-1.0"
}, },
"node_modules/@types/node": {
"version": "25.2.3",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.16.0"
}
},
"node_modules/blake3-wasm": { "node_modules/blake3-wasm": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz", "resolved": "https://registry.npmmirror.com/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
@@ -1264,6 +1276,19 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }
}, },
"node_modules/get-tsconfig": {
"version": "4.13.6",
"resolved": "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.13.6.tgz",
"integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==",
"dev": true,
"license": "MIT",
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
"funding": {
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
"node_modules/kleur": { "node_modules/kleur": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz", "resolved": "https://registry.npmmirror.com/kleur/-/kleur-4.1.5.tgz",
@@ -1309,6 +1334,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/resolve-pkg-maps": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.3", "version": "7.7.3",
"resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz", "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.3.tgz",
@@ -1388,6 +1423,26 @@
"license": "0BSD", "license": "0BSD",
"optional": true "optional": true
}, },
"node_modules/tsx": {
"version": "4.21.0",
"resolved": "https://registry.npmmirror.com/tsx/-/tsx-4.21.0.tgz",
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
},
"bin": {
"tsx": "dist/cli.mjs"
},
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.3"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.9.3", "version": "5.9.3",
"resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz",
@@ -1412,6 +1467,13 @@
"node": ">=20.18.1" "node": ">=20.18.1"
} }
}, },
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz",
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
"dev": true,
"license": "MIT"
},
"node_modules/unenv": { "node_modules/unenv": {
"version": "2.0.0-rc.24", "version": "2.0.0-rc.24",
"resolved": "https://registry.npmmirror.com/unenv/-/unenv-2.0.0-rc.24.tgz", "resolved": "https://registry.npmmirror.com/unenv/-/unenv-2.0.0-rc.24.tgz",
+4 -2
View File
@@ -9,7 +9,8 @@
"scripts": { "scripts": {
"dev": "wrangler dev -c wrangler.toml", "dev": "wrangler dev -c wrangler.toml",
"deploymy": "wrangler deploy -c wrangler.my.toml", "deploymy": "wrangler deploy -c wrangler.my.toml",
"deploy": "wrangler deploy " "deploy": "wrangler deploy",
"selfcheck": "npx tsx tests/selfcheck.ts"
}, },
"keywords": [ "keywords": [
"bitwarden", "bitwarden",
@@ -33,8 +34,9 @@
}, },
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^4.20260131.0", "@cloudflare/workers-types": "^4.20260131.0",
"@types/node": "^25.2.3",
"tsx": "^4.21.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"wrangler": "^4.61.1" "wrangler": "^4.61.1"
} }
} }
+5 -9
View File
@@ -1,9 +1,10 @@
import { Env, DEFAULT_DEV_SECRET } from '../types'; import { Env, DEFAULT_DEV_SECRET } from '../types';
import { StorageService } from '../services/storage'; import { StorageService } from '../services/storage';
import { jsonResponse, htmlResponse, errorResponse } from '../utils/response'; import { jsonResponse, errorResponse } from '../utils/response';
import { renderJwtSecretWarningPage, JwtSecretState } from './setupPages';
import { handleRegisterPage } from './setupRegisterPage'; import { handleRegisterPage } from './setupRegisterPage';
type JwtSecretState = 'missing' | 'default' | 'too_short';
function getJwtSecretState(env: Env): JwtSecretState | null { function getJwtSecretState(env: Env): JwtSecretState | null {
const secret = (env.JWT_SECRET || '').trim(); const secret = (env.JWT_SECRET || '').trim();
if (!secret) return 'missing'; if (!secret) return 'missing';
@@ -21,14 +22,9 @@ export async function handleSetupPage(request: Request, env: Env): Promise<Respo
return new Response(null, { status: 404 }); return new Response(null, { status: 404 });
} }
// Guard: require a strong JWT_SECRET before allowing setup/registration. // 引导页内会处理 JWT_SECRET 检测与分流(坏密钥停留在修复步骤)。
const jwtState = getJwtSecretState(env); const jwtState = getJwtSecretState(env);
if (jwtState) { return handleRegisterPage(request, env, jwtState);
return htmlResponse(renderJwtSecretWarningPage(request, jwtState), 200);
}
// Serve the registration/setup UI (split into a dedicated module).
return handleRegisterPage(request, env);
} }
// GET /setup/status // GET /setup/status
+1049 -164
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1694
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,4 +1,4 @@
name = "nodewarden-test" name = "nodewarden"
main = "src/index.ts" main = "src/index.ts"
compatibility_date = "2024-01-01" compatibility_date = "2024-01-01"