Skip to content

Commit

Permalink
Merge pull request #89729 from JJJollyjim/bitwarden-rs-test
Browse files Browse the repository at this point in the history
nixos/bitwarden_rs: add test
  • Loading branch information
Lassulus committed Aug 22, 2020
2 parents d118333 + f5f2d89 commit dd2ecd0
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 2 deletions.
6 changes: 6 additions & 0 deletions maintainers/maintainer-list.nix
Expand Up @@ -3835,6 +3835,12 @@
githubId = 51518420;
name = "jitwit";
};
jjjollyjim = {
email = "jamie@kwiius.com";
github = "JJJollyjim";
githubId = 691552;
name = "Jamie McClymont";
};
jk = {
email = "hello+nixpkgs@j-k.io";
github = "06kellyjac";
Expand Down
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Expand Up @@ -34,6 +34,7 @@ in
bind = handleTest ./bind.nix {};
bitcoind = handleTest ./bitcoind.nix {};
bittorrent = handleTest ./bittorrent.nix {};
bitwarden = handleTest ./bitwarden.nix {};
blockbook-frontend = handleTest ./blockbook-frontend.nix {};
buildkite-agents = handleTest ./buildkite-agents.nix {};
boot = handleTestOn ["x86_64-linux"] ./boot.nix {}; # syslinux is unsupported on aarch64
Expand Down
188 changes: 188 additions & 0 deletions nixos/tests/bitwarden.nix
@@ -0,0 +1,188 @@
{ system ? builtins.currentSystem
, config ? { }
, pkgs ? import ../.. { inherit system config; }
}:

# These tests will:
# * Set up a bitwarden-rs server
# * Have Firefox use the web vault to create an account, log in, and save a password to the valut
# * Have the bw cli log in and read that password from the vault
#
# Note that Firefox must be on the same machine as the server for WebCrypto APIs to be available (or HTTPS must be configured)
#
# The same tests should work without modification on the official bitwarden server, if we ever package that.

with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
let
backends = [ "sqlite" "mysql" "postgresql" ];

dbPassword = "please_dont_hack";

userEmail = "meow@example.com";
userPassword = "also_super_secret_ZJWpBKZi668QGt"; # Must be complex to avoid interstitial warning on the signup page

storedPassword = "seeeecret";

makeBitwardenTest = backend: makeTest {
name = "bitwarden_rs-${backend}";
meta = {
maintainers = with pkgs.stdenv.lib.maintainers; [ jjjollyjim ];
};

nodes = {
server = { pkgs, ... }:
let backendConfig = {
mysql = {
services.mysql = {
enable = true;
initialScript = pkgs.writeText "mysql-init.sql" ''
CREATE DATABASE bitwarden;
CREATE USER 'bitwardenuser'@'localhost' IDENTIFIED BY '${dbPassword}';
GRANT ALL ON `bitwarden`.* TO 'bitwardenuser'@'localhost';
FLUSH PRIVILEGES;
'';
package = pkgs.mysql;
};

services.bitwarden_rs.config.databaseUrl = "mysql://bitwardenuser:${dbPassword}@localhost/bitwarden";

systemd.services.bitwarden_rs.after = [ "mysql.service" ];
};

postgresql = {
services.postgresql = {
enable = true;
initialScript = pkgs.writeText "postgresql-init.sql" ''
CREATE DATABASE bitwarden;
CREATE USER bitwardenuser WITH PASSWORD '${dbPassword}';
GRANT ALL PRIVILEGES ON DATABASE bitwarden TO bitwardenuser;
'';
};

services.bitwarden_rs.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";

systemd.services.bitwarden_rs.after = [ "postgresql.service" ];
};

sqlite = { };
};
in
mkMerge [
backendConfig.${backend}
{
services.bitwarden_rs = {
enable = true;
dbBackend = backend;
config.rocketPort = 80;
};

networking.firewall.allowedTCPPorts = [ 80 ];

environment.systemPackages =
let
testRunner = pkgs.writers.writePython3Bin "test-runner"
{
libraries = [ pkgs.python3Packages.selenium ];
} ''
from selenium.webdriver import Firefox
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = Options()
options.add_argument('--headless')
driver = Firefox(options=options)
driver.implicitly_wait(20)
driver.get('http://localhost/#/register')
wait = WebDriverWait(driver, 10)
wait.until(EC.title_contains("Create Account"))
driver.find_element_by_css_selector('input#email').send_keys(
'${userEmail}'
)
driver.find_element_by_css_selector('input#name').send_keys(
'A Cat'
)
driver.find_element_by_css_selector('input#masterPassword').send_keys(
'${userPassword}'
)
driver.find_element_by_css_selector('input#masterPasswordRetype').send_keys(
'${userPassword}'
)
driver.find_element_by_xpath("//button[contains(., 'Submit')]").click()
wait.until_not(EC.title_contains("Create Account"))
driver.find_element_by_css_selector('input#masterPassword').send_keys(
'${userPassword}'
)
driver.find_element_by_xpath("//button[contains(., 'Log In')]").click()
wait.until(EC.title_contains("My Vault"))
driver.find_element_by_xpath("//button[contains(., 'Add Item')]").click()
driver.find_element_by_css_selector('input#name').send_keys(
'secrets'
)
driver.find_element_by_css_selector('input#loginPassword').send_keys(
'${storedPassword}'
)
driver.find_element_by_xpath("//button[contains(., 'Save')]").click()
'';
in
[ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];

virtualisation.memorySize = 768;
}
];

client = { pkgs, ... }:
{
environment.systemPackages = [ pkgs.bitwarden-cli ];
};
};

testScript = ''
start_all()
server.wait_for_unit("bitwarden_rs.service")
server.wait_for_open_port(80)
with subtest("configure the cli"):
client.succeed("bw --nointeraction config server http://server")
with subtest("can't login to nonexistant account"):
client.fail(
"bw --nointeraction --raw login ${userEmail} ${userPassword}"
)
with subtest("use the web interface to sign up, log in, and save a password"):
server.succeed("PYTHONUNBUFFERED=1 test-runner | systemd-cat -t test-runner")
with subtest("log in with the cli"):
key = client.succeed(
"bw --nointeraction --raw login ${userEmail} ${userPassword}"
).strip()
with subtest("sync with the cli"):
client.succeed(f"bw --nointeraction --raw --session {key} sync -f")
with subtest("get the password with the cli"):
password = client.succeed(
f"bw --nointeraction --raw --session {key} list items | ${pkgs.jq}/bin/jq -r .[].login.password"
)
assert password.strip() == "${storedPassword}"
'';
};
in
builtins.listToAttrs (
map
(backend: { name = backend; value = makeBitwardenTest backend; })
backends
)
4 changes: 3 additions & 1 deletion pkgs/tools/security/bitwarden_rs/default.nix
@@ -1,4 +1,4 @@
{ stdenv, rustPlatform, fetchFromGitHub
{ stdenv, rustPlatform, fetchFromGitHub, nixosTests
, pkgconfig, openssl
, Security, CoreServices
, dbBackend ? "sqlite", libmysqlclient, postgresql }:
Expand Down Expand Up @@ -35,6 +35,8 @@ in rustPlatform.buildRustPackage rec {
runHook postCheck
'';

passthru.tests = nixosTests.bitwarden;

meta = with stdenv.lib; {
description = "Unofficial Bitwarden compatible server written in Rust";
homepage = "https://github.com/dani-garcia/bitwarden_rs";
Expand Down
4 changes: 3 additions & 1 deletion pkgs/tools/security/bitwarden_rs/vault.nix
@@ -1,4 +1,4 @@
{ stdenv, fetchurl }:
{ stdenv, fetchurl, nixosTests }:

stdenv.mkDerivation rec {
pname = "bitwarden_rs-vault";
Expand All @@ -16,6 +16,8 @@ stdenv.mkDerivation rec {
mv web-vault vault
'';

passthru.tests = nixosTests.bitwarden;

meta = with stdenv.lib; {
description = "Integrates the web vault into bitwarden_rs";
homepage = "https://github.com/dani-garcia/bw_web_builds";
Expand Down

0 comments on commit dd2ecd0

Please sign in to comment.