mirror of
https://github.com/gotify/server.git
synced 2026-05-08 06:22:16 +08:00
99 lines
2.4 KiB
Go
99 lines
2.4 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gotify/server/v2/auth"
|
|
"github.com/gotify/server/v2/auth/password"
|
|
"github.com/gotify/server/v2/model"
|
|
)
|
|
|
|
// SessionDatabase is the interface for session-related database access.
|
|
type SessionDatabase interface {
|
|
GetUserByName(name string) (*model.User, error)
|
|
CreateClient(client *model.Client, quota uint32) error
|
|
GetClientByToken(token string) (*model.Client, error)
|
|
DeleteClientByID(id uint) error
|
|
}
|
|
|
|
// SessionAPI provides handlers for cookie-based session authentication.
|
|
type SessionAPI struct {
|
|
DB SessionDatabase
|
|
NotifyDeleted func(uint, string)
|
|
SecureCookie bool
|
|
}
|
|
|
|
// Login authenticates via basic auth, creates a client, sets an HttpOnly cookie, and returns user info.
|
|
func (a *SessionAPI) Login(ctx *gin.Context) {
|
|
name, pass, ok := ctx.Request.BasicAuth()
|
|
if !ok {
|
|
ctx.AbortWithError(401, errors.New("basic auth required"))
|
|
return
|
|
}
|
|
|
|
user, err := a.DB.GetUserByName(name)
|
|
if err != nil {
|
|
ctx.AbortWithError(500, err)
|
|
return
|
|
}
|
|
if user == nil || !password.ComparePassword(user.Pass, []byte(pass)) {
|
|
ctx.AbortWithError(401, errors.New("invalid credentials"))
|
|
return
|
|
}
|
|
|
|
clientParams := ClientParams{}
|
|
if err := ctx.Bind(&clientParams); err != nil {
|
|
return
|
|
}
|
|
|
|
client := model.Client{
|
|
Name: clientParams.Name,
|
|
Token: auth.GenerateNotExistingToken(generateClientToken, a.clientExists),
|
|
UserID: user.ID,
|
|
}
|
|
if success := successOrAbort(ctx, 500, a.DB.CreateClient(&client, 0)); !success {
|
|
return
|
|
}
|
|
|
|
auth.SetCookie(ctx.Writer, client.Token, auth.CookieMaxAge, a.SecureCookie)
|
|
|
|
ctx.JSON(200, &model.UserExternal{
|
|
ID: user.ID,
|
|
Name: user.Name,
|
|
Admin: user.Admin,
|
|
})
|
|
}
|
|
|
|
// Logout deletes the client for the current session and clears the cookie.
|
|
func (a *SessionAPI) Logout(ctx *gin.Context) {
|
|
auth.SetCookie(ctx.Writer, "", -1, a.SecureCookie)
|
|
|
|
tokenID := auth.TryGetTokenID(ctx)
|
|
if tokenID == "" {
|
|
ctx.AbortWithError(400, errors.New("no client auth provided"))
|
|
return
|
|
}
|
|
client, err := a.DB.GetClientByToken(tokenID)
|
|
if err != nil {
|
|
ctx.AbortWithError(500, err)
|
|
return
|
|
}
|
|
if client == nil {
|
|
ctx.Status(200)
|
|
return
|
|
}
|
|
|
|
a.NotifyDeleted(client.UserID, client.Token)
|
|
if success := successOrAbort(ctx, 500, a.DB.DeleteClientByID(client.ID)); !success {
|
|
return
|
|
}
|
|
|
|
ctx.Status(200)
|
|
}
|
|
|
|
func (a *SessionAPI) clientExists(token string) bool {
|
|
client, _ := a.DB.GetClientByToken(token)
|
|
return client != nil
|
|
}
|