github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbnm/installer/installer.go (about)

     1  package installer
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/keybase/client/go/kbnm/hostmanifest"
     9  )
    10  
    11  const kbnmAppName = "io.keybase.kbnm"
    12  
    13  // CurrentUser returns a hostmanifest.User while allowing for overrides using
    14  // environment variables:
    15  // * KBNM_INSTALL_ROOT != "" will force the user paths to be root
    16  // * KBNM_INSTALL_OVERLAY will prefix the paths
    17  func CurrentUser() (hostmanifest.User, error) {
    18  	u, err := hostmanifest.CurrentUser()
    19  	if err != nil {
    20  		return nil, err
    21  	}
    22  	if os.Getenv("KBNM_INSTALL_ROOT") != "" {
    23  		u.Admin = true
    24  		u.Path = ""
    25  	}
    26  	overlay := os.Getenv("KBNM_INSTALL_OVERLAY")
    27  	if overlay != "" {
    28  		u.Path = filepath.Join(overlay, u.Path)
    29  	}
    30  	return u, err
    31  }
    32  
    33  // UninstallKBNM removes NativeMessaging whitelisting for KBNM.
    34  func UninstallKBNM() error {
    35  	u, err := CurrentUser()
    36  	if err != nil {
    37  		return err
    38  	}
    39  
    40  	app := hostmanifest.App{
    41  		Name: kbnmAppName,
    42  	}
    43  
    44  	for _, whitelist := range hostmanifest.KnownInstallers() {
    45  		if err := whitelist.Uninstall(u, app); err != nil {
    46  			return err
    47  		}
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  // InstallKBNM writes NativeMessaging whitelisting for KBNM.
    54  func InstallKBNM(path string) error {
    55  	u, err := CurrentUser()
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	// If we're installing in an overlay, we need to strip it as a prefix from
    61  	// the path we detect.
    62  	overlay := os.Getenv("KBNM_INSTALL_OVERLAY")
    63  	if overlay != "" {
    64  		// This is a bit arcane because filepath.HasPrefix deprecated due to
    65  		// being broken, but what it does is it attempts to map path as
    66  		// relative to overlay. If it succeeds and they're both absolute paths
    67  		// (which means the relative path won't start with "../"), then make
    68  		// path an absolute path with the overlay removed
    69  		// filepath.Rel takes care of normalizing paths which is an advantage
    70  		// over direct string comparisons which would be simpler.
    71  		rel, err := filepath.Rel(overlay, path)
    72  		if err == nil && !strings.HasPrefix(rel, ".") {
    73  			path = "/" + rel
    74  		}
    75  	}
    76  
    77  	app := hostmanifest.App{
    78  		Name:        kbnmAppName,
    79  		Description: "Keybase Native Messaging API",
    80  		Path:        path,
    81  		Type:        "stdio",
    82  	}
    83  
    84  	var manifest hostmanifest.AppManifest
    85  	for browser, whitelist := range hostmanifest.KnownInstallers() {
    86  		switch browser {
    87  		case "chrome", "chromium":
    88  			manifest = hostmanifest.ChromeApp{
    89  				App: app,
    90  				AllowedOrigins: []string{
    91  					// Production public version in the store
    92  					"chrome-extension://ognfafcpbkogffpmmdglhbjboeojlefj/",
    93  					// Hard-coded key from the repo version
    94  					"chrome-extension://kockbbfoibcdfibclaojljblnhpnjndg/",
    95  					// Keybase-internal version
    96  					"chrome-extension://gnjkbjlgkpiaehpibpdefaieklbfljjm/",
    97  				},
    98  			}
    99  		case "firefox":
   100  			manifest = hostmanifest.FirefoxApp{
   101  				App: app,
   102  				AllowedExtensions: []string{
   103  					"keybase@keybase.io",
   104  				},
   105  			}
   106  		}
   107  
   108  		if err := whitelist.Install(u, manifest); err != nil {
   109  			return err
   110  		}
   111  	}
   112  	return nil
   113  }