mirror of
https://github.com/gotify/server.git
synced 2026-05-06 21:42:07 +08:00
144 lines
3.5 KiB
Go
144 lines
3.5 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"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) 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
|
|
}
|
|
|
|
// swagger:operation POST /auth/local/login auth localLogin
|
|
//
|
|
// Authenticate via basic auth and create a session.
|
|
//
|
|
// ---
|
|
// consumes: [application/x-www-form-urlencoded]
|
|
// produces: [application/json]
|
|
// security:
|
|
// - basicAuth: []
|
|
// parameters:
|
|
// - name: name
|
|
// in: formData
|
|
// description: the client name to create
|
|
// required: true
|
|
// type: string
|
|
// responses:
|
|
// 200:
|
|
// description: Ok
|
|
// schema:
|
|
// $ref: "#/definitions/CurrentUser"
|
|
// headers:
|
|
// Set-Cookie:
|
|
// type: string
|
|
// description: session cookie
|
|
// 401:
|
|
// description: Unauthorized
|
|
// schema:
|
|
// $ref: "#/definitions/Error"
|
|
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
|
|
}
|
|
|
|
elevatedUntil := time.Now().Add(model.DefaultElevationDuration)
|
|
client := model.Client{
|
|
Name: clientParams.Name,
|
|
Token: auth.GenerateNotExistingToken(generateClientToken, a.clientExists),
|
|
UserID: user.ID,
|
|
ElevatedUntil: &elevatedUntil,
|
|
}
|
|
if success := successOrAbort(ctx, 500, a.DB.CreateClient(&client)); !success {
|
|
return
|
|
}
|
|
|
|
auth.SetCookie(ctx.Writer, client.Token, auth.CookieMaxAge, a.SecureCookie)
|
|
|
|
ctx.JSON(200, &model.CurrentUserExternal{
|
|
ID: user.ID,
|
|
Name: user.Name,
|
|
Admin: user.Admin,
|
|
ClientID: client.ID,
|
|
ElevatedUntil: client.ElevatedUntil,
|
|
})
|
|
}
|
|
|
|
// swagger:operation POST /auth/logout auth logout
|
|
//
|
|
// End the current session.
|
|
//
|
|
// Clears the session cookie and deletes the associated client.
|
|
//
|
|
// ---
|
|
// produces: [application/json]
|
|
// security:
|
|
// - clientTokenHeader: []
|
|
// - clientTokenQuery: []
|
|
// - basicAuth: []
|
|
// responses:
|
|
// 200:
|
|
// description: Ok
|
|
// headers:
|
|
// Set-Cookie:
|
|
// type: string
|
|
// description: cleared session cookie
|
|
// 400:
|
|
// description: Bad Request
|
|
// schema:
|
|
// $ref: "#/definitions/Error"
|
|
func (a *SessionAPI) Logout(ctx *gin.Context) {
|
|
auth.SetCookie(ctx.Writer, "", -1, a.SecureCookie)
|
|
|
|
client := auth.GetClient(ctx)
|
|
if client == nil {
|
|
ctx.AbortWithError(403, errors.New("no client auth provided"))
|
|
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
|
|
}
|