mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-06 03:31:02 -06:00
Login via api
This commit is contained in:
72
server/internal/api/api.go
Normal file
72
server/internal/api/api.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shroff/phylum/server/internal/app"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func Setup(r *gin.RouterGroup) {
|
||||
setupAuthRoutes(r)
|
||||
r.Use(func(c *gin.Context) {
|
||||
authHeader := strings.Split(c.GetHeader("Authorization"), " ")
|
||||
logrus.Info(authHeader)
|
||||
rersponseObj := gin.H{
|
||||
"ERR": "Unauthorized",
|
||||
}
|
||||
c.JSON(401, rersponseObj)
|
||||
})
|
||||
setupResourceRoutes(r)
|
||||
}
|
||||
|
||||
func setupAuthRoutes(r *gin.RouterGroup) {
|
||||
group := r.Group("/auth")
|
||||
group.POST("/login", handleLoginRoute)
|
||||
}
|
||||
|
||||
func setupResourceRoutes(r *gin.RouterGroup) {
|
||||
group := r.Group("/resources")
|
||||
group.GET("/:id/metadata")
|
||||
group.PUT("/:id/metadata")
|
||||
group.GET("/:id/contents")
|
||||
group.PUT("/:id/contents")
|
||||
}
|
||||
|
||||
func handleLoginRoute(c *gin.Context) {
|
||||
username, ok := c.GetQuery("username")
|
||||
if !ok {
|
||||
c.AbortWithStatusJSON(401, gin.H{
|
||||
"ERR_CODE": "missing_params",
|
||||
"ERR_DETAILS": "Missing username input",
|
||||
})
|
||||
return
|
||||
}
|
||||
password, ok := c.GetQuery("password")
|
||||
if !ok {
|
||||
c.AbortWithStatusJSON(401, gin.H{
|
||||
"ERR_CODE": "missing_params",
|
||||
"ERR_DETAILS": "Missing password input",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if token, err := app.Default.CreateAccessToken(username, password); err != nil {
|
||||
if errors.Is(err, app.ErrInvalidUsernamePassword) {
|
||||
c.AbortWithStatusJSON(401, gin.H{
|
||||
"ERR_CODE": "invalid_username_or_password",
|
||||
})
|
||||
} else {
|
||||
c.AbortWithStatusJSON(401, gin.H{
|
||||
"ERR_DETAILS": err.Error(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
c.JSON(200, gin.H{
|
||||
"access_token": token.ID,
|
||||
"expires": token.Expires.Time.String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -24,30 +24,30 @@ var accessTokenValiditiy = pgtype.Interval{
|
||||
var ErrInvalidUsernamePassword = errors.New("invalid username or password")
|
||||
var ErrAccessTokenExpired = errors.New("access token expired")
|
||||
|
||||
func (a App) CreateAccessToken(username, password, deviceInfo string) (string, error) {
|
||||
func (a App) CreateAccessToken(username, password string) (sql.AccessToken, error) {
|
||||
if user, err := a.FindUser(context.Background(), username); err != nil {
|
||||
if err == pgx.ErrNoRows {
|
||||
return "", ErrInvalidUsernamePassword
|
||||
return sql.AccessToken{}, ErrInvalidUsernamePassword
|
||||
}
|
||||
logrus.Info(err)
|
||||
return "", err
|
||||
return sql.AccessToken{}, err
|
||||
} else {
|
||||
if b, err := cryptutil.VerifyPassword(password, user.PasswordHash); err != nil {
|
||||
logrus.Info(err.Error())
|
||||
return "", err
|
||||
return sql.AccessToken{}, err
|
||||
} else if !b {
|
||||
return "", ErrInvalidUsernamePassword
|
||||
return sql.AccessToken{}, ErrInvalidUsernamePassword
|
||||
}
|
||||
}
|
||||
accessToken := GenerateRandomString(accessTokenLength)
|
||||
if err := a.Db.Queries().InsertAccessToken(context.Background(), sql.InsertAccessTokenParams{
|
||||
ID: accessToken,
|
||||
if token, err := a.Db.Queries().InsertAccessToken(context.Background(), sql.InsertAccessTokenParams{
|
||||
ID: GenerateRandomString(accessTokenLength),
|
||||
Validity: accessTokenValiditiy,
|
||||
Username: username,
|
||||
}); err != nil {
|
||||
return "", err
|
||||
return sql.AccessToken{}, err
|
||||
} else {
|
||||
return token, nil
|
||||
}
|
||||
return accessToken, nil
|
||||
}
|
||||
|
||||
func (a App) VerifyAccessToken(accessToken string) (string, error) {
|
||||
|
||||
@@ -8,10 +8,6 @@ import (
|
||||
"github.com/shroff/phylum/server/internal/storage"
|
||||
)
|
||||
|
||||
type storageManager struct {
|
||||
db *db.DbHandler
|
||||
}
|
||||
|
||||
func restoreStorageBackends(db *db.DbHandler) (map[string]storage.Storage, error) {
|
||||
backends, err := db.Queries().AllStorageBackends(context.Background())
|
||||
if err != nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/fvbock/endless"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shroff/phylum/server/internal/api"
|
||||
"github.com/shroff/phylum/server/internal/app"
|
||||
webdav "github.com/shroff/phylum/server/internal/handler_webdav"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -24,6 +25,8 @@ func setupServeCommand() *cobra.Command {
|
||||
|
||||
webdav.SetupHandler(engine.Group(config.GetString("webdav_prefix")), app.Default)
|
||||
|
||||
api.Setup(engine.Group("/api/v1"))
|
||||
|
||||
server := endless.NewServer(config.GetString("listen"), engine)
|
||||
server.BeforeBegin = func(addr string) {
|
||||
logrus.Info("Listening on " + addr)
|
||||
|
||||
@@ -108,11 +108,12 @@ func setupUserLoginCommand() *cobra.Command {
|
||||
}
|
||||
password := string(bytes)
|
||||
|
||||
accessToken, err := app.Default.CreateAccessToken(username, password, "cmd")
|
||||
accessToken, err := app.Default.CreateAccessToken(username, password)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
logrus.Info("Access Token: " + accessToken)
|
||||
logrus.Info("Access Token: " + accessToken.ID)
|
||||
logrus.Info(" Valid Until: " + accessToken.Expires.Time.String())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,12 +27,12 @@ func (q *Queries) AccessTokenById(ctx context.Context, id string) (AccessToken,
|
||||
return i, err
|
||||
}
|
||||
|
||||
const insertAccessToken = `-- name: InsertAccessToken :exec
|
||||
const insertAccessToken = `-- name: InsertAccessToken :one
|
||||
INSERT INTO access_tokens(
|
||||
id, created, expires, username
|
||||
) VALUES(
|
||||
$1::text, NOW(), NOW() + $2::interval, $3::text
|
||||
)
|
||||
) RETURNING id, created, expires, username
|
||||
`
|
||||
|
||||
type InsertAccessTokenParams struct {
|
||||
@@ -41,7 +41,14 @@ type InsertAccessTokenParams struct {
|
||||
Username string
|
||||
}
|
||||
|
||||
func (q *Queries) InsertAccessToken(ctx context.Context, arg InsertAccessTokenParams) error {
|
||||
_, err := q.db.Exec(ctx, insertAccessToken, arg.ID, arg.Validity, arg.Username)
|
||||
return err
|
||||
func (q *Queries) InsertAccessToken(ctx context.Context, arg InsertAccessTokenParams) (AccessToken, error) {
|
||||
row := q.db.QueryRow(ctx, insertAccessToken, arg.ID, arg.Validity, arg.Username)
|
||||
var i AccessToken
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Created,
|
||||
&i.Expires,
|
||||
&i.Username,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
-- name: AccessTokenById :one
|
||||
SELECT * from access_tokens where id = $1;
|
||||
|
||||
-- name: InsertAccessToken :exec
|
||||
-- name: InsertAccessToken :one
|
||||
INSERT INTO access_tokens(
|
||||
id, created, expires, username
|
||||
) VALUES(
|
||||
@id::text, NOW(), NOW() + @validity::interval, @username::text
|
||||
);
|
||||
) RETURNING *;
|
||||
|
||||
Reference in New Issue
Block a user