Clean up browser bridge and mutation helpers
This commit is contained in:
@@ -15,6 +15,8 @@ import (
|
||||
|
||||
"git.julianfamily.org/keepassgo/internal/grpcaddr"
|
||||
keepassgov1 "git.julianfamily.org/keepassgo/proto/keepassgo/v1"
|
||||
gcodes "google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -22,6 +24,7 @@ const (
|
||||
defaultFirefoxID = "browser@keepassgo.com"
|
||||
maxNativeMessageSize = 1024 * 1024
|
||||
chromiumIDBytes = 16
|
||||
responseVersion = "1"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
@@ -162,33 +165,25 @@ func HandleRequest(ctx context.Context, req Request, client Client) Response {
|
||||
if err != nil {
|
||||
return Response{Success: false, Error: err.Error(), Status: disconnectedStatus(conn.GRPCAddress)}
|
||||
}
|
||||
return Response{Success: true, Status: status, Version: "1"}
|
||||
return Response{Success: true, Status: status, Version: responseVersion}
|
||||
case "find-logins":
|
||||
status, err := statusResponse(ctx, client, conn.GRPCAddress)
|
||||
if err != nil {
|
||||
return Response{Success: false, Error: err.Error(), Status: disconnectedStatus(conn.GRPCAddress)}
|
||||
}
|
||||
if status.Locked {
|
||||
return Response{Success: true, Status: status, Matches: nil, Version: "1"}
|
||||
}
|
||||
matches, err := findMatches(ctx, client, req.URL)
|
||||
if err != nil {
|
||||
return Response{Success: false, Error: err.Error(), Status: status}
|
||||
}
|
||||
return Response{Success: true, Status: status, Matches: matches, Version: "1"}
|
||||
case "get-login":
|
||||
status, err := statusResponse(ctx, client, conn.GRPCAddress)
|
||||
if err != nil {
|
||||
if status := inferredActionStatus(conn.GRPCAddress, err); status != nil {
|
||||
return Response{Success: true, Status: status, Matches: nil, Version: responseVersion}
|
||||
}
|
||||
return Response{Success: false, Error: err.Error(), Status: disconnectedStatus(conn.GRPCAddress)}
|
||||
}
|
||||
if status.Locked {
|
||||
return Response{Success: false, Error: "vault is locked", Status: status}
|
||||
}
|
||||
return Response{Success: true, Status: availableStatus(conn.GRPCAddress), Matches: matches, Version: responseVersion}
|
||||
case "get-login":
|
||||
credential, err := loadCredential(ctx, client, req.EntryID, req.URL)
|
||||
if err != nil {
|
||||
return Response{Success: false, Error: err.Error(), Status: status}
|
||||
if status := inferredActionStatus(conn.GRPCAddress, err); status != nil {
|
||||
return Response{Success: false, Error: err.Error(), Status: status}
|
||||
}
|
||||
return Response{Success: false, Error: err.Error(), Status: disconnectedStatus(conn.GRPCAddress)}
|
||||
}
|
||||
return Response{Success: true, Status: status, Credential: credential, Version: "1"}
|
||||
return Response{Success: true, Status: availableStatus(conn.GRPCAddress), Credential: credential, Version: responseVersion}
|
||||
default:
|
||||
return Response{Success: false, Error: fmt.Sprintf("unsupported action %q", action)}
|
||||
}
|
||||
@@ -198,6 +193,21 @@ func disconnectedStatus(addr string) *Status {
|
||||
return &Status{Connected: false, GRPCAddress: strings.TrimSpace(addr)}
|
||||
}
|
||||
|
||||
func availableStatus(addr string) *Status {
|
||||
return &Status{Connected: true, Locked: false, GRPCAddress: strings.TrimSpace(addr)}
|
||||
}
|
||||
|
||||
func inferredActionStatus(addr string, err error) *Status {
|
||||
switch gstatus.Code(err) {
|
||||
case gcodes.FailedPrecondition:
|
||||
return &Status{Connected: true, Locked: true, GRPCAddress: strings.TrimSpace(addr)}
|
||||
case gcodes.OK:
|
||||
return availableStatus(addr)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func statusResponse(ctx context.Context, client Client, addr string) (*Status, error) {
|
||||
resp, err := client.Status(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
"testing"
|
||||
|
||||
keepassgov1 "git.julianfamily.org/keepassgo/proto/keepassgo/v1"
|
||||
gcodes "google.golang.org/grpc/codes"
|
||||
gstatus "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func TestReadRequestAndWriteResponse(t *testing.T) {
|
||||
@@ -70,8 +72,7 @@ func TestReadRequestAndWriteResponse(t *testing.T) {
|
||||
func TestHandleRequestFindLogins(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := fakeClient{
|
||||
status: &keepassgov1.GetSessionStatusResponse{Locked: false, EntryCount: 2},
|
||||
client := &fakeClient{
|
||||
matches: []*keepassgov1.BrowserLoginMatch{
|
||||
{Id: "vault-console", Title: "Vault Console", Username: "dannyocean", Url: "https://vault.example.invalid", Quality: "exact-host"},
|
||||
},
|
||||
@@ -87,12 +88,15 @@ func TestHandleRequestFindLogins(t *testing.T) {
|
||||
if len(resp.Matches) != 1 || resp.Matches[0].ID != "vault-console" {
|
||||
t.Fatalf("HandleRequest().Matches = %#v, want vault-console", resp.Matches)
|
||||
}
|
||||
if client.statusCalls != 0 {
|
||||
t.Fatalf("HandleRequest(find-logins) statusCalls = %d, want 0", client.statusCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRequestStatusIncludesPendingApprovalCounts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := fakeClient{
|
||||
client := &fakeClient{
|
||||
status: &keepassgov1.GetSessionStatusResponse{
|
||||
Locked: false,
|
||||
EntryCount: 2,
|
||||
@@ -121,8 +125,7 @@ func TestHandleRequestStatusIncludesPendingApprovalCounts(t *testing.T) {
|
||||
func TestHandleRequestGetLogin(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := fakeClient{
|
||||
status: &keepassgov1.GetSessionStatusResponse{Locked: false, EntryCount: 1},
|
||||
client := &fakeClient{
|
||||
credential: &keepassgov1.GetBrowserCredentialResponse{
|
||||
Id: "vault-console",
|
||||
Username: "dannyocean",
|
||||
@@ -142,12 +145,35 @@ func TestHandleRequestGetLogin(t *testing.T) {
|
||||
if resp.Credential == nil || resp.Credential.ID != "vault-console" {
|
||||
t.Fatalf("HandleRequest().Credential = %#v, want vault-console", resp.Credential)
|
||||
}
|
||||
if client.statusCalls != 0 {
|
||||
t.Fatalf("HandleRequest(get-login) statusCalls = %d, want 0", client.statusCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRequestFindLoginsInfersLockedStatusFromRPC(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
client := &fakeClient{matchesErr: gstatus.Error(gcodes.FailedPrecondition, "vault is locked")}
|
||||
resp := HandleRequest(context.Background(), Request{
|
||||
Action: "find-logins",
|
||||
BearerToken: "secret",
|
||||
URL: "https://vault.example.invalid/login",
|
||||
}, client)
|
||||
if !resp.Success {
|
||||
t.Fatalf("HandleRequest(find-logins locked) success = false, error = %q", resp.Error)
|
||||
}
|
||||
if resp.Status == nil || !resp.Status.Locked {
|
||||
t.Fatalf("HandleRequest(find-logins locked).Status = %#v, want locked status", resp.Status)
|
||||
}
|
||||
if client.statusCalls != 0 {
|
||||
t.Fatalf("HandleRequest(find-logins locked) statusCalls = %d, want 0", client.statusCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRequestRequiresBearerToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
resp := HandleRequest(context.Background(), Request{Action: "status"}, fakeClient{})
|
||||
resp := HandleRequest(context.Background(), Request{Action: "status"}, &fakeClient{})
|
||||
if resp.Success {
|
||||
t.Fatal("HandleRequest().Success = true, want false without token")
|
||||
}
|
||||
@@ -282,10 +308,13 @@ func TestEnsureNativeHostManifestsInstallsFirefoxAndDiscoveredChromium(t *testin
|
||||
}
|
||||
|
||||
type fakeClient struct {
|
||||
status *keepassgov1.GetSessionStatusResponse
|
||||
matches []*keepassgov1.BrowserLoginMatch
|
||||
credential *keepassgov1.GetBrowserCredentialResponse
|
||||
err error
|
||||
status *keepassgov1.GetSessionStatusResponse
|
||||
matches []*keepassgov1.BrowserLoginMatch
|
||||
credential *keepassgov1.GetBrowserCredentialResponse
|
||||
err error
|
||||
matchesErr error
|
||||
credentialErr error
|
||||
statusCalls int
|
||||
}
|
||||
|
||||
func writeExtensionManifest(t *testing.T, path, name string) {
|
||||
@@ -333,7 +362,8 @@ func assertManifestContainsExtension(t *testing.T, path, field, want string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (f fakeClient) Status(context.Context) (*keepassgov1.GetSessionStatusResponse, error) {
|
||||
func (f *fakeClient) Status(context.Context) (*keepassgov1.GetSessionStatusResponse, error) {
|
||||
f.statusCalls++
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
@@ -343,14 +373,20 @@ func (f fakeClient) Status(context.Context) (*keepassgov1.GetSessionStatusRespon
|
||||
return f.status, nil
|
||||
}
|
||||
|
||||
func (f fakeClient) FindBrowserLogins(context.Context, string) ([]*keepassgov1.BrowserLoginMatch, error) {
|
||||
func (f *fakeClient) FindBrowserLogins(context.Context, string) ([]*keepassgov1.BrowserLoginMatch, error) {
|
||||
if f.matchesErr != nil {
|
||||
return nil, f.matchesErr
|
||||
}
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
return f.matches, nil
|
||||
}
|
||||
|
||||
func (f fakeClient) GetBrowserCredential(context.Context, string, string) (*keepassgov1.GetBrowserCredentialResponse, error) {
|
||||
func (f *fakeClient) GetBrowserCredential(context.Context, string, string) (*keepassgov1.GetBrowserCredentialResponse, error) {
|
||||
if f.credentialErr != nil {
|
||||
return nil, f.credentialErr
|
||||
}
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user