Add read-only sharing, API tokens and OpenAPI spec
- Share a note as a live read-only page at /s/{token} with optional password and expiry
- Share page renders with the shared parser (TOC, footnotes, math, Mermaid, code highlighting)
and only serves images from the note's own .assets directory
- Shares follow renames made through the API or externally
- Manage shares and API tokens from the command palette and file tree
- Accept read/write API tokens as Bearer credentials; management endpoints require a session
- Serve a hand-written openapi.json, checked against the route table in tests
This commit is contained in:
1 parent
7b076346a4
commit
5ac01894e6
26 files changed
+3147
-52
No files matched your search
@@ -0,0 +1,63 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"rawmark/internal/auth"
|
||||
)
|
||||
|
||||
func (s *Server) listTokens(w http.ResponseWriter, r *http.Request) {
|
||||
tokens, err := s.store.APITokens()
|
||||
if err != nil {
|
||||
internalError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"tokens": tokens})
|
||||
}
|
||||
|
||||
// createToken 返回的 token 明文只出现这一次,服务器只保存哈希
|
||||
func (s *Server) createToken(w http.ResponseWriter, r *http.Request) {
|
||||
var body struct{ Name, Scope string }
|
||||
if !readJSON(w, r, &body) {
|
||||
return
|
||||
}
|
||||
name := strings.TrimSpace(body.Name)
|
||||
if name == "" || len([]rune(name)) > 100 {
|
||||
writeError(w, 400, "名称不能为空且不超过 100 个字符")
|
||||
return
|
||||
}
|
||||
plain, t, err := s.auth.CreateAPIToken(name, body.Scope)
|
||||
if errors.Is(err, auth.ErrBadScope) {
|
||||
writeError(w, 400, err.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
internalError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"token": plain, "info": t})
|
||||
}
|
||||
|
||||
func (s *Server) deleteToken(w http.ResponseWriter, r *http.Request) {
|
||||
ok, err := s.store.DeleteAPIToken(r.PathValue("id"))
|
||||
if err != nil {
|
||||
internalError(w, r, err)
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
writeError(w, 404, "令牌不存在")
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]bool{"ok": true})
|
||||
}
|
||||
|
||||
//go:embed openapi.json
|
||||
var openAPISpec []byte
|
||||
|
||||
func serveOpenAPI(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(openAPISpec)
|
||||
}
|
||||
Reference in new issue
Block a user