git.sophuwu.com > goauth   
              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>`