From ae30a69f523c583100604f36c3927315f56887d9 Mon Sep 17 00:00:00 2001 From: Jonathan Hope Date: Mon, 4 Dec 2023 22:56:50 -0800 Subject: [PATCH] feat: chromium manifest --- .goreleaser.yaml | 6 ++- cmd/cli/cmd/cmd.go | 28 +++++++++++++- internal/paths/paths.go | 35 +++++++++++++++++ internal/paths/paths_test.go | 74 ++++++++++++++++++++++++++++++++++++ pkg/api/install_manfiest.go | 12 +++++- 5 files changed, 151 insertions(+), 4 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 35b714e..6138f51 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -166,7 +166,7 @@ snapcrafts: apps: armaria: command: armaria - plugs: ["dot-mozilla", "dot-chrome"] + plugs: ["dot-mozilla", "dot-chrome", "dot-chromium"] armaria-host: command: armaria-host plugs: @@ -178,3 +178,7 @@ snapcrafts: interface: personal-files write: - $HOME/.config/google-chrome/NativeMessagingHosts + dot-chromium: + interface: personal-files + write: + - $HOME/.config/chromium/NativeMessagingHosts diff --git a/cmd/cli/cmd/cmd.go b/cmd/cli/cmd/cmd.go index a966220..d76ee6c 100644 --- a/cmd/cli/cmd/cmd.go +++ b/cmd/cli/cmd/cmd.go @@ -75,8 +75,9 @@ type ManifestCmd struct { // InstallManifestCmd is a CLI command to the app manifest. type InstallManifestCmd struct { - Firefox InstallFirefoxManifestCmd `cmd:"" help:"Install the app manifest for Firefox."` - Chrome InstallChromeManifestCmd `cmd:"" help:"Install the app manifest for Chrome."` + Firefox InstallFirefoxManifestCmd `cmd:"" help:"Install the app manifest for Firefox."` + Chrome InstallChromeManifestCmd `cmd:"" help:"Install the app manifest for Chrome."` + Chromium InstallChromiumManifestCmd `cmd:"" help:"Install the app manifest for Chromium."` } // AddBookCmd is a CLI command to add a bookmark. @@ -735,3 +736,26 @@ func (r *InstallChromeManifestCmd) Run(ctx *Context) error { return nil } + +// InstallChromiumManifestCmd is a CLI command to install the app manifest for Chromium. +type InstallChromiumManifestCmd struct { +} + +// Run install app manifest for Chromium. +func (r *InstallChromiumManifestCmd) Run(ctx *Context) error { + start := time.Now() + + err := armariaapi.InstallManifestChromium() + + if err != nil { + formatError(ctx.Writer, ctx.Formatter, err) + ctx.ReturnCode(1) + return nil + } + + elapsed := time.Since(start) + + formatSuccess(ctx.Writer, ctx.Formatter, fmt.Sprintf("Installed in %s", elapsed)) + + return nil +} diff --git a/internal/paths/paths.go b/internal/paths/paths.go index 824a1b8..1735be3 100644 --- a/internal/paths/paths.go +++ b/internal/paths/paths.go @@ -222,6 +222,41 @@ func chromeManifestInternal(goos string, getenv getenvFn, userHome userHomeFn, j return join(folder, manifestFilename), nil } +// Chromium Manifest gets the path to the Chromium app manifest. +// The path is different per platform and maps to the following: +// - Linux: ~/.config/chromium/NativeMessagingHosts +// - Windows: ~/AppData/Local/Armaria +// - Mac: ~/Library/Application Support/Chromium +func ChromiumManifest() (string, error) { + return chromiumManifestInternal(runtime.GOOS, os.Getenv, os.UserHomeDir, filepath.Join, os.MkdirAll) +} + +// chromiumManifestInternal allows DI for ChromiumManifest. +func chromiumManifestInternal(goos string, getenv getenvFn, userHome userHomeFn, join joinFn, mkDirAll mkDirAllFn) (string, error) { + home, err := realHome(getenv, userHome) + if err != nil { + return "", fmt.Errorf("error getting real home dir while getting chromium manifest path: %w", err) + } + + var folder string + if goos == "linux" { + folder = join(home, ".config", "chromium", "NativeMessagingHosts") + } else if goos == "windows" { + // The manifest can be anywhere in Windows, but it needs a supporting registry entry. + folder = join(home, "AppData", "Local", "Armaria") + } else if goos == "darwin" { + folder = join(home, "Library", "Application Support", "Chromium", "NativeMessagingHosts") + } else { + panic("Unsupported operating system") + } + + if err = mkDirAll(folder, os.ModePerm); err != nil { + return "", fmt.Errorf("error creating folder while getting chromium manifest path: %w", err) + } + + return join(folder, manifestFilename), nil +} + // realHome returns the true home directory of the current user. // Snap will replace the $HOME env var with a sandboxed directory. func realHome(getenv getenvFn, userHome userHomeFn) (string, error) { diff --git a/internal/paths/paths_test.go b/internal/paths/paths_test.go index b29cbeb..79145cb 100644 --- a/internal/paths/paths_test.go +++ b/internal/paths/paths_test.go @@ -391,3 +391,77 @@ func TestChromeManifestPath(t *testing.T) { }) } } + +func TestChromiumManifestPath(t *testing.T) { + type test struct { + goos string + folderPath string + folderCreated bool + snapRealHome string + manifestPath string + } + + tests := []test{ + { + goos: "windows", + folderPath: "~/AppData/Local/Armaria", + folderCreated: true, + manifestPath: "~/AppData/Local/Armaria/armaria.json", + }, + { + goos: "linux", + folderPath: "~/.config/chromium/NativeMessagingHosts", + folderCreated: true, + manifestPath: "~/.config/chromium/NativeMessagingHosts/armaria.json", + }, + { + goos: "linux", + folderPath: "~/snap/.config/chromium/NativeMessagingHosts", + folderCreated: true, + snapRealHome: "~/snap", + manifestPath: "~/snap/.config/chromium/NativeMessagingHosts/armaria.json", + }, + { + goos: "darwin", + folderPath: "~/Library/Application Support/Chromium/NativeMessagingHosts", + folderCreated: true, + manifestPath: "~/Library/Application Support/Chromium/NativeMessagingHosts/armaria.json", + }, + } + + userHome := func() (string, error) { + return "~", nil + } + + for _, tc := range tests { + t.Run(fmt.Sprintf("GOOS: %s, SNAP_REAL_HOME: %s", tc.goos, tc.snapRealHome), func(t *testing.T) { + folderCreated := false + + mkDirAll := func(path string, perm os.FileMode) error { + folderCreated = true + if path != tc.folderPath { + t.Errorf("folder: got %+v; want %+v", path, tc.folderPath) + } + + return nil + } + + getenv := func(key string) string { + return tc.snapRealHome + } + + got, err := chromiumManifestInternal(tc.goos, getenv, userHome, path.Join, mkDirAll) + if err != nil { + t.Fatalf("unexpected error: %+v", err) + } + + if folderCreated != tc.folderCreated { + t.Fatalf("folder created: got %+v; want %+v", folderCreated, tc.folderCreated) + } + + if got != tc.manifestPath { + t.Errorf("manfiestPath: got %+v; want %+v", got, tc.manifestPath) + } + }) + } +} diff --git a/pkg/api/install_manfiest.go b/pkg/api/install_manfiest.go index 1742739..02368e6 100644 --- a/pkg/api/install_manfiest.go +++ b/pkg/api/install_manfiest.go @@ -31,6 +31,16 @@ func InstallManifestChrome() error { return installManifest(path) } +// InstallManifestChromium installs the app manifest for Firefox. +func InstallManifestChromium() error { + path, err := paths.ChromiumManifest() + if err != nil { + return fmt.Errorf("error getting chromium manfiest path while installing manifest: %w", err) + } + + return installManifest(path) +} + // installManifest installs the app manifest. func installManifest(path string) error { hostPath, err := paths.Host() @@ -45,7 +55,7 @@ func installManifest(path string) error { Path: hostPath, HostType: "stdio", AllowedExtensions: []string{"armaria@armaria.net"}, - AllowedOrigins: []string{"chrome-extension://armaria/"}, + AllowedOrigins: []string{"chrome-extension://cahkgigfdplmhgjbioakkgennhncioli/"}, } buffer, err := json.Marshal(manifest)