compiles
This commit is contained in:
parent
a468f0629b
commit
0378151b9f
12 changed files with 157 additions and 120 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"dynatron.me/x/blasphem/internal/common"
|
"dynatron.me/x/blasphem/internal/common"
|
||||||
|
"dynatron.me/x/blasphem/pkg/blas/core"
|
||||||
"dynatron.me/x/blasphem/pkg/cmd/serve"
|
"dynatron.me/x/blasphem/pkg/cmd/serve"
|
||||||
"dynatron.me/x/blasphem/pkg/config"
|
"dynatron.me/x/blasphem/pkg/config"
|
||||||
|
|
||||||
|
@ -25,7 +26,12 @@ func main() {
|
||||||
log.Fatal().Err(err).Msg("Config read failed")
|
log.Fatal().Err(err).Msg("Config read failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCmd.AddCommand(serve.Command(config))
|
bl, err := core.New(config)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("Core create failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCmd.AddCommand(serve.Command(bl))
|
||||||
|
|
||||||
err = rootCmd.Execute()
|
err = rootCmd.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"dynatron.me/x/blasphem/pkg/auth/provider"
|
"dynatron.me/x/blasphem/pkg/auth/provider"
|
||||||
"dynatron.me/x/blasphem/pkg/frontend"
|
|
||||||
"dynatron.me/x/blasphem/pkg/storage"
|
"dynatron.me/x/blasphem/pkg/storage"
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
|
@ -42,9 +41,10 @@ type AuthError struct {
|
||||||
Description string `json:"error_description"`
|
Description string `json:"error_description"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *authenticator) installRoutes(e *echo.Echo) {
|
func (a *authenticator) InstallRoutes(e *echo.Echo) {
|
||||||
authG := e.Group("/auth")
|
authG := e.Group("/auth")
|
||||||
authG.GET("/authorize", frontend.AliasHandler("authorize.html"))
|
panic("reinstall authorize")
|
||||||
|
//authG.GET("/authorize", frontend.AliasHandler("authorize.html"))
|
||||||
authG.GET("/providers", a.ProvidersHandler)
|
authG.GET("/providers", a.ProvidersHandler)
|
||||||
authG.POST("/token", a.TokenHandler)
|
authG.POST("/token", a.TokenHandler)
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ func (a *authenticator) installRoutes(e *echo.Echo) {
|
||||||
loginFlow.DELETE("/:flow_id", a.LoginFlowDeleteHandler)
|
loginFlow.DELETE("/:flow_id", a.LoginFlowDeleteHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(e *echo.Echo, s storage.Store) (Authenticator, error) {
|
func New(s storage.Store) (Authenticator, error) {
|
||||||
a := &authenticator{
|
a := &authenticator{
|
||||||
providers: make(map[string]provider.AuthProvider),
|
providers: make(map[string]provider.AuthProvider),
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,6 @@ func New(e *echo.Echo, s storage.Store) (Authenticator, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.installRoutes(e)
|
|
||||||
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,5 +123,3 @@ func (a *authenticator) Check(f *LoginFlow, req *http.Request, rm map[string]int
|
||||||
|
|
||||||
return nil, clientID, ErrInvalidAuth
|
return nil, clientID, ErrInvalidAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
//func (a *Authenticator) GetOrCreateCreds(
|
|
||||||
|
|
|
@ -275,6 +275,11 @@ func (r *RefreshToken) AccessToken(req *http.Request) (string, error) {
|
||||||
}).SignedString([]byte(r.JWTKey))
|
}).SignedString([]byte(r.JWTKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *authenticator) ValidateAccessToken(token AccessToken) *RefreshToken {
|
||||||
|
panic("not implemented")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *authenticator) verifyAndGetCredential(tr *TokenRequest) *Credentials {
|
func (a *authenticator) verifyAndGetCredential(tr *TokenRequest) *Credentials {
|
||||||
cred, success := a.authCodes.get(tr)
|
cred, success := a.authCodes.get(tr)
|
||||||
if !success {
|
if !success {
|
||||||
|
|
|
@ -2,12 +2,8 @@ package blas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"dynatron.me/x/blasphem/internal/common"
|
|
||||||
"dynatron.me/x/blasphem/pkg/auth"
|
"dynatron.me/x/blasphem/pkg/auth"
|
||||||
|
"dynatron.me/x/blasphem/pkg/blas/core"
|
||||||
"dynatron.me/x/blasphem/pkg/bus"
|
"dynatron.me/x/blasphem/pkg/bus"
|
||||||
"dynatron.me/x/blasphem/pkg/config"
|
"dynatron.me/x/blasphem/pkg/config"
|
||||||
"dynatron.me/x/blasphem/pkg/storage"
|
"dynatron.me/x/blasphem/pkg/storage"
|
||||||
|
@ -22,65 +18,12 @@ type Core interface {
|
||||||
Versioner
|
Versioner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ Core = (*core.Blas)(nil)
|
||||||
|
|
||||||
type Shutdowner interface {
|
type Shutdowner interface {
|
||||||
Shutdown(context.Context) error
|
ShutdownBlas(context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Versioner interface {
|
type Versioner interface {
|
||||||
Version() string
|
Version() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Blas struct {
|
|
||||||
bus.Bus
|
|
||||||
storage.Store
|
|
||||||
Config *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Blas) Version() string {
|
|
||||||
return common.Version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Blas) Conf() *config.Config { return b.Config }
|
|
||||||
|
|
||||||
func (b *Blas) ShutdownBlas(ctx context.Context) error {
|
|
||||||
b.Bus.ShutdownBus()
|
|
||||||
b.Store.ShutdownStore()
|
|
||||||
return ctx.Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Blas) ConfigDir() (cd string) {
|
|
||||||
if b.Config.DataDir != nil {
|
|
||||||
cd = *b.Config.DataDir
|
|
||||||
}
|
|
||||||
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case cd == "":
|
|
||||||
return path.Join(home, "."+common.AppName)
|
|
||||||
case strings.HasPrefix(cd, "~/"):
|
|
||||||
return path.Join(home, cd[2:])
|
|
||||||
default:
|
|
||||||
return cd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Blas) openStore() error {
|
|
||||||
// TODO: based on config, open filestore or db store
|
|
||||||
stor, err := storage.OpenFileStore(b.ConfigDir())
|
|
||||||
b.Store = stor
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(cfg *config.Config) (*Blas, error) {
|
|
||||||
b := &Blas{
|
|
||||||
Bus: bus.New(),
|
|
||||||
Config: cfg,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := b.openStore()
|
|
||||||
return b, err
|
|
||||||
}
|
|
||||||
|
|
75
pkg/blas/core/core.go
Normal file
75
pkg/blas/core/core.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"dynatron.me/x/blasphem/internal/common"
|
||||||
|
"dynatron.me/x/blasphem/pkg/auth"
|
||||||
|
"dynatron.me/x/blasphem/pkg/bus"
|
||||||
|
"dynatron.me/x/blasphem/pkg/config"
|
||||||
|
"dynatron.me/x/blasphem/pkg/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Blas struct {
|
||||||
|
bus.Bus
|
||||||
|
storage.Store
|
||||||
|
auth.Authenticator
|
||||||
|
Config *config.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Blas) Version() string {
|
||||||
|
return common.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Blas) Conf() *config.Config { return b.Config }
|
||||||
|
|
||||||
|
func (b *Blas) ShutdownBlas(ctx context.Context) error {
|
||||||
|
b.Bus.ShutdownBus()
|
||||||
|
b.Store.ShutdownStore()
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Blas) ConfigDir() (cd string) {
|
||||||
|
if b.Config.DataDir != nil {
|
||||||
|
cd = *b.Config.DataDir
|
||||||
|
}
|
||||||
|
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case cd == "":
|
||||||
|
return path.Join(home, "."+common.AppName)
|
||||||
|
case strings.HasPrefix(cd, "~/"):
|
||||||
|
return path.Join(home, cd[2:])
|
||||||
|
default:
|
||||||
|
return cd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Blas) openStore() error {
|
||||||
|
// TODO: based on config, open filestore or db store
|
||||||
|
stor, err := storage.OpenFileStore(b.ConfigDir())
|
||||||
|
b.Store = stor
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg *config.Config) (b *Blas, err error) {
|
||||||
|
b = &Blas{
|
||||||
|
Bus: bus.New(),
|
||||||
|
Config: cfg,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = b.openStore()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Authenticator, err = auth.New(b.Store)
|
||||||
|
return b, err
|
||||||
|
}
|
|
@ -2,18 +2,18 @@ package serve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"dynatron.me/x/blasphem/internal/common"
|
"dynatron.me/x/blasphem/internal/common"
|
||||||
"dynatron.me/x/blasphem/pkg/config"
|
"dynatron.me/x/blasphem/pkg/blas"
|
||||||
"dynatron.me/x/blasphem/pkg/server"
|
"dynatron.me/x/blasphem/pkg/server"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServeOptions struct {
|
type ServeOptions struct {
|
||||||
cfg *config.Config
|
core blas.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
func Command(cfg *config.Config) *cobra.Command {
|
func Command(core blas.Core) *cobra.Command {
|
||||||
opts := makeOptions(cfg)
|
opts := makeOptions(core)
|
||||||
serveCmd := &cobra.Command{
|
serveCmd := &cobra.Command{
|
||||||
Use: "serve",
|
Use: "serve",
|
||||||
Short: "starts the " + common.AppName + " server",
|
Short: "starts the " + common.AppName + " server",
|
||||||
|
@ -23,9 +23,9 @@ func Command(cfg *config.Config) *cobra.Command {
|
||||||
return serveCmd
|
return serveCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeOptions(cfg *config.Config) *ServeOptions {
|
func makeOptions(core blas.Core) *ServeOptions {
|
||||||
return &ServeOptions{
|
return &ServeOptions{
|
||||||
cfg: cfg,
|
core: core,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ func (o *ServeOptions) Options(_ *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ServeOptions) Execute() error {
|
func (o *ServeOptions) Execute() error {
|
||||||
server, err := server.New(o.cfg)
|
server, err := server.New(o.core)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,4 @@ type (
|
||||||
Instance interface {
|
Instance interface {
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
Key string
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,9 +6,15 @@ import (
|
||||||
"dynatron.me/x/blasphem/pkg/component"
|
"dynatron.me/x/blasphem/pkg/component"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Registry = make(map[component.Key]component.Setup)
|
type (
|
||||||
|
Key string
|
||||||
|
)
|
||||||
|
|
||||||
func Register(key component.Key, c component.Setup) {
|
type Instance = component.Instance
|
||||||
|
|
||||||
|
var Registry = make(map[Key]component.Setup)
|
||||||
|
|
||||||
|
func Register(key Key, c component.Setup) {
|
||||||
_, already := Registry[key]
|
_, already := Registry[key]
|
||||||
if already {
|
if already {
|
||||||
panic(fmt.Sprintf("component %s already exists", key))
|
panic(fmt.Sprintf("component %s already exists", key))
|
||||||
|
|
|
@ -5,20 +5,35 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"dynatron.me/x/blasphem/pkg/blas"
|
||||||
|
"dynatron.me/x/blasphem/pkg/component/reg"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const FrontendKey = "frontend"
|
||||||
|
|
||||||
//go:embed frontend/hass_frontend
|
//go:embed frontend/hass_frontend
|
||||||
var root embed.FS
|
var root embed.FS
|
||||||
|
|
||||||
var RootFS fs.FS
|
type Frontend struct {
|
||||||
|
fsHandler echo.HandlerFunc
|
||||||
|
rootFS fs.FS
|
||||||
|
|
||||||
var FSHandler echo.HandlerFunc
|
routeInstall sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
func AliasHandler(toFile string) echo.HandlerFunc {
|
func (fe *Frontend) InstallRoutes(e *echo.Echo) {
|
||||||
|
fe.routeInstall.Do(func() {
|
||||||
|
e.GET("/*", fe.fsHandler)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fe *Frontend) AliasHandler(toFile string) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
file, err := RootFS.Open(toFile)
|
file, err := fe.rootFS.Open(toFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -33,13 +48,22 @@ func AliasHandler(toFile string) echo.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func (*Frontend) Shutdown() {}
|
||||||
|
|
||||||
|
func Setup(_ blas.Core) (reg.Instance, error) {
|
||||||
|
fe := &Frontend{}
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
RootFS, err = fs.Sub(root, "frontend/hass_frontend")
|
fe.rootFS, err = fs.Sub(root, "frontend/hass_frontend")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
FSHandler = echo.StaticDirectoryHandler(RootFS, false)
|
fe.fsHandler = echo.StaticDirectoryHandler(fe.rootFS, false)
|
||||||
|
|
||||||
|
return fe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
reg.Register(FrontendKey, Setup)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,46 +12,33 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/ziflex/lecho/v3"
|
"github.com/ziflex/lecho/v3"
|
||||||
|
|
||||||
"dynatron.me/x/blasphem/pkg/auth"
|
|
||||||
"dynatron.me/x/blasphem/pkg/blas"
|
"dynatron.me/x/blasphem/pkg/blas"
|
||||||
"dynatron.me/x/blasphem/pkg/config"
|
|
||||||
"dynatron.me/x/blasphem/pkg/frontend"
|
|
||||||
conf "dynatron.me/x/blasphem/pkg/server/config"
|
conf "dynatron.me/x/blasphem/pkg/server/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
*blas.Blas
|
blas.Core
|
||||||
*echo.Echo
|
*echo.Echo
|
||||||
auth.Authenticator
|
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) installRoutes() {
|
func (s *Server) installRoutes() {
|
||||||
s.GET("/*", frontend.FSHandler)
|
|
||||||
s.GET("/api/websocket", s.wsHandler)
|
s.GET("/api/websocket", s.wsHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg *config.Config) (s *Server, err error) {
|
func New(core blas.Core) (s *Server, err error) {
|
||||||
b, err := blas.New(cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s = &Server{
|
s = &Server{
|
||||||
Blas: b,
|
Core: core,
|
||||||
Echo: echo.New(),
|
Echo: echo.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Authenticator, err = auth.New(s.Echo, b.Store)
|
|
||||||
if err != nil {
|
|
||||||
return s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Echo.Debug = true
|
s.Echo.Debug = true
|
||||||
s.Echo.HideBanner = true
|
s.Echo.HideBanner = true
|
||||||
logger := lecho.From(log.Logger)
|
logger := lecho.From(log.Logger)
|
||||||
s.Echo.Logger = logger
|
s.Echo.Logger = logger
|
||||||
|
|
||||||
|
cfg := s.Conf()
|
||||||
|
|
||||||
if cfg.Server.LogRequestErrors {
|
if cfg.Server.LogRequestErrors {
|
||||||
s.Echo.Use(lecho.Middleware(lecho.Config{
|
s.Echo.Use(lecho.Middleware(lecho.Config{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
|
@ -79,7 +66,7 @@ func New(cfg *config.Config) (s *Server, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Shutdown(ctx context.Context) error {
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
err := s.Blas.ShutdownBlas(ctx)
|
err := s.ShutdownBlas(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -90,8 +77,8 @@ func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
func (s *Server) Go() error {
|
func (s *Server) Go() error {
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
log.Info().Str("version", s.Version()).Str("bind", s.Config.Server.Bind).Msg("Server listening")
|
log.Info().Str("version", s.Version()).Str("bind", s.Conf().Server.Bind).Msg("Server listening")
|
||||||
err := s.Start(s.Config.Server.Bind)
|
err := s.Start(s.Conf().Server.Bind)
|
||||||
if err != nil && err != http.ErrServerClosed {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
s.Logger.Fatal(err)
|
s.Logger.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func New(s blas.Core, c echo.Context, conn *websocket.Conn) WS {
|
func New(s blas.Core, c echo.Context, conn *websocket.Conn) WS {
|
||||||
ws := &wsSession{
|
ws := &wsSession{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
|
|
|
@ -14,7 +14,7 @@ type authPhase struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ws *wsSession) sendAuthRequired() error {
|
func (ws *wsSession) sendAuthRequired() error {
|
||||||
authReq := &struct{
|
authReq := &struct {
|
||||||
MsgBase
|
MsgBase
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
}{
|
}{
|
||||||
|
@ -53,7 +53,5 @@ func (ap *authPhase) handleMsg(r io.Reader) error {
|
||||||
|
|
||||||
log.Error().Str("remote", ap.ec.Request().RemoteAddr).Msg("websocket auth failed")
|
log.Error().Str("remote", ap.ec.Request().RemoteAddr).Msg("websocket auth failed")
|
||||||
|
|
||||||
|
|
||||||
return auth.ErrInvalidAuth
|
return auth.ErrInvalidAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue