Notes/session.go

120 lines
2.1 KiB
Go
Raw Permalink Normal View History

2023-06-15 07:24:23 +02:00
package main
import (
// Standard
"database/sql"
2023-06-16 07:11:27 +02:00
"errors"
2023-06-17 09:11:14 +02:00
"fmt"
"net/http"
2023-06-15 07:24:23 +02:00
"time"
)
type Session struct {
UUID string
UserID int
Created time.Time
}
2023-06-17 09:11:14 +02:00
func CreateSession() (session Session, err error) {// {{{
2023-06-15 07:24:23 +02:00
var rows *sql.Rows
if rows, err = db.Query(`
INSERT INTO public.session(uuid)
VALUES(gen_random_uuid())
RETURNING uuid, created`,
); err != nil {
return
}
defer rows.Close()
if rows.Next() {
rows.Scan(&session.UUID, &session.Created)
}
return
2023-06-17 09:11:14 +02:00
}// }}}
func sessionUUID(r *http.Request) (string, error) {// {{{
headers := r.Header["X-Session-Id"]
if len(headers) > 0 {
return headers[0], nil
}
return "", errors.New("Invalid session")
}// }}}
func ValidateSession(r *http.Request, notFoundIsError bool) (session Session, found bool, err error) {// {{{
var uuid string
if uuid, err = sessionUUID(r); err != nil {
return
}
2023-06-16 07:11:27 +02:00
2023-06-17 09:11:14 +02:00
session.UUID = uuid
if found, err = session.Retrieve(); err != nil {
return
}
if notFoundIsError && !found {
err = errors.New("Invalid session")
return
}
return
}// }}}
func (session *Session) Retrieve() (found bool, err error) {// {{{
2023-06-16 07:11:27 +02:00
var rows *sql.Rows
if rows, err = db.Query(`
SELECT
uuid, user_id, created
FROM public.session
WHERE
2023-06-17 09:11:14 +02:00
uuid = $1 AND
created + $2::interval >= NOW()
2023-06-16 07:11:27 +02:00
`,
session.UUID,
2023-06-17 09:11:14 +02:00
fmt.Sprintf("%d days", config.Session.DaysValid),
2023-06-16 07:11:27 +02:00
); err != nil {
return
}
defer rows.Close()
2023-06-17 09:11:14 +02:00
found = false
2023-06-16 07:11:27 +02:00
if rows.Next() {
2023-06-17 09:11:14 +02:00
found = true
2023-06-16 07:11:27 +02:00
rows.Scan(&session.UUID, &session.UserID, &session.Created)
}
return
2023-06-17 09:11:14 +02:00
}// }}}
func (session *Session) Authenticate(username, password string) (authenticated bool, err error) {// {{{
2023-06-16 07:11:27 +02:00
var rows *sql.Rows
if rows, err = db.Query(`
SELECT id
FROM public.user
WHERE
username=$1 AND
2023-07-20 10:06:28 +02:00
password=password_hash(SUBSTRING(password FROM 1 FOR 32), $2::bytea)
2023-06-16 07:11:27 +02:00
`,
username,
password,
); err != nil {
return
}
defer rows.Close()
if rows.Next() {
rows.Scan(&session.UserID)
authenticated = session.UserID > 0
}
if authenticated {
_, err = db.Exec("UPDATE public.session SET user_id=$1 WHERE uuid=$2", session.UserID, session.UUID)
if err != nil {
return
}
}
return
2023-06-17 09:11:14 +02:00
}// }}}
// vim: foldmethod=marker