[READ-ONLY] Mirror of https://github.com/andrioid/gostack. Experimental backend stack (work-in-progress)
0

Configure Feed

Select the types of activity you want to include in your feed.

can now verify firebase id token

+68 -34
+15 -6
cmd/serve.go
··· 1 1 package cmd 2 2 3 3 import ( 4 + "context" 4 5 "fmt" 6 + "log" 5 7 "net/http" 6 8 "os" 7 9 10 + firebase "firebase.google.com/go" 8 11 "github.com/andrioid/gostack/graphql" 9 12 "github.com/andrioid/gostack/module" 10 13 "github.com/andrioid/gostack/places" ··· 13 16 _ "github.com/jinzhu/gorm/dialects/sqlite" 14 17 "github.com/spf13/cobra" 15 18 "github.com/spf13/viper" 19 + "google.golang.org/api/option" 16 20 ) 17 21 18 22 // serveCmd represents the serve command ··· 61 65 // Firebase 62 66 // https://firebase.google.com/docs/auth/admin/verify-id-tokens 63 67 // https://firebase.google.com/docs/admin/setup 64 - //opt := option.WithCredentialsFile(viper.GetString("firebase.serviceAccountFile")) 65 - //app, err := firebase.NewApp(context.Background(), nil, opt) 66 - //if err != nil { 67 - // log.Fatalf("error initializing app: %v\n", err) 68 - //} 68 + opt := option.WithCredentialsFile(viper.GetString("firebase.serviceAccountFile")) 69 + app, err := firebase.NewApp(context.Background(), nil, opt) 70 + if err != nil { 71 + log.Fatalf("error initializing app: %v\n", err) 72 + } 73 + firebaseAuth, err := app.Auth(context.Background()) 74 + if err != nil { 75 + panic(err) 76 + } 69 77 // TODO: app isn't accessable to graphql package, so maybe create middleware for token verification 70 78 71 79 // Modules ··· 75 83 graphql.CreateSchema(modules) 76 84 77 85 r := mux.NewRouter() 78 - r.HandleFunc("/graphql", graphql.HTTPHandler) 86 + 87 + r.HandleFunc("/graphql", graphql.HTTPHandler(firebaseAuth)) 79 88 r.PathPrefix("/").Handler(http.FileServer(http.Dir("./client/build"))) 80 89 http.Handle("/", r) 81 90
+53 -28
graphql/graphql.go
··· 5 5 "fmt" 6 6 "net/http" 7 7 8 + "firebase.google.com/go/auth" 8 9 "github.com/andrioid/gostack/module" 9 10 "github.com/graphql-go/graphql" 10 11 ) 12 + 13 + const bearer = "Bearer" 11 14 12 15 // https://github.com/graphql-go/graphql/blob/master/examples/http/main.go 13 16 ··· 51 54 var schema graphql.Schema 52 55 53 56 // HTTPHandler tells the http-server how to process GraphQL 54 - func HTTPHandler(w http.ResponseWriter, r *http.Request) { 55 - var query string 56 - auth := r.Header.Get("Authorization") 57 + func HTTPHandler(a *auth.Client) func(http.ResponseWriter, *http.Request) { 58 + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 59 + var query string 60 + t, _ := authorizationFromHeader(r) 57 61 58 - if auth != "" { 59 - // TODO: Verify the token found with Firebase SDK 60 - fmt.Println("Auth header", auth) 61 - } 62 - if r.Method == http.MethodPost { 63 - decoder := json.NewDecoder(r.Body) 64 - var t struct { 65 - Query string 62 + token, err := a.VerifyIDToken(t) 63 + if err != nil { 64 + fmt.Println("Error verifying token", err) 65 + } 66 + 67 + if t != "" { 68 + // TODO: Verify the token found with Firebase SDK 69 + fmt.Println("Auth header", t, token) 70 + } 71 + if r.Method == http.MethodPost { 72 + decoder := json.NewDecoder(r.Body) 73 + var t struct { 74 + Query string 75 + } 76 + err := decoder.Decode(&t) 77 + if err != nil { 78 + http.Error(w, "Invalid request", http.StatusBadRequest) 79 + return 80 + } 81 + defer r.Body.Close() 82 + query = t.Query 83 + } else { 84 + query = r.URL.Query().Get("query") 66 85 } 67 - err := decoder.Decode(&t) 68 - if err != nil { 69 - http.Error(w, "Invalid request", http.StatusBadRequest) 70 - return 86 + if query == "" { 87 + fmt.Println("Query is empty") 71 88 } 72 - defer r.Body.Close() 73 - query = t.Query 74 - } else { 75 - query = r.URL.Query().Get("query") 89 + result := ExecuteQuery(query, schema) 90 + w.Header().Set("Content-Type", "application/json") 91 + w.Header().Set("Access-Control-Allow-Credentials", "true") 92 + w.Header().Set("Access-Control-Allow-Methods", "POST") 93 + w.Header().Set("Access-Control-Allow-Headers", "ContentType, Authorization") 94 + w.Header().Set("Access-Control-Allow-Origin", "*") 95 + json.NewEncoder(w).Encode(result) 96 + return 97 + }) 98 + } 99 + 100 + func authorizationFromHeader(req *http.Request) (string, error) { 101 + header := req.Header.Get("Authorization") 102 + if header == "" { 103 + return "", fmt.Errorf("Authorization header not found") 76 104 } 77 - if query == "" { 78 - fmt.Println("Query is empty") 105 + 106 + l := len(bearer) 107 + if len(header) > l+1 && header[:l] == bearer { 108 + return header[l+1:], nil 79 109 } 80 - result := ExecuteQuery(query, schema) 81 - w.Header().Set("Content-Type", "application/json") 82 - w.Header().Set("Access-Control-Allow-Credentials", "true") 83 - w.Header().Set("Access-Control-Allow-Methods", "POST") 84 - w.Header().Set("Access-Control-Allow-Headers", "ContentType, Authorization") 85 - w.Header().Set("Access-Control-Allow-Origin", "*") 86 - json.NewEncoder(w).Encode(result) 110 + 111 + return "", fmt.Errorf("Authorization header format must be 'Bearer {token}'") 87 112 } 88 113 89 114 // ExecuteQuery does stuff