Skip to content
This repository has been archived by the owner on Oct 31, 2021. It is now read-only.

Commit

Permalink
Returning CustomToken from registration and authenticating with ID to…
Browse files Browse the repository at this point in the history
…ken on all other endpoints
  • Loading branch information
jendakol authored and marekaf committed Sep 3, 2020
1 parent 4e9d4c0 commit 2a5e0fd
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 35 deletions.
17 changes: 17 additions & 0 deletions internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
// Auther is an auth abstraction layer interface
type Auther interface {
CustomToken(ctx context.Context, uid string) (string, error)
AuthenticateToken(ctx context.Context, customToken string) (string, error)
}

// Client to interact with auth API
Expand All @@ -20,10 +21,26 @@ func (c *Client) CustomToken(ctx context.Context, uid string) (string, error) {
return client.CustomToken(ctx, uid)
}

//AuthenticateToken Verifies provided token and if valid, extracts eHRID from it.
func (c *Client) AuthenticateToken(ctx context.Context, customToken string) (string, error) {
client := firebase.FirebaseAuth
token, err := client.VerifyIDToken(ctx, customToken)
if err != nil {
return "", err
}

return token.UID, nil
}

// MockClient mocks auth client functionaly for unit tests
type MockClient struct{}

// CustomToken creates a signed custom authentication token with the specified user ID.
func (c *MockClient) CustomToken(uid string) (string, error) {
return "abc", nil
}

//AuthenticateToken Verifies provided token and if valid, extracts eHRID from it.
func (c *MockClient) AuthenticateToken(ctx context.Context, customToken string) (string, error) {
return "ehrid", nil
}
24 changes: 17 additions & 7 deletions internal/functions/changepushtoken/change-push-token.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,52 @@
package changepushtoken

import (
"cloud.google.com/go/firestore"
"context"
"fmt"
"net/http"

"cloud.google.com/go/firestore"
"github.com/covid19cz/erouska-backend/internal/auth"
"github.com/covid19cz/erouska-backend/internal/constants"
"github.com/covid19cz/erouska-backend/internal/firebase/structs"
"github.com/covid19cz/erouska-backend/internal/logging"
"github.com/covid19cz/erouska-backend/internal/store"
"github.com/covid19cz/erouska-backend/internal/utils/errors"
httputils "github.com/covid19cz/erouska-backend/internal/utils/http"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type request struct {
Ehrid string `json:"ehrid" validate:"required"`
IDToken string `json:"idToken" validate:"required"`
PushRegistrationToken string `json:"pushRegistrationToken" validate:"required"`
}

//ChangePushToken Handler
func ChangePushToken(w http.ResponseWriter, r *http.Request) {
var ctx = r.Context()
logger := logging.FromContext(ctx)
client := store.Client{}
storeClient := store.Client{}
authClient := auth.Client{}

var request request

if !httputils.DecodeJSONOrReportError(w, r, &request) {
return
}

logger.Debugf("Handling ChangePushToken request: %+v", request)
ehrid, err := authClient.AuthenticateToken(ctx, request.IDToken)
if err != nil {
logger.Debugf("Unverifiable token provided: %+v %+v", request.IDToken, err.Error())
httputils.SendErrorResponse(w, r, &errors.UnauthenticatedError{Msg: "Invalid token"})
return
}

logger.Debugf("Handling ChangePushToken request: %v %+v", ehrid, request)

doc := client.Doc(constants.CollectionRegistrations, request.Ehrid)
doc := storeClient.Doc(constants.CollectionRegistrations, ehrid)

err := client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
err = storeClient.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
rec, err := tx.Get(doc)

if err != nil {
Expand All @@ -45,7 +55,7 @@ func ChangePushToken(w http.ResponseWriter, r *http.Request) {
}
// not found:

return fmt.Errorf("Could not find registration for %v: %v", request.Ehrid, err)
return fmt.Errorf("Could not find registration for %v: %v", ehrid, err)
}

var registration structs.Registration
Expand Down
28 changes: 19 additions & 9 deletions internal/functions/coviddata/get-covid-data.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ import (
"net/http"
"time"

"github.com/covid19cz/erouska-backend/internal/utils/errors"

"github.com/covid19cz/erouska-backend/internal/auth"
"github.com/covid19cz/erouska-backend/internal/constants"
"github.com/covid19cz/erouska-backend/internal/logging"
"github.com/covid19cz/erouska-backend/internal/store"
"github.com/covid19cz/erouska-backend/internal/utils"
"github.com/covid19cz/erouska-backend/internal/utils/errors"
httputils "github.com/covid19cz/erouska-backend/internal/utils/http"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type getRequest struct {
Date string `json:"date"`
IDToken string `json:"idToken" validate:"required"`
Date string `json:"date"`
}

type response struct {
Expand Down Expand Up @@ -91,17 +92,26 @@ func fetchIncrease(ctx context.Context, client store.Client, date string) (*Incr

// GetCovidData handler.
func GetCovidData(w http.ResponseWriter, r *http.Request) {

var ctx = r.Context()
logger := logging.FromContext(ctx)
client := store.Client{}
storeClient := store.Client{}
authClient := auth.Client{}

var req getRequest

if !httputils.DecodeJSONOrReportError(w, r, &req) {
return
}

ehrid, err := authClient.AuthenticateToken(ctx, req.IDToken)
if err != nil {
logger.Debugf("Unverifiable token provided: %+v %+v", req.IDToken, err.Error())
httputils.SendErrorResponse(w, r, &errors.UnauthenticatedError{Msg: "Invalid token"})
return
}

logger.Debugf("Handling GetCovidData request: %v %+v", ehrid, req)

date := req.Date

// if no date was specified in input
Expand All @@ -116,7 +126,7 @@ func GetCovidData(w http.ResponseWriter, r *http.Request) {

failed := false

totalsData, err := fetchTotals(ctx, client, date)
totalsData, err := fetchTotals(ctx, storeClient, date)
if err != nil {
logger.Errorf("Error fetching data from firestore: %v", err)
failed = true
Expand All @@ -125,7 +135,7 @@ func GetCovidData(w http.ResponseWriter, r *http.Request) {
return
}
}
increaseData, err := fetchIncrease(ctx, client, date)
increaseData, err := fetchIncrease(ctx, storeClient, date)
if err != nil {
logger.Errorf("Error fetching data from firestore: %v", err)
failed = true
Expand All @@ -140,13 +150,13 @@ func GetCovidData(w http.ResponseWriter, r *http.Request) {
t, _ := time.Parse("20060102", date)
date = t.AddDate(0, 0, -1).Format("20060102")

totalsData, err = fetchTotals(ctx, client, date)
totalsData, err = fetchTotals(ctx, storeClient, date)
if err != nil {
logger.Errorf("Error refetching data from firestore: %v", err)
httputils.SendErrorResponse(w, r, err)
return
}
increaseData, err = fetchIncrease(ctx, client, date)
increaseData, err = fetchIncrease(ctx, storeClient, date)
if err != nil {
logger.Errorf("Error refetching data from firestore: %v", err)
httputils.SendErrorResponse(w, r, err)
Expand Down
18 changes: 14 additions & 4 deletions internal/functions/isehridactive/is-ehrid-active.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package isehridactive

import (
"github.com/covid19cz/erouska-backend/internal/auth"
"github.com/covid19cz/erouska-backend/internal/constants"
"github.com/covid19cz/erouska-backend/internal/logging"
"github.com/covid19cz/erouska-backend/internal/store"
"github.com/covid19cz/erouska-backend/internal/utils/errors"
httputils "github.com/covid19cz/erouska-backend/internal/utils/http"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net/http"
)

type queryRequest struct {
Ehrid string `json:"ehrid" validate:"required"`
IDToken string `json:"idToken" validate:"required"`
}

type queryResponse struct {
Expand All @@ -22,17 +24,25 @@ type queryResponse struct {
func IsEhridActive(w http.ResponseWriter, r *http.Request) {
var ctx = r.Context()
logger := logging.FromContext(ctx)
client := store.Client{}
storeClient := store.Client{}
authClient := auth.Client{}

var request queryRequest

if !httputils.DecodeJSONOrReportError(w, r, &request) {
return
}

logger.Debugf("Handling isEhridActive request: %+v", request)
ehrid, err := authClient.AuthenticateToken(ctx, request.IDToken)
if err != nil {
logger.Debugf("Unverifiable token provided: %+v %+v", request.IDToken, err.Error())
httputils.SendErrorResponse(w, r, &errors.UnauthenticatedError{Msg: "Invalid token"})
return
}

logger.Debugf("Handling isEhridActive request: %v %+v", ehrid, request)

_, err := client.Doc(constants.CollectionRegistrations, request.Ehrid).Get(ctx)
_, err = storeClient.Doc(constants.CollectionRegistrations, ehrid).Get(ctx)

var active bool

Expand Down
6 changes: 2 additions & 4 deletions internal/functions/registerehrid/register-ehrid.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package registerehrid

import (
"cloud.google.com/go/firestore"
"context"
"fmt"
"net/http"

rpccode "google.golang.org/genproto/googleapis/rpc/code"

"cloud.google.com/go/firestore"
"github.com/avast/retry-go"
"github.com/covid19cz/erouska-backend/internal/auth"
"github.com/covid19cz/erouska-backend/internal/constants"
Expand Down Expand Up @@ -71,7 +69,7 @@ func RegisterEhrid(w http.ResponseWriter, r *http.Request) {
customToken, err := authClient.CustomToken(ctx, ehrid)
if err != nil {
logger.Fatalf("error minting custom token: %v\n", err.Error())
httputils.SendErrorResponse(w, r, rpccode.Code_INTERNAL, "Unknown error")
httputils.SendErrorResponse(w, r, &errors.UnknownError{Msg: "ahoj"})
}

logger.Debugf("Got custom token: %v\n", customToken)
Expand Down
29 changes: 19 additions & 10 deletions internal/functions/registernotification/register-notification.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
package registernotification

import (
"cloud.google.com/go/firestore"
"context"
"fmt"
"github.com/covid19cz/erouska-backend/internal/pubsub"
"github.com/covid19cz/erouska-backend/internal/utils/errors"
"net/http"

"cloud.google.com/go/firestore"
"github.com/covid19cz/erouska-backend/internal/auth"
"github.com/covid19cz/erouska-backend/internal/constants"
"github.com/covid19cz/erouska-backend/internal/firebase/structs"
"github.com/covid19cz/erouska-backend/internal/logging"
"github.com/covid19cz/erouska-backend/internal/pubsub"
"github.com/covid19cz/erouska-backend/internal/store"
"github.com/covid19cz/erouska-backend/internal/utils"
"github.com/covid19cz/erouska-backend/internal/utils/errors"
httputils "github.com/covid19cz/erouska-backend/internal/utils/http"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type request struct {
Ehrid string `json:"ehrid" validate:"required"`
IDToken string `json:"idToken" validate:"required"`
}

//AftermathPayload Struct holding aftermath input data.
Expand All @@ -31,7 +32,8 @@ type AftermathPayload struct {
func RegisterNotification(w http.ResponseWriter, r *http.Request) {
var ctx = r.Context()
logger := logging.FromContext(ctx)
client := store.Client{}
storeClient := store.Client{}
authClient := auth.Client{}
pubSubClient := pubsub.Client{}

var request request
Expand All @@ -40,11 +42,18 @@ func RegisterNotification(w http.ResponseWriter, r *http.Request) {
return
}

logger.Debugf("Handling RegisterNotification request: %+v", request)
ehrid, err := authClient.AuthenticateToken(ctx, request.IDToken)
if err != nil {
logger.Debugf("Unverifiable token provided: %+v %+v", request.IDToken, err.Error())
httputils.SendErrorResponse(w, r, &errors.UnauthenticatedError{Msg: "Invalid token"})
return
}

logger.Debugf("Handling RegisterNotification request: %v %+v", ehrid, request)

doc := client.Doc(constants.CollectionRegistrations, request.Ehrid)
doc := storeClient.Doc(constants.CollectionRegistrations, ehrid)

err := client.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
err = storeClient.RunTransaction(ctx, func(ctx context.Context, tx *firestore.Transaction) error {
rec, err := tx.Get(doc)

if err != nil {
Expand All @@ -53,7 +62,7 @@ func RegisterNotification(w http.ResponseWriter, r *http.Request) {
}
// not found:

return &errors.NotFoundError{Msg: fmt.Sprintf("Could not find registration for %v: %v", request.Ehrid, err)}
return &errors.NotFoundError{Msg: fmt.Sprintf("Could not find registration for %v: %v", ehrid, err)}
}

var registration structs.Registration
Expand All @@ -77,7 +86,7 @@ func RegisterNotification(w http.ResponseWriter, r *http.Request) {
return
}

aftermathPayload := AftermathPayload(request)
aftermathPayload := AftermathPayload{Ehrid: ehrid}

topicName := constants.TopicRegisterNotification
logger.Debugf("Publishing event to %v: %+v", topicName, aftermathPayload)
Expand Down
16 changes: 15 additions & 1 deletion internal/utils/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (mr *MalformedRequestError) Code() rpccode.Code {
return rpccode.Code_INVALID_ARGUMENT
}

//NotFoundError Error for malformed request
//NotFoundError Error for not found
type NotFoundError struct {
Msg string
}
Expand All @@ -59,3 +59,17 @@ func (mr *NotFoundError) Error() string {
func (mr *NotFoundError) Code() rpccode.Code {
return rpccode.Code_NOT_FOUND
}

//UnauthenticatedError Error for unauthenticated
type UnauthenticatedError struct {
Msg string
}

func (mr *UnauthenticatedError) Error() string {
return mr.Msg
}

//Code Code of the error.
func (mr *UnauthenticatedError) Code() rpccode.Code {
return rpccode.Code_UNAUTHENTICATED
}

0 comments on commit 2a5e0fd

Please sign in to comment.