Move browser bridge gRPC address to flag

This commit is contained in:
Joe Julian
2026-04-12 07:38:23 -07:00
parent 77e92a2368
commit 8117e3e8c1
4 changed files with 63 additions and 29 deletions
+48 -12
View File
@@ -14,7 +14,14 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
) )
type bridgeConfig struct {
grpcAddr string
}
func main() { func main() {
cfg := bridgeConfig{
grpcAddr: resolveGlobalGRPCAddr(os.Args[1:]),
}
if len(os.Args) > 1 { if len(os.Args) > 1 {
switch strings.TrimSpace(os.Args[1]) { switch strings.TrimSpace(os.Args[1]) {
case "install-native-host": case "install-native-host":
@@ -23,13 +30,13 @@ func main() {
} }
return return
case "status": case "status":
if err := runStatus(os.Args[2:]); err != nil { if err := runStatus(cfg, stripGlobalGRPCAddrFlags(os.Args[2:])); err != nil {
fail(err) fail(err)
} }
return return
} }
} }
if err := runNativeMessage(); err != nil { if err := runNativeMessage(cfg); err != nil {
_ = browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()}) _ = browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()})
os.Exit(1) os.Exit(1)
} }
@@ -80,50 +87,79 @@ func runInstallNativeHost(args []string) error {
return nil return nil
} }
func runStatus(args []string) error { func runStatus(cfg bridgeConfig, args []string) error {
fs := flag.NewFlagSet("status", flag.ContinueOnError) fs := flag.NewFlagSet("status", flag.ContinueOnError)
grpcAddr := fs.String("grpc-addr", grpcaddr.Default(runtime.GOOS), "KeePassGO local gRPC address")
token := fs.String("token", "", "KeePassGO API bearer token") token := fs.String("token", "", "KeePassGO API bearer token")
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
return err return err
} }
req := browserbridge.Request{ req := browserbridge.Request{
Action: "status", Action: "status",
GRPCAddress: strings.TrimSpace(*grpcAddr),
BearerToken: strings.TrimSpace(*token), BearerToken: strings.TrimSpace(*token),
} }
conn, client, ctx, err := dialBridge(context.Background(), req) conn, client, ctx, err := dialBridge(context.Background(), cfg, req)
if err != nil { if err != nil {
return err return err
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
resp := browserbridge.HandleRequest(ctx, req, client) resp := browserbridge.HandleRequest(ctx, req, cfg.grpcAddr, client)
enc := json.NewEncoder(os.Stdout) enc := json.NewEncoder(os.Stdout)
enc.SetIndent("", " ") enc.SetIndent("", " ")
return enc.Encode(resp) return enc.Encode(resp)
} }
func runNativeMessage() error { func runNativeMessage(cfg bridgeConfig) error {
req, err := browserbridge.ReadRequest(os.Stdin) req, err := browserbridge.ReadRequest(os.Stdin)
if err != nil { if err != nil {
return err return err
} }
conn, client, ctx, err := dialBridge(context.Background(), req) conn, client, ctx, err := dialBridge(context.Background(), cfg, req)
if err != nil { if err != nil {
return browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()}) return browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()})
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
return browserbridge.WriteResponse(os.Stdout, browserbridge.HandleRequest(ctx, req, client)) return browserbridge.WriteResponse(os.Stdout, browserbridge.HandleRequest(ctx, req, cfg.grpcAddr, client))
} }
func dialBridge(ctx context.Context, req browserbridge.Request) (*grpc.ClientConn, *browserbridge.GRPCClient, context.Context, error) { func dialBridge(ctx context.Context, cfg bridgeConfig, req browserbridge.Request) (*grpc.ClientConn, *browserbridge.GRPCClient, context.Context, error) {
return browserbridge.DialRequest(ctx, req) return browserbridge.DialRequest(ctx, req, cfg.grpcAddr)
} }
func defaultBinaryPath() (string, error) { func defaultBinaryPath() (string, error) {
return browserbridge.ResolveBridgeBinaryPath("") return browserbridge.ResolveBridgeBinaryPath("")
} }
func resolveGlobalGRPCAddr(args []string) string {
addr := grpcaddr.Default(runtime.GOOS)
for i := 0; i < len(args); i++ {
arg := strings.TrimSpace(args[i])
switch {
case arg == "--grpc-addr" && i+1 < len(args):
return strings.TrimSpace(args[i+1])
case strings.HasPrefix(arg, "--grpc-addr="):
return strings.TrimSpace(strings.TrimPrefix(arg, "--grpc-addr="))
}
}
return addr
}
func stripGlobalGRPCAddrFlags(args []string) []string {
out := make([]string, 0, len(args))
for i := 0; i < len(args); i++ {
arg := strings.TrimSpace(args[i])
switch {
case arg == "--grpc-addr" && i+1 < len(args):
i++
continue
case strings.HasPrefix(arg, "--grpc-addr="):
continue
default:
out = append(out, args[i])
}
}
return out
}
func fail(err error) { func fail(err error) {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
+4 -5
View File
@@ -29,7 +29,6 @@ const (
type Request struct { type Request struct {
Action string `json:"action"` Action string `json:"action"`
GRPCAddress string `json:"grpcAddress,omitempty"`
BearerToken string `json:"bearerToken,omitempty"` BearerToken string `json:"bearerToken,omitempty"`
URL string `json:"url,omitempty"` URL string `json:"url,omitempty"`
EntryID string `json:"entryId,omitempty"` EntryID string `json:"entryId,omitempty"`
@@ -139,9 +138,9 @@ func WriteResponse(w io.Writer, resp Response) error {
return err return err
} }
func (r Request) Connection() (Connection, error) { func (r Request) Connection(grpcAddr string) (Connection, error) {
return normalizeConnection(Connection{ return normalizeConnection(Connection{
GRPCAddress: strings.TrimSpace(r.GRPCAddress), GRPCAddress: strings.TrimSpace(grpcAddr),
BearerToken: strings.TrimSpace(r.BearerToken), BearerToken: strings.TrimSpace(r.BearerToken),
}) })
} }
@@ -158,8 +157,8 @@ func normalizeConnection(conn Connection) (Connection, error) {
return conn, nil return conn, nil
} }
func HandleRequest(ctx context.Context, req Request, client Client) Response { func HandleRequest(ctx context.Context, req Request, grpcAddr string, client Client) Response {
conn, err := req.Connection() conn, err := req.Connection(grpcAddr)
if err != nil { if err != nil {
return Response{Success: false, Error: err.Error()} return Response{Success: false, Error: err.Error()}
} }
+9 -10
View File
@@ -23,7 +23,6 @@ func TestReadRequestAndWriteResponse(t *testing.T) {
var input bytes.Buffer var input bytes.Buffer
body, err := json.Marshal(Request{ body, err := json.Marshal(Request{
Action: "find-logins", Action: "find-logins",
GRPCAddress: "127.0.0.1:47777",
BearerToken: "secret", BearerToken: "secret",
URL: "https://example.invalid/login", URL: "https://example.invalid/login",
}) })
@@ -44,8 +43,8 @@ func TestReadRequestAndWriteResponse(t *testing.T) {
if req.Action != "find-logins" || req.BearerToken != "secret" { if req.Action != "find-logins" || req.BearerToken != "secret" {
t.Fatalf("ReadRequest() = %#v, want action and token preserved", req) t.Fatalf("ReadRequest() = %#v, want action and token preserved", req)
} }
if conn, err := req.Connection(); err != nil || conn.GRPCAddress != "127.0.0.1:47777" { if conn, err := req.Connection("127.0.0.1:47777"); err != nil || conn.GRPCAddress != "127.0.0.1:47777" {
t.Fatalf("req.Connection() = (%#v, %v), want explicit tcp address preserved", conn, err) t.Fatalf("req.Connection(127.0.0.1:47777) = (%#v, %v), want explicit tcp address preserved", conn, err)
} }
var output bytes.Buffer var output bytes.Buffer
@@ -81,7 +80,7 @@ func TestHandleRequestFindLogins(t *testing.T) {
Action: "find-logins", Action: "find-logins",
BearerToken: "secret", BearerToken: "secret",
URL: "https://vault.example.invalid/login", URL: "https://vault.example.invalid/login",
}, client) }, "", client)
if !resp.Success { if !resp.Success {
t.Fatalf("HandleRequest() success = false, error = %q", resp.Error) t.Fatalf("HandleRequest() success = false, error = %q", resp.Error)
} }
@@ -107,7 +106,7 @@ func TestHandleRequestStatusIncludesPendingApprovalCounts(t *testing.T) {
resp := HandleRequest(context.Background(), Request{ resp := HandleRequest(context.Background(), Request{
Action: "status", Action: "status",
BearerToken: "secret", BearerToken: "secret",
}, client) }, "", client)
if !resp.Success { if !resp.Success {
t.Fatalf("HandleRequest(status) success = false, error = %q", resp.Error) t.Fatalf("HandleRequest(status) success = false, error = %q", resp.Error)
} }
@@ -138,7 +137,7 @@ func TestHandleRequestGetLogin(t *testing.T) {
BearerToken: "secret", BearerToken: "secret",
EntryID: "vault-console", EntryID: "vault-console",
URL: "https://vault.example.invalid/login", URL: "https://vault.example.invalid/login",
}, client) }, "", client)
if !resp.Success { if !resp.Success {
t.Fatalf("HandleRequest() success = false, error = %q", resp.Error) t.Fatalf("HandleRequest() success = false, error = %q", resp.Error)
} }
@@ -158,7 +157,7 @@ func TestHandleRequestFindLoginsInfersLockedStatusFromRPC(t *testing.T) {
Action: "find-logins", Action: "find-logins",
BearerToken: "secret", BearerToken: "secret",
URL: "https://vault.example.invalid/login", URL: "https://vault.example.invalid/login",
}, client) }, "", client)
if !resp.Success { if !resp.Success {
t.Fatalf("HandleRequest(find-logins locked) success = false, error = %q", resp.Error) t.Fatalf("HandleRequest(find-logins locked) success = false, error = %q", resp.Error)
} }
@@ -173,7 +172,7 @@ func TestHandleRequestFindLoginsInfersLockedStatusFromRPC(t *testing.T) {
func TestHandleRequestRequiresBearerToken(t *testing.T) { func TestHandleRequestRequiresBearerToken(t *testing.T) {
t.Parallel() t.Parallel()
resp := HandleRequest(context.Background(), Request{Action: "status"}, &fakeClient{}) resp := HandleRequest(context.Background(), Request{Action: "status"}, "", &fakeClient{})
if resp.Success { if resp.Success {
t.Fatal("HandleRequest().Success = true, want false without token") t.Fatal("HandleRequest().Success = true, want false without token")
} }
@@ -183,9 +182,9 @@ func TestRequestConnectionDefaultsAddress(t *testing.T) {
t.Parallel() t.Parallel()
req := Request{Action: "status", BearerToken: "secret"} req := Request{Action: "status", BearerToken: "secret"}
conn, err := req.Connection() conn, err := req.Connection("")
if err != nil { if err != nil {
t.Fatalf("Connection() error = %v", err) t.Fatalf("Connection(\"\") error = %v", err)
} }
if conn.GRPCAddress == "" { if conn.GRPCAddress == "" {
t.Fatal("Connection().GRPCAddress = empty, want default address") t.Fatal("Connection().GRPCAddress = empty, want default address")
+2 -2
View File
@@ -17,8 +17,8 @@ type GRPCClient struct {
client keepassgov1.VaultServiceClient client keepassgov1.VaultServiceClient
} }
func DialRequest(ctx context.Context, req Request) (*grpc.ClientConn, *GRPCClient, context.Context, error) { func DialRequest(ctx context.Context, req Request, grpcAddr string) (*grpc.ClientConn, *GRPCClient, context.Context, error) {
conn, err := req.Connection() conn, err := req.Connection(grpcAddr)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }