Skip to content

rickypc/native-messaging-host

Repository files navigation

Build Coverage Dependabot GoDev GoDoc License

Native Messaging Host Module for Go

native-messaging-host is a module for sending native messaging protocol message marshalled from struct and receiving native messaging protocol message unmarshalled to struct. native-messaging-host can auto-update itself using update URL that response with Google Chrome update manifest, as well as it provides hook to install and uninstall manifest file to native messaging host location.

Installation and Usage

Package documentation can be found on GoDev or GoDoc.

Installation can be done with a normal go get:

$ go get github.com/rickypc/native-messaging-host

Sending Message

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
response := &host.H{"key":"value"}

// Write message from response to os.Stdout.
if err := messaging.PostMessage(os.Stdout, response); err != nil {
  log.Fatalf("messaging.PostMessage error: %v", err)
}

// Log response.
log.Printf("response: %+v", response)

Receiving Message

// Ensure func main returned after calling [runtime.Goexit][5].
defer os.Exit(0)

messaging := (&host.Host{}).Init()

// host.H is a shortcut to map[string]interface{}
request := &host.H{}

// Read message from os.Stdin to request.
if err := messaging.OnMessage(os.Stdin, request); err != nil {
  log.Fatalf("messaging.OnMessage error: %v", err)
}

// Log request.
log.Printf("request: %+v", request)

Auto Update Configuration

updates.xml example for cross platform executable:

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.all' version='1.0.0' />
  </app>
</gupdate>

updates.xml example for individual platform executable:

<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
  <app appid='tld.domain.sub.app.name'>
    <updatecheck codebase='https://sub.domain.tld/app.download.darwin' os='darwin' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.linux' os='linux' version='1.0.0' />
    <updatecheck codebase='https://sub.domain.tld/app.download.exe' os='windows' version='1.0.0' />
  </app>
</gupdate>
// It will do daily update check.
messaging := (&host.Host{
  AppName:   "tld.domain.sub.app.name",
  UpdateUrl: "https://sub.domain.tld/updates.xml", // It follows [update manifest][2]
  Version:   "1.0.0",                              // Current version, it must follow [SemVer][6]
}).Init()

Install and Uninstall Hooks

// AllowedExts is a list of extensions that should have access to the native messaging host. 
// See [native messaging manifest](https://bit.ly/3aDA1Hv)
messaging := (&host.Host{
  AppName:     "tld.domain.sub.app.name",
  AllowedExts: []string{"chrome-extension://XXX/", "chrome-extension://YYY/"},
}).Init()

...

// When you need to install.
if err := messaging.Install(); err != nil {
  log.Printf("install error: %v", err)
}

...

// When you need to uninstall.
host.Uninstall()

Syntactic Sugar

You can import client package separately.

import "github.com/rickypc/native-messaging-host/client"
GET call with context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resp := client.MustGetWithContext(ctx, "https://domain.tld")
defer resp.Body.Close()
GET call with tar.gz content
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

client.MustGetAndUntarWithContext(ctx, "https://domain.tld", "/path/to/extract")
GET call with zip content
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

client.MustGetAndUnzipWithContext(ctx, "https://domain.tld", "/path/to/extract")
POST call with context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

resp := client.MustPostWithContext(ctx, "https://domain.tld", "application/json", strings.NewReader("{}"))
defer resp.Body.Close()

Contributing

If you would like to contribute code to Native Messaging Host repository you can do so through GitHub by forking the repository and sending a pull request.

If you do not agree to Contribution Agreement, do not contribute any code to Native Messaging Host repository.

When submitting code, please make every effort to follow existing conventions and style in order to keep the code as readable as possible. Please also include appropriate test cases.

That's it! Thank you for your contribution!

License

Copyright (c) 2018 - 2022 Richard Huang.

This utility is free software, licensed under: Mozilla Public License (MPL-2.0).

Documentation and other similar content are provided under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.