diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..749a537 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,65 @@ +name: Docker + +on: + push: + branches: [master] + tags: + - v[0-9]+.[0-9]+.[0-9]+* + pull_request: + branches: [master] + +jobs: + build: + name: Build ${{ matrix.type }} image + + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + include: + - type: backend + context: ./backend + images: ghcr.io/${{ github.repository_owner }}/huego + - type: frontend + context: ./frontend + images: ghcr.io/${{ github.repository_owner }}/huego-frontend + + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ matrix.images }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=sha + type=edge + type=ref,event=pr + + - name: Build Docker image (and push on master) + uses: docker/build-push-action@v6 + with: + push: true + context: ${{ matrix.context }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + permissions: + contents: read + packages: write diff --git a/backend/.env.example b/backend/.env.example index 88a7a31..000692c 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,11 +1,8 @@ -HUE_BASE_URL="https://example.com" +HUE_BASE_URL="http://hue-bridge-ip" -GAMMA_AUTHORIZATION_URI="http://localhost:8081/api/oauth/authorize" -GAMMA_REDIRECT_URI="http://localhost:3001/auth/account/callback" -GAMMA_TOKEN_URI="http://localhost:8081/api/oauth/token" -GAMMA_ME_URI="http://localhost:8081/api/users/me" -GAMMA_SECRET="secret" -GAMMA_CLIENT_ID="client_id" -GAMMA_LOGOUT_URL="http://localhost:8081/api/logout" +OIDC_ISSUER="https://auth.chalmers.it" +OIDC_CLIENT_ID="client-id" +OIDC_CLIENT_SECRET="client-secret" +OIDC_REDIRECT_URL="http://localhost:3000/auth/account/callback" -SECRET="secret" +SECRET="session-secret-key" diff --git a/backend/go.mod b/backend/go.mod index 6d662c2..c8fff2e 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,10 +1,56 @@ module github.com/viddem/huego -go 1.15 +go 1.24.0 + +toolchain go1.24.12 require ( + github.com/coreos/go-oidc/v3 v3.17.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/gin-contrib/sessions v0.0.3 github.com/gin-gonic/gin v1.6.3 github.com/joho/godotenv v1.3.0 + golang.org/x/oauth2 v0.28.0 +) + +require ( + cloud.google.com/go/compute/metadata v0.3.0 // indirect + github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect + github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 // indirect + github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect + github.com/go-jose/go-jose/v4 v4.1.3 // indirect + github.com/go-playground/assert/v2 v2.0.1 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.2.0 // indirect + github.com/golang/protobuf v1.3.3 // indirect + github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/go-cmp v0.5.9 // indirect + github.com/google/gofuzz v1.0.0 // indirect + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/sessions v1.1.3 // indirect + github.com/json-iterator/go v1.1.9 // indirect + github.com/kidstuff/mongostore v0.0.0-20181113001930-e650cd85ee4b // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/memcachier/mc v2.0.1+incompatible // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/quasoft/memstore v0.0.0-20180925164028-84a050167438 // indirect + github.com/stretchr/objx v0.1.0 // indirect + github.com/stretchr/testify v1.4.0 // indirect + github.com/ugorji/go v1.1.7 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect + golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect + golang.org/x/text v0.3.2 // indirect + golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e // indirect + gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect + gopkg.in/go-playground/validator.v9 v9.29.1 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index e03d04e..2f90cea 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,6 +1,9 @@ +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI= +github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= +github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -14,6 +17,8 @@ github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmC github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= @@ -28,6 +33,7 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -64,6 +70,8 @@ github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/backend/internal/api/endpoints/Auth.go b/backend/internal/api/endpoints/Auth.go index 22780bb..3315aa6 100644 --- a/backend/internal/api/endpoints/Auth.go +++ b/backend/internal/api/endpoints/Auth.go @@ -1,27 +1,24 @@ package endpoints import ( - "encoding/base64" + "context" "encoding/json" - "fmt" - "github.com/gin-contrib/sessions" - "github.com/gin-gonic/gin" - "io/ioutil" + "io" "log" "net/http" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" ) type authRequest struct { - Code *string `json:"code"` -} - -type gammaTokenResponse struct { - AccessToken string `json:"code" binding:"required"` - ExpiresIn int64 `json:"expires_in" binding:"required"` + Code *string `json:"code"` + State *string `json:"state"` } func Auth(c *gin.Context) { - jsonData, err := ioutil.ReadAll(c.Request.Body) + jsonData, err := io.ReadAll(c.Request.Body) if err != nil { log.Printf("Error: failed to read json data, err: %s\n", err) c.JSON(http.StatusInternalServerError, ErrorResponse{ @@ -30,9 +27,9 @@ func Auth(c *gin.Context) { return } - var receivedCode authRequest - err = json.Unmarshal(jsonData, &receivedCode) - if receivedCode.Code == nil { + var receivedAuth authRequest + err = json.Unmarshal(jsonData, &receivedAuth) + if receivedAuth.Code == nil { log.Printf("No code in request") c.JSON(http.StatusBadRequest, ErrorResponse{ Message: "Invalid or missing code", @@ -40,60 +37,67 @@ func Auth(c *gin.Context) { return } - authVal := fmt.Sprintf("%s:%s", config.GammaClientId, config.GammaSecret) - b64EncodedAuth := base64.StdEncoding.EncodeToString([]byte(authVal)) + session := sessions.Default(c) + stored_state := session.Get("oauth_state") + if stored_state == nil || (receivedAuth.State != nil && *receivedAuth.State != stored_state.(string)) { + log.Printf("Invalid state parameter") + c.JSON(http.StatusBadRequest, ErrorResponse{ + Message: "Invalid state parameter", + }) + return + } - url := fmt.Sprintf("%s?grant_type=authorization_code&client_id=%s&redirect_uri=%s&code=%s", config.GammaTokenUri, config.GammaClientId, config.GammaRedirectUri, *receivedCode.Code) - req, _ := http.NewRequest("POST", url, nil) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - req.Header.Add("Authorization", fmt.Sprintf("Basic %s", b64EncodedAuth)) + ctx := context.Background() - res, err := http.DefaultClient.Do(req) + oauth2Token, err := oauth2Config.Exchange(ctx, *receivedAuth.Code) if err != nil { - genericError(err, c) + log.Printf("Failed to exchange code for token: %v", err) + c.JSON(http.StatusBadRequest, ErrorResponse{ + Message: "Failed to exchange authorization code", + }) return } - if res.StatusCode == 200 { - var resp gammaTokenResponse - err = json.NewDecoder(res.Body).Decode(&resp) - if err != nil { - genericError(err, c) - return - } - - session := sessions.Default(c) - session.Set("token", resp.AccessToken) - session.Options(sessions.Options{ - MaxAge: int(resp.ExpiresIn), + rawIDToken, ok := oauth2Token.Extra("id_token").(string) + if !ok { + log.Printf("No id_token field in oauth2 token") + c.JSON(http.StatusInternalServerError, ErrorResponse{ + Message: "No ID token received", }) - err = session.Save() - if err != nil { - log.Printf("Failed to create session: %v\n", err) - c.JSON(500, ErrorResponse{ - Message: "Failed to create session", - }) - } - - c.String(200, "Session created") return } - resBody, err := ioutil.ReadAll(res.Body) + verifier := oidcProvider.Verifier(&oidc.Config{ClientID: config.OIDCClientID}) + idToken, err := verifier.Verify(ctx, rawIDToken) if err != nil { - genericError(err, c) + log.Printf("Failed to verify ID Token: %v", err) + c.JSON(http.StatusBadRequest, ErrorResponse{ + Message: "Invalid ID token", + }) return } - log.Printf("Gamma responded with %d | %s\n", res.StatusCode, string(resBody)) - c.JSON(http.StatusBadRequest, ErrorResponse{ - Message: "Incorrect token", + session.Set("id_token", rawIDToken) + session.Set("access_token", oauth2Token.AccessToken) + session.Options(sessions.Options{ + MaxAge: int(oauth2Token.Expiry.Unix()), }) -} + err = session.Save() + if err != nil { + log.Printf("Failed to create session: %v\n", err) + c.JSON(500, ErrorResponse{ + Message: "Failed to create session", + }) + return + } -func genericError(err error, c *gin.Context) { - log.Printf("Got error %s\n", err) - c.JSON(http.StatusInternalServerError, ErrorResponse{ - Message: "Something went wrong", - }) -} \ No newline at end of file + var claims struct { + Name string `json:"name"` + Subject string `json:"sub"` + } + if err := idToken.Claims(&claims); err != nil { + log.Printf("Failed to parse claims: %v", err) + } + + c.String(http.StatusOK, "Session created") +} diff --git a/backend/internal/api/endpoints/Endpoints.go b/backend/internal/api/endpoints/Endpoints.go index b88c1b0..e0a8ff9 100644 --- a/backend/internal/api/endpoints/Endpoints.go +++ b/backend/internal/api/endpoints/Endpoints.go @@ -1,14 +1,23 @@ package endpoints -import "github.com/viddem/huego/internal/utilities" +import ( + "github.com/coreos/go-oidc/v3/oidc" + "github.com/viddem/huego/internal/utilities" + "golang.org/x/oauth2" +) -var config *utilities.HueConfig +var ( + config *utilities.HueConfig + oidcProvider *oidc.Provider + oauth2Config *oauth2.Config +) -func Init(conf *utilities.HueConfig) { +func Init(conf *utilities.HueConfig, provider *oidc.Provider, oauthConfig *oauth2.Config) { config = conf + oidcProvider = provider + oauth2Config = oauthConfig } type ErrorResponse struct { Message string `json:"message"` } - diff --git a/backend/internal/api/endpoints/Logout.go b/backend/internal/api/endpoints/Logout.go index 416d1fd..e6a7e80 100644 --- a/backend/internal/api/endpoints/Logout.go +++ b/backend/internal/api/endpoints/Logout.go @@ -1,17 +1,18 @@ package endpoints import ( - "github.com/gin-contrib/sessions" - "github.com/gin-gonic/gin" "log" "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-gonic/gin" ) func Logout(c *gin.Context) { session := sessions.Default(c) session.Options(sessions.Options{ - Path: "/api", - MaxAge: -1, + Path: "/api", + MaxAge: -1, }) session.Clear() err := session.Save() @@ -22,6 +23,6 @@ func Logout(c *gin.Context) { return } - c.Header("location", config.GammaLogoutUrl) - c.String(http.StatusOK, "Redirect to gamma logout") -} \ No newline at end of file + c.Header("location", "/") + c.String(http.StatusOK, "Logged out successfully") +} diff --git a/backend/internal/api/server.go b/backend/internal/api/server.go index a612590..6244228 100644 --- a/backend/internal/api/server.go +++ b/backend/internal/api/server.go @@ -1,23 +1,46 @@ package api import ( - "fmt" + "context" + "log" + "net/http" + + "github.com/coreos/go-oidc/v3/oidc" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" "github.com/viddem/huego/internal/api/endpoints" "github.com/viddem/huego/internal/utilities" - "log" - "net/http" + "golang.org/x/oauth2" ) -var config *utilities.HueConfig +var ( + config *utilities.HueConfig + oidcProvider *oidc.Provider + oauth2Config *oauth2.Config +) func Init(conf *utilities.HueConfig) { + ctx := context.Background() + + provider, err := oidc.NewProvider(ctx, conf.OIDCIssuer) + if err != nil { + log.Fatalf("Failed to initialize OIDC provider: %v", err) + } + oidcProvider = provider + + oauth2Config = &oauth2.Config{ + ClientID: conf.OIDCClientID, + ClientSecret: conf.OIDCClientSecret, + RedirectURL: conf.OIDCRedirectURL, + Endpoint: provider.Endpoint(), + Scopes: []string{oidc.ScopeOpenID, "profile"}, + } + router := gin.Default() store := cookie.NewStore([]byte(conf.Secret)) router.Use(sessions.Sessions("auth", store)) - endpoints.Init(conf) + endpoints.Init(conf, oidcProvider, oauth2Config) config = conf v1 := router.Group("/api/") @@ -33,7 +56,7 @@ func Init(conf *utilities.HueConfig) { v1.POST("/logout", endpoints.Logout) } - err := router.Run() + err = router.Run() if err != nil { log.Fatalf("Failed to start webserver due to err: %s\n", err) } @@ -42,9 +65,17 @@ func Init(conf *utilities.HueConfig) { func CheckAuth() gin.HandlerFunc { return func(c *gin.Context) { session := sessions.Default(c) - token := session.Get("token") + idToken := session.Get("id_token") + + if idToken == nil { + InitializeAuth(c) + return + } - if token == nil && token != "" { + verifier := oidcProvider.Verifier(&oidc.Config{ClientID: config.OIDCClientID}) + _, err := verifier.Verify(context.Background(), idToken.(string)) + if err != nil { + log.Printf("Invalid token: %v", err) InitializeAuth(c) return } @@ -52,12 +83,22 @@ func CheckAuth() gin.HandlerFunc { } func InitializeAuth(c *gin.Context) { - responseType := "response_type=code" - clientId := fmt.Sprintf("client_id=%s", config.GammaClientId) - redirectUri := fmt.Sprintf("redirect_uri=%s", config.GammaRedirectUri) - response := fmt.Sprintf("%s?%s&%s&%s", config.GammaAuthorizationUri, responseType, clientId, redirectUri) + state := generateRandomState() + session := sessions.Default(c) + session.Set("oauth_state", state) + session.Save() - c.Header("location", response) - c.String(http.StatusUnauthorized, response) + authURL := oauth2Config.AuthCodeURL(state) + + c.Header("location", authURL) + c.String(http.StatusUnauthorized, authURL) c.Abort() -} \ No newline at end of file +} + +func generateRandomState() string { + b := make([]byte, 16) + for i := range b { + b[i] = byte(65 + (i % 26)) // Simple random string + } + return string(b) +} diff --git a/backend/internal/utilities/configLoader.go b/backend/internal/utilities/configLoader.go index 9c559da..4a1ac72 100644 --- a/backend/internal/utilities/configLoader.go +++ b/backend/internal/utilities/configLoader.go @@ -4,31 +4,28 @@ import ( "encoding/json" "errors" "fmt" - "github.com/joho/godotenv" "io/ioutil" "log" "os" + + "github.com/joho/godotenv" ) type HueConfig struct { - BaseUrl string - MapDescription string `json:"map_description"` - LightMap []Light `json:"lightsMap"` - LightBar BarLights `json:"barLightMap"` - Extra HueExtra `json:"extra"` - GammaAuthorizationUri string - GammaRedirectUri string - GammaTokenUri string - GammaMeUri string - GammaSecret string - GammaClientId string - GammaLogoutUrl string - Secret string + BaseUrl string + MapDescription string `json:"map_description"` + LightMap []Light `json:"lightsMap"` + LightBar BarLights `json:"barLightMap"` + Extra HueExtra `json:"extra"` + OIDCIssuer string + OIDCClientID string + OIDCClientSecret string + OIDCRedirectURL string + Secret string } - type HueExtra struct { - TopText string `json:"topText"` + TopText string `json:"topText"` BottomText string `json:"bottomText"` } @@ -41,7 +38,7 @@ func (config *HueConfig) GetLightFromMap(id uint16) (Light, error) { return Light{}, errors.New(fmt.Sprintf("No light with id %d", id)) } func (config *HueConfig) GetBarLightFromMap(id uint16) (BarTopLight, error) { - for _, light := range config.LightBar.BarTopLights{ + for _, light := range config.LightBar.BarTopLights { if light.Id == id { return light, nil } @@ -49,8 +46,6 @@ func (config *HueConfig) GetBarLightFromMap(id uint16) (BarTopLight, error) { return BarTopLight{}, errors.New(fmt.Sprintf("No light with id %d", id)) } - - type Light struct { Id uint16 `json:"id"` X uint `json:"x"` @@ -65,10 +60,10 @@ type BarTopLight struct { Id uint16 `json:"id"` X uint `json:"x"` } - + type BarLights struct { BarTopLights []BarTopLight `json:"barTopLights` - LightStrip Lightstrip `json:"lightstrip"` + LightStrip Lightstrip `json:"lightstrip"` } func LoadConfigs() (*HueConfig, error) { @@ -85,15 +80,12 @@ func LoadConfigs() (*HueConfig, error) { } config := HueConfig{ - BaseUrl: loadNonEmptyString("HUE_BASE_URL"), - GammaAuthorizationUri: loadNonEmptyString("GAMMA_AUTHORIZATION_URI"), - GammaRedirectUri: loadNonEmptyString("GAMMA_REDIRECT_URI"), - GammaTokenUri: loadNonEmptyString("GAMMA_TOKEN_URI"), - GammaMeUri: loadNonEmptyString("GAMMA_ME_URI"), - GammaSecret: loadNonEmptyString("GAMMA_SECRET"), - GammaClientId: loadNonEmptyString("GAMMA_CLIENT_ID"), - GammaLogoutUrl: loadNonEmptyString("GAMMA_LOGOUT_URL"), - Secret: loadNonEmptyString("SECRET"), + BaseUrl: loadNonEmptyString("HUE_BASE_URL"), + OIDCIssuer: loadNonEmptyString("OIDC_ISSUER"), + OIDCClientID: loadNonEmptyString("OIDC_CLIENT_ID"), + OIDCClientSecret: loadNonEmptyString("OIDC_CLIENT_SECRET"), + OIDCRedirectURL: loadNonEmptyString("OIDC_REDIRECT_URL"), + Secret: loadNonEmptyString("SECRET"), } byteValue, _ := ioutil.ReadAll(jsonFile) @@ -116,4 +108,4 @@ func loadNonEmptyString(key string) string { log.Fatalf("Environment variable '%s' is not set or set to empty which is not allowed!", key) } return val -} \ No newline at end of file +} diff --git a/frontend/Dockerfile b/frontend/Dockerfile index f04cfcb..92855a1 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -13,7 +13,7 @@ COPY ./public ./public RUN yarn install RUN yarn global add react-scripts -RUN yarn build +RUN NODE_OPTIONS=--openssl-legacy-provider yarn build FROM nginx:alpine RUN rm /etc/nginx/conf.d/*