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
Preferencesand turn on theAllow DuckDuckGo browser integrationsetting:
-
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 theCommandssection 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.
-
handshakeSends abw-handshakecommand and establishes communication with the native messaging service in the desktop app- Parameters: none
- Example Usage:
npm run handshake
-
statusSends abw-statuscommand and returns an array of the accounts configured in the desktop app.- Parameters: none
- Example Usage:
npm run status
-
createSends abw-credential-createcommand 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:
-
updateSends abw-credential-updatecommand 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:
-
retrieveSends abw-credential-retrievalcommand and returns a list of credentials matching the uri provided- Parameters:
--uri - Example Usage:
npm run retrieve -- --uri google.com
- Parameters:
-
generateSends abw-generate-passwordcommand 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 thepathsnode of this file, the files in the paths provided are compiled into pure JavaScript and placed in thedistfolder. -
package.json: Themodule_aliasis 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
distfolder at the top level of thenative-messaging-test-runnerand re-run the command. -
If you are adding/editing command files and getting a
MODULE_NOT_FOUNDerror 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.