Files
markdown-hub/internal/api/totp.go
T
anders 4df87cbf9a Phase 2-6: Git sync, sharing, 2FA, AI integration
- Git: init, commit, log, diff, restore, remotes, push/pull
- Auto-commit on every file save
- Sharing: share/unshare files with other users (ro/rw)
- Shared documents view in sidebar
- 2FA: TOTP setup/verify/disable, enforced at login
- AI: verify spec endpoint (LiteLLM), generate (summarize/prompt/expand)
- Light/dark theme with CSS variables
- File delete (recursive for folders)
- Admin panel + preferences panel
- File creation timestamp display
2026-05-22 19:53:24 +02:00

76 lines
1.9 KiB
Go

package api
import (
"net/http"
"markdownhub/internal/auth"
)
func (s *Server) handleTOTPSetup(w http.ResponseWriter, r *http.Request) {
userID := getUserID(r)
// Generate secret
secret := auth.GenerateTOTPSecret()
// Get user email for URI
var email string
s.db.QueryRow("SELECT email FROM users WHERE id = ?", userID).Scan(&email)
uri := auth.TOTPUri(secret, email, "MarkdownHub")
// Store secret (not yet verified)
s.db.Exec("UPDATE users SET totp_secret = ? WHERE id = ?", secret, userID)
writeJSON(w, 200, map[string]string{
"secret": secret,
"uri": uri,
})
}
func (s *Server) handleTOTPVerify(w http.ResponseWriter, r *http.Request) {
var req struct {
Code string `json:"code"`
}
if err := decodeBody(r, &req); err != nil || req.Code == "" {
writeJSON(w, 400, map[string]string{"error": "code required"})
return
}
userID := getUserID(r)
var secret string
s.db.QueryRow("SELECT totp_secret FROM users WHERE id = ?", userID).Scan(&secret)
if secret == "" {
writeJSON(w, 400, map[string]string{"error": "TOTP not set up"})
return
}
if !auth.ValidateTOTP(secret, req.Code) {
writeJSON(w, 401, map[string]string{"error": "invalid code"})
return
}
writeJSON(w, 200, map[string]string{"status": "verified"})
}
func (s *Server) handleTOTPDisable(w http.ResponseWriter, r *http.Request) {
var req struct {
Code string `json:"code"`
}
if err := decodeBody(r, &req); err != nil || req.Code == "" {
writeJSON(w, 400, map[string]string{"error": "code required"})
return
}
userID := getUserID(r)
var secret string
s.db.QueryRow("SELECT totp_secret FROM users WHERE id = ?", userID).Scan(&secret)
if !auth.ValidateTOTP(secret, req.Code) {
writeJSON(w, 401, map[string]string{"error": "invalid code"})
return
}
s.db.Exec("UPDATE users SET totp_secret = NULL WHERE id = ?", userID)
writeJSON(w, 200, map[string]string{"status": "disabled"})
}