Skip to content
This repository has been archived by the owner on Jul 12, 2023. It is now read-only.

Commit

Permalink
Do not return 500s from redirect service for missing realms (#1382)
Browse files Browse the repository at this point in the history
  • Loading branch information
sethvargo authored Dec 16, 2020
1 parent 10c0852 commit c5acc33
Show file tree
Hide file tree
Showing 19 changed files with 1,548 additions and 510 deletions.
72 changes: 5 additions & 67 deletions cmd/enx-redirect/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,18 @@ import (
"context"
"crypto/sha1"
"fmt"
"net/http"
"os"
"strconv"

"github.com/google/exposure-notifications-verification-server/internal/routes"
"github.com/google/exposure-notifications-verification-server/pkg/buildinfo"
"github.com/google/exposure-notifications-verification-server/pkg/cache"
"github.com/google/exposure-notifications-verification-server/pkg/config"
"github.com/google/exposure-notifications-verification-server/pkg/controller"
"github.com/google/exposure-notifications-verification-server/pkg/controller/associated"
"github.com/google/exposure-notifications-verification-server/pkg/controller/middleware"
"github.com/google/exposure-notifications-verification-server/pkg/controller/redirect"
"github.com/google/exposure-notifications-verification-server/pkg/render"

"github.com/google/exposure-notifications-server/pkg/logging"
"github.com/google/exposure-notifications-server/pkg/observability"
"github.com/google/exposure-notifications-server/pkg/server"

"github.com/gorilla/mux"
"github.com/sethvargo/go-signalcontext"
)

Expand Down Expand Up @@ -77,7 +71,6 @@ func realMain(ctx context.Context) error {
return fmt.Errorf("error initializing observability exporter: %w", err)
}
defer oe.Close()
ctx, obs := middleware.WithObservability(ctx)
logger.Infow("observability exporter", "config", oeConfig)

// Setup cacher
Expand All @@ -97,68 +90,13 @@ func realMain(ctx context.Context) error {
}
defer db.Close()

// Create the router
r := mux.NewRouter()

// Common observability context
r.Use(obs)

// Create the renderer
h, err := render.New(ctx, cfg.AssetsPath, cfg.DevMode)
// Setup routes
mux, err := routes.ENXRedirect(ctx, cfg, db, cacher)
if err != nil {
return fmt.Errorf("failed to create renderer: %w", err)
return fmt.Errorf("failed to setup routes: %w", err)
}

// Request ID injection
populateRequestID := middleware.PopulateRequestID(h)
r.Use(populateRequestID)

// Logger injection
populateLogger := middleware.PopulateLogger(logger)
r.Use(populateLogger)

// Install common security headers
r.Use(middleware.SecureHeaders(cfg.DevMode, "html"))

// Enable debug headers
processDebug := middleware.ProcessDebug()
r.Use(processDebug)

// iOS and Android include functionality to associate data between web-apps
// and device apps. Things like handoff between websites and apps, or
// shared credentials are the common usecases. The redirect server
// publishes the metadata needed to share data between the two domains to
// offer a more seemless experience between the website and apps. iOS and
// Android publish specs as to what this format looks like, and both live
// under the /.well-known directory on the server.
//
// Android Specs:
// https://developer.android.com/training/app-links/verify-site-associations
// iOS Specs:
// https://developer.apple.com/documentation/safariservices/supporting_associated_domains
{ // .well-known directory
wk := r.PathPrefix("/.well-known").Subrouter()

// Enable the iOS and Android redirect handler.
assocHandler, err := associated.New(ctx, cfg, db, cacher, h)
if err != nil {
return fmt.Errorf("failed to create associated links handler %w", err)
}
wk.PathPrefix("/apple-app-site-association").Handler(assocHandler.HandleIos()).Methods("GET")
wk.PathPrefix("/assetlinks.json").Handler(assocHandler.HandleAndroid()).Methods("GET")
}

r.Handle("/health", controller.HandleHealthz(ctx, nil, h)).Methods("GET")

redirectController, err := redirect.New(ctx, db, cfg, cacher, h)
if err != nil {
return err
}
r.PathPrefix("/").Handler(redirectController.HandleIndex()).Methods("GET")

mux := http.NewServeMux()
mux.Handle("/", r)

// Run server
srv, err := server.New(cfg.Port)
if err != nil {
return fmt.Errorf("failed to create server: %w", err)
Expand Down
4 changes: 2 additions & 2 deletions cmd/server/assets/400.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

<body>
<main role="main" class="container mt-5">
<h1>Not found</h1>
<h1>Bad request</h1>
<p>
The page you requested does not exist.
That request is not valid.
</p>
</main>
</body>
Expand Down
2 changes: 2 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,13 @@ func realMain(ctx context.Context) error {
return fmt.Errorf("failed to create firebase auth provider: %w", err)
}

// Setup routes
mux, err := routes.Server(ctx, cfg, db, authProvider, cacher, certificateSigner, limiterStore)
if err != nil {
return fmt.Errorf("failed to setup routes: %w", err)
}

// Run server
srv, err := server.New(cfg.Port)
if err != nil {
return fmt.Errorf("failed to create server: %w", err)
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,7 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-shellwords v1.0.5 h1:JhhFTIOslh5ZsPrpa3Wdg8bF0WI3b44EMblmU9wIsXc=
github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
Expand Down
112 changes: 112 additions & 0 deletions internal/routes/enx_redirect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package routes

import (
"context"
"fmt"
"net/http"

"github.com/google/exposure-notifications-verification-server/pkg/cache"
"github.com/google/exposure-notifications-verification-server/pkg/config"
"github.com/google/exposure-notifications-verification-server/pkg/controller"
"github.com/google/exposure-notifications-verification-server/pkg/controller/associated"
"github.com/google/exposure-notifications-verification-server/pkg/controller/middleware"
"github.com/google/exposure-notifications-verification-server/pkg/controller/redirect"
"github.com/google/exposure-notifications-verification-server/pkg/database"
"github.com/google/exposure-notifications-verification-server/pkg/render"

"github.com/google/exposure-notifications-server/pkg/logging"

"github.com/gorilla/mux"
)

// ENXRedirect defines routes for the redirector service for ENX.
func ENXRedirect(
ctx context.Context,
cfg *config.RedirectConfig,
db *database.Database,
cacher cache.Cacher,
) (http.Handler, error) {
// Create the router
r := mux.NewRouter()

// Common observability context
ctx, obs := middleware.WithObservability(ctx)
r.Use(obs)

// Create the renderer
h, err := render.New(ctx, cfg.AssetsPath, cfg.DevMode)
if err != nil {
return nil, fmt.Errorf("failed to create renderer: %w", err)
}

// Request ID injection
populateRequestID := middleware.PopulateRequestID(h)
r.Use(populateRequestID)

// Logger injection
populateLogger := middleware.PopulateLogger(logging.FromContext(ctx))
r.Use(populateLogger)

// Install common security headers
r.Use(middleware.SecureHeaders(cfg.DevMode, "html"))

// Enable debug headers
processDebug := middleware.ProcessDebug()
r.Use(processDebug)

// Handle health.
r.Handle("/health", controller.HandleHealthz(ctx, nil, h)).Methods("GET")

// iOS and Android include functionality to associate data between web-apps
// and device apps. Things like handoff between websites and apps, or
// shared credentials are the common usecases. The redirect server
// publishes the metadata needed to share data between the two domains to
// offer a more seemless experience between the website and apps. iOS and
// Android publish specs as to what this format looks like, and both live
// under the /.well-known directory on the server.
//
// Android Specs:
// https://developer.android.com/training/app-links/verify-site-associations
// iOS Specs:
// https://developer.apple.com/documentation/safariservices/supporting_associated_domains
//
{
wk := r.PathPrefix("/.well-known").Subrouter()

// Enable the iOS and Android redirect handler.
assocController, err := associated.New(ctx, cfg, db, cacher, h)
if err != nil {
return nil, fmt.Errorf("failed to create associated links controller: %w", err)
}
wk.PathPrefix("/apple-app-site-association").Handler(assocController.HandleIos()).Methods("GET")
wk.PathPrefix("/assetlinks.json").Handler(assocController.HandleAndroid()).Methods("GET")
}

// Handle redirects.
redirectController, err := redirect.New(ctx, db, cfg, cacher, h)
if err != nil {
return nil, fmt.Errorf("failed to create redirect controller: %w", err)
}
r.PathPrefix("/").Handler(redirectController.HandleIndex()).Methods("GET")

// Wrap the main router in the mutating middleware method. This cannot be
// inserted as middleware because gorilla processes the method before
// middleware.
mux := http.NewServeMux()
mux.Handle("/", middleware.MutateMethod()(r))
return mux, nil
}
9 changes: 2 additions & 7 deletions pkg/controller/associated/android.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,8 @@ type Target struct {
}

// getAndroidData finds all the android data apps.
func (c *Controller) getAndroidData(region string) ([]AndroidData, error) {
realm, err := c.db.FindRealmByRegion(region)
if err != nil {
return nil, fmt.Errorf("unable to lookup realm: %w", err)
}

apps, err := c.db.ListActiveApps(realm.ID, database.WithAppOS(database.OSTypeAndroid))
func (c *Controller) getAndroidData(realmID uint) ([]AndroidData, error) {
apps, err := c.db.ListActiveApps(realmID, database.WithAppOS(database.OSTypeAndroid))
if err != nil {
return nil, fmt.Errorf("failed to get android data: %w", err)
}
Expand Down
Loading

0 comments on commit c5acc33

Please sign in to comment.