144 lines
4.1 KiB
Go
144 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"git.julianfamily.org/keepassgo/internal/browserbridge"
|
|
"git.julianfamily.org/keepassgo/internal/grpcaddr"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) > 1 {
|
|
switch strings.TrimSpace(os.Args[1]) {
|
|
case "install-native-host":
|
|
if err := runInstallNativeHost(os.Args[2:]); err != nil {
|
|
fail(err)
|
|
}
|
|
return
|
|
case "status":
|
|
if err := runStatus(os.Args[2:]); err != nil {
|
|
fail(err)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
if err := runNativeMessage(); err != nil {
|
|
_ = browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()})
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func runInstallNativeHost(args []string) error {
|
|
fs := flag.NewFlagSet("install-native-host", flag.ContinueOnError)
|
|
browserName := fs.String("browser", string(browserbridge.BrowserFirefox), "target browser: firefox, chrome, chromium")
|
|
binaryPath := fs.String("binary", "", "path to keepassgo-browser-bridge binary")
|
|
extensionID := fs.String("extension-id", "", "browser extension id (required for chrome/chromium)")
|
|
extensionKey := fs.String("extension-key", "", "Chromium manifest public key used to derive a fixed extension id")
|
|
extensionKeyFile := fs.String("extension-key-file", "", "path to a Chromium manifest public key file")
|
|
outputPath := fs.String("output", "", "native host manifest output path")
|
|
if err := fs.Parse(args); err != nil {
|
|
return err
|
|
}
|
|
path := strings.TrimSpace(*binaryPath)
|
|
if path == "" {
|
|
resolved, err := defaultBinaryPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path = resolved
|
|
}
|
|
resolvedExtensionID := strings.TrimSpace(*extensionID)
|
|
if resolvedExtensionID == "" {
|
|
keyValue := strings.TrimSpace(*extensionKey)
|
|
if keyValue == "" && strings.TrimSpace(*extensionKeyFile) != "" {
|
|
data, err := os.ReadFile(strings.TrimSpace(*extensionKeyFile))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
keyValue = string(data)
|
|
}
|
|
if keyValue != "" {
|
|
derivedID, err := browserbridge.ChromiumExtensionIDFromManifestKey(keyValue)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
resolvedExtensionID = derivedID
|
|
}
|
|
}
|
|
installed, err := browserbridge.InstallManifest(browserbridge.Browser(strings.TrimSpace(*browserName)), path, resolvedExtensionID, strings.TrimSpace(*outputPath))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Fprintln(os.Stdout, installed)
|
|
return nil
|
|
}
|
|
|
|
func runStatus(args []string) error {
|
|
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")
|
|
if err := fs.Parse(args); err != nil {
|
|
return err
|
|
}
|
|
req := browserbridge.Request{
|
|
Action: "status",
|
|
GRPCAddress: strings.TrimSpace(*grpcAddr),
|
|
BearerToken: strings.TrimSpace(*token),
|
|
}
|
|
connCfg, err := req.Connection()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
conn, client, ctx, err := browserbridge.Dial(context.Background(), connCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() { _ = conn.Close() }()
|
|
resp := browserbridge.HandleRequest(ctx, req, client)
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(resp)
|
|
}
|
|
|
|
func runNativeMessage() error {
|
|
req, err := browserbridge.ReadRequest(os.Stdin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
connCfg, err := req.Connection()
|
|
if err != nil {
|
|
return browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()})
|
|
}
|
|
conn, client, ctx, err := browserbridge.Dial(context.Background(), connCfg)
|
|
if err != nil {
|
|
return browserbridge.WriteResponse(os.Stdout, browserbridge.Response{Success: false, Error: err.Error()})
|
|
}
|
|
defer func() { _ = conn.Close() }()
|
|
return browserbridge.WriteResponse(os.Stdout, browserbridge.HandleRequest(ctx, req, client))
|
|
}
|
|
|
|
func defaultBinaryPath() (string, error) {
|
|
self, err := os.Executable()
|
|
if err == nil && strings.TrimSpace(self) != "" {
|
|
return self, nil
|
|
}
|
|
self, err = exec.LookPath("keepassgo-browser-bridge")
|
|
if err == nil {
|
|
return self, nil
|
|
}
|
|
return filepath.Abs("./keepassgo-browser-bridge")
|
|
}
|
|
|
|
func fail(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|