package auth import ( "cpone-dashboard/db" "crypto/sha256" "encoding/hex" "html/template" "net/http" ) type passwordData struct { Username string Error string Success string } func ShowPassword(w http.ResponseWriter, r *http.Request) { renderPassword(w, passwordData{Username: Username(r)}) } func DoChangePassword(w http.ResponseWriter, r *http.Request) { username := Username(r) current := r.FormValue("current_password") newPass := r.FormValue("new_password") confirm := r.FormValue("confirm_password") fail := func(msg string) { w.WriteHeader(http.StatusUnprocessableEntity) renderPassword(w, passwordData{Username: username, Error: msg}) } if newPass != confirm { fail("Password baru dan konfirmasi tidak cocok.") return } if len(newPass) < 6 { fail("Password baru minimal 6 karakter.") return } // Verifikasi password lama var storedHash, salt string err := db.DB.QueryRow( `SELECT User_Password, COALESCE(User_Salt, '') FROM dashboard_user WHERE User_Username = ? AND User_IsActive = 'Y'`, username, ).Scan(&storedHash, &salt) if err != nil || !checkPassword(current, salt, storedHash) { fail("Password saat ini tidak sesuai.") return } // Generate salt + hash baru newSalt := newUUID() newHash := hashPassword(newPass, newSalt) _, err = db.DB.Exec( `UPDATE dashboard_user SET User_Password = ?, User_Salt = ?, User_UpdatedAt = NOW() WHERE User_Username = ?`, newHash, newSalt, username, ) if err != nil { fail("Gagal menyimpan password baru, coba lagi.") return } renderPassword(w, passwordData{Username: username, Success: "Password berhasil diubah."}) } func renderPassword(w http.ResponseWriter, data passwordData) { t := template.Must(template.ParseFS(tmplFS, "templates/auth/password.html")) t.ExecuteTemplate(w, "password", data) } func hashPassword(password, salt string) string { h := sha256.Sum256([]byte(salt + ":" + password)) return hex.EncodeToString(h[:]) }