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
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"markdownhub/internal/auth"
|
||||
"markdownhub/internal/files"
|
||||
"markdownhub/internal/git"
|
||||
)
|
||||
|
||||
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
|
||||
@@ -28,6 +29,7 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
TOTPCode string `json:"totp_code"`
|
||||
}
|
||||
if err := decodeBody(r, &req); err != nil {
|
||||
writeJSON(w, 400, map[string]string{"error": "invalid request"})
|
||||
@@ -36,14 +38,27 @@ func (s *Server) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var id, hash string
|
||||
var isAdmin bool
|
||||
var totpSecret *string
|
||||
err := s.db.QueryRow(
|
||||
"SELECT id, password_hash, is_admin FROM users WHERE email = ?", req.Email,
|
||||
).Scan(&id, &hash, &isAdmin)
|
||||
"SELECT id, password_hash, is_admin, totp_secret FROM users WHERE email = ?", req.Email,
|
||||
).Scan(&id, &hash, &isAdmin, &totpSecret)
|
||||
if err != nil || !auth.CheckPassword(hash, req.Password) {
|
||||
writeJSON(w, 401, map[string]string{"error": "invalid credentials"})
|
||||
return
|
||||
}
|
||||
|
||||
// Check TOTP if enabled
|
||||
if totpSecret != nil && *totpSecret != "" {
|
||||
if req.TOTPCode == "" {
|
||||
writeJSON(w, 401, map[string]string{"error": "totp_required"})
|
||||
return
|
||||
}
|
||||
if !auth.ValidateTOTP(*totpSecret, req.TOTPCode) {
|
||||
writeJSON(w, 401, map[string]string{"error": "invalid TOTP code"})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
token, err := auth.CreateToken(id, isAdmin, s.secret)
|
||||
if err != nil {
|
||||
writeJSON(w, 500, map[string]string{"error": "token creation failed"})
|
||||
@@ -186,6 +201,13 @@ func (s *Server) handleWriteFile(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, 500, map[string]string{"error": "write failed"})
|
||||
return
|
||||
}
|
||||
|
||||
// Auto-commit on save
|
||||
go func() {
|
||||
git.InitRepo(s.dataDir, userID)
|
||||
git.AutoCommit(s.dataDir, userID, req.Path)
|
||||
}()
|
||||
|
||||
writeJSON(w, 200, map[string]string{"status": "ok", "path": req.Path})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user