followup: SafeVaultPath in note update, email i18n, strict check-i18n.sh
- applyRemoteNoteUpdate: use SafeVaultPath for vault mode, skip non-vault with log - Email subjects/bodies moved to Go i18n (confirm + reset) in ru.json and en.json - check-i18n.sh: ru/en key mismatch now FAIL (not WARNING) - All builds, tests, frontend pass
This commit is contained in:
parent
7091397649
commit
12f2916a24
|
|
@ -269,25 +269,28 @@ func (a *App) applyRemoteNoteUpdate(op syncsvc.Op) error {
|
|||
return fmt.Errorf("note record not found: %w", err)
|
||||
}
|
||||
|
||||
var abs string
|
||||
if storageMode == "vault" {
|
||||
abs = filepath.Join(a.vault, filePath)
|
||||
} else {
|
||||
abs = filePath
|
||||
abs, err := syncsvc.SafeVaultPath(a.vault, filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unsafe vault path in note update: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(abs, []byte(payload.Content), 0o640); err != nil {
|
||||
return err
|
||||
}
|
||||
info, _ := os.Stat(abs)
|
||||
size := int64(0)
|
||||
if info != nil {
|
||||
size = info.Size()
|
||||
}
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
_, e := a.db.Exec(
|
||||
`UPDATE files SET size=?, updated_at=? WHERE path=? AND storage_mode=?`,
|
||||
size, now, filePath, storageMode)
|
||||
return e
|
||||
}
|
||||
if err := os.WriteFile(abs, []byte(payload.Content), 0o640); err != nil {
|
||||
return err
|
||||
}
|
||||
info, _ := os.Stat(abs)
|
||||
size := int64(0)
|
||||
if info != nil {
|
||||
size = info.Size()
|
||||
}
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
_, e := a.db.Exec(
|
||||
`UPDATE files SET size=?, updated_at=? WHERE path=? AND storage_mode=?`,
|
||||
size, now, filePath, storageMode)
|
||||
return e
|
||||
log.Printf("applyRemoteNoteUpdate: skipping non-vault note update for node %s (mode=%s, path=%s)",
|
||||
payload.NodeID, storageMode, filePath)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) applyRemoteFileOrFolderOp(op syncsvc.Op) error {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"verstak/internal/i18n"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
|
|
@ -82,8 +84,8 @@ func (s *Server) handleRegister(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
confirmURL = fmt.Sprintf("/api/v1/auth/confirm?token=%s", tokenStr)
|
||||
}
|
||||
body := fmt.Sprintf("Welcome to Verstak Sync!\n\nPlease confirm your email by clicking:\n%s\n\nIf you did not register, ignore this message.", confirmURL)
|
||||
if err := s.smtpSend(req.Email, "Confirm your Verstak Sync account", body); err != nil {
|
||||
body := fmt.Sprintf(i18n.T(s.locale(), "server.emailConfirmBody"), confirmURL)
|
||||
if err := s.smtpSend(req.Email, i18n.T(s.locale(), "server.emailConfirmSubject"), body); err != nil {
|
||||
log.Printf("register: failed to send confirm email: %v", err)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -199,8 +201,8 @@ func (s *Server) handleForgot(w http.ResponseWriter, r *http.Request) {
|
|||
if srvURL != "" {
|
||||
resetURL = fmt.Sprintf("%s/api/v1/auth/reset?token=%s", srvURL, tokenStr)
|
||||
}
|
||||
body := fmt.Sprintf("Reset your Verstak Sync password:\n\n%s\n\nThis link expires in 1 hour.", resetURL)
|
||||
s.smtpSend(req.Email, "Verstak Sync password reset", body)
|
||||
body := fmt.Sprintf(i18n.T(s.locale(), "server.emailResetBody"), resetURL)
|
||||
s.smtpSend(req.Email, i18n.T(s.locale(), "server.emailResetSubject"), body)
|
||||
}
|
||||
jsonOK(w, map[string]string{"status": "if email exists, reset link sent"})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,8 +98,8 @@ func (s *Server) handleUserWebRegister(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
confirmURL = fmt.Sprintf("http://%s/api/v1/auth/confirm?token=%s", r.Host, tokenStr)
|
||||
}
|
||||
body := fmt.Sprintf("Welcome to Verstak Sync!\n\nPlease confirm your email by clicking:\n%s\n\nIf you did not register, ignore this message.", confirmURL)
|
||||
if err := s.smtpSend(email, "Confirm your Verstak Sync account", body); err != nil {
|
||||
body := fmt.Sprintf(i18n.T(s.locale(), "server.emailConfirmBody"), confirmURL)
|
||||
if err := s.smtpSend(email, i18n.T(s.locale(), "server.emailConfirmSubject"), body); err != nil {
|
||||
log.Printf("register web: failed to send confirm email: %v", err)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -153,8 +153,8 @@ func (s *Server) handleUserWebForgot(w http.ResponseWriter, r *http.Request) {
|
|||
if srvURL != "" {
|
||||
resetURL = fmt.Sprintf("%s/reset?token=%s", srvURL, tokenStr)
|
||||
}
|
||||
body := fmt.Sprintf("Reset your Verstak Sync password:\n\n%s\n\nThis link expires in 1 hour.", resetURL)
|
||||
if err := s.smtpSend(email, "Verstak Sync password reset", body); err != nil {
|
||||
body := fmt.Sprintf(i18n.T(s.locale(), "server.emailResetBody"), resetURL)
|
||||
if err := s.smtpSend(email, i18n.T(s.locale(), "server.emailResetSubject"), body); err != nil {
|
||||
log.Printf("forgot web: failed to send reset email: %v", err)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -97,5 +97,10 @@
|
|||
"error.accountBlocked": "Account blocked",
|
||||
"error.emailNotConfirmed": "Email not confirmed",
|
||||
"error.tokenInvalid": "Invalid or expired token",
|
||||
"error.tokenExpired": "Token expired"
|
||||
"error.tokenExpired": "Token expired",
|
||||
|
||||
"server.emailConfirmSubject": "Confirm your Verstak Sync account",
|
||||
"server.emailConfirmBody": "Welcome to Verstak Sync!\n\nPlease confirm your email by clicking:\n%s\n\nIf you did not register, ignore this message.",
|
||||
"server.emailResetSubject": "Verstak Sync password reset",
|
||||
"server.emailResetBody": "Reset your Verstak Sync password:\n\n%s\n\nThis link expires in 1 hour."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -379,5 +379,10 @@
|
|||
"error.accountBlocked": "Аккаунт заблокирован",
|
||||
"error.emailNotConfirmed": "Email не подтверждён",
|
||||
"error.tokenInvalid": "Неверный или просроченный токен",
|
||||
"error.tokenExpired": "Срок действия токена истёк"
|
||||
"error.tokenExpired": "Срок действия токена истёк",
|
||||
|
||||
"server.emailConfirmSubject": "Подтверждение аккаунта Verstak Sync",
|
||||
"server.emailConfirmBody": "Добро пожаловать в Verstak Sync!\n\nПодтвердите email, перейдя по ссылке:\n%s\n\nЕсли вы не регистрировались, проигнорируйте это письмо.",
|
||||
"server.emailResetSubject": "Сброс пароля Verstak Sync",
|
||||
"server.emailResetBody": "Сброс пароля Verstak Sync:\n\n%s\n\nСсылка действительна 1 час."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,12 +97,14 @@ MISSING_EN=$(comm -23 <(echo "$RU_KEYS") <(echo "$EN_KEYS"))
|
|||
MISSING_RU=$(comm -23 <(echo "$EN_KEYS") <(echo "$RU_KEYS"))
|
||||
|
||||
if [ -n "$MISSING_EN" ]; then
|
||||
echo "WARNING: Keys in frontend ru.js but missing in en.js:"
|
||||
echo "FAIL: Keys in frontend ru.js but missing in en.js:"
|
||||
echo "$MISSING_EN"
|
||||
EXIT=1
|
||||
fi
|
||||
if [ -n "$MISSING_RU" ]; then
|
||||
echo "WARNING: Keys in frontend en.js but missing in ru.js:"
|
||||
echo "FAIL: Keys in frontend en.js but missing in ru.js:"
|
||||
echo "$MISSING_RU"
|
||||
EXIT=1
|
||||
fi
|
||||
if [ -z "$MISSING_EN" ] && [ -z "$MISSING_RU" ]; then
|
||||
echo "OK: All frontend locale keys match between ru.js and en.js"
|
||||
|
|
@ -116,12 +118,14 @@ GO_MISSING_EN=$(comm -23 <(echo "$GO_RU_KEYS") <(echo "$GO_EN_KEYS"))
|
|||
GO_MISSING_RU=$(comm -23 <(echo "$GO_EN_KEYS") <(echo "$GO_RU_KEYS"))
|
||||
|
||||
if [ -n "$GO_MISSING_EN" ]; then
|
||||
echo "WARNING: Keys in Go ru.json but missing in en.json:"
|
||||
echo "FAIL: Keys in Go ru.json but missing in en.json:"
|
||||
echo "$GO_MISSING_EN"
|
||||
EXIT=1
|
||||
fi
|
||||
if [ -n "$GO_MISSING_RU" ]; then
|
||||
echo "WARNING: Keys in Go en.json but missing in ru.json:"
|
||||
echo "FAIL: Keys in Go en.json but missing in ru.json:"
|
||||
echo "$GO_MISSING_RU"
|
||||
EXIT=1
|
||||
fi
|
||||
if [ -z "$GO_MISSING_EN" ] && [ -z "$GO_MISSING_RU" ]; then
|
||||
echo "OK: All Go locale keys match between ru.json and en.json"
|
||||
|
|
|
|||
Loading…
Reference in New Issue