Skip to content

Commit 7411f2b

Browse files
committed
add support for x-api-key auth method
1 parent e0208cf commit 7411f2b

File tree

3 files changed

+50
-7
lines changed

3 files changed

+50
-7
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ Operators, you should copy/paste content of this content straight to your projec
88

99
If you were at `firehose-core` version `1.0.0` and are bumping to `1.1.0`, you should copy the content between those 2 version to your own repository, replacing placeholder value `fire{chain}` with your chain's own binary.
1010

11+
## v1.2.1
12+
13+
### Fixed
14+
15+
* Fixed `tools firehose-client` which was broken because of bad flag handling
16+
17+
### Added
18+
19+
* Added `--api-key-env-var` flag to firehose-clients, which allows you to pass your API Key from an environment variable (HTTP header `x-api-key`) instead of a JWT (`Authorization: bearer`), where supported.
20+
1121
## v1.2.0
1222

1323
* Poller is now fetching blocks in an optimized way, it will fetch several blocks at once and then process them.

cmd/tools/firehose/firehose.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ func getFirehoseClientFromCmd[B firecore.Block, C any](cmd *cobra.Command, logge
5151
requestInfo = &firehoseRequestInfo{}
5252

5353
jwt := os.Getenv(sflags.MustGetString(cmd, "api-token-env-var"))
54+
apiKey := os.Getenv(sflags.MustGetString(cmd, "api-key-env-var"))
55+
5456
plaintext := sflags.MustGetBool(cmd, "plaintext")
5557
insecure := sflags.MustGetBool(cmd, "insecure")
5658

@@ -64,7 +66,7 @@ func getFirehoseClientFromCmd[B firecore.Block, C any](cmd *cobra.Command, logge
6466

6567
var rawClient any
6668
if kind == "stream-client" {
67-
rawClient, connClose, requestInfo.GRPCCallOpts, err = client.NewFirehoseClient(endpoint, jwt, insecure, plaintext)
69+
rawClient, connClose, requestInfo.GRPCCallOpts, err = client.NewFirehoseClient(endpoint, jwt, apiKey, insecure, plaintext)
6870
} else if kind == "fetch-client" {
6971
rawClient, connClose, err = client.NewFirehoseFetchClient(endpoint, jwt, insecure, plaintext)
7072
} else {
@@ -113,7 +115,8 @@ func addFirehoseStreamClientFlagsToSet[B firecore.Block](flags *pflag.FlagSet, c
113115
}
114116

115117
func addFirehoseFetchClientFlagsToSet[B firecore.Block](flags *pflag.FlagSet, chain *firecore.Chain[B]) {
116-
flags.StringP("api-token-env-var", "a", "FIREHOSE_API_TOKEN", "Look for a JWT in this environment variable to authenticate against endpoint")
118+
flags.StringP("api-token-env-var", "a", "FIREHOSE_API_TOKEN", "Look for a JWT in this environment variable to authenticate against endpoint (alternative to api-key-env-var)")
119+
flags.String("api-key-env-var", "FIREHOSE_API_KEY", "Look for an API key directly in this environment variable to authenticate against endpoint (alternative to api-token-env-var)")
117120
flags.String("compression", "none", "The HTTP compression: use either 'none', 'gzip' or 'zstd'")
118121
flags.BoolP("plaintext", "p", false, "Use plaintext connection to Firehose")
119122
flags.BoolP("insecure", "k", false, "Use SSL connection to Firehose but skip SSL certificate validation")

firehose/client/client.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package client
22

33
import (
4+
"context"
45
"crypto/tls"
56
"fmt"
67

@@ -11,13 +12,13 @@ import (
1112
"google.golang.org/grpc/credentials"
1213
"google.golang.org/grpc/credentials/insecure"
1314
"google.golang.org/grpc/credentials/oauth"
15+
"google.golang.org/grpc/metadata"
1416
)
1517

1618
// firehoseClient, closeFunc, grpcCallOpts, err := NewFirehoseClient(endpoint, jwt, insecure, plaintext)
1719
// defer closeFunc()
1820
// stream, err := firehoseClient.Blocks(context.Background(), request, grpcCallOpts...)
19-
func NewFirehoseClient(endpoint, jwt string, useInsecureTSLConnection, usePlainTextConnection bool) (cli pbfirehose.StreamClient, closeFunc func() error, callOpts []grpc.CallOption, err error) {
20-
skipAuth := jwt == "" || usePlainTextConnection
21+
func NewFirehoseClient(endpoint, jwt, apiKey string, useInsecureTSLConnection, usePlainTextConnection bool) (cli pbfirehose.StreamClient, closeFunc func() error, callOpts []grpc.CallOption, err error) {
2122

2223
if useInsecureTSLConnection && usePlainTextConnection {
2324
return nil, nil, nil, fmt.Errorf("option --insecure and --plaintext are mutually exclusive, they cannot be both specified at the same time")
@@ -39,14 +40,43 @@ func NewFirehoseClient(endpoint, jwt string, useInsecureTSLConnection, usePlainT
3940
closeFunc = conn.Close
4041
cli = pbfirehose.NewStreamClient(conn)
4142

42-
if !skipAuth {
43-
credentials := oauth.NewOauthAccess(&oauth2.Token{AccessToken: jwt, TokenType: "Bearer"})
44-
callOpts = append(callOpts, grpc.PerRPCCredentials(credentials))
43+
if !usePlainTextConnection {
44+
if jwt != "" {
45+
credentials := oauth.NewOauthAccess(&oauth2.Token{AccessToken: jwt, TokenType: "Bearer"})
46+
callOpts = append(callOpts, grpc.PerRPCCredentials(credentials))
47+
} else if apiKey != "" {
48+
callOpts = append(callOpts, grpc.PerRPCCredentials(&ApiKeyAuth{ApiKey: apiKey}))
49+
}
4550
}
4651

4752
return
4853
}
4954

55+
type ApiKeyAuth struct {
56+
ApiKey string
57+
}
58+
59+
func (a *ApiKeyAuth) GetRequestMetadata(ctx context.Context, uri ...string) (out map[string]string, err error) {
60+
md, ok := metadata.FromOutgoingContext(ctx)
61+
if !ok {
62+
md = metadata.New(nil)
63+
}
64+
out = make(map[string]string)
65+
for k, v := range md {
66+
if len(v) != 0 {
67+
out[k] = v[0]
68+
}
69+
}
70+
if a.ApiKey != "" {
71+
out["x-api-key"] = a.ApiKey
72+
}
73+
return
74+
}
75+
76+
func (a *ApiKeyAuth) RequireTransportSecurity() bool {
77+
return true
78+
}
79+
5080
func NewFirehoseFetchClient(endpoint, jwt string, useInsecureTSLConnection, usePlainTextConnection bool) (cli pbfirehose.FetchClient, closeFunc func() error, err error) {
5181

5282
if useInsecureTSLConnection && usePlainTextConnection {

0 commit comments

Comments
 (0)