External API

The extension provides an external API to allow other apps/extensions make requests using the Chrome messaging API.

There are simple one-time messages (with a single response) APIs, as well as some longer-lived connection-based APIs.

General

All API responses take the basic form (some commands might contain more fields):

Field nameTypeDescription
errorboolWhether the request succeeded.
message!stringA short message providing more details.
stack?stringA JavaScript stack trace for errors.

Messages

These APIs are simple one-time messages: you send a single request and get back a single response.

The nassh background page adds a listener for chrome.runtime.onMessage (internal) and chrome.runtime.onMessageExternal (external) which can be invoked by other apps / extensions by calling chrome.runtime.sendMessage. The possible messages are documented in the next sections, but they all must have the command field set to select the right function.

Example

External callers can make requests like:

// Extension id for stable Secure Shell.
const id = 'iodihamcpbpeioajjeobimgagajmlibd';

// Open a new crosh window.
const msg = {
  'command': 'crosh',
};

// Send the request and wait for a response.
chrome.runtime.sendMessage(id, msg, null, (response) => {
  if (chrome.runtime.lastError) {
    console.log(`Extension doesn't exist: ${chrome.runtime.lastError.message}`);
    //onError();
  } else {
    if (response.error) {
      console.log(`Remote failed:`, response);
      //onError();
    } else {
      console.log(`Remote worked:`, response);
      //onSuccess();
    }
  }
});

Internal callers use the same form but omit id as it'll automatically go to the right background page.

API

Hello

This is a simple stub message to help with debugging. It will respond with some basic messaging details.

Field nameTypeDescription
command!stringMust be hello.

The response will have these additional fields:

Field nameTypeDescription
message!stringWill be hello.
internalboolWhether the sender is the same extension.
idstringThe extension id of the sender.

Mount

On ChromeOS, trigger a SFTP filesystem mount with the Files app.

This is a one-shot API that does not allow for interactive UI. It is meant to automatically set up connections that use key auth only.

Field nameTypeDescription
command!stringMust be mount.
knownHosts!stringFile contents of known_hosts to be used for connection. e.g. output from ssh-keyscan <ssh-server>
identityFile!stringFile contents of private key identity_file (e.g. contents of id_rsa file -----BEGIN RSA PRIVATE KEY----- ...)
username!stringUsername for connection
hostname!stringHostname or IP address for connection
portnumber=Port, default is 22
fileSystemId!stringID used for ChromeOS mounted filesystem
displayName!stringDisplay name in ChromeOS Files.app for mounted filesystem

Unmount

On ChromeOS, unmount an existing SFTP filesystem mount.

Field nameTypeDescription
command!stringMust be unmount.
fileSystemId!stringID used for ChromeOS mounted filesystem.

Get Mount Info

On ChromeOS, return information about a particular mount.

On success, the information will be returned in the data field.

Field nameTypeDescription
command!stringMust be getMountInfo.
fileSystemId!stringID used for ChromeOS mounted filesystem.

The response will have these additional fields:

Field nameTypeDescription
info?ObjectThe mount information.

Set Mount Info

On ChromeOS, update configuration for a particular mount. Note: Not all fields are configurable.

Field nameTypeDescription
command!stringMust be setMountInfo.
fileSystemId!stringID used for ChromeOS mounted filesystem.
info!ObjectNew settings to use.

Crosh

On ChromeOS, open a new crosh session.

Field nameTypeDescription
command!stringMust be crosh.
heightnumber=The height of the new window.
widthnumber=The width of the new window.

Nassh

Open a new ssh session.

Field nameTypeDescription
command!stringMust be nassh.
heightnumber=The height of the new window.
widthnumber=The width of the new window.
urlstring=(internal) URL to open instead for specific profiles.

Import Preferences

NB: This is only available to Secure Shell itself.

Import saved preferences for nassh & hterm.

Field nameTypeDescription
command!stringMust be prefsImport.
prefs!ObjectThe preferences to import.
asJsonbool=Whether the prefs are a JSON string.

Export Preferences

NB: This is only available to Secure Shell itself.

Export saved preferences for nassh & hterm.

Field nameTypeDescription
command!stringMust be prefsExport.
asJsonbool=Whether the prefs will be a JSON string.

The response will have these additional fields:

Field nameTypeDescription
prefs!ObjectThe exported preferences as JSON or an object.

Protocol Registration

Open a dedicated page for registering protocol handlers (e.g. ssh://). The web platform does not allow us to register handlers without user intent, so this provides a simple/clear UI for users to manually trigger.

Field nameTypeDescription
command!stringMust be openProtoReg.

Connections

These APIs are more complicated: they create a bidirection channel for sending & receiving multiple messages.

The nassh background page adds a listener for chrome.runtime.onConnect (internal) and chrome.runtime.onConnectExternal (external) which can be invoked by other apps / extensions by calling chrome.runtime.connect. The possible endpoints are documented in the next sections. The name field from the initial connect call is used to select the endpoint.

Unknown requests will usually result in an immediate error and the channel being closed, so make sure to listen for onDisconnect events!

Example

External callers can make requests like:

// Extension id for stable Secure Shell.
const id = 'iodihamcpbpeioajjeobimgagajmlibd';

// Connect to the 'hello' endpoint.
const port = chrome.runtime.connect(id, {name: 'hello'});

// Listen for new messages from Secure Shell.
port.onMessage((msg) => {
  console.log('Received message:', msg);
});

// Listen for disconnect events.
port.onDisconnect(() => {
  if (chrome.runtime.lastError) {
    console.log(`Connection aborted: ${chrome.runtime.lastError.message}`);
    //onError();
  } else {
    console.log('Connection finished');
  }
});

// Send some messages over the channel.
// NB: Responses will be handled via the event listener above, not here.
port.postMessage('hello');
port.postMessage('hi');
// Secure Shell will close the channel after this message.
port.postMessage('bye');

Internal callers use the same form but omit id as it'll automatically go to the right background page.

API

Hello

This is a simple stub endpoint to help with debugging.

The input message will be a simple string.

It will respond with some basic messaging details.

port.postMessage('hello');
port.postMessage('hi');
port.postMessage('bye');

The response will have these additional fields:

Field nameTypeDescription
message!stringA random friendly response.
internalboolWhether the sender is the same extension.
idstringThe extension id of the sender.

Mount

NB: This is only available to Secure Shell itself.

On ChromeOS, trigger a SFTP filesystem mount with the Files app.

This API allows for interactive auth, so it's a bit more complicated.

Requests

These are messages sent to the background page.

# Create a new mount connection.
{
  command: 'connect',
  # Arguments to CommandInstance.
  argv: {...},
  # Arguments to CommandInstance.connectTo.
  connectOptions: {...},
}
# Write data to the connection (e.g. user input).
{
  command: 'write',
  data: '...',
}
# Return secure user input.
{
  command: 'input',
  data: '...',
}

Responses

These are messages sent to the foreground page.

# An error occurred, usually at the JS level rather than SSH.
{
  error: true,
  message: 'Information about the error',
}

All other responses will have error=false.

# Write data to the terminal (e.g. ssh client/server messages).
{
  command: 'write',
  message: 'The data to display',
}
# Display a message using the terminal overlay UI.
{
  command: 'overlay',
  message: 'The message to display',
  # How long to display the overlay.
  timeout: number|null,
}
# Get secure user input from the user.
{
  command: 'input',
  message: 'The prompt to display',
  # Whether to display user input as they enter it.
  echo: bool,
  # The max input we expect.
  length: number,
}
# The process has exited prematurely.
{
  command: 'exit',
  # The process exit status.
  status: number,
}
# The mount has been setup.
{
  command: 'done',
}