mirror of
				https://github.com/steveiliop56/tinyauth.git
				synced 2025-10-31 06:05:43 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			v4.0.0-alp
			...
			refactor/r
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 59d2bce189 | 
							
								
								
									
										28
									
								
								cmd/root.go
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								cmd/root.go
									
									
									
									
									
								
							| @@ -8,13 +8,13 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| 	totpCmd "tinyauth/cmd/totp" | 	totpCmd "tinyauth/cmd/totp" | ||||||
| 	userCmd "tinyauth/cmd/user" | 	userCmd "tinyauth/cmd/user" | ||||||
| 	"tinyauth/internal/api" |  | ||||||
| 	"tinyauth/internal/auth" | 	"tinyauth/internal/auth" | ||||||
| 	"tinyauth/internal/constants" | 	"tinyauth/internal/constants" | ||||||
| 	"tinyauth/internal/docker" | 	"tinyauth/internal/docker" | ||||||
| 	"tinyauth/internal/handlers" | 	"tinyauth/internal/handlers" | ||||||
| 	"tinyauth/internal/hooks" | 	"tinyauth/internal/hooks" | ||||||
| 	"tinyauth/internal/providers" | 	"tinyauth/internal/providers" | ||||||
|  | 	"tinyauth/internal/server" | ||||||
| 	"tinyauth/internal/types" | 	"tinyauth/internal/types" | ||||||
| 	"tinyauth/internal/utils" | 	"tinyauth/internal/utils" | ||||||
|  |  | ||||||
| @@ -114,8 +114,8 @@ var rootCmd = &cobra.Command{ | |||||||
| 			RedirectCookieName:    redirectCookieName, | 			RedirectCookieName:    redirectCookieName, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Create api config | 		// Create server config | ||||||
| 		apiConfig := types.APIConfig{ | 		serverConfig := types.ServerConfig{ | ||||||
| 			Port:    config.Port, | 			Port:    config.Port, | ||||||
| 			Address: config.Address, | 			Address: config.Address, | ||||||
| 		} | 		} | ||||||
| @@ -140,10 +140,7 @@ var rootCmd = &cobra.Command{ | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Create docker service | 		// Create docker service | ||||||
| 		docker := docker.NewDocker() | 		docker, err := docker.NewDocker() | ||||||
|  |  | ||||||
| 		// Initialize docker |  | ||||||
| 		err = docker.Init() |  | ||||||
| 		HandleError(err, "Failed to initialize docker") | 		HandleError(err, "Failed to initialize docker") | ||||||
|  |  | ||||||
| 		// Create auth service | 		// Create auth service | ||||||
| @@ -152,24 +149,19 @@ var rootCmd = &cobra.Command{ | |||||||
| 		// Create OAuth providers service | 		// Create OAuth providers service | ||||||
| 		providers := providers.NewProviders(oauthConfig) | 		providers := providers.NewProviders(oauthConfig) | ||||||
|  |  | ||||||
| 		// Initialize providers |  | ||||||
| 		providers.Init() |  | ||||||
|  |  | ||||||
| 		// Create hooks service | 		// Create hooks service | ||||||
| 		hooks := hooks.NewHooks(hooksConfig, auth, providers) | 		hooks := hooks.NewHooks(hooksConfig, auth, providers) | ||||||
|  |  | ||||||
| 		// Create handlers | 		// Create handlers | ||||||
| 		handlers := handlers.NewHandlers(handlersConfig, auth, hooks, providers, docker) | 		handlers := handlers.NewHandlers(handlersConfig, auth, hooks, providers, docker) | ||||||
|  |  | ||||||
| 		// Create API | 		// Create server | ||||||
| 		api := api.NewAPI(apiConfig, handlers) | 		srv, err := server.NewServer(serverConfig, handlers) | ||||||
|  | 		HandleError(err, "Failed to create server") | ||||||
|  |  | ||||||
| 		// Setup routes | 		// Start server | ||||||
| 		api.Init() | 		err = srv.Start() | ||||||
| 		api.SetupRoutes() | 		HandleError(err, "Failed to start server") | ||||||
|  |  | ||||||
| 		// Start |  | ||||||
| 		api.Run() |  | ||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -16,36 +16,38 @@ import ( | |||||||
| 	"golang.org/x/crypto/bcrypt" | 	"golang.org/x/crypto/bcrypt" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewAuth(config types.AuthConfig, docker *docker.Docker) *Auth { |  | ||||||
| 	return &Auth{ |  | ||||||
| 		Config:        config, |  | ||||||
| 		Docker:        docker, |  | ||||||
| 		LoginAttempts: make(map[string]*types.LoginAttempt), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Auth struct { | type Auth struct { | ||||||
| 	Config        types.AuthConfig | 	Config        types.AuthConfig | ||||||
| 	Docker        *docker.Docker | 	Docker        *docker.Docker | ||||||
| 	LoginAttempts map[string]*types.LoginAttempt | 	LoginAttempts map[string]*types.LoginAttempt | ||||||
| 	LoginMutex    sync.RWMutex | 	LoginMutex    sync.RWMutex | ||||||
|  | 	Store         *sessions.CookieStore | ||||||
| } | } | ||||||
|  |  | ||||||
| func (auth *Auth) GetSession(c *gin.Context) (*sessions.Session, error) { | func NewAuth(config types.AuthConfig, docker *docker.Docker) *Auth { | ||||||
| 	// Create cookie store | 	// Create cookie store | ||||||
| 	store := sessions.NewCookieStore([]byte(auth.Config.HMACSecret), []byte(auth.Config.EncryptionSecret)) | 	store := sessions.NewCookieStore([]byte(config.HMACSecret), []byte(config.EncryptionSecret)) | ||||||
|  |  | ||||||
| 	// Configure cookie store | 	// Configure cookie store | ||||||
| 	store.Options = &sessions.Options{ | 	store.Options = &sessions.Options{ | ||||||
| 		Path:     "/", | 		Path:     "/", | ||||||
| 		MaxAge:   auth.Config.SessionExpiry, | 		MaxAge:   config.SessionExpiry, | ||||||
| 		Secure:   auth.Config.CookieSecure, | 		Secure:   config.CookieSecure, | ||||||
| 		HttpOnly: true, | 		HttpOnly: true, | ||||||
| 		Domain:   fmt.Sprintf(".%s", auth.Config.Domain), | 		Domain:   fmt.Sprintf(".%s", config.Domain), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return &Auth{ | ||||||
|  | 		Config:        config, | ||||||
|  | 		Docker:        docker, | ||||||
|  | 		LoginAttempts: make(map[string]*types.LoginAttempt), | ||||||
|  | 		Store:         store, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (auth *Auth) GetSession(c *gin.Context) (*sessions.Session, error) { | ||||||
| 	// Get session | 	// Get session | ||||||
| 	session, err := store.Get(c.Request, auth.Config.SessionCookieName) | 	session, err := auth.Store.Get(c.Request, auth.Config.SessionCookieName) | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Warn().Err(err).Msg("Invalid session, clearing cookie and retrying") | 		log.Warn().Err(err).Msg("Invalid session, clearing cookie and retrying") | ||||||
| @@ -54,7 +56,7 @@ func (auth *Auth) GetSession(c *gin.Context) (*sessions.Session, error) { | |||||||
| 		c.SetCookie(auth.Config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.Config.Domain), auth.Config.CookieSecure, true) | 		c.SetCookie(auth.Config.SessionCookieName, "", -1, "/", fmt.Sprintf(".%s", auth.Config.Domain), auth.Config.CookieSecure, true) | ||||||
|  |  | ||||||
| 		// Try to get the session again | 		// Try to get the session again | ||||||
| 		session, err = store.Get(c.Request, auth.Config.SessionCookieName) | 		session, err = auth.Store.Get(c.Request, auth.Config.SessionCookieName) | ||||||
|  |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			// If we still can't get the session, log the error and return nil | 			// If we still can't get the session, log the error and return nil | ||||||
|   | |||||||
| @@ -11,35 +11,30 @@ import ( | |||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewDocker() *Docker { |  | ||||||
| 	return &Docker{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Docker struct { | type Docker struct { | ||||||
| 	Client  *client.Client | 	Client  *client.Client | ||||||
| 	Context context.Context | 	Context context.Context | ||||||
| } | } | ||||||
|  |  | ||||||
| func (docker *Docker) Init() error { | func NewDocker() (*Docker, error) { | ||||||
| 	// Create a new docker client | 	// Create a new docker client | ||||||
| 	client, err := client.NewClientWithOpts(client.FromEnv) | 	client, err := client.NewClientWithOpts(client.FromEnv) | ||||||
|  |  | ||||||
| 	// Check if there was an error | 	// Check if there was an error | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Create the context | 	// Create the context | ||||||
| 	docker.Context = context.Background() | 	ctx := context.Background() | ||||||
|  |  | ||||||
| 	// Negotiate API version | 	// Negotiate API version | ||||||
| 	client.NegotiateAPIVersion(docker.Context) | 	client.NegotiateAPIVersion(ctx) | ||||||
|  |  | ||||||
| 	// Set client | 	return &Docker{ | ||||||
| 	docker.Client = client | 		Client:  client, | ||||||
|  | 		Context: ctx, | ||||||
| 	// Done | 	}, nil | ||||||
| 	return nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (docker *Docker) GetContainers() ([]container.Summary, error) { | func (docker *Docker) GetContainers() ([]container.Summary, error) { | ||||||
|   | |||||||
| @@ -18,6 +18,14 @@ import ( | |||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type Handlers struct { | ||||||
|  | 	Config    types.HandlersConfig | ||||||
|  | 	Auth      *auth.Auth | ||||||
|  | 	Hooks     *hooks.Hooks | ||||||
|  | 	Providers *providers.Providers | ||||||
|  | 	Docker    *docker.Docker | ||||||
|  | } | ||||||
|  |  | ||||||
| func NewHandlers(config types.HandlersConfig, auth *auth.Auth, hooks *hooks.Hooks, providers *providers.Providers, docker *docker.Docker) *Handlers { | func NewHandlers(config types.HandlersConfig, auth *auth.Auth, hooks *hooks.Hooks, providers *providers.Providers, docker *docker.Docker) *Handlers { | ||||||
| 	return &Handlers{ | 	return &Handlers{ | ||||||
| 		Config:    config, | 		Config:    config, | ||||||
| @@ -28,14 +36,6 @@ func NewHandlers(config types.HandlersConfig, auth *auth.Auth, hooks *hooks.Hook | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type Handlers struct { |  | ||||||
| 	Config    types.HandlersConfig |  | ||||||
| 	Auth      *auth.Auth |  | ||||||
| 	Hooks     *hooks.Hooks |  | ||||||
| 	Providers *providers.Providers |  | ||||||
| 	Docker    *docker.Docker |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (h *Handlers) AuthHandler(c *gin.Context) { | func (h *Handlers) AuthHandler(c *gin.Context) { | ||||||
| 	// Create struct for proxy | 	// Create struct for proxy | ||||||
| 	var proxy types.Proxy | 	var proxy types.Proxy | ||||||
|   | |||||||
| @@ -12,6 +12,12 @@ import ( | |||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type Hooks struct { | ||||||
|  | 	Config    types.HooksConfig | ||||||
|  | 	Auth      *auth.Auth | ||||||
|  | 	Providers *providers.Providers | ||||||
|  | } | ||||||
|  |  | ||||||
| func NewHooks(config types.HooksConfig, auth *auth.Auth, providers *providers.Providers) *Hooks { | func NewHooks(config types.HooksConfig, auth *auth.Auth, providers *providers.Providers) *Hooks { | ||||||
| 	return &Hooks{ | 	return &Hooks{ | ||||||
| 		Config:    config, | 		Config:    config, | ||||||
| @@ -20,12 +26,6 @@ func NewHooks(config types.HooksConfig, auth *auth.Auth, providers *providers.Pr | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| type Hooks struct { |  | ||||||
| 	Config    types.HooksConfig |  | ||||||
| 	Auth      *auth.Auth |  | ||||||
| 	Providers *providers.Providers |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext { | func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext { | ||||||
| 	// Get session cookie and basic auth | 	// Get session cookie and basic auth | ||||||
| 	cookie, err := hooks.Auth.GetSessionCookie(c) | 	cookie, err := hooks.Auth.GetSessionCookie(c) | ||||||
|   | |||||||
| @@ -10,32 +10,24 @@ import ( | |||||||
| 	"golang.org/x/oauth2" | 	"golang.org/x/oauth2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewOAuth(config oauth2.Config, insecureSkipVerify bool) *OAuth { |  | ||||||
| 	return &OAuth{ |  | ||||||
| 		Config:             config, |  | ||||||
| 		InsecureSkipVerify: insecureSkipVerify, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type OAuth struct { | type OAuth struct { | ||||||
| 	Config             oauth2.Config | 	Config   oauth2.Config | ||||||
| 	Context            context.Context | 	Context  context.Context | ||||||
| 	Token              *oauth2.Token | 	Token    *oauth2.Token | ||||||
| 	Verifier           string | 	Verifier string | ||||||
| 	InsecureSkipVerify bool |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (oauth *OAuth) Init() { | func NewOAuth(config oauth2.Config, insecureSkipVerify bool) *OAuth { | ||||||
| 	// Create transport with TLS | 	// Create transport with TLS | ||||||
| 	transport := &http.Transport{ | 	transport := &http.Transport{ | ||||||
| 		TLSClientConfig: &tls.Config{ | 		TLSClientConfig: &tls.Config{ | ||||||
| 			InsecureSkipVerify: oauth.InsecureSkipVerify, | 			InsecureSkipVerify: insecureSkipVerify, | ||||||
| 			MinVersion:         tls.VersionTLS12, | 			MinVersion:         tls.VersionTLS12, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Create a new context | 	// Create a new context | ||||||
| 	oauth.Context = context.Background() | 	ctx := context.Background() | ||||||
|  |  | ||||||
| 	// Create the HTTP client with the transport | 	// Create the HTTP client with the transport | ||||||
| 	httpClient := &http.Client{ | 	httpClient := &http.Client{ | ||||||
| @@ -43,9 +35,16 @@ func (oauth *OAuth) Init() { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Set the HTTP client in the context | 	// Set the HTTP client in the context | ||||||
| 	oauth.Context = context.WithValue(oauth.Context, oauth2.HTTPClient, httpClient) | 	ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient) | ||||||
|  |  | ||||||
| 	// Create the verifier | 	// Create the verifier | ||||||
| 	oauth.Verifier = oauth2.GenerateVerifier() | 	verifier := oauth2.GenerateVerifier() | ||||||
|  |  | ||||||
|  | 	return &OAuth{ | ||||||
|  | 		Config:   config, | ||||||
|  | 		Context:  ctx, | ||||||
|  | 		Verifier: verifier, | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (oauth *OAuth) GetAuthURL(state string) string { | func (oauth *OAuth) GetAuthURL(state string) string { | ||||||
|   | |||||||
| @@ -11,12 +11,6 @@ import ( | |||||||
| 	"golang.org/x/oauth2/endpoints" | 	"golang.org/x/oauth2/endpoints" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewProviders(config types.OAuthConfig) *Providers { |  | ||||||
| 	return &Providers{ |  | ||||||
| 		Config: config, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Providers struct { | type Providers struct { | ||||||
| 	Config  types.OAuthConfig | 	Config  types.OAuthConfig | ||||||
| 	Github  *oauth.OAuth | 	Github  *oauth.OAuth | ||||||
| @@ -24,60 +18,57 @@ type Providers struct { | |||||||
| 	Generic *oauth.OAuth | 	Generic *oauth.OAuth | ||||||
| } | } | ||||||
|  |  | ||||||
| func (providers *Providers) Init() { | func NewProviders(config types.OAuthConfig) *Providers { | ||||||
|  | 	providers := &Providers{ | ||||||
|  | 		Config: config, | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// If we have a client id and secret for github, initialize the oauth provider | 	// If we have a client id and secret for github, initialize the oauth provider | ||||||
| 	if providers.Config.GithubClientId != "" && providers.Config.GithubClientSecret != "" { | 	if config.GithubClientId != "" && config.GithubClientSecret != "" { | ||||||
| 		log.Info().Msg("Initializing Github OAuth") | 		log.Info().Msg("Initializing Github OAuth") | ||||||
|  |  | ||||||
| 		// Create a new oauth provider with the github config | 		// Create a new oauth provider with the github config | ||||||
| 		providers.Github = oauth.NewOAuth(oauth2.Config{ | 		providers.Github = oauth.NewOAuth(oauth2.Config{ | ||||||
| 			ClientID:     providers.Config.GithubClientId, | 			ClientID:     config.GithubClientId, | ||||||
| 			ClientSecret: providers.Config.GithubClientSecret, | 			ClientSecret: config.GithubClientSecret, | ||||||
| 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/github", providers.Config.AppURL), | 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/github", config.AppURL), | ||||||
| 			Scopes:       GithubScopes(), | 			Scopes:       GithubScopes(), | ||||||
| 			Endpoint:     endpoints.GitHub, | 			Endpoint:     endpoints.GitHub, | ||||||
| 		}, false) | 		}, false) | ||||||
|  |  | ||||||
| 		// Initialize the oauth provider |  | ||||||
| 		providers.Github.Init() |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// If we have a client id and secret for google, initialize the oauth provider | 	// If we have a client id and secret for google, initialize the oauth provider | ||||||
| 	if providers.Config.GoogleClientId != "" && providers.Config.GoogleClientSecret != "" { | 	if config.GoogleClientId != "" && config.GoogleClientSecret != "" { | ||||||
| 		log.Info().Msg("Initializing Google OAuth") | 		log.Info().Msg("Initializing Google OAuth") | ||||||
|  |  | ||||||
| 		// Create a new oauth provider with the google config | 		// Create a new oauth provider with the google config | ||||||
| 		providers.Google = oauth.NewOAuth(oauth2.Config{ | 		providers.Google = oauth.NewOAuth(oauth2.Config{ | ||||||
| 			ClientID:     providers.Config.GoogleClientId, | 			ClientID:     config.GoogleClientId, | ||||||
| 			ClientSecret: providers.Config.GoogleClientSecret, | 			ClientSecret: config.GoogleClientSecret, | ||||||
| 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/google", providers.Config.AppURL), | 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/google", config.AppURL), | ||||||
| 			Scopes:       GoogleScopes(), | 			Scopes:       GoogleScopes(), | ||||||
| 			Endpoint:     endpoints.Google, | 			Endpoint:     endpoints.Google, | ||||||
| 		}, false) | 		}, false) | ||||||
|  |  | ||||||
| 		// Initialize the oauth provider |  | ||||||
| 		providers.Google.Init() |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// If we have a client id and secret for generic oauth, initialize the oauth provider | 	// If we have a client id and secret for generic oauth, initialize the oauth provider | ||||||
| 	if providers.Config.GenericClientId != "" && providers.Config.GenericClientSecret != "" { | 	if config.GenericClientId != "" && config.GenericClientSecret != "" { | ||||||
| 		log.Info().Msg("Initializing Generic OAuth") | 		log.Info().Msg("Initializing Generic OAuth") | ||||||
|  |  | ||||||
| 		// Create a new oauth provider with the generic config | 		// Create a new oauth provider with the generic config | ||||||
| 		providers.Generic = oauth.NewOAuth(oauth2.Config{ | 		providers.Generic = oauth.NewOAuth(oauth2.Config{ | ||||||
| 			ClientID:     providers.Config.GenericClientId, | 			ClientID:     config.GenericClientId, | ||||||
| 			ClientSecret: providers.Config.GenericClientSecret, | 			ClientSecret: config.GenericClientSecret, | ||||||
| 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/generic", providers.Config.AppURL), | 			RedirectURL:  fmt.Sprintf("%s/api/oauth/callback/generic", config.AppURL), | ||||||
| 			Scopes:       providers.Config.GenericScopes, | 			Scopes:       config.GenericScopes, | ||||||
| 			Endpoint: oauth2.Endpoint{ | 			Endpoint: oauth2.Endpoint{ | ||||||
| 				AuthURL:  providers.Config.GenericAuthURL, | 				AuthURL:  config.GenericAuthURL, | ||||||
| 				TokenURL: providers.Config.GenericTokenURL, | 				TokenURL: config.GenericTokenURL, | ||||||
| 			}, | 			}, | ||||||
| 		}, providers.Config.GenericSkipSSL) | 		}, config.GenericSkipSSL) | ||||||
|  |  | ||||||
| 		// Initialize the oauth provider |  | ||||||
| 		providers.Generic.Init() |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return providers | ||||||
| } | } | ||||||
|  |  | ||||||
| func (providers *Providers) GetProvider(provider string) *oauth.OAuth { | func (providers *Providers) GetProvider(provider string) *oauth.OAuth { | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| package api | package server | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @@ -15,20 +15,13 @@ import ( | |||||||
| 	"github.com/rs/zerolog/log" | 	"github.com/rs/zerolog/log" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func NewAPI(config types.APIConfig, handlers *handlers.Handlers) *API { | type Server struct { | ||||||
| 	return &API{ | 	Config   types.ServerConfig | ||||||
| 		Config:   config, |  | ||||||
| 		Handlers: handlers, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type API struct { |  | ||||||
| 	Config   types.APIConfig |  | ||||||
| 	Router   *gin.Engine |  | ||||||
| 	Handlers *handlers.Handlers | 	Handlers *handlers.Handlers | ||||||
|  | 	Router   *gin.Engine | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (api *API) Init() { | func NewServer(config types.ServerConfig, handlers *handlers.Handlers) (*Server, error) { | ||||||
| 	// Disable gin logs | 	// Disable gin logs | ||||||
| 	gin.SetMode(gin.ReleaseMode) | 	gin.SetMode(gin.ReleaseMode) | ||||||
| 
 | 
 | ||||||
| @@ -42,7 +35,7 @@ func (api *API) Init() { | |||||||
| 	dist, err := fs.Sub(assets.Assets, "dist") | 	dist, err := fs.Sub(assets.Assets, "dist") | ||||||
| 
 | 
 | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatal().Err(err).Msg("Failed to get UI assets") | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Create file server | 	// Create file server | ||||||
| @@ -69,41 +62,38 @@ func (api *API) Init() { | |||||||
| 		} | 		} | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	// Set router | 	// Proxy routes | ||||||
| 	api.Router = router | 	router.GET("/api/auth/:proxy", handlers.AuthHandler) | ||||||
|  | 
 | ||||||
|  | 	// Auth routes | ||||||
|  | 	router.POST("/api/login", handlers.LoginHandler) | ||||||
|  | 	router.POST("/api/totp", handlers.TotpHandler) | ||||||
|  | 	router.POST("/api/logout", handlers.LogoutHandler) | ||||||
|  | 
 | ||||||
|  | 	// Context routes | ||||||
|  | 	router.GET("/api/app", handlers.AppHandler) | ||||||
|  | 	router.GET("/api/user", handlers.UserHandler) | ||||||
|  | 
 | ||||||
|  | 	// OAuth routes | ||||||
|  | 	router.GET("/api/oauth/url/:provider", handlers.OauthUrlHandler) | ||||||
|  | 	router.GET("/api/oauth/callback/:provider", handlers.OauthCallbackHandler) | ||||||
|  | 
 | ||||||
|  | 	// App routes | ||||||
|  | 	router.GET("/api/healthcheck", handlers.HealthcheckHandler) | ||||||
|  | 
 | ||||||
|  | 	// Return the server | ||||||
|  | 	return &Server{ | ||||||
|  | 		Config:   config, | ||||||
|  | 		Handlers: handlers, | ||||||
|  | 		Router:   router, | ||||||
|  | 	}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (api *API) SetupRoutes() { | func (s *Server) Start() error { | ||||||
| 	// Proxy |  | ||||||
| 	api.Router.GET("/api/auth/:proxy", api.Handlers.AuthHandler) |  | ||||||
| 
 |  | ||||||
| 	// Auth |  | ||||||
| 	api.Router.POST("/api/login", api.Handlers.LoginHandler) |  | ||||||
| 	api.Router.POST("/api/totp", api.Handlers.TotpHandler) |  | ||||||
| 	api.Router.POST("/api/logout", api.Handlers.LogoutHandler) |  | ||||||
| 
 |  | ||||||
| 	// Context |  | ||||||
| 	api.Router.GET("/api/app", api.Handlers.AppHandler) |  | ||||||
| 	api.Router.GET("/api/user", api.Handlers.UserHandler) |  | ||||||
| 
 |  | ||||||
| 	// OAuth |  | ||||||
| 	api.Router.GET("/api/oauth/url/:provider", api.Handlers.OauthUrlHandler) |  | ||||||
| 	api.Router.GET("/api/oauth/callback/:provider", api.Handlers.OauthCallbackHandler) |  | ||||||
| 
 |  | ||||||
| 	// App |  | ||||||
| 	api.Router.GET("/api/healthcheck", api.Handlers.HealthcheckHandler) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (api *API) Run() { |  | ||||||
| 	log.Info().Str("address", api.Config.Address).Int("port", api.Config.Port).Msg("Starting server") |  | ||||||
| 
 |  | ||||||
| 	// Run server | 	// Run server | ||||||
| 	err := api.Router.Run(fmt.Sprintf("%s:%d", api.Config.Address, api.Config.Port)) | 	log.Info().Str("address", s.Config.Address).Int("port", s.Config.Port).Msg("Starting server") | ||||||
| 
 | 
 | ||||||
| 	// Check for errors | 	return s.Router.Run(fmt.Sprintf("%s:%d", s.Config.Address, s.Config.Port)) | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal().Err(err).Msg("Failed to start server") |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // zerolog is a middleware for gin that logs requests using zerolog | // zerolog is a middleware for gin that logs requests using zerolog | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package api_test | package server_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| @@ -8,19 +8,19 @@ import ( | |||||||
| 	"reflect" | 	"reflect" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"tinyauth/internal/api" |  | ||||||
| 	"tinyauth/internal/auth" | 	"tinyauth/internal/auth" | ||||||
| 	"tinyauth/internal/docker" | 	"tinyauth/internal/docker" | ||||||
| 	"tinyauth/internal/handlers" | 	"tinyauth/internal/handlers" | ||||||
| 	"tinyauth/internal/hooks" | 	"tinyauth/internal/hooks" | ||||||
| 	"tinyauth/internal/providers" | 	"tinyauth/internal/providers" | ||||||
|  | 	"tinyauth/internal/server" | ||||||
| 	"tinyauth/internal/types" | 	"tinyauth/internal/types" | ||||||
| 
 | 
 | ||||||
| 	"github.com/magiconair/properties/assert" | 	"github.com/magiconair/properties/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Simple API config for tests | // Simple server config for tests | ||||||
| var apiConfig = types.APIConfig{ | var serverConfig = types.ServerConfig{ | ||||||
| 	Port:    8080, | 	Port:    8080, | ||||||
| 	Address: "0.0.0.0", | 	Address: "0.0.0.0", | ||||||
| } | } | ||||||
| @@ -68,15 +68,11 @@ var user = types.User{ | |||||||
| 	Password: "$2a$10$AvGHLTYv3xiRJ0xV9xs3XeVIlkGTygI9nqIamFYB5Xu.5.0UWF7B6", // pass | 	Password: "$2a$10$AvGHLTYv3xiRJ0xV9xs3XeVIlkGTygI9nqIamFYB5Xu.5.0UWF7B6", // pass | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // We need all this to be able to test the API | // We need all this to be able to test the server | ||||||
| func getAPI(t *testing.T) *api.API { | func getServer(t *testing.T) *server.Server { | ||||||
| 	// Create docker service | 	// Create docker service | ||||||
| 	docker := docker.NewDocker() | 	docker, err := docker.NewDocker() | ||||||
| 
 | 
 | ||||||
| 	// Initialize docker |  | ||||||
| 	err := docker.Init() |  | ||||||
| 
 |  | ||||||
| 	// Check if there was an error |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Fatalf("Failed to initialize docker: %v", err) | 		t.Fatalf("Failed to initialize docker: %v", err) | ||||||
| 	} | 	} | ||||||
| @@ -93,31 +89,29 @@ func getAPI(t *testing.T) *api.API { | |||||||
| 	// Create providers service | 	// Create providers service | ||||||
| 	providers := providers.NewProviders(types.OAuthConfig{}) | 	providers := providers.NewProviders(types.OAuthConfig{}) | ||||||
| 
 | 
 | ||||||
| 	// Initialize providers |  | ||||||
| 	providers.Init() |  | ||||||
| 
 |  | ||||||
| 	// Create hooks service | 	// Create hooks service | ||||||
| 	hooks := hooks.NewHooks(hooksConfig, auth, providers) | 	hooks := hooks.NewHooks(hooksConfig, auth, providers) | ||||||
| 
 | 
 | ||||||
| 	// Create handlers service | 	// Create handlers service | ||||||
| 	handlers := handlers.NewHandlers(handlersConfig, auth, hooks, providers, docker) | 	handlers := handlers.NewHandlers(handlersConfig, auth, hooks, providers, docker) | ||||||
| 
 | 
 | ||||||
| 	// Create API | 	// Create server | ||||||
| 	api := api.NewAPI(apiConfig, handlers) | 	srv, err := server.NewServer(serverConfig, handlers) | ||||||
| 
 | 
 | ||||||
| 	// Setup routes | 	if err != nil { | ||||||
| 	api.Init() | 		t.Fatalf("Failed to create server: %v", err) | ||||||
| 	api.SetupRoutes() | 	} | ||||||
| 
 | 
 | ||||||
| 	return api | 	// Return the server | ||||||
|  | 	return srv | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Test login (we will need this for the other tests) | // Test login | ||||||
| func TestLogin(t *testing.T) { | func TestLogin(t *testing.T) { | ||||||
| 	t.Log("Testing login") | 	t.Log("Testing login") | ||||||
| 
 | 
 | ||||||
| 	// Get API | 	// Get server | ||||||
| 	api := getAPI(t) | 	api := getServer(t) | ||||||
| 
 | 
 | ||||||
| 	// Create recorder | 	// Create recorder | ||||||
| 	recorder := httptest.NewRecorder() | 	recorder := httptest.NewRecorder() | ||||||
| @@ -162,8 +156,8 @@ func TestLogin(t *testing.T) { | |||||||
| func TestAppContext(t *testing.T) { | func TestAppContext(t *testing.T) { | ||||||
| 	t.Log("Testing app context") | 	t.Log("Testing app context") | ||||||
| 
 | 
 | ||||||
| 	// Get API | 	// Get server | ||||||
| 	api := getAPI(t) | 	api := getServer(t) | ||||||
| 
 | 
 | ||||||
| 	// Create recorder | 	// Create recorder | ||||||
| 	recorder := httptest.NewRecorder() | 	recorder := httptest.NewRecorder() | ||||||
| @@ -230,8 +224,8 @@ func TestAppContext(t *testing.T) { | |||||||
| func TestUserContext(t *testing.T) { | func TestUserContext(t *testing.T) { | ||||||
| 	t.Log("Testing user context") | 	t.Log("Testing user context") | ||||||
| 
 | 
 | ||||||
| 	// Get API | 	// Get server | ||||||
| 	api := getAPI(t) | 	api := getServer(t) | ||||||
| 
 | 
 | ||||||
| 	// Create recorder | 	// Create recorder | ||||||
| 	recorder := httptest.NewRecorder() | 	recorder := httptest.NewRecorder() | ||||||
| @@ -288,8 +282,8 @@ func TestUserContext(t *testing.T) { | |||||||
| func TestLogout(t *testing.T) { | func TestLogout(t *testing.T) { | ||||||
| 	t.Log("Testing logout") | 	t.Log("Testing logout") | ||||||
| 
 | 
 | ||||||
| 	// Get API | 	// Get server | ||||||
| 	api := getAPI(t) | 	api := getServer(t) | ||||||
| 
 | 
 | ||||||
| 	// Create recorder | 	// Create recorder | ||||||
| 	recorder := httptest.NewRecorder() | 	recorder := httptest.NewRecorder() | ||||||
| @@ -319,5 +313,3 @@ func TestLogout(t *testing.T) { | |||||||
| 		t.Fatalf("Cookie not flushed") | 		t.Fatalf("Cookie not flushed") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // TODO: Testing for the oauth stuff |  | ||||||
| @@ -69,8 +69,8 @@ type OAuthConfig struct { | |||||||
| 	AppURL              string | 	AppURL              string | ||||||
| } | } | ||||||
|  |  | ||||||
| // APIConfig is the configuration for the API | // ServerConfig is the configuration for the server | ||||||
| type APIConfig struct { | type ServerConfig struct { | ||||||
| 	Port    int | 	Port    int | ||||||
| 	Address string | 	Address string | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user