| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				@@ -1,10 +1,14 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				package bootstrap
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"bytes"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"encoding/json"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"fmt"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"net/http"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"net/url"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"os"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"strings"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"time"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"tinyauth/internal/config"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"tinyauth/internal/controller"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"tinyauth/internal/middleware"
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -29,40 +33,43 @@ type Service interface {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				type BootstrapApp struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Config config.Config
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					config config.Config
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					uuid   string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func NewBootstrapApp(config config.Config) *BootstrapApp {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return &BootstrapApp{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Config: config,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						config: config,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Parse users
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					users, err := utils.GetUsers(app.Config.Users, app.Config.UsersFile)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					users, err := utils.GetUsers(app.config.Users, app.config.UsersFile)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Get OAuth configs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					oauthProviders, err := utils.GetOAuthProvidersConfig(os.Environ(), os.Args, app.Config.AppURL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					oauthProviders, err := utils.GetOAuthProvidersConfig(os.Environ(), os.Args, app.config.AppURL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Get cookie domain
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					cookieDomain, err := utils.GetCookieDomain(app.Config.AppURL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					cookieDomain, err := utils.GetCookieDomain(app.config.AppURL)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return err
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Cookie names
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					appUrl, _ := url.Parse(app.Config.AppURL) // Already validated
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					cookieId := utils.GenerateIdentifier(appUrl.Hostname())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					appUrl, _ := url.Parse(app.config.AppURL) // Already validated
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					uuid := utils.GenerateUUID(appUrl.Hostname())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					app.uuid = uuid
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					cookieId := strings.Split(uuid, "-")[0]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					sessionCookieName := fmt.Sprintf("%s-%s", config.SessionCookieName, cookieId)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					csrfCookieName := fmt.Sprintf("%s-%s", config.CSRFCookieName, cookieId)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					redirectCookieName := fmt.Sprintf("%s-%s", config.RedirectCookieName, cookieId)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -70,26 +77,26 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Create configs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					authConfig := service.AuthServiceConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Users:             users,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						OauthWhitelist:    app.Config.OAuthWhitelist,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SessionExpiry:     app.Config.SessionExpiry,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SecureCookie:      app.Config.SecureCookie,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						OauthWhitelist:    app.config.OAuthWhitelist,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SessionExpiry:     app.config.SessionExpiry,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SecureCookie:      app.config.SecureCookie,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						CookieDomain:      cookieDomain,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						LoginTimeout:      app.Config.LoginTimeout,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						LoginMaxRetries:   app.Config.LoginMaxRetries,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						LoginTimeout:      app.config.LoginTimeout,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						LoginMaxRetries:   app.config.LoginMaxRetries,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SessionCookieName: sessionCookieName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Setup services
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var ldapService *service.LdapService
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if app.Config.LdapAddress != "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if app.config.LdapAddress != "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ldapConfig := service.LdapServiceConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Address:      app.Config.LdapAddress,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BindDN:       app.Config.LdapBindDN,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BindPassword: app.Config.LdapBindPassword,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BaseDN:       app.Config.LdapBaseDN,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Insecure:     app.Config.LdapInsecure,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							SearchFilter: app.Config.LdapSearchFilter,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Address:      app.config.LdapAddress,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BindDN:       app.config.LdapBindDN,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BindPassword: app.config.LdapBindPassword,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							BaseDN:       app.config.LdapBaseDN,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Insecure:     app.config.LdapInsecure,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							SearchFilter: app.config.LdapSearchFilter,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ldapService = service.NewLdapService(ldapConfig)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -104,7 +111,7 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Bootstrap database
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					databaseService := service.NewDatabaseService(service.DatabaseServiceConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						DatabasePath: app.Config.DatabasePath,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						DatabasePath: app.config.DatabasePath,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					})
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					log.Debug().Str("service", fmt.Sprintf("%T", databaseService)).Msg("Initializing service")
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -183,8 +190,8 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Create engine
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					engine := gin.New()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if len(app.Config.TrustedProxies) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						engine.SetTrustedProxies(strings.Split(app.Config.TrustedProxies, ","))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if len(app.config.TrustedProxies) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ","))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if config.Version != "development" {
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -219,24 +226,24 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Create controllers
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					contextController := controller.NewContextController(controller.ContextControllerConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Providers:             configuredProviders,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Title:                 app.Config.Title,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL:                app.Config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Title:                 app.config.Title,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL:                app.config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						CookieDomain:          cookieDomain,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ForgotPasswordMessage: app.Config.ForgotPasswordMessage,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						BackgroundImage:       app.Config.BackgroundImage,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						OAuthAutoRedirect:     app.Config.OAuthAutoRedirect,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ForgotPasswordMessage: app.config.ForgotPasswordMessage,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						BackgroundImage:       app.config.BackgroundImage,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						OAuthAutoRedirect:     app.config.OAuthAutoRedirect,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}, apiRouter)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL:             app.Config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SecureCookie:       app.Config.SecureCookie,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL:             app.config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						SecureCookie:       app.config.SecureCookie,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						CSRFCookieName:     csrfCookieName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						RedirectCookieName: redirectCookieName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						CookieDomain:       cookieDomain,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}, apiRouter, authService, oauthBrokerService)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					proxyController := controller.NewProxyController(controller.ProxyControllerConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL: app.Config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						AppURL: app.config.AppURL,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}, apiRouter, dockerService, authService)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					userController := controller.NewUserController(controller.UserControllerConfig{
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -244,7 +251,7 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}, apiRouter, authService)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ResourcesDir: app.Config.ResourcesDir,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ResourcesDir: app.config.ResourcesDir,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}, mainRouter)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					healthController := controller.NewHealthController(apiRouter)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -264,8 +271,14 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						ctrl.SetupRoutes()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// If analytics are not disabled, start heartbeat
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if !app.config.DisableAnalytics {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						log.Debug().Msg("Starting heartbeat routine")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						go app.heartbeat()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Start server
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					address := fmt.Sprintf("%s:%d", app.Config.Address, app.Config.Port)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					address := fmt.Sprintf("%s:%d", app.config.Address, app.config.Port)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					log.Info().Msgf("Starting server on %s", address)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err := engine.Run(address); err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						log.Fatal().Err(err).Msg("Failed to start server")
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -273,3 +286,55 @@ func (app *BootstrapApp) Setup() error {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func (app *BootstrapApp) heartbeat() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ticker := time.NewTicker(time.Duration(12) * time.Hour)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					defer ticker.Stop()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					type heartbeat struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						UUID    string `json:"uuid"`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Version string `json:"version"`
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var body heartbeat
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					body.UUID = app.uuid
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					body.Version = config.Version
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					bodyJson, err := json.Marshal(body)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						log.Error().Err(err).Msg("Failed to marshal heartbeat body")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					client := &http.Client{}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					heartbeatURL := config.ApiServer + "/v1/instances/heartbeat"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for ; true; <-ticker.C {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						log.Debug().Msg("Sending heartbeat")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						req, err := http.NewRequest(http.MethodPost, heartbeatURL, bytes.NewReader(bodyJson))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							log.Error().Err(err).Msg("Failed to create heartbeat request")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							continue
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						req.Header.Add("Content-Type", "application/json")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						res, err := client.Do(req)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							log.Error().Err(err).Msg("Failed to send heartbeat")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							continue
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						res.Body.Close()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if res.StatusCode != 200 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							log.Debug().Str("status", res.Status).Msg("Heartbeat returned non-200 status")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						 
							
							
							
						 
					 | 
				
			
			 | 
			 | 
			
				 
 |