feat: 云笔记增强 - 安全加固 + 回收站/版本历史/分享/批量导出 + 前端优化
- 安全: 认证改随机token会话(弃固定cookie), 笔记密码SHA256升级为bcrypt(自动迁移), 堵住GET /api/notes/:id泄露带密码笔记, CORS收紧+SameSite防CSRF, 上传图片内容嗅探 - 回收站: 软删除(deleted_at), 列表/恢复/彻底删除/清空, 目录子树连删连恢复 - 版本历史: note_versions表存快照, 每次保存自动留档, 支持查看/回滚 - 分享: 生成随机token分享链接, 支持过期时间, 公开阅读页share.html - 批量导出: 全部笔记打包zip(按目录结构+front matter) - 前端: 深色模式, Mermaid图表, 待办清单checkbox, 字数统计; 后台新增回收站/历史/分享面板和批量导出按钮 - 新增deploy/note-manager.service systemd单元与smoke_test.py
This commit is contained in:
+37
-8
@@ -1,20 +1,49 @@
|
||||
package middleware
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CORS 跨域中间件
|
||||
// 这是同源应用(前端、后台、API 都在同一服务),因此默认不对外部跨域放行。
|
||||
// 仅允许本站自身的 Origin 访问,避免任意外部站点的跨域请求读取或携带凭证。
|
||||
func CORS() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Header("Access-Control-Allow-Origin", "*")
|
||||
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||
c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Accept, Authorization")
|
||||
c.Header("Access-Control-Max-Age", "86400")
|
||||
origin := c.GetHeader("Origin")
|
||||
host := c.Request.Host
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
// 同源请求或没有 Origin 的请求(curl 等)直接放行
|
||||
if origin == "" || strings.Contains(origin, "://"+host) {
|
||||
// 仍允许同源反射,方便调试
|
||||
if origin != "" {
|
||||
c.Header("Access-Control-Allow-Origin", origin)
|
||||
c.Header("Vary", "Origin")
|
||||
}
|
||||
if c.Request.Method == http.MethodOptions {
|
||||
c.AbortWithStatus(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
// 非同源且非本站:拒绝携带凭证的跨域请求
|
||||
if c.Request.Method == http.MethodOptions {
|
||||
// 预检请求直接拒绝
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
// 允许无凭证的只读公开请求,但不返回 Allow-Origin,浏览器会拦截跨域读取
|
||||
if c.Request.Method == http.MethodGet {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 写操作(POST/PUT/DELETE)来自外部站点的跨域请求:拦截
|
||||
c.AbortWithStatus(http.StatusForbidden)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user