aysec0/aysec
GitHub: aysec0/aysec
一套可自托管的全栈网络安全培训平台,集成课程管理、CTF 挑战赛、博客系统和付费订阅,开箱即用。
Stars: 0 | Forks: 0
# 个人站点 + 网络安全培训平台
包含网络安全培训平台的个人网站:免费 + 付费课程,CTF
带有评分/排行榜的挑战赛、博客/解题报告(writeup)、用户账户、进度
追踪以及 Stripe 结账。
**技术栈:** 原生 HTML/CSS/JS 前端 · Node.js + Express 后端 · SQLite
(通过 `better-sqlite3`) · Stripe 支付 · HttpOnly cookie 中的 JWT 认证。
## 快速开始
```
cp .env.example .env # edit secrets
npm install
npm run db:init # creates ./data/app.db + seeds sample data
npm run dev # → http://localhost:3000
```
默认管理员 (填充数据后):`admin` / `changeme` — 请立即修改。
## 布局
```
.
├── server.js # Express entry, mounts routes + static
├── db/
│ ├── schema.sql # Tables (users, courses, lessons, challenges, …)
│ ├── index.js # better-sqlite3 connection + migrate()
│ └── init.js # Run once: migrate + seed sample data
├── routes/
│ ├── auth.js # /api/auth/{register,login,logout,me}
│ ├── courses.js # /api/courses, /api/courses/:slug
│ ├── challenges.js # /api/challenges/*, leaderboard, flag submit
│ ├── posts.js # /api/posts, /api/posts/:slug
│ └── payments.js # Stripe checkout + webhook
├── middleware/
│ └── auth.js # JWT cookie helpers, requireAuth/requireAdmin
└── public/ # Static frontend (vanilla)
├── index.html # Landing
├── courses.html # Course list (filters: free/paid/difficulty + search)
├── course-detail.html # Detail + lesson viewer (served at /courses/:slug)
├── challenges.html # CTF grid (filters: category + difficulty) + leaderboard
├── challenge-detail.html # Challenge + flag submit form (served at /challenges/:slug)
├── blog.html # Posts + writeups (filters: kind + search)
├── post-detail.html # Single post (served at /blog/:slug)
├── about.html
├── dashboard.html # User stats, enrolled courses w/ progress, recent solves
├── login.html, signup.html
├── 404.html # Terminal-style not-found
├── css/styles.css # Full design system in CSS variables
├── js/
│ ├── theme.js # Sets data-theme early to avoid FOUC
│ ├── api.js # fetch wrapper + escapeHtml/fmtPrice/fmtDate helpers
│ ├── layout.js # Injects navbar/footer + theme toggle + auth state
│ ├── terminal.js # Hero typewriter (landing only)
│ ├── main.js # Landing section loaders
│ ├── auth.js # Login + signup form handling
│ ├── courses-list.js # Course list page
│ ├── course-detail.js # Course detail + lesson viewer
│ ├── challenges-list.js # CTF list + leaderboard
│ ├── challenge-detail.js # Challenge detail + flag submission
│ ├── blog-list.js # Blog list
│ ├── post-detail.js # Post detail (markdown HTML from API)
│ └── dashboard.js # User dashboard
└── img/favicon.svg
```
## API 接口 (当前)
| 方法 | 路径 | 认证 | 备注 |
|--------|------------------------------------|--------|----------------------------------------|
| POST | `/api/auth/register` | — | `{username, email, password}` |
| POST | `/api/auth/login` | — | `{identifier, password}` (email 或 username) |
| POST | `/api/auth/logout` | — | |
| GET | `/api/auth/me` | 用户 | 返回当前用户 |
| GET | `/api/courses` | — | 已发布的课程 |
| GET | `/api/courses/:slug` | — | 课程 + 课时 + 访问标识 |
| GET | `/api/challenges` | — | 已发布的挑战 (包含解决次数,你的解决标识) |
| GET | `/api/challenges/:slug` | — | 挑战详情 |
| POST | `/api/challenges/:slug/submit` | 用户 | `{flag}` — sha256 校验,限速 |
| GET | `/api/challenges/leaderboard/top` | — | 前 50 名得分者 |
| GET | `/api/posts` | — | `?kind=writeup` 进行筛选 |
| GET | `/api/posts/:slug` | — | |
| POST | `/api/payments/checkout` | 用户 | `{courseSlug}` → Stripe 结账 URL |
| POST | `/api/payments/webhook` | Stripe | 在 `checkout.session.completed` 时授予访问权限 |
## 部署说明
- **本地 + VPS:** 开箱即用。SQLite 文件位于 `./data/app.db`。
- **Vercel / Netlify:** 本地 SQLite 文件在冷启动之间不会持久化。
替换为 **[Turso](https://turso.tech)** (兼容 SQLite 的无服务器数据库):
- 将 `better-sqlite3` 替换为 `@libsql/client`。
- 在 `.env` 中设置 `TURSO_URL` + `TURSO_AUTH_TOKEN`。
- SQL 保持不变。
- **Stripe webhook URL:** `https://your-site/api/payments/webhook。` 将
`STRIPE_WEBHOOK_SECRET` 设置为你的 Stripe 仪表板中的签名密钥。
## 路线图
**已完成**
- [x] 基于 token 的主题 (深色 + 浅色),通过 `layout.js` 共享导航栏/页脚
- [x] 落地页 (hero / 关于 / 课程 / CTF / 排行榜 / 解题报告 / CTA)
- [x] DB schema + 初始数据 (3 门课程,9 个课时,4 个挑战,3 篇文章)
- [x] 认证:注册 / 登录 / 登出 / me / 仪表板 (HttpOnly cookie 中的 JWT)
- [x] `/courses` + `/courses/:slug`,带有课时查看器 + 进度追踪
- [x] 免费课程自主注册,付费课程 Stripe 结账
- [x] 课时 + 文章的 Markdown 渲染 (通过 `marked`)
- [x] `/challenges` + 筛选器 (分类,难度) + `/challenges/:slug` 包含 flag 提交,sha256 验证,5次/分钟限速,排行榜
- [x] `/blog` + 筛选器 + `/blog/:slug` (阅读时间,标签,复制链接)
- [x] `/login`,`/signup` (验证,通过 `?next=` 实现登录后重定向)
- [x] `/about`,`/dashboard` (统计数据,进行中的课程,最近的解决记录)
- [x] 自定义 404 页面
**下一步**
- [ ] 管理面板 (对课程、课时、挑战、文章进行 CRUD 操作)
- [ ] 邮箱验证 + 密码重置
- [ ] 文章评论 (或外部 Discord 频道链接)
- [ ] 博客的 RSS 订阅源
- [ ] 将数据库层切换至 Turso/libsql 以用于无服务器部署
- [ ] 文本代码块的语法高亮 (Prism / Shiki)
- [ ] 一旦非管理员用户可以发帖,即对渲染的 markdown 进行 HTML 净化 (DOMPurify)
## 测试
```
npm start # in one terminal
node _scripts/smoke.mjs # 18 routes return 200
node _scripts/e2e.mjs # signup → flag → dashboard → leaderboard
```
## 自定义
- **品牌 / 代号:** 在 `public/index.html`,
`public/404.html`,`public/img/favicon.svg` 和 `db/init.js` 中找到 `aysec` 并替换。
- **颜色:** 全部定义在
`public/css/styles.css` 顶部的 `:root` 和 `[data-theme="light"]` 中。可在该处替换主题色 / 终端 / 分类颜色。
- **Hero 终端:** `public/js/terminal.js` — 编辑 `lines` 数组。
## 许可证
个人项目。请在发布前选择相应的许可证。
标签:better-sqlite3, CEH认证, CRTO备考, CTF挑战, Express, GNU通用公共许可证, HttpOnly Cookie, JWT认证, MITM代理, Node.js, OSCP备考, OSEP备考, OSWE备考, PNPT备考, RESTful API, Security+认证, SQLite, Stripe支付集成, Syscall, Web安全, Web开发, 个人作品集, 个人网站, 免费与付费课程, 博客, 在线教育, 多模态安全, 学习路径, 安全认证, 实战靶场, 实验室工具箱, 技能档案, 排行榜, 提示词优化, 数据可视化, 活动日历, 游戏化学习, 漏洞复现报告, 用户账户, 等级系统, 纯HTML/CSS/JS, 经验值, 网络安全培训平台, 网络安全课程, 自定义脚本, 蓝队分析, 进度跟踪, 速查表