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 = `
`