Login technically works
parent
b5aecea322
commit
3aade31bd6
@ -0,0 +1,13 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
server: {
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: 'http://localhost:4000/api',
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: path => path.replace(/^\/api/, ''),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
@ -1,50 +1,180 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// Entities
|
// Entities
|
||||||
|
|
||||||
type Utente struct {
|
type User struct {
|
||||||
ID string
|
ID string
|
||||||
Username string
|
Username string
|
||||||
Permissions []string
|
Permissions []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Stanza struct {
|
type Room struct {
|
||||||
ID string
|
ID string
|
||||||
Posti []string
|
SeatIDs []string
|
||||||
|
|
||||||
|
// gridRows, gridCols int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actions
|
type Seat struct {
|
||||||
|
ID string
|
||||||
|
|
||||||
|
// OccupiedBy is an empty list or a singleton of a userID
|
||||||
|
OccupiedBy []string
|
||||||
|
|
||||||
type AzioneBase struct {
|
// x, y, w, h int
|
||||||
Tipo string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AzioneStanza struct {
|
// Database Interfaces
|
||||||
AzioneBase
|
|
||||||
UserID string
|
type Store interface {
|
||||||
StanzaID string
|
GetUser(userID string) (*User, error)
|
||||||
|
GetRoom(roomID string) (*Room, error)
|
||||||
|
GetSeat(seatID string) (*Seat, error)
|
||||||
|
|
||||||
|
GetOccupiedSeats(roomID string) ([]string, error)
|
||||||
|
GetFreeSeats(roomID string) ([]string, error)
|
||||||
|
GetUserSeat(userID string) ([]string, error)
|
||||||
|
|
||||||
|
OccupySeat(userID, roomID, seatID string) error
|
||||||
|
FreeSeat(userID, roomID, seatID string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type AzioneOccupaPosto struct {
|
// TODO: Create an SQLite implementation
|
||||||
AzioneStanza
|
|
||||||
PostoID string
|
type memDB struct {
|
||||||
|
users map[string]*User
|
||||||
|
rooms map[string]*Room
|
||||||
|
seats map[string]*Seat
|
||||||
}
|
}
|
||||||
|
|
||||||
type AzioneLiberaPosto struct {
|
func NewInMemoryStore() Store {
|
||||||
AzioneStanza
|
db := &memDB{
|
||||||
PostoID string
|
make(map[string]*User),
|
||||||
|
make(map[string]*Room),
|
||||||
|
make(map[string]*Seat),
|
||||||
|
}
|
||||||
|
|
||||||
|
db.rooms["aula-stud"] = &Room{
|
||||||
|
ID: "aula-stud",
|
||||||
|
SeatIDs: []string{
|
||||||
|
"aula-stud/posto-1",
|
||||||
|
"aula-stud/posto-2",
|
||||||
|
"aula-stud/posto-3",
|
||||||
|
"aula-stud/posto-4",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
db.seats["aula-stud/posto-1"] = &Seat{
|
||||||
|
ID: "aula-stud/posto-1",
|
||||||
|
OccupiedBy: []string{},
|
||||||
|
}
|
||||||
|
db.seats["aula-stud/posto-2"] = &Seat{
|
||||||
|
ID: "aula-stud/posto-2",
|
||||||
|
OccupiedBy: []string{},
|
||||||
|
}
|
||||||
|
db.seats["aula-stud/posto-3"] = &Seat{
|
||||||
|
ID: "aula-stud/posto-3",
|
||||||
|
OccupiedBy: []string{},
|
||||||
|
}
|
||||||
|
db.seats["aula-stud/posto-4"] = &Seat{
|
||||||
|
ID: "aula-stud/posto-4",
|
||||||
|
OccupiedBy: []string{},
|
||||||
|
}
|
||||||
|
|
||||||
|
db.users["aziis98"] = &User{
|
||||||
|
ID: "aziis98",
|
||||||
|
Username: "aziis98",
|
||||||
|
Permissions: []string{"admin"},
|
||||||
|
}
|
||||||
|
|
||||||
|
db.users["bachoseven"] = &User{
|
||||||
|
ID: "bachoseven",
|
||||||
|
Username: "bachoseven",
|
||||||
|
Permissions: []string{"admin"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database Interfaces
|
func (db *memDB) GetUser(userID string) (*User, error) {
|
||||||
|
user, present := db.users[userID]
|
||||||
|
if !present {
|
||||||
|
return nil, fmt.Errorf(`no such user "%s"`, userID)
|
||||||
|
}
|
||||||
|
|
||||||
type Store interface {
|
return user, nil
|
||||||
// Entities
|
}
|
||||||
|
|
||||||
GetUtente(userID string) *Utente
|
func (db *memDB) GetRoom(roomID string) (*Room, error) {
|
||||||
GetStanza(stanzaID string) *Stanza
|
room, present := db.rooms[roomID]
|
||||||
|
if !present {
|
||||||
|
return nil, fmt.Errorf(`no such room "%s"`, roomID)
|
||||||
|
}
|
||||||
|
|
||||||
// Available Seats
|
return room, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *memDB) GetSeat(seatID string) (*Seat, error) {
|
||||||
|
seat, present := db.seats[seatID]
|
||||||
|
if !present {
|
||||||
|
return nil, fmt.Errorf(`no such seat "%s"`, seatID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return seat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *memDB) GetOccupiedSeats(roomID string) ([]string, error) {
|
||||||
|
room, err := db.GetRoom(roomID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
seats := []string{}
|
||||||
|
for _, seatID := range room.SeatIDs {
|
||||||
|
seat := db.seats[seatID]
|
||||||
|
if len(seat.OccupiedBy) == 1 {
|
||||||
|
seats = append(seats, seatID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return seats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *memDB) GetFreeSeats(roomID string) ([]string, error) {
|
||||||
|
room, err := db.GetRoom(roomID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
seats := []string{}
|
||||||
|
for _, seatID := range room.SeatIDs {
|
||||||
|
seat := db.seats[seatID]
|
||||||
|
if len(seat.OccupiedBy) == 0 {
|
||||||
|
seats = append(seats, seatID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return seats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *memDB) GetUserSeat(userID string) ([]string, error) {
|
||||||
|
for _, seat := range db.seats {
|
||||||
|
if len(seat.OccupiedBy) > 0 && seat.OccupiedBy[0] == userID {
|
||||||
|
return []string{userID}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *memDB) OccupySeat(userID string, roomID string, seatID string) error {
|
||||||
|
db.seats[seatID].OccupiedBy = []string{userID}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
GetPostiOccupati(stanzaID string) []string
|
func (db *memDB) FreeSeat(userID string, roomID string, seatID string) error {
|
||||||
GetPostiLiberi(stanzaID string) []string
|
db.seats[seatID].OccupiedBy = []string{}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package httputil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type H map[string]interface{}
|
||||||
|
|
||||||
|
func WriteJSON(w http.ResponseWriter, data interface{}) error {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
return json.NewEncoder(w).Encode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadJSON(r *http.Request, data interface{}) error {
|
||||||
|
return json.NewDecoder(r.Body).Decode(data)
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/auth"
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/db"
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/httputil"
|
||||||
|
"git.phc.dm.unipi.it/aziis98/posti-dm/server/util"
|
||||||
|
"github.com/alecthomas/repr"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
sessions map[string]*db.User
|
||||||
|
authService *auth.AuthService
|
||||||
|
|
||||||
|
Database db.Store
|
||||||
|
ApiRoute chi.Router
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer() *Server {
|
||||||
|
server := &Server{
|
||||||
|
sessions: make(map[string]*db.User),
|
||||||
|
Database: db.NewInMemoryStore(),
|
||||||
|
ApiRoute: chi.NewRouter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server.authService = &auth.AuthService{
|
||||||
|
CheckUserPassword: func(userID, password string) error {
|
||||||
|
repr.Println("Sessions: ", server.sessions)
|
||||||
|
|
||||||
|
if password != "phc" {
|
||||||
|
return fmt.Errorf(`invalid password`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
UserPermissions: func(userID string) ([]string, error) {
|
||||||
|
user, err := server.Database.GetUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.Permissions, nil
|
||||||
|
},
|
||||||
|
SessionTokenFromUser: func(userID string) (string, error) {
|
||||||
|
user, err := server.Database.GetUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := util.RandomHash(10)
|
||||||
|
server.sessions[token] = user
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
},
|
||||||
|
UserFromSessionToken: func(session string) (string, error) {
|
||||||
|
user, present := server.sessions[session]
|
||||||
|
if !present {
|
||||||
|
return "", auth.ErrNoUserForSession
|
||||||
|
}
|
||||||
|
|
||||||
|
return user.ID, nil
|
||||||
|
},
|
||||||
|
AuthenticationFailed: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.Error(w, `not authenticated`, http.StatusUnauthorized)
|
||||||
|
}),
|
||||||
|
OtherError: func(err error) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
server.setupRoutes()
|
||||||
|
|
||||||
|
return server
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *Server) setupRoutes() {
|
||||||
|
api := server.ApiRoute
|
||||||
|
db := server.Database
|
||||||
|
|
||||||
|
// Authenticated Routes
|
||||||
|
|
||||||
|
api.Post("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var credentials struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := httputil.ReadJSON(r, &credentials); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
server.authService.Login(w, r, credentials.Username, credentials.Password)
|
||||||
|
})
|
||||||
|
|
||||||
|
api.With(server.authService.LoggedMiddleware()).
|
||||||
|
Post("/logout", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
server.authService.Logout(w)
|
||||||
|
})
|
||||||
|
|
||||||
|
api.With(server.authService.LoggedMiddleware()).
|
||||||
|
Get("/current-seat", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
userID, err := server.authService.UserFromSession(r)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
occupiedSeatID, err := db.GetUserSeat(userID)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(occupiedSeatID) == 0 {
|
||||||
|
httputil.WriteJSON(w, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
seat, err := db.GetSeat(occupiedSeatID[0])
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
httputil.WriteJSON(w, seat)
|
||||||
|
})
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RandomHash(len int) string {
|
||||||
|
buff := make([]byte, len)
|
||||||
|
rand.Read(buff)
|
||||||
|
str := base64.StdEncoding.EncodeToString(buff)
|
||||||
|
return str[:len]
|
||||||
|
}
|
Loading…
Reference in New Issue