2020-06-06 10:55:50 +00:00
|
|
|
{ system ? builtins.currentSystem
|
|
|
|
, config ? { }
|
|
|
|
, pkgs ? import ../.. { inherit system config; }
|
|
|
|
}:
|
|
|
|
|
|
|
|
# These tests will:
|
2021-07-01 09:14:51 +00:00
|
|
|
# * Set up a vaultwarden server
|
2020-06-06 10:55:50 +00:00
|
|
|
# * 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";
|
|
|
|
|
2021-07-01 09:14:51 +00:00
|
|
|
makeVaultwardenTest = backend: makeTest {
|
|
|
|
name = "vaultwarden-${backend}";
|
2020-06-06 10:55:50 +00:00
|
|
|
meta = {
|
2021-01-10 19:08:30 +00:00
|
|
|
maintainers = with pkgs.lib.maintainers; [ jjjollyjim ];
|
2020-06-06 10:55:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
'';
|
2021-06-04 14:08:41 +00:00
|
|
|
package = pkgs.mariadb;
|
2020-06-06 10:55:50 +00:00
|
|
|
};
|
|
|
|
|
2021-07-01 09:14:51 +00:00
|
|
|
services.vaultwarden.config.databaseUrl = "mysql://bitwardenuser:${dbPassword}@localhost/bitwarden";
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2021-07-01 09:14:51 +00:00
|
|
|
systemd.services.vaultwarden.after = [ "mysql.service" ];
|
2020-06-06 10:55:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2021-07-01 09:14:51 +00:00
|
|
|
services.vaultwarden.config.databaseUrl = "postgresql://bitwardenuser:${dbPassword}@localhost/bitwarden";
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2021-07-01 09:14:51 +00:00
|
|
|
systemd.services.vaultwarden.after = [ "postgresql.service" ];
|
2020-06-06 10:55:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
sqlite = { };
|
|
|
|
};
|
|
|
|
in
|
|
|
|
mkMerge [
|
|
|
|
backendConfig.${backend}
|
|
|
|
{
|
2021-07-01 09:14:51 +00:00
|
|
|
services.vaultwarden = {
|
2020-06-06 10:55:50 +00:00
|
|
|
enable = true;
|
|
|
|
dbBackend = backend;
|
2022-07-28 00:00:28 +00:00
|
|
|
config = {
|
|
|
|
rocketAddress = "0.0.0.0";
|
|
|
|
rocketPort = 80;
|
|
|
|
};
|
2020-06-06 10:55:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
|
|
|
|
|
|
|
environment.systemPackages =
|
|
|
|
let
|
|
|
|
testRunner = pkgs.writers.writePython3Bin "test-runner"
|
|
|
|
{
|
|
|
|
libraries = [ pkgs.python3Packages.selenium ];
|
2022-12-14 13:56:34 +00:00
|
|
|
flakeIgnore = [
|
|
|
|
"E501"
|
|
|
|
];
|
2020-06-06 10:55:50 +00:00
|
|
|
} ''
|
2022-07-28 00:00:28 +00:00
|
|
|
|
|
|
|
from selenium.webdriver.common.by import By
|
2020-06-06 10:55:50 +00:00
|
|
|
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)
|
|
|
|
|
2023-01-12 09:48:12 +00:00
|
|
|
wait.until(EC.title_contains("Create account"))
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2022-12-14 13:56:34 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_email').send_keys(
|
|
|
|
'${userEmail}'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2022-12-14 13:56:34 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_name').send_keys(
|
|
|
|
'A Cat'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2022-12-14 13:56:34 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_master-password').send_keys(
|
|
|
|
'${userPassword}'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2022-12-14 13:56:34 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#register-form_input_confirm-master-password').send_keys(
|
|
|
|
'${userPassword}'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2023-03-28 02:44:49 +00:00
|
|
|
if driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').is_selected():
|
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#checkForBreaches').click()
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2023-01-12 09:48:12 +00:00
|
|
|
driver.find_element(By.XPATH, "//button[contains(., 'Create account')]").click()
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2023-01-12 09:48:12 +00:00
|
|
|
wait.until_not(EC.title_contains("Create account"))
|
|
|
|
|
|
|
|
driver.find_element(By.XPATH, "//button[contains(., 'Continue')]").click()
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2022-12-14 13:56:34 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#login_input_master-password').send_keys(
|
|
|
|
'${userPassword}'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2023-01-12 09:48:12 +00:00
|
|
|
driver.find_element(By.XPATH, "//button[contains(., 'Log in')]").click()
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2023-03-28 02:44:49 +00:00
|
|
|
wait.until(EC.title_contains("Vaults"))
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2023-03-28 02:44:49 +00:00
|
|
|
driver.find_element(By.XPATH, "//button[contains(., 'New item')]").click()
|
2020-06-06 10:55:50 +00:00
|
|
|
|
2022-07-28 00:00:28 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#name').send_keys(
|
2022-12-14 13:56:34 +00:00
|
|
|
'secrets'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
2022-07-28 00:00:28 +00:00
|
|
|
driver.find_element(By.CSS_SELECTOR, 'input#loginPassword').send_keys(
|
2022-12-14 13:56:34 +00:00
|
|
|
'${storedPassword}'
|
2020-06-06 10:55:50 +00:00
|
|
|
)
|
|
|
|
|
2022-07-28 00:00:28 +00:00
|
|
|
driver.find_element(By.XPATH, "//button[contains(., 'Save')]").click()
|
2020-06-06 10:55:50 +00:00
|
|
|
'';
|
|
|
|
in
|
|
|
|
[ pkgs.firefox-unwrapped pkgs.geckodriver testRunner ];
|
|
|
|
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
client = { pkgs, ... }:
|
|
|
|
{
|
|
|
|
environment.systemPackages = [ pkgs.bitwarden-cli ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
testScript = ''
|
|
|
|
start_all()
|
2021-07-01 09:14:51 +00:00
|
|
|
server.wait_for_unit("vaultwarden.service")
|
2020-06-06 10:55:50 +00:00
|
|
|
server.wait_for_open_port(80)
|
|
|
|
|
|
|
|
with subtest("configure the cli"):
|
|
|
|
client.succeed("bw --nointeraction config server http://server")
|
|
|
|
|
2022-12-18 00:31:14 +00:00
|
|
|
with subtest("can't login to nonexistent account"):
|
2020-06-06 10:55:50 +00:00
|
|
|
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
|
2021-07-01 09:14:51 +00:00
|
|
|
(backend: { name = backend; value = makeVaultwardenTest backend; })
|
2020-06-06 10:55:50 +00:00
|
|
|
backends
|
|
|
|
)
|