Native Messaging Test Runner
The Native Messaging Test Runner is a Node application for testing the Native Messaging
functionality in Desktop, specifically the commands received from the DuckDuckGo browser. It
communicates with the desktop app using Inter-process communication (IPC). It was created to enable
development on the native messages themselves, and to give QA the ability to test these commands. It
is located
here at
the root of the desktop
app in bitwarden/clients
repo.
Getting Started
-
Clone the bitwarden/clients repo
-
Run the desktop app locally following these instructions
-
In the running desktop app, go to
Preferences
and turn on theAllow DuckDuckGo browser integration
setting: -
In a separate terminal, navigate into
apps/desktop/native-messaging-test-runner
-
Run
npm ci
-
Pick a command and run it! A good one to start with is
status
. A full list of commands can be seen in theCommands
section of this doc. Some commands take parameters such ascreate
. When running these, pass parameters the following way, with two additional dashes before all of the parameters:npm run create -- --name NewLogin!
NOTE You will need to accept the prompt in the desktop app before each command. This is for sure an area of improvement.
These commands are run against your local running desktop instance and whatever accounts you have in there. You will need to set up your accounts and vaults beforehand to test these commands properly.
Architecture and Structure
Commands
The commands folder contains the executable node scripts/commands. There is currently one file per native messaging command for testing.
-
handshake
Sends abw-handshake
command and establishes communication with the native messaging service in the desktop app- Parameters: none
- Example Usage:
npm run handshake
-
status
Sends abw-status
command and returns an array of the accounts configured in the desktop app.- Parameters: none
- Example Usage:
npm run status
-
create
Sends abw-credential-create
command and creates a new login with the provided name and test data for the other fields.- Parameters:
--name
- Example Usage:
npm run create -- --name NewLoginFromTestRunner
- Parameters:
-
update
Sends abw-credential-update
command and updates a credential with the provided fields.- Parameters:
--name
,--username
,--password
,--uri
,--credentialId
- Example Usage:
npm run update -- --name UpdateLoginFromTestRunner --username rmaccallum --password dolphin123 --uri google.com --credentialId 8fdd5921-4b10-4c47-9f92-af2b0106d63a
- Parameters:
-
retrieve
Sends abw-credential-retrieval
command and returns a list of credentials matching the uri provided- Parameters:
--uri
- Example Usage:
npm run retrieve -- --uri google.com
- Parameters:
-
generate
Sends abw-generate-password
command and returns a password/passphrase using the settings of the userId passed to it- Parameters:
--userId
- Example Usage:
npm run generate -- --userId fe2af956-a6a6-468c-bc8c-ae6600e48bdd
- Parameters:
IPCService
This service manages the connections to a socket and the sending and receiving of messages on that socket.
NativeMessageService
This service uses the IPCService to connect to the locally running Bitwarden desktop app's IPC proxy
service. It uses Bitwarden's crypto service and functions to handle encryption and decryption of the
messages. It utilizes a test public/private key pair located in the
/native-messaging-test-runner/src/variables.ts
file.
Other
I thought Node used JavaScript? How are we using TypeScript classes, including the ones from libs?
Great question! With a little magic✨ we are compiling these TypeScript files into the JavaScript that Node knows and loves. This is done is with a couple of mechanisms:
-
tsconfig.json
: In thepaths
node of this file, the files in the paths provided are compiled into pure JavaScript and placed in thedist
folder. -
package.json
: Themodule_alias
is installed which allows us to map any services used in the TypeScript files to their compiled JavaScript equivalents. The paths of the files that are used directly in any of the command files are defined in the"_moduleAliases"
node of the package.json.
Deferred
Class that overrides the default implementations of the JavaScript Promise
interface's resolve
and reject
methods in order to allow us to await responses to messages sent over IPC.
logUtils
Utils class that adds nice color formatting to console.log()
s throughout this app.
race
Utility used by the IPCService
when creating a promise that allows the usage of a timeout when
waiting for messages. We can't guarantee that we will get a response from the desktop app, so this
allows us to gracefully cancel if a response isn't received in a timely manner.
Troubleshooting
-
If you are seeing unexpected behavior with services used by the test runner or when editing commands, delete the
dist
folder at the top level of thenative-messaging-test-runner
and re-run the command. -
If you are adding/editing command files and getting a
MODULE_NOT_FOUND
error when running the command, make sure you haveimport "module-alias/register";
in your command file. This maps the compiled JavaScript classes to the ones used in the Typescript files.