219
package htsesh
//
// import (
// "crypto/rand"
// "crypto/sha1"
// "crypto/sha512"
// "crypto/subtle"
// "encoding/base64"
// "encoding/json"
// "fmt"
// "github.com/pquerna/otp/totp"
// "net/http"
// "os"
// "sync/atomic"
// "time"
// )
//
// type session struct {
// V []byte
// T time.Time
// }
//
// func (s *session) Hash() string {
// h := sha512.New()
// h.Write(s.V)
// h.Write([]byte(s.T.String()))
// return base64.URLEncoding.EncodeToString(h.Sum(nil))
// }
//
// func newSession(w http.ResponseWriter) error {
// s := session{
// V: make([]byte, 32),
// T: time.Now().Add(time.Hour),
// }
// n, err := rand.Read(s.V)
// if err != nil || 32 != len(s.V) || n != 32 {
// return fmt.Errorf("failed to generate session: %w", err)
// }
// http.SetCookie(w, &http.Cookie{
// Name: "session_id",
// Value: s.Hash(),
// HttpOnly: true,
// Secure: true,
// Expires: s.T,
// SameSite: http.SameSiteStrictMode,
// })
// sessionID.Store(&s)
// return nil
// }
//
// func validateSession(r *http.Request) bool {
// cookie, err := r.Cookie("session_id")
// if err != nil {
// return false
// }
// s := sessionID.Load()
// if s == nil || cookie.Value != s.Hash() {
// return false
// }
// if time.Now().After((*s).T) || (*s).T.After(time.Now().Add(time.Hour)) {
// sessionID.Store(nil)
// return false
// }
// return true
// }
//
// var sessionID atomic.Pointer[session]
//
// func Authenticate(next http.HandlerFunc) http.Handler {
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
//
// if validateSession(r) || loginHandler(w, r) {
// next.ServeHTTP(w, r)
// return
// }
// w.Header().Set("Content-Type", "text/html")
// w.WriteHeader(http.StatusUnauthorized)
// w.Write([]byte(html))
// })
// }
//
// type User struct {
// Username string // `storm:"id,index,unique"`
// OTP string
// Hash []byte
// Salt []byte
// }
//
// func randomBytes(b *[]byte, n int) error {
// *b = make([]byte, n)
// nn, err := rand.Read(*b)
// if err != nil || nn != n {
// return err
// }
// return nil
// }
//
// func (u *User) HashPassword(password string) []byte {
// h := sha512.New()
// h.Write([]byte(password))
// h.Write(u.Salt)
// return h.Sum(nil)
// }
//
// func (u *User) CheckPassword(password string) bool {
// return subtle.ConstantTimeCompare(u.Hash, u.HashPassword(password)) == 1
// }
//
// func Sh1(username string) string {
// h := sha1.New()
// h.Write([]byte(username))
// return base64.URLEncoding.EncodeToString(h.Sum(nil))
// }
//
// func LoadUser(username string) (*User, error) {
// var u User
// b, err := os.ReadFile("./.passwd/" + Sh1(username))
// if err != nil {
// return nil, err
// }
// err = json.Unmarshal(b, &u)
// if err != nil {
// return nil, err
// }
// return &u, nil
// }
//
// func NewUser(username, password string) error {
// var u User
// u.Username = username
//
// if err := randomBytes(&u.Salt, 32); err != nil {
// return err
// }
// u.Hash = u.HashPassword(password)
//
// host, err := os.Hostname()
// if err != nil {
// host = "unknown.host"
// }
// k, err := totp.Generate(totp.GenerateOpts{
// Issuer: host,
// AccountName: username,
// })
// if err != nil {
// return err
// }
// u.OTP = k.Secret()
// var b []byte
// b, err = json.Marshal(&u)
// if err != nil {
// return err
// }
// fmt.Println("user", username, "created with secret", u.OTP)
// return os.WriteFile("./.passwd/"+Sh1(username), b, 0600)
//
// }
//
// func (u *User) ValidateOtp(otp string) bool {
// return totp.Validate(otp, u.OTP)
// }
//
// func loginHandler(w http.ResponseWriter, r *http.Request) bool {
// if r.Method != http.MethodPost {
// return false
// }
//
// err := r.ParseForm()
// if err != nil {
// return false
// }
//
// username := r.FormValue("username")
// password := r.FormValue("password")
// otp := r.FormValue("otp")
//
// if username == "" || password == "" || otp == "" {
// return false
// }
//
// u, err := LoadUser(username)
// if err != nil {
// return false
// }
// if !(u.CheckPassword(password) && u.ValidateOtp(otp)) {
// return false
// }
//
// return newSession(w) == nil
// }
//
// func init() {
// if err := os.MkdirAll("./.passwd", 0700); err != nil {
// panic(err)
// }
// dr, err := os.ReadDir("./.passwd")
// if err != nil {
// panic(err)
// }
// if len(dr) == 0 {
// if err = NewUser("user", "password"); err != nil {
// panic(err)
// }
// }
// }
//
// func main() {
//
// http.ListenAndServe(":8000", Authenticate(func(w http.ResponseWriter, r *http.Request) {
// w.Write([]byte("Hello, world!"))
// }))
// }
//
// var html = `<html><body><form method="post" style="width: min-content;height: min-content;transform: translate(-50%,-50%);top: 50%;position: absolute;left: 50%;"><input type="text" placeholder="username" autocomplete="off" name="username">
// <input type="password" autocomplete="off" name="password" placeholder="password">
// <input type="text" autocomplete="off" placeholder="otp" name="otp">
// <input type="submit" value="submit">
// </form></body></html>`