Setup sessions

This commit is contained in:
Zoe Roux 2024-08-29 16:32:35 +02:00
parent 306dbbd024
commit 8a2fb36cb0
No known key found for this signature in database
6 changed files with 106 additions and 13 deletions

View File

@ -17,20 +17,25 @@
### Lifecycle
```
`/login` { login, password } -> token
`/login/$provider` { redirectUrl, tenant? } -> redirect
`/register` { email, username, password } -> token
`/logout` w/ optional `?session=id`
Login:
`POST /session { login, password } -> token`
`GET /login/$provider { redirectUrl, tenant? } -> redirect`
Register:
`POST /users { email, username, password } -> token`
Logout
`DELETE /session` w/ optional `?session=id`
`/jwt` retrieve a jwt from an opaque token (also update last online value for session & user)
```
### Profiles
```
Get `/users` -> user[]
Get/Put/Patch/Delete `/users/$username` (or /users/me) -> user
Get/Post/Delete `/users/$username/logo` (or /users/me/logo) -> png
Get/Put/Patch/Delete `/users/$id` (or /users/me) -> user
Get/Post/Delete `/users/$id/logo` (or /users/me/logo) -> png
```
Put/Patch of a user can edit the password if the `oldPassword` value is set and valid (or the user has the `users.password` permission).\
@ -41,10 +46,15 @@ Put/Patch can edit custom claims (roles & permissons for example) if the user ha
Read others requires `users.read` permission.\
Write/Delete requires `users.write` permission (if it's not your account).
POST /users is how you register.
### Sessions
Get `/sessions` list all of your active sessions (and devices)
(can then use `/logout?session=id`)
GET `/sessions` list all of your active sessions (and devices)
POST `/sessions` is how you login
Delete `/sessions` (or `/sessions/$id`) is how you logout
GET `/users/$id/sessions` can be used by admins to list others session
### Api keys

View File

@ -1,12 +1,17 @@
package main
import (
"cmp"
"context"
"crypto/rand"
"encoding/base64"
"maps"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/labstack/echo/v4"
"github.com/zoriya/kyoo/keibi/dbc"
)
type LoginDto struct {
@ -14,8 +19,30 @@ type LoginDto struct {
Password string `json:"password" validate:"required"`
}
func (h *Handler) createToken(c echo.Context, user *User) error {
return nil
func (h *Handler) createSession(c echo.Context, user *User) error {
ctx := context.Background()
id := make([]byte, 64)
_, err := rand.Read(id)
if err != nil {
return err
}
dev := cmp.Or(c.Param("device"), c.Request().Header.Get("User-Agent"))
device := &dev
if dev == "" {
device = nil
}
session, err := h.db.CreateSession(ctx, dbc.CreateSessionParams{
ID: base64.StdEncoding.EncodeToString(id),
UserID: user.ID,
Device: device,
})
if err != nil {
return err
}
return c.JSON(201, session)
}
func (h *Handler) CreateJwt(c echo.Context, user *User) error {

View File

@ -0,0 +1,5 @@
begin;
drop table sessions;
commit;

View File

@ -0,0 +1,11 @@
begin;
create table sessions(
id varchar(128) not null primary key,
user_id uuid not null references users(id) on delete cascade,
created_date timestampz not null default now()::timestampz,
last_used timestampz not null default now()::timestampz,
device varchar(1024)
);
commit;

View File

@ -0,0 +1,40 @@
-- name: GetUserFromSession :one
select
u.*
from
users as u
left join sessions as s on u.id = s.user_id
where
s.id = $1
limit 1;
-- name: TouchSession :exec
update
sessions
set
last_used = now()::timestampz
where
id = $1;
-- name: GetUserSessions :many
select
*
from
sessions
where
user_id = $1
order by
last_used;
-- name: CreateSession :one
insert into sessions(id, user_id, device)
values ($1, $2, $3)
returning
*;
-- name: DeleteSession :one
delete from sessions
where id = $1
returning
*;

View File

@ -102,5 +102,5 @@ func (h *Handler) Register(c echo.Context) error {
return echo.NewHTTPError(409, "Email or username already taken")
}
user := MapDbUser(&duser)
return h.createToken(c, &user)
return h.createSession(c, &user)
}