Move browser bridge gRPC address to flag
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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()}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user