Fix routing, hash api keys, start ws
This commit is contained in:
parent
c670c76d76
commit
22c4afadb6
9 changed files with 45 additions and 24 deletions
|
@ -2,6 +2,8 @@ package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/base64"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"dynatron.me/x/stillbox/pkg/gordio/database"
|
"dynatron.me/x/stillbox/pkg/gordio/database"
|
||||||
|
@ -24,7 +26,9 @@ func (a *authenticator) CheckAPIKey(ctx context.Context, key string) (*UserID, e
|
||||||
}
|
}
|
||||||
|
|
||||||
db := database.FromCtx(ctx)
|
db := database.FromCtx(ctx)
|
||||||
apik, err := db.GetAPIKey(ctx, keyUuid)
|
hash := sha256.Sum256([]byte(keyUuid.String()))
|
||||||
|
b64hash := base64.StdEncoding.EncodeToString(hash[:])
|
||||||
|
apik, err := db.GetAPIKey(ctx, b64hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if database.IsNoRows(err) {
|
if database.IsNoRows(err) {
|
||||||
log.Error().Str("apikey", keyUuid.String()).Msg("no such key")
|
log.Error().Str("apikey", keyUuid.String()).Msg("no such key")
|
||||||
|
@ -36,7 +40,7 @@ func (a *authenticator) CheckAPIKey(ctx context.Context, key string) (*UserID, e
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apik.Disabled != nil && *apik.Disabled) || (apik.Expires.Valid && time.Now().After(apik.Expires.Time)) {
|
if (apik.Disabled != nil && *apik.Disabled) || (apik.Expires.Valid && time.Now().After(apik.Expires.Time)) {
|
||||||
log.Error().Str("key", apik.ApiKey.String()).Msg("key disabled")
|
log.Error().Str("key", apik.ApiKey).Msg("key disabled")
|
||||||
return nil, ErrUnauthorized
|
return nil, ErrUnauthorized
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,13 @@ type jwtAuth interface {
|
||||||
Login(ctx context.Context, username, password string) (token string, err error)
|
Login(ctx context.Context, username, password string) (token string, err error)
|
||||||
|
|
||||||
// InstallVerifyMiddleware installs the JWT verifier middleware to the provided chi Router.
|
// InstallVerifyMiddleware installs the JWT verifier middleware to the provided chi Router.
|
||||||
InstallVerifyMiddleware(r chi.Router)
|
VerifyMiddleware() func(http.Handler) http.Handler
|
||||||
|
|
||||||
// InstallAuthMiddleware installs the JWT authenticator middleware to the provided chi Router.
|
// InstallAuthMiddleware installs the JWT authenticator middleware to the provided chi Router.
|
||||||
InstallAuthMiddleware(r chi.Router)
|
AuthMiddleware() func(http.Handler) http.Handler
|
||||||
|
|
||||||
// InstallRoutes installs the auth route to the provided chi Router.
|
// InstallRoutes installs the auth route to the provided chi Router.
|
||||||
InstallRoutes(r chi.Router)
|
Routes() chi.Router
|
||||||
}
|
}
|
||||||
|
|
||||||
type claims map[string]interface{}
|
type claims map[string]interface{}
|
||||||
|
@ -40,12 +40,12 @@ func (a *authenticator) Authenticated(r *http.Request) (claims, bool) {
|
||||||
return cl, err != nil && tok != nil
|
return cl, err != nil && tok != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) InstallVerifyMiddleware(r chi.Router) {
|
func (a *authenticator) VerifyMiddleware() func(http.Handler) http.Handler {
|
||||||
r.Use(jwtauth.Verifier(a.jwt))
|
return jwtauth.Verifier(a.jwt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) InstallAuthMiddleware(r chi.Router) {
|
func (a *authenticator) AuthMiddleware() func(http.Handler) http.Handler {
|
||||||
r.Use(jwtauth.Authenticator(a.jwt))
|
return jwtauth.Authenticator(a.jwt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) Login(ctx context.Context, username, password string) (token string, err error) {
|
func (a *authenticator) Login(ctx context.Context, username, password string) (token string, err error) {
|
||||||
|
@ -89,8 +89,11 @@ func (a *authenticator) newToken(uid int32) string {
|
||||||
return tokenString
|
return tokenString
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) InstallRoutes(r chi.Router) {
|
func (a *authenticator) Routes() chi.Router {
|
||||||
|
r := chi.NewRouter()
|
||||||
r.Post("/auth", a.routeAuth)
|
r.Post("/auth", a.routeAuth)
|
||||||
|
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) routeAuth(w http.ResponseWriter, r *http.Request) {
|
func (a *authenticator) routeAuth(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ type ApiKey struct {
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Expires pgtype.Timestamp `json:"expires"`
|
Expires pgtype.Timestamp `json:"expires"`
|
||||||
Disabled *bool `json:"disabled"`
|
Disabled *bool `json:"disabled"`
|
||||||
ApiKey uuid.UUID `json:"api_key"`
|
ApiKey string `json:"api_key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Call struct {
|
type Call struct {
|
||||||
|
|
|
@ -15,9 +15,9 @@ type Querier interface {
|
||||||
AddCall(ctx context.Context, arg AddCallParams) (uuid.UUID, error)
|
AddCall(ctx context.Context, arg AddCallParams) (uuid.UUID, error)
|
||||||
CreateAPIKey(ctx context.Context, owner int, expires pgtype.Timestamp, disabled *bool) (ApiKey, error)
|
CreateAPIKey(ctx context.Context, owner int, expires pgtype.Timestamp, disabled *bool) (ApiKey, error)
|
||||||
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
||||||
DeleteAPIKey(ctx context.Context, apiKey uuid.UUID) error
|
DeleteAPIKey(ctx context.Context, apiKey string) error
|
||||||
DeleteUser(ctx context.Context, username string) error
|
DeleteUser(ctx context.Context, username string) error
|
||||||
GetAPIKey(ctx context.Context, apiKey uuid.UUID) (ApiKey, error)
|
GetAPIKey(ctx context.Context, apiKey string) (ApiKey, error)
|
||||||
GetTalkgroupTags(ctx context.Context, systemID int, tgid int) ([]string, error)
|
GetTalkgroupTags(ctx context.Context, systemID int, tgid int) ([]string, error)
|
||||||
GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
GetTalkgroupsWithAllTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
||||||
GetTalkgroupsWithAnyTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
GetTalkgroupsWithAnyTags(ctx context.Context, tags []string) ([]Talkgroup, error)
|
||||||
|
|
|
@ -8,7 +8,6 @@ package database
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/jackc/pgx/v5/pgtype"
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ const deleteAPIKey = `-- name: DeleteAPIKey :exec
|
||||||
DELETE FROM api_keys WHERE api_key = $1
|
DELETE FROM api_keys WHERE api_key = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) DeleteAPIKey(ctx context.Context, apiKey uuid.UUID) error {
|
func (q *Queries) DeleteAPIKey(ctx context.Context, apiKey string) error {
|
||||||
_, err := q.db.Exec(ctx, deleteAPIKey, apiKey)
|
_, err := q.db.Exec(ctx, deleteAPIKey, apiKey)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -95,7 +94,7 @@ const getAPIKey = `-- name: GetAPIKey :one
|
||||||
SELECT id, owner, created_at, expires, disabled, api_key FROM api_keys WHERE api_key = $1
|
SELECT id, owner, created_at, expires, disabled, api_key FROM api_keys WHERE api_key = $1
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAPIKey(ctx context.Context, apiKey uuid.UUID) (ApiKey, error) {
|
func (q *Queries) GetAPIKey(ctx context.Context, apiKey string) (ApiKey, error) {
|
||||||
row := q.db.QueryRow(ctx, getAPIKey, apiKey)
|
row := q.db.QueryRow(ctx, getAPIKey, apiKey)
|
||||||
var i ApiKey
|
var i ApiKey
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
|
|
|
@ -17,21 +17,19 @@ func (s *Server) setupRoutes() {
|
||||||
|
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
// authenticated routes
|
// authenticated routes
|
||||||
s.auth.InstallVerifyMiddleware(r)
|
r.Use(s.auth.AuthMiddleware(), s.auth.VerifyMiddleware())
|
||||||
s.auth.InstallAuthMiddleware(r)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
r.Use(rateLimiter())
|
r.Use(rateLimiter())
|
||||||
r.Use(render.SetContentType(render.ContentTypeJSON))
|
r.Use(render.SetContentType(render.ContentTypeJSON))
|
||||||
// public routes
|
// public routes
|
||||||
s.auth.InstallRoutes(r)
|
r.Mount("/", s.auth.Routes())
|
||||||
s.sources.InstallPublicRoutes(r)
|
r.Mount("/", s.sources.PublicRoutes())
|
||||||
})
|
})
|
||||||
|
|
||||||
r.Group(func(r chi.Router) {
|
r.Group(func(r chi.Router) {
|
||||||
r.Use(rateLimiter())
|
r.Use(rateLimiter(), s.auth.VerifyMiddleware())
|
||||||
s.auth.InstallVerifyMiddleware(r)
|
|
||||||
|
|
||||||
// optional auth routes
|
// optional auth routes
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package sources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"dynatron.me/x/stillbox/pkg/gordio/calls"
|
"dynatron.me/x/stillbox/pkg/gordio/calls"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
@ -25,12 +26,15 @@ func (s *Sources) Register(name string, src Source) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sources) InstallPublicRoutes(r chi.Router) {
|
func (s *Sources) PublicRoutes() chi.Router {
|
||||||
|
r := chi.NewRouter()
|
||||||
for _, si := range *s {
|
for _, si := range *s {
|
||||||
if rs, ok := si.Source.(PublicRouteSource); ok {
|
if rs, ok := si.Source.(PublicRouteSource); ok {
|
||||||
rs.InstallPublicRoutes(r)
|
rs.InstallPublicRoutes(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ingestor interface {
|
type Ingestor interface {
|
||||||
|
|
13
pkg/gordio/ws/session.go
Normal file
13
pkg/gordio/ws/session.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package ws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
|
// "github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SessionManager struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionManager) InstallPrivateRoutes(r chi.Router) {
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ CREATE TABLE IF NOT EXISTS api_keys(
|
||||||
created_at TIMESTAMP NOT NULL,
|
created_at TIMESTAMP NOT NULL,
|
||||||
expires TIMESTAMP,
|
expires TIMESTAMP,
|
||||||
disabled BOOLEAN,
|
disabled BOOLEAN,
|
||||||
api_key UUID UNIQUE NOT NULL
|
api_key TEXT UNIQUE NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS systems(
|
CREATE TABLE IF NOT EXISTS systems(
|
||||||
|
|
Loading…
Reference in a new issue