Slight refactor

main
Antonio De Lucreziis 3 years ago
parent a6c06dc831
commit 4b53126d6a

@ -3,11 +3,11 @@
## Usage ## Usage
```bash ```bash
# Development Mode: also starts "npm run dev" inside "frontend/" # Development Mode: also starts "npm run dev" inside "_frontend/"
$ MODE=dev go run . $ MODE=dev go run .
# Production Mode # Production Mode
$ cd frontend $ cd _frontend
$ npm run build $ npm run build
$ go build $ go build
``` ```

@ -0,0 +1,144 @@
import { render } from 'preact'
import { useState, useEffect } from 'preact/hooks'
const InputNumero = ({ name, id, value, setValue }) => (
<div class="compound-input">
<input
class="grow"
type="number"
name={name}
id={id}
value={value}
onInput={e => setValue(e.target.value)}
/>
<button type="button" class="square" onClick={() => setValue(value => value + 1)}>
<span class="material-symbols-outlined">add</span>
</button>
<button type="button" class="square" onClick={() => setValue(value => value - 1)}>
<span class="material-symbols-outlined">remove</span>
</button>
</div>
)
const App = () => {
const [user, setUser] = useState(null)
useEffect(() => {
fetch('/api/user')
.then(res => {
if (res.ok) {
return res.json()
}
})
.then(user => setUser(user))
}, [])
const [numeroGiocatori, setNumeroGiocatori] = useState(10)
const [numLupi, setNumLupi] = useState(2)
const [numFattucchiere, setNumFattucchiere] = useState(1)
const [numGuardie, setNumGuardie] = useState(1)
const [numCacciatori, setNumCacciatori] = useState(1)
const [numMedium, setNumMedium] = useState(1)
const [numVeggenti, setNumVeggenti] = useState(1)
const [tooManyRuoli, setTooManyRuoli] = useState(false)
useEffect(() => {
const totalNumGiocatoriConRuolo =
numLupi + numFattucchiere + numGuardie + numCacciatori + numMedium + numVeggenti
console.log(totalNumGiocatoriConRuolo)
setTooManyRuoli(numeroGiocatori < totalNumGiocatoriConRuolo)
}, [numLupi, numFattucchiere, numGuardie, numCacciatori, numMedium, numVeggenti])
return (
<>
<header>
<h1>
<a href="/">Lupus Lite</a>
</h1>
<h2>Crea Partita</h2>
{user && (
<div>
(Accesso eseguito come <b>{user.username}</b>)
</div>
)}
</header>
<hr />
<form action="/api/crea-partita" method="post">
<h2 className="fill-row">Nuova Partita</h2>
<p class="fill-row">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Esse ipsam quisquam
laborum nemo at dignissimos excepturi sapiente incidunt enim fuga?
</p>
<div class="compact">
<label for="numero-giocatori">Numero Giocatori</label>
<InputNumero
name="numero-giocatori"
id="numero-giocatori"
value={numeroGiocatori}
setValue={setNumeroGiocatori}
/>
<label for="numero-lupi">Numero Lupi</label>
<InputNumero
name="numero-lupi"
id="numero-lupi"
value={numLupi}
setValue={setNumLupi}
/>
<label for="numero-fattucchiere">Numero Fattucchiere</label>
<InputNumero
name="numero-fattucchiere"
id="numero-fattucchiere"
value={numFattucchiere}
setValue={setNumFattucchiere}
/>
<label for="numero-lupi">Numero Guardie</label>
<InputNumero
name="numero-guardie"
id="numero-guardie"
value={numGuardie}
setValue={setNumGuardie}
/>
<label for="numero-lupi">Numero Cacciatori</label>
<InputNumero
name="numero-cacciatori"
id="numero-cacciatori"
value={numCacciatori}
setValue={setNumCacciatori}
/>
<label for="numero-lupi">Numero Medium</label>
<InputNumero
name="numero-medium"
id="numero-medium"
value={numMedium}
setValue={setNumMedium}
/>
<label for="numero-lupi">Numero Veggenti</label>
<InputNumero
name="numero-veggenti"
id="numero-veggenti"
value={numVeggenti}
setValue={setNumVeggenti}
/>
</div>
{tooManyRuoli && (
<div class="info">
<div class="icon">
<span class="material-symbols-outlined">error</span>
</div>
<div class="description">
Attenzione il numero di giocatori con ruolo è più alto del numero di
giocatori totali.
</div>
</div>
)}
<button class="fill-row">Crea Partita</button>
</form>
</>
)
}
render(<App />, document.querySelector('main'))

@ -126,6 +126,14 @@ form {
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
gap: 1rem 0.5rem; gap: 1rem 0.5rem;
.compact {
grid-column: span 2;
display: grid;
grid-template-columns: auto 1fr;
gap: 0.5rem;
}
max-width: 35rem; max-width: 35rem;
width: 100%; width: 100%;
@ -137,7 +145,9 @@ form {
} }
label { label {
align-self: center;
justify-self: end; justify-self: end;
font-weight: var(--ft-sans-wt-bold); font-weight: var(--ft-sans-wt-bold);
} }
@ -145,13 +155,32 @@ form {
justify-self: end; justify-self: end;
} }
& > :last-child { .info {
margin-top: 1rem; grid-column: span 2;
display: flex;
align-items: start;
gap: 0.25rem;
.description {
width: 100%;
}
} }
@media screen and (max-width: 512px) { @media screen and (max-width: 512px) {
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 0.25rem;
.compact {
grid-column: span 1;
grid-template-columns: 1fr;
gap: 0.25rem;
}
.info {
grid-column: span 1;
}
.fill-row { .fill-row {
grid-column: span 1; grid-column: span 1;
@ -161,8 +190,6 @@ form {
label { label {
justify-self: start; justify-self: start;
align-self: end; align-self: end;
padding-top: 0.5rem;
} }
button[type='submit'] { button[type='submit'] {

@ -0,0 +1,17 @@
package auth
import (
"github.com/aziis98/lupus-lite/database"
"github.com/aziis98/lupus-lite/model"
)
type AuthService interface {
Register(username, password string) error
Login(username, password string) (string, error)
UserForSession(token string) (string, error)
GetUser(username string) (model.User, error)
}
func NewInMemoryAuthService(db database.Database) AuthService {
return &memAuth{db, map[string]string{}}
}

@ -0,0 +1,57 @@
package auth
import (
"fmt"
"github.com/aziis98/lupus-lite/database"
"github.com/aziis98/lupus-lite/model"
"github.com/aziis98/lupus-lite/util"
"golang.org/x/crypto/bcrypt"
)
type memAuth struct {
db database.Database
sessions map[string]string
}
func (auth *memAuth) Register(username, password string) error {
passwordBCrypt, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
return auth.db.CreateUser(model.User{
Username: username,
PasswordBCrypt: passwordBCrypt,
})
}
func (auth *memAuth) Login(username, password string) (string, error) {
user, err := auth.db.GetUser(username)
if err != nil {
return "", err
}
if err := bcrypt.CompareHashAndPassword(user.PasswordBCrypt, []byte(password)); err != nil {
return "", err
}
token := util.GenerateRandomString(16)
auth.sessions[token] = username
return token, nil
}
func (auth *memAuth) UserForSession(token string) (string, error) {
username, ok := auth.sessions[token]
if !ok {
return "", fmt.Errorf(`invalid session token`)
}
return username, nil
}
func (auth *memAuth) GetUser(username string) (model.User, error) {
return auth.db.GetUser(username)
}

@ -1,136 +1 @@
package main package main
import (
"encoding/json"
"fmt"
"os"
"golang.org/x/crypto/bcrypt"
)
// PublicUser is the "public" version of the "User" struct, this excludes private information
type PublicUser struct {
Username string `json:"username"`
}
// User represents a user in the database
type User struct {
Username string `json:"username"`
PasswordBCrypt []byte `json:"passwordBCrypt"`
}
func (u User) PublicUser() PublicUser {
return PublicUser{
Username: u.Username,
}
}
type Database interface {
GetUsers() ([]User, error)
GetUser(username string) (User, error)
CreateUser(user User) error
}
type memDB struct {
Users map[string]User `json:"users"`
}
func NewInMemoryDB() (Database, error) {
var db memDB
exampleFile, err := os.Open("example-db.local.json")
if err != nil {
return nil, err
}
if err := json.NewDecoder(exampleFile).Decode(&db); err != nil {
return nil, err
}
return &db, nil
}
func (db *memDB) GetUsers() ([]User, error) {
users := make([]User, 0, len(db.Users))
for _, u := range db.Users {
users = append(users, u)
}
return users, nil
}
func (db *memDB) GetUser(username string) (User, error) {
user, ok := db.Users[username]
if !ok {
return User{}, fmt.Errorf(`no user with username %q`, username)
}
return user, nil
}
func (db *memDB) CreateUser(user User) error {
if _, ok := db.Users[user.Username]; ok {
return fmt.Errorf(`user with username %q already exists`, user.Username)
}
db.Users[user.Username] = user
return nil
}
type Auth interface {
Register(username, password string) error
Login(username, password string) (string, error)
UserForSession(token string) (string, error)
GetUser(username string) (User, error)
}
type memAuth struct {
db Database
sessions map[string]string
}
func NewInMemoryAuth(db Database) Auth {
return &memAuth{db, map[string]string{}}
}
func (auth *memAuth) Register(username, password string) error {
passwordBCrypt, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return err
}
return auth.db.CreateUser(User{
Username: username,
PasswordBCrypt: passwordBCrypt,
})
}
func (auth *memAuth) Login(username, password string) (string, error) {
user, err := auth.db.GetUser(username)
if err != nil {
return "", err
}
if err := bcrypt.CompareHashAndPassword(user.PasswordBCrypt, []byte(password)); err != nil {
return "", err
}
token := GenerateRandomString(16)
auth.sessions[token] = username
return token, nil
}
func (auth *memAuth) UserForSession(token string) (string, error) {
username, ok := auth.sessions[token]
if !ok {
return "", fmt.Errorf(`invalid session token`)
}
return username, nil
}
func (auth *memAuth) GetUser(username string) (User, error) {
return auth.db.GetUser(username)
}

@ -0,0 +1,89 @@
package database
import (
"encoding/json"
"fmt"
"os"
"github.com/aziis98/lupus-lite/model"
"github.com/aziis98/lupus-lite/util"
)
type Database interface {
CreateUser(user model.User) error
GetUsers() ([]model.User, error)
GetUser(username string) (model.User, error)
CreatePartita(partitaConfig model.PartitaConfig) (model.Partita, error)
GetPartita(uid string) (model.Partita, error)
}
type memDB struct {
Users map[string]model.User `json:"users"`
Partite map[string]model.Partita `json:"partite"`
}
func NewInMemoryDB() (Database, error) {
var db memDB
exampleFile, err := os.Open("example-db.local.json")
if err != nil {
return nil, err
}
if err := json.NewDecoder(exampleFile).Decode(&db); err != nil {
return nil, err
}
return &db, nil
}
func (db *memDB) GetUsers() ([]model.User, error) {
users := make([]model.User, 0, len(db.Users))
for _, u := range db.Users {
users = append(users, u)
}
return users, nil
}
func (db *memDB) GetUser(username string) (model.User, error) {
user, ok := db.Users[username]
if !ok {
return model.User{}, fmt.Errorf(`no user with username %q`, username)
}
return user, nil
}
func (db *memDB) CreateUser(user model.User) error {
if _, ok := db.Users[user.Username]; ok {
return fmt.Errorf(`user with username %q already exists`, user.Username)
}
db.Users[user.Username] = user
return nil
}
func (db *memDB) CreatePartita(partitaConfig model.PartitaConfig) (model.Partita, error) {
uid := util.GenerateRandomString(12)
partita := model.Partita{
Uid: uid,
Config: partitaConfig,
Players: []string{},
Iniziata: false,
}
db.Partite[uid] = partita
return partita, nil
}
func (db *memDB) GetPartita(uid string) (model.Partita, error) {
partita, ok := db.Partite[uid]
if !ok {
return model.Partita{}, fmt.Errorf(`nessuna partita con uid %q`, uid)
}
return partita, nil
}

@ -1,100 +0,0 @@
import { render } from 'preact'
import { useState, useEffect } from 'preact/hooks'
const InputNumero = ({ name, id, value, setValue }) => (
<div class="compound-input">
<input
class="grow"
type="number"
name={name}
id={id}
value={value}
onInput={e => setValue(e.target.value)}
/>
<button type="button" class="square" onClick={() => setValue(value => value + 1)}>
<span class="material-symbols-outlined">add</span>
</button>
<button type="button" class="square" onClick={() => setValue(value => value - 1)}>
<span class="material-symbols-outlined">remove</span>
</button>
</div>
)
const App = () => {
const [user, setUser] = useState(null)
useEffect(() => {
fetch('/api/user')
.then(res => {
if (res.ok) {
return res.json()
}
})
.then(user => setUser(user))
})
const [numeroGiocatori, setNumeroGiocatori] = useState(10)
const [numLupi, setNumLupi] = useState(2)
const [numFattucchiere, setNumFattucchiere] = useState(1)
return (
<>
<header>
<h1>
<a href="/">Lupus Lite</a>
</h1>
<h2>Crea Partita</h2>
{user && (
<div>
(Accesso eseguito come <b>{user.username}</b>)
</div>
)}
</header>
<hr />
<form action="/api/crea-partita" method="post">
<h2 className="fill-row">Nuova Partita</h2>
<p class="fill-row">
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Esse ipsam quisquam
laborum nemo at dignissimos excepturi sapiente incidunt enim fuga?
</p>
<label for="numero-giocatori">Numero Giocatori</label>
<InputNumero
name="numero-giocatori"
id="numero-giocatori"
value={numeroGiocatori}
setValue={setNumeroGiocatori}
/>
<label for="numero-lupi">Numero Lupi</label>
<InputNumero
name="numero-lupi"
id="numero-lupi"
value={numLupi}
setValue={setNumLupi}
/>
<label for="numero-fattucchiere">Numero Fattucchiere</label>
<InputNumero
name="numero-fattucchiere"
id="numero-fattucchiere"
value={numFattucchiere}
setValue={setNumFattucchiere}
/>
<label for="numero-lupi">Numero Lupi</label>
<InputNumero
name="numero-lupi"
id="numero-lupi"
value={numLupi}
setValue={setNumLupi}
/>
<label for="numero-lupi">Numero Lupi</label>
<InputNumero
name="numero-lupi"
id="numero-lupi"
value={numLupi}
setValue={setNumLupi}
/>
<button class="fill-row">Crea Partita</button>
</form>
</>
)
}
render(<App />, document.querySelector('main'))

@ -0,0 +1,103 @@
package lupus
// StatoPartita rappresenta lo stato della partita
type StatoPartita struct {
Uid string `json:"uid"` // Uid corrispondente come in "Partita"
Players []Player `json:"players"` // Players è una mappa da username a giocatore
Time uint `json:"time"` // Time indica la fase corrente del gioco (la parità indica notte/giorno e si inizia da "Notte 0")
Actions []Action `json:"actions"` // PhaseActions indica quali azioni sono state fatte in una certa fase
}
type Player struct {
Username string `json:"username"`
Ruolo Ruolo `json:"ruolo"`
Vivo bool `json:"vivo"`
}
type Ruolo struct {
Uid string `json:"uid"`
Nome string `json:"nome"`
Fazione string `json:"fazione"`
Aura string `json:"aura"`
}
type Action struct {
Uid string `json:"uid"`
Time uint `json:"time"` // Time indica in quale fase è stata compiuta l'azione
Player string `json:"player"`
TargetPlayer string `json:"targetPlayer"`
}
var (
AuraBianca = "bianca"
AuraNera = "nera"
)
var (
FazioneBuoni = "buoni"
FazioneCattivi = "cattivi"
)
var (
Contadino = Ruolo{
Uid: "contadino",
Nome: "Contadino",
Fazione: FazioneBuoni,
Aura: AuraBianca,
}
Lupo = Ruolo{
Uid: "lupo",
Nome: "Lupo",
Fazione: FazioneCattivi,
Aura: AuraNera,
}
Fattucchiera = Ruolo{
Uid: "fattucchiera",
Nome: "Fattucchiera",
Fazione: FazioneCattivi,
Aura: AuraNera,
}
Indemoniato = Ruolo{
Uid: "indemoniato",
Nome: "Indemoniato",
Fazione: FazioneCattivi,
Aura: AuraBianca,
}
Guardia = Ruolo{
Uid: "guardia",
Nome: "Guardia",
Fazione: FazioneBuoni,
Aura: AuraBianca,
}
Cacciatore = Ruolo{
Uid: "cacciatore",
Nome: "Cacciatore",
Fazione: FazioneBuoni,
Aura: AuraBianca,
}
Medium = Ruolo{
Uid: "medium",
Nome: "Medium",
Fazione: FazioneBuoni,
Aura: AuraBianca,
}
Veggente = Ruolo{
Uid: "veggente",
Nome: "Veggente",
Fazione: FazioneBuoni,
Aura: AuraBianca,
}
)
// Ruoli è una lista di ruoli comuni, l'ordine è puramente casuale
var Ruoli = []Ruolo{
Contadino,
Lupo,
Fattucchiera,
Indemoniato,
Guardia,
Cacciatore,
Medium,
Veggente,
}

@ -6,6 +6,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/aziis98/lupus-lite/routes"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/fiber/v2/middleware/recover"
@ -19,15 +20,15 @@ func main() {
app.Use(recover.New()) app.Use(recover.New())
// Static files // Static files
app.Static("/", "./frontend/dist") app.Static("/", "./_frontend/dist")
// Api routes // Api routes
app.Route("/api", mountApiRoutes) app.Route("/api", routes.Api)
if strings.HasPrefix(mode, "dev") { if strings.HasPrefix(mode, "dev") {
log.Printf(`Running dev server for frontend: "npm run dev"`) log.Printf(`Running dev server for frontend: "npm run dev"`)
err := (exec.Command("sh", "-c", "cd frontend/ && npm run dev").Start()) err := (exec.Command("sh", "-c", "cd _frontend/ && npm run dev").Start())
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

@ -0,0 +1,33 @@
package model
// PublicUser is the "public" version of the "User" struct, this excludes private information
type PublicUser struct {
Username string `json:"username"`
}
// User represents a user in the database
type User struct {
Username string `json:"username"`
PasswordBCrypt []byte `json:"passwordBCrypt"`
}
func (u User) PublicUser() PublicUser {
return PublicUser{
Username: u.Username,
}
}
type PartitaConfig struct {
// NumeroGiocatori indica il numero totale di giocatori (per capire quanto tutti sono entrati nella partita)
NumeroGiocatori int
// NumeroPerRuolo indica quanti giocatori di un certo ruolo ci dovrebbero essere
NumeroPerRuolo map[string]int
}
type Partita struct {
Uid string // Uid è il codice identificativo della partita.
Config PartitaConfig // Config è la configurazione iniziale della partita.
Players []string // Players è la lista di giocatori che sono entrati in questa partita.
Iniziata bool // Iniziata indica se la partita è iniziata, quando lo è c'è una tabella corrispondente StatoPartita con le informazioni sui vari giocatori e sullo stato attuale del gioco.
}

@ -1,126 +1 @@
package main package main
import (
"encoding/json"
"fmt"
"log"
"time"
"github.com/gofiber/fiber/v2"
)
const UserKey = "github.com/aziis98/lupus-lite/user"
func requestUser(c *fiber.Ctx) *User {
return c.Locals(UserKey).(*User)
}
func RequireLoggedMiddleware(auth Auth) fiber.Handler {
return func(c *fiber.Ctx) error {
token := c.Cookies("sid")
if token == "" {
return fmt.Errorf(`request has no session token`)
}
username, err := auth.UserForSession(token)
if err != nil {
return err
}
user, err := auth.GetUser(username)
if err != nil {
return err
}
c.Locals(UserKey, &user)
return c.Next()
}
}
func mountApiRoutes(api fiber.Router) {
db, err := NewInMemoryDB()
if err != nil {
log.Fatal(err)
}
auth := NewInMemoryAuth(db)
requireLogged := RequireLoggedMiddleware(auth)
api.Get("/status", func(c *fiber.Ctx) error {
s, err := json.MarshalIndent(db, "", " ")
if err != nil {
return err
}
log.Println(string(s))
return c.SendString("ok")
})
api.Post("/login", func(c *fiber.Ctx) error {
var loginForm struct {
Username string `form:"username"`
Password string `form:"password"`
}
if err := c.BodyParser(&loginForm); err != nil {
return err
}
token, err := auth.Login(loginForm.Username, loginForm.Password)
if err != nil {
return err
}
c.Cookie(&fiber.Cookie{
Name: "sid",
Value: token,
Path: "/",
Expires: time.Now().Add(3 * 24 * time.Hour),
})
return c.Redirect("/")
})
api.Post("/logout", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "sid",
Value: "",
Path: "/",
Expires: time.Now(),
})
return c.SendString("ok")
})
api.Post("/register", func(c *fiber.Ctx) error {
var loginForm struct {
Username string `form:"username"`
Password string `form:"password"`
Password2 string `form:"password2"`
}
if err := c.BodyParser(&loginForm); err != nil {
return err
}
if err := validateUsername(loginForm.Username); err != nil {
return err
}
if err := validatePasswords(loginForm.Password, loginForm.Password2); err != nil {
return err
}
if err := auth.Register(loginForm.Username, loginForm.Password); err != nil {
return err
}
return c.Redirect("/login")
})
api.Get("/user", requireLogged, func(c *fiber.Ctx) error {
return c.JSON(requestUser(c).PublicUser())
})
}

@ -0,0 +1,100 @@
package routes
import (
"encoding/json"
"log"
"time"
"github.com/aziis98/lupus-lite/auth"
"github.com/aziis98/lupus-lite/database"
"github.com/aziis98/lupus-lite/util"
"github.com/gofiber/fiber/v2"
)
func Api(api fiber.Router) {
db, err := database.NewInMemoryDB()
if err != nil {
log.Fatal(err)
}
auth := auth.NewInMemoryAuthService(db)
requireLogged := RequireLoggedMiddleware(auth)
api.Get("/status", func(c *fiber.Ctx) error {
s, err := json.MarshalIndent(db, "", " ")
if err != nil {
return err
}
log.Println(string(s))
return c.SendString("ok")
})
api.Post("/login", func(c *fiber.Ctx) error {
var loginForm struct {
Username string `form:"username"`
Password string `form:"password"`
}
if err := c.BodyParser(&loginForm); err != nil {
return err
}
token, err := auth.Login(loginForm.Username, loginForm.Password)
if err != nil {
return err
}
c.Cookie(&fiber.Cookie{
Name: "sid",
Value: token,
Path: "/",
Expires: time.Now().Add(3 * 24 * time.Hour),
})
return c.Redirect("/")
})
api.Post("/logout", func(c *fiber.Ctx) error {
c.Cookie(&fiber.Cookie{
Name: "sid",
Value: "",
Path: "/",
Expires: time.Now(),
})
return c.SendString("ok")
})
api.Post("/register", func(c *fiber.Ctx) error {
var loginForm struct {
Username string `form:"username"`
Password string `form:"password"`
Password2 string `form:"password2"`
}
if err := c.BodyParser(&loginForm); err != nil {
return err
}
if err := util.ValidateUsername(loginForm.Username); err != nil {
return err
}
if err := util.ValidatePasswords(loginForm.Password, loginForm.Password2); err != nil {
return err
}
if err := auth.Register(loginForm.Username, loginForm.Password); err != nil {
return err
}
return c.Redirect("/login")
})
api.Get("/user", requireLogged, func(c *fiber.Ctx) error {
return c.JSON(requestUser(c).PublicUser())
})
}

@ -0,0 +1,38 @@
package routes
import (
"fmt"
"github.com/aziis98/lupus-lite/auth"
"github.com/aziis98/lupus-lite/model"
"github.com/gofiber/fiber/v2"
)
const UserKey = "github.com/aziis98/lupus-lite/user"
func requestUser(c *fiber.Ctx) *model.User {
return c.Locals(UserKey).(*model.User)
}
func RequireLoggedMiddleware(auth auth.AuthService) fiber.Handler {
return func(c *fiber.Ctx) error {
token := c.Cookies("sid")
if token == "" {
return fmt.Errorf(`request has no session token`)
}
username, err := auth.UserForSession(token)
if err != nil {
return err
}
user, err := auth.GetUser(username)
if err != nil {
return err
}
c.Locals(UserKey, &user)
return c.Next()
}
}

@ -0,0 +1,33 @@
package util
import (
"math/rand"
"time"
"unicode"
)
const alphabet = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func init() {
rand.Seed(time.Now().UnixNano())
}
func GenerateRandomString(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = alphabet[rand.Intn(len(alphabet))]
}
return string(b)
}
func IsWhitespaceFree(s string) bool {
for _, r := range s {
if unicode.IsSpace(r) {
return false
}
}
return true
}

@ -1,8 +1,10 @@
package main package util
import "fmt" import (
"fmt"
)
func validateUsername(username string) error { func ValidateUsername(username string) error {
if !IsWhitespaceFree(username) { if !IsWhitespaceFree(username) {
return fmt.Errorf(`username cannot contain spaces`) return fmt.Errorf(`username cannot contain spaces`)
} }
@ -15,7 +17,7 @@ func validateUsername(username string) error {
return nil return nil
} }
func validatePasswords(password, password2 string) error { func ValidatePasswords(password, password2 string) error {
if password != password2 { if password != password2 {
return fmt.Errorf(`the two password fields don't match`) return fmt.Errorf(`the two password fields don't match`)
} }

@ -1,33 +1 @@
package main package main
import (
"math/rand"
"time"
"unicode"
)
const alphabet = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func init() {
rand.Seed(time.Now().UnixNano())
}
func GenerateRandomString(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = alphabet[rand.Intn(len(alphabet))]
}
return string(b)
}
func IsWhitespaceFree(s string) bool {
for _, r := range s {
if unicode.IsSpace(r) {
return false
}
}
return true
}

Loading…
Cancel
Save