重組前檢查點:根目錄 main package

This commit is contained in:
2026-10-03 09:23:38 +08:00
commit f373cb8d37
45 changed files with 5332 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
package main
import (
"errors"
"flag"
"fmt"
"strings"
"gorm.io/gorm"
)
// runUpdatePassword 解析旗標並重設指定帳號的密碼。此為管理用指令,
// 不需驗證舊密碼;密碼更新成功後一併撤銷該使用者所有 Session,
// 避免既有登入在密碼重設後續存。
func runUpdatePassword(args []string) error {
fs := flag.NewFlagSet("update-password", flag.ExitOnError)
username := fs.String("username", "", "登入帳號(必填)")
password := fs.String("password", "", "新密碼(選填;省略時於終端機輸入)")
fs.Parse(args)
name := strings.TrimSpace(*username)
if name == "" {
return errors.New("username 不可為空")
}
pw, err := resolvePassword(*password)
if err != nil {
return err
}
db, err := openDB()
if err != nil {
return fmt.Errorf("database: %w", err)
}
u, err := findUserByUsername(db, name)
if err != nil {
return err
}
if err := u.SetPassword(pw); err != nil {
return fmt.Errorf("hash password: %w", err)
}
revoked, err := updateUserPassword(db, u)
if err != nil {
return err
}
fmt.Printf("密碼更新成功:id=%d username=%s(已撤銷 %d 個 Session)\n", u.ID, u.Username, revoked)
return nil
}
// findUserByUsername 以帳號查詢使用者,查無時回傳可讀的錯誤。
func findUserByUsername(db *gorm.DB, username string) (*User, error) {
var u User
err := db.Where("username = ?", username).First(&u).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("username %q 不存在", username)
}
if err != nil {
return nil, fmt.Errorf("query user: %w", err)
}
return &u, nil
}
// updateUserPassword 於單一交易內寫入新密碼雜湊並刪除該使用者所有
// Session,回傳撤銷的 Session 數;交易確保密碼與 Session 不會只更新一半。
func updateUserPassword(db *gorm.DB, u *User) (int64, error) {
var revoked int64
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(u).Update("password_hash", u.PasswordHash).Error; err != nil {
return fmt.Errorf("update password: %w", err)
}
res := tx.Where("user_id = ?", u.ID).Delete(&Session{})
if res.Error != nil {
return fmt.Errorf("delete sessions: %w", res.Error)
}
revoked = res.RowsAffected
return nil
})
return revoked, err
}