Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2025-02-07 11:17:02 +01:00
Membership::confirm_user_invitations fix and tests
Dieser Commit ist enthalten in:
Ursprung
3ec4b0c476
Commit
da8be29de0
7 geänderte Dateien mit 381 neuen und 190 gelöschten Zeilen
170
playwright/tests/organization.smtp.spec.ts
Normale Datei
170
playwright/tests/organization.smtp.spec.ts
Normale Datei
|
@ -0,0 +1,170 @@
|
||||||
|
import { test, expect, type TestInfo } from '@playwright/test';
|
||||||
|
import { MailDev } from 'maildev';
|
||||||
|
|
||||||
|
import * as utils from "../global-utils";
|
||||||
|
import { createAccount, logUser } from './setups/user';
|
||||||
|
|
||||||
|
let users = utils.loadEnv();
|
||||||
|
|
||||||
|
let mailserver, user1Mails, user2Mails, user3Mails;
|
||||||
|
|
||||||
|
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
||||||
|
mailserver = new MailDev({
|
||||||
|
port: process.env.MAILDEV_SMTP_PORT,
|
||||||
|
web: { port: process.env.MAILDEV_HTTP_PORT },
|
||||||
|
})
|
||||||
|
|
||||||
|
await mailserver.listen();
|
||||||
|
|
||||||
|
await utils.startVaultwarden(browser, testInfo, {
|
||||||
|
SMTP_HOST: process.env.MAILDEV_HOST,
|
||||||
|
SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM,
|
||||||
|
});
|
||||||
|
|
||||||
|
user1Mails = mailserver.iterator(users.user1.email);
|
||||||
|
user2Mails = mailserver.iterator(users.user2.email);
|
||||||
|
user3Mails = mailserver.iterator(users.user3.email);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll('Teardown', async ({}, testInfo: TestInfo) => {
|
||||||
|
utils.stopVaultwarden(testInfo);
|
||||||
|
utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create user3', async ({ page }) => {
|
||||||
|
await createAccount(test, page, users.user3, user3Mails);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Invite users', async ({ page }) => {
|
||||||
|
await createAccount(test, page, users.user1, user1Mails);
|
||||||
|
await logUser(test, page, users.user1, user1Mails);
|
||||||
|
|
||||||
|
await test.step('Create Org', async () => {
|
||||||
|
await page.getByRole('link', { name: 'New organisation' }).click();
|
||||||
|
await page.getByLabel('Organisation name (required)').fill('Test');
|
||||||
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
await page.locator('div').filter({ hasText: 'Members' }).nth(2).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Invite user2', async () => {
|
||||||
|
await page.getByRole('button', { name: 'Invite member' }).click();
|
||||||
|
await page.getByLabel('Email (required)').fill(users.user2.email);
|
||||||
|
await page.getByRole('tab', { name: 'Collections' }).click();
|
||||||
|
await page.getByLabel('Permission').selectOption('edit');
|
||||||
|
await page.getByLabel('Select collections').click();
|
||||||
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Invite user3', async () => {
|
||||||
|
await page.getByRole('button', { name: 'Invite member' }).click();
|
||||||
|
await page.getByLabel('Email (required)').fill(users.user3.email);
|
||||||
|
await page.getByRole('tab', { name: 'Collections' }).click();
|
||||||
|
await page.getByLabel('Permission').selectOption('edit');
|
||||||
|
await page.getByLabel('Select collections').click();
|
||||||
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invited with new account', async ({ page }) => {
|
||||||
|
const { value: invited } = await user2Mails.next();
|
||||||
|
expect(invited.subject).toContain("Join Test")
|
||||||
|
|
||||||
|
await test.step('Create account', async () => {
|
||||||
|
await page.setContent(invited.html);
|
||||||
|
const link = await page.getByTestId("invite").getAttribute("href");
|
||||||
|
await page.goto(link);
|
||||||
|
await expect(page).toHaveTitle(/Create account | Vaultwarden Web/);
|
||||||
|
|
||||||
|
await page.getByLabel('Name').fill(users.user2.name);
|
||||||
|
await page.getByLabel('Master password\n (required)', { exact: true }).fill(users.user2.password);
|
||||||
|
await page.getByLabel('Re-type master password').fill(users.user2.password);
|
||||||
|
await page.getByRole('button', { name: 'Create account' }).click();
|
||||||
|
|
||||||
|
// Back to the login page
|
||||||
|
await expect(page).toHaveTitle('Vaultwarden Web');
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/);
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
|
||||||
|
const { value: welcome } = await user2Mails.next();
|
||||||
|
expect(welcome.subject).toContain("Welcome")
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Login', async () => {
|
||||||
|
await page.getByLabel(/Email address/).fill(users.user2.email);
|
||||||
|
await page.getByRole('button', { name: 'Continue' }).click();
|
||||||
|
|
||||||
|
// Unlock page
|
||||||
|
await page.getByLabel('Master password').fill(users.user2.password);
|
||||||
|
await page.getByRole('button', { name: 'Log in with master password' }).click();
|
||||||
|
|
||||||
|
// We are now in the default vault page
|
||||||
|
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
||||||
|
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
|
||||||
|
const { value: logged } = await user2Mails.next();
|
||||||
|
expect(logged.subject).toContain("New Device Logged");
|
||||||
|
});
|
||||||
|
|
||||||
|
const { value: accepted } = await user1Mails.next();
|
||||||
|
expect(accepted.subject).toContain("Invitation to Test accepted")
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invited with existing account', async ({ page }) => {
|
||||||
|
const { value: invited } = await user3Mails.next();
|
||||||
|
expect(invited.subject).toContain("Join Test")
|
||||||
|
|
||||||
|
await page.setContent(invited.html);
|
||||||
|
const link = await page.getByTestId("invite").getAttribute("href");
|
||||||
|
|
||||||
|
await page.goto(link);
|
||||||
|
|
||||||
|
// We should be on login page with email prefilled
|
||||||
|
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
||||||
|
await page.getByRole('button', { name: 'Continue' }).click();
|
||||||
|
|
||||||
|
// Unlock page
|
||||||
|
await page.getByLabel('Master password').fill(users.user3.password);
|
||||||
|
await page.getByRole('button', { name: 'Log in with master password' }).click();
|
||||||
|
|
||||||
|
// We are now in the default vault page
|
||||||
|
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
||||||
|
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
|
||||||
|
const { value: logged } = await user3Mails.next();
|
||||||
|
expect(logged.subject).toContain("New Device Logged")
|
||||||
|
|
||||||
|
const { value: accepted } = await user1Mails.next();
|
||||||
|
expect(accepted.subject).toContain("Invitation to Test accepted")
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Confirm invited user', async ({ page }) => {
|
||||||
|
await logUser(test, page, users.user1, user1Mails);
|
||||||
|
await page.getByLabel('Switch products').click();
|
||||||
|
await page.getByRole('link', { name: ' Admin Console' }).click();
|
||||||
|
await page.getByRole('link', { name: 'Members' }).click();
|
||||||
|
|
||||||
|
await test.step('Accept user2', async () => {
|
||||||
|
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
|
||||||
|
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
|
||||||
|
const { value: logged } = await user2Mails.next();
|
||||||
|
expect(logged.subject).toContain("Invitation to Test confirmed");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Organization is visible', async ({ page }) => {
|
||||||
|
await logUser(test, page, users.user2, user2Mails);
|
||||||
|
await page.getByLabel('vault: Test').click();
|
||||||
|
await expect(page.getByLabel('Filter: Default collection')).toBeVisible();
|
||||||
|
});
|
|
@ -6,38 +6,21 @@ import { createAccount, logUser } from './setups/user';
|
||||||
|
|
||||||
let users = utils.loadEnv();
|
let users = utils.loadEnv();
|
||||||
|
|
||||||
let mailserver, user1Mails, user2Mails, user3Mails;
|
|
||||||
|
|
||||||
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
||||||
mailserver = new MailDev({
|
await utils.startVaultwarden(browser, testInfo);
|
||||||
port: process.env.MAILDEV_SMTP_PORT,
|
|
||||||
web: { port: process.env.MAILDEV_HTTP_PORT },
|
|
||||||
})
|
|
||||||
|
|
||||||
await mailserver.listen();
|
|
||||||
|
|
||||||
await utils.startVaultwarden(browser, testInfo, {
|
|
||||||
SMTP_HOST: process.env.MAILDEV_HOST,
|
|
||||||
SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM,
|
|
||||||
});
|
|
||||||
|
|
||||||
user1Mails = mailserver.iterator(users.user1.email);
|
|
||||||
user2Mails = mailserver.iterator(users.user2.email);
|
|
||||||
user3Mails = mailserver.iterator(users.user3.email);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterAll('Teardown', async ({}, testInfo: TestInfo) => {
|
test.afterAll('Teardown', async ({}, testInfo: TestInfo) => {
|
||||||
utils.stopVaultwarden(testInfo);
|
utils.stopVaultwarden(testInfo);
|
||||||
utils.closeMails(mailserver, [user1Mails, user2Mails, user3Mails]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Create user3', async ({ page }) => {
|
test('Create user3', async ({ page }) => {
|
||||||
await createAccount(test, page, users.user3, user3Mails);
|
await createAccount(test, page, users.user3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Invite users', async ({ page }) => {
|
test('Invite users', async ({ page }) => {
|
||||||
await createAccount(test, page, users.user1, user1Mails);
|
await createAccount(test, page, users.user1);
|
||||||
await logUser(test, page, users.user1, user1Mails);
|
await logUser(test, page, users.user1);
|
||||||
|
|
||||||
await test.step('Create Org', async () => {
|
await test.step('Create Org', async () => {
|
||||||
await page.getByRole('link', { name: 'New organisation' }).click();
|
await page.getByRole('link', { name: 'New organisation' }).click();
|
||||||
|
@ -55,6 +38,8 @@ test('Invite users', async ({ page }) => {
|
||||||
await page.getByLabel('Options list').getByText('Default collection').click();
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
await page.getByRole('button', { name: 'Save' }).click();
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/);
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('Invite user3', async () => {
|
await test.step('Invite user3', async () => {
|
||||||
|
@ -66,99 +51,44 @@ test('Invite users', async ({ page }) => {
|
||||||
await page.getByLabel('Options list').getByText('Default collection').click();
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
await page.getByRole('button', { name: 'Save' }).click();
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Confirm existing user3', async () => {
|
||||||
|
await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click();
|
||||||
|
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invited with new account', async ({ page }) => {
|
test('Create invited account', async ({ page }) => {
|
||||||
const { value: invited } = await user2Mails.next();
|
await createAccount(test, page, users.user2);
|
||||||
expect(invited.subject).toContain("Join Test")
|
|
||||||
|
|
||||||
await test.step('Create account', async () => {
|
|
||||||
await page.setContent(invited.html);
|
|
||||||
const link = await page.getByTestId("invite").getAttribute("href");
|
|
||||||
await page.goto(link);
|
|
||||||
await expect(page).toHaveTitle(/Create account | Vaultwarden Web/);
|
|
||||||
|
|
||||||
await page.getByLabel('Name').fill(users.user2.name);
|
|
||||||
await page.getByLabel('Master password\n (required)', { exact: true }).fill(users.user2.password);
|
|
||||||
await page.getByLabel('Re-type master password').fill(users.user2.password);
|
|
||||||
await page.getByRole('button', { name: 'Create account' }).click();
|
|
||||||
|
|
||||||
// Back to the login page
|
|
||||||
await expect(page).toHaveTitle('Vaultwarden Web');
|
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText(/Your new account has been created/);
|
|
||||||
|
|
||||||
const { value: welcome } = await user2Mails.next();
|
|
||||||
expect(welcome.subject).toContain("Welcome")
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Login', async () => {
|
|
||||||
await page.getByLabel(/Email address/).fill(users.user2.email);
|
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
|
|
||||||
// Unlock page
|
|
||||||
await page.getByLabel('Master password').fill(users.user2.password);
|
|
||||||
await page.getByRole('button', { name: 'Log in with master password' }).click();
|
|
||||||
|
|
||||||
// We are now in the default vault page
|
|
||||||
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
|
||||||
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
|
||||||
|
|
||||||
const { value: logged } = await user2Mails.next();
|
|
||||||
expect(logged.subject).toContain("New Device Logged");
|
|
||||||
});
|
|
||||||
|
|
||||||
const { value: accepted } = await user1Mails.next();
|
|
||||||
expect(accepted.subject).toContain("Invitation to Test accepted")
|
|
||||||
});
|
|
||||||
|
|
||||||
test('invited with existing account', async ({ page }) => {
|
|
||||||
const { value: invited } = await user3Mails.next();
|
|
||||||
expect(invited.subject).toContain("Join Test")
|
|
||||||
|
|
||||||
await page.setContent(invited.html);
|
|
||||||
const link = await page.getByTestId("invite").getAttribute("href");
|
|
||||||
|
|
||||||
await page.goto(link);
|
|
||||||
|
|
||||||
// We should be on login page with email prefilled
|
|
||||||
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
|
||||||
await page.getByRole('button', { name: 'Continue' }).click();
|
|
||||||
|
|
||||||
// Unlock page
|
|
||||||
await page.getByLabel('Master password').fill(users.user3.password);
|
|
||||||
await page.getByRole('button', { name: 'Log in with master password' }).click();
|
|
||||||
|
|
||||||
// We are now in the default vault page
|
|
||||||
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
|
||||||
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
|
||||||
|
|
||||||
const { value: logged } = await user3Mails.next();
|
|
||||||
expect(logged.subject).toContain("New Device Logged")
|
|
||||||
|
|
||||||
const { value: accepted } = await user1Mails.next();
|
|
||||||
expect(accepted.subject).toContain("Invitation to Test accepted")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Confirm invited user', async ({ page }) => {
|
test('Confirm invited user', async ({ page }) => {
|
||||||
await logUser(test, page, users.user1, user1Mails);
|
await logUser(test, page, users.user1);
|
||||||
await page.getByLabel('Switch products').click();
|
await page.getByLabel('Switch products').click();
|
||||||
await page.getByRole('link', { name: ' Admin Console' }).click();
|
await page.getByRole('link', { name: ' Admin Console' }).click();
|
||||||
await page.getByRole('link', { name: 'Members' }).click();
|
await page.getByRole('link', { name: 'Members' }).click();
|
||||||
|
|
||||||
await test.step('Accept user2', async () => {
|
await test.step('Confirm user2', async () => {
|
||||||
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
|
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
|
||||||
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
||||||
await page.getByRole('button', { name: 'Confirm' }).click();
|
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
||||||
|
|
||||||
const { value: logged } = await user2Mails.next();
|
|
||||||
expect(logged.subject).toContain("Invitation to Test confirmed");
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Organization is visible', async ({ page }) => {
|
test('Organization is visible', async ({ context, page }) => {
|
||||||
await logUser(test, page, users.user2, user2Mails);
|
await logUser(test, page, users.user2);
|
||||||
await page.getByLabel('vault: Test').click();
|
await page.getByLabel('vault: Test').click();
|
||||||
await expect(page.getByLabel('Filter: Default collection')).toBeVisible();
|
await expect(page.getByLabel('Filter: Default collection')).toBeVisible();
|
||||||
|
|
||||||
|
const page2 = await context.newPage();
|
||||||
|
await logUser(test, page2, users.user3);
|
||||||
|
await page2.getByLabel('vault: Test').click();
|
||||||
|
await expect(page2.getByLabel('Filter: Default collection')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
146
playwright/tests/sso_organization.smtp.spec.ts
Normale Datei
146
playwright/tests/sso_organization.smtp.spec.ts
Normale Datei
|
@ -0,0 +1,146 @@
|
||||||
|
import { test, expect, type TestInfo } from '@playwright/test';
|
||||||
|
import { MailDev } from 'maildev';
|
||||||
|
|
||||||
|
import * as utils from "../global-utils";
|
||||||
|
import { logNewUser, logUser } from './setups/sso';
|
||||||
|
|
||||||
|
let users = utils.loadEnv();
|
||||||
|
|
||||||
|
let mailServer, mail1Buffer, mail2Buffer, mail3Buffer;
|
||||||
|
|
||||||
|
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
||||||
|
mailServer = new MailDev({
|
||||||
|
port: process.env.MAILDEV_SMTP_PORT,
|
||||||
|
web: { port: process.env.MAILDEV_HTTP_PORT },
|
||||||
|
})
|
||||||
|
|
||||||
|
await mailServer.listen();
|
||||||
|
|
||||||
|
await utils.startVaultwarden(browser, testInfo, {
|
||||||
|
SMTP_HOST: process.env.MAILDEV_HOST,
|
||||||
|
SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM,
|
||||||
|
SSO_ENABLED: true,
|
||||||
|
SSO_ONLY: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
mail1Buffer = mailServer.buffer(users.user1.email);
|
||||||
|
mail2Buffer = mailServer.buffer(users.user2.email);
|
||||||
|
mail3Buffer = mailServer.buffer(users.user3.email);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll('Teardown', async ({}) => {
|
||||||
|
utils.stopVaultwarden();
|
||||||
|
[mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close());
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create user3', async ({ page }) => {
|
||||||
|
await logNewUser(test, page, users.user3, { mailBuffer: mail3Buffer });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Invite users', async ({ page }) => {
|
||||||
|
await logNewUser(test, page, users.user1, { mailBuffer: mail1Buffer });
|
||||||
|
|
||||||
|
await test.step('Create Org', async () => {
|
||||||
|
await page.getByRole('link', { name: 'New organisation' }).click();
|
||||||
|
await page.getByLabel('Organisation name (required)').fill('Test');
|
||||||
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
await page.locator('div').filter({ hasText: 'Members' }).nth(2).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Invite user2', async () => {
|
||||||
|
await page.getByRole('button', { name: 'Invite member' }).click();
|
||||||
|
await page.getByLabel('Email (required)').fill(users.user2.email);
|
||||||
|
await page.getByRole('tab', { name: 'Collections' }).click();
|
||||||
|
await page.getByLabel('Permission').selectOption('edit');
|
||||||
|
await page.getByLabel('Select collections').click();
|
||||||
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Invite user3', async () => {
|
||||||
|
await page.getByRole('button', { name: 'Invite member' }).click();
|
||||||
|
await page.getByLabel('Email (required)').fill(users.user3.email);
|
||||||
|
await page.getByRole('tab', { name: 'Collections' }).click();
|
||||||
|
await page.getByLabel('Permission').selectOption('edit');
|
||||||
|
await page.getByLabel('Select collections').click();
|
||||||
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.fail('invited with new account', async ({ page }) => {
|
||||||
|
const link = await test.step('Extract email link', async () => {
|
||||||
|
const invited = await mail2Buffer.next((m) => m.subject === "Join Test");
|
||||||
|
await page.setContent(invited.html);
|
||||||
|
return await page.getByTestId("invite").getAttribute("href");
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Redirect to Keycloak', async () => {
|
||||||
|
await page.goto(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Keycloak login', async () => {
|
||||||
|
await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible();
|
||||||
|
await page.getByLabel(/Username/).fill(users.user2.name);
|
||||||
|
await page.getByLabel('Password', { exact: true }).fill(users.user2.password);
|
||||||
|
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Create Vault account', async () => {
|
||||||
|
await expect(page.getByText('Set master password')).toBeVisible();
|
||||||
|
await page.getByLabel('Master password', { exact: true }).fill(users.user2.password);
|
||||||
|
await page.getByLabel('Re-type master password').fill(users.user2.password);
|
||||||
|
await page.getByRole('button', { name: 'Submit' }).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Default vault page', async () => {
|
||||||
|
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
||||||
|
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Check mails', async () => {
|
||||||
|
await expect(mail2Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined();
|
||||||
|
await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('invited with existing account', async ({ page }) => {
|
||||||
|
const link = await test.step('Extract email link', async () => {
|
||||||
|
const invited = await mail3Buffer.next((m) => m.subject === "Join Test");
|
||||||
|
await page.setContent(invited.html);
|
||||||
|
return await page.getByTestId("invite").getAttribute("href");
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Redirect to Keycloak', async () => {
|
||||||
|
await page.goto(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Keycloak login', async () => {
|
||||||
|
await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible();
|
||||||
|
await page.getByLabel(/Username/).fill(users.user3.name);
|
||||||
|
await page.getByLabel('Password', { exact: true }).fill(users.user3.password);
|
||||||
|
await page.getByRole('button', { name: 'Sign In' }).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Unlock vault', async () => {
|
||||||
|
await expect(page).toHaveTitle('Vaultwarden Web');
|
||||||
|
await page.getByLabel('Master password').fill(users.user3.password);
|
||||||
|
await page.getByRole('button', { name: 'Unlock' }).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Default vault page', async () => {
|
||||||
|
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
||||||
|
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Check mails', async () => {
|
||||||
|
await expect(mail3Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined();
|
||||||
|
await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,39 +6,23 @@ import { logNewUser, logUser } from './setups/sso';
|
||||||
|
|
||||||
let users = utils.loadEnv();
|
let users = utils.loadEnv();
|
||||||
|
|
||||||
let mailServer, mail1Buffer, mail2Buffer, mail3Buffer;
|
|
||||||
|
|
||||||
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => {
|
||||||
mailServer = new MailDev({
|
|
||||||
port: process.env.MAILDEV_SMTP_PORT,
|
|
||||||
web: { port: process.env.MAILDEV_HTTP_PORT },
|
|
||||||
})
|
|
||||||
|
|
||||||
await mailServer.listen();
|
|
||||||
|
|
||||||
await utils.startVaultwarden(browser, testInfo, {
|
await utils.startVaultwarden(browser, testInfo, {
|
||||||
SMTP_HOST: process.env.MAILDEV_HOST,
|
|
||||||
SMTP_FROM: process.env.VAULTWARDEN_SMTP_FROM,
|
|
||||||
SSO_ENABLED: true,
|
SSO_ENABLED: true,
|
||||||
SSO_ONLY: true,
|
SSO_ONLY: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
mail1Buffer = mailServer.buffer(users.user1.email);
|
|
||||||
mail2Buffer = mailServer.buffer(users.user2.email);
|
|
||||||
mail3Buffer = mailServer.buffer(users.user3.email);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterAll('Teardown', async ({}) => {
|
test.afterAll('Teardown', async ({}) => {
|
||||||
utils.stopVaultwarden();
|
utils.stopVaultwarden();
|
||||||
[mailServer, mail1Buffer, mail2Buffer, mail3Buffer].map((m) => m?.close());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Create user2', async ({ page }) => {
|
test('Create user3', async ({ page }) => {
|
||||||
await logNewUser(test, page, users.user2, { mailBuffer: mail2Buffer });
|
await logNewUser(test, page, users.user3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Invite users', async ({ page }) => {
|
test('Invite users', async ({ page }) => {
|
||||||
await logNewUser(test, page, users.user1, { mailBuffer: mail1Buffer });
|
await logNewUser(test, page, users.user1);
|
||||||
|
|
||||||
await test.step('Create Org', async () => {
|
await test.step('Create Org', async () => {
|
||||||
await page.getByRole('link', { name: 'New organisation' }).click();
|
await page.getByRole('link', { name: 'New organisation' }).click();
|
||||||
|
@ -56,6 +40,8 @@ test('Invite users', async ({ page }) => {
|
||||||
await page.getByLabel('Options list').getByText('Default collection').click();
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
await page.getByRole('button', { name: 'Save' }).click();
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
await expect(page.getByRole('row', { name: users.user2.email })).toHaveText(/Invited/);
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('Invite user3', async () => {
|
await test.step('Invite user3', async () => {
|
||||||
|
@ -67,76 +53,42 @@ test('Invite users', async ({ page }) => {
|
||||||
await page.getByLabel('Options list').getByText('Default collection').click();
|
await page.getByLabel('Options list').getByText('Default collection').click();
|
||||||
await page.getByRole('button', { name: 'Save' }).click();
|
await page.getByRole('button', { name: 'Save' }).click();
|
||||||
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
await expect(page.getByTestId("toast-message")).toHaveText('User(s) invited');
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
|
await expect(page.getByRole('row', { name: users.user3.name })).toHaveText(/Needs confirmation/);
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step('Confirm existing user3', async () => {
|
||||||
|
await page.getByRole('row', { name: users.user3.name }).getByLabel('Options').click();
|
||||||
|
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
||||||
|
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||||
|
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invited with existing account', async ({ page }) => {
|
test('Create invited account', async ({ page }) => {
|
||||||
const link = await test.step('Extract email link', async () => {
|
await logNewUser(test, page, users.user2);
|
||||||
const invited = await mail2Buffer.next((m) => m.subject === "Join Test");
|
});
|
||||||
await page.setContent(invited.html);
|
|
||||||
return await page.getByTestId("invite").getAttribute("href");
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Redirect to Keycloak', async () => {
|
test('Confirm invited user', async ({ page }) => {
|
||||||
await page.goto(link);
|
await logUser(test, page, users.user1);
|
||||||
});
|
await page.getByLabel('Switch products').click();
|
||||||
|
await page.getByRole('link', { name: ' Admin Console' }).click();
|
||||||
|
await page.getByRole('link', { name: 'Members' }).click();
|
||||||
|
|
||||||
await test.step('Keycloak login', async () => {
|
await expect(page.getByRole('row', { name: users.user2.name })).toHaveText(/Needs confirmation/);
|
||||||
await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible();
|
|
||||||
await page.getByLabel(/Username/).fill(users.user2.name);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(users.user2.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Unlock vault', async () => {
|
await test.step('Confirm user2', async () => {
|
||||||
await expect(page).toHaveTitle('Vaultwarden Web');
|
await page.getByRole('row', { name: users.user2.name }).getByLabel('Options').click();
|
||||||
await page.getByLabel('Master password').fill(users.user2.password);
|
await page.getByRole('menuitem', { name: 'Confirm' }).click();
|
||||||
await page.getByRole('button', { name: 'Unlock' }).click();
|
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||||
});
|
await expect(page.getByTestId("toast-message")).toHaveText(/confirmed/);
|
||||||
|
await page.locator('#toast-container').getByRole('button').click();
|
||||||
await test.step('Default vault page', async () => {
|
|
||||||
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
|
||||||
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Check mails', async () => {
|
|
||||||
await expect(mail2Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined();
|
|
||||||
await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('invited with new account', async ({ page }) => {
|
test('Organization is visible', async ({ page }) => {
|
||||||
const link = await test.step('Extract email link', async () => {
|
await logUser(test, page, users.user2);
|
||||||
const invited = await mail3Buffer.next((m) => m.subject === "Join Test");
|
await page.getByLabel('vault: Test').click();
|
||||||
await page.setContent(invited.html);
|
await expect(page.getByLabel('Filter: Default collection')).toBeVisible();
|
||||||
return await page.getByTestId("invite").getAttribute("href");
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Redirect to Keycloak', async () => {
|
|
||||||
await page.goto(link);
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Keycloak login', async () => {
|
|
||||||
await expect(page.getByRole('heading', { name: 'Sign in to your account' })).toBeVisible();
|
|
||||||
await page.getByLabel(/Username/).fill(users.user3.name);
|
|
||||||
await page.getByLabel('Password', { exact: true }).fill(users.user3.password);
|
|
||||||
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Create Vault account', async () => {
|
|
||||||
await expect(page.getByText('Set master password')).toBeVisible();
|
|
||||||
await page.getByLabel('Master password', { exact: true }).fill(users.user3.password);
|
|
||||||
await page.getByLabel('Re-type master password').fill(users.user3.password);
|
|
||||||
await page.getByRole('button', { name: 'Submit' }).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Default vault page', async () => {
|
|
||||||
await expect(page).toHaveTitle(/Vaultwarden Web/);
|
|
||||||
await expect(page.getByTestId("toast-title")).toHaveText("Invitation accepted");
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step('Check mails', async () => {
|
|
||||||
await expect(mail3Buffer.next((m) => m.subject.includes("New Device Logged"))).resolves.toBeDefined();
|
|
||||||
await expect(mail1Buffer.next((m) => m.subject === "Invitation to Test accepted")).resolves.toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -293,6 +293,8 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, mut co
|
||||||
|
|
||||||
if CONFIG.mail_enabled() {
|
if CONFIG.mail_enabled() {
|
||||||
mail::send_set_password(&user.email.to_lowercase(), &user.name).await?;
|
mail::send_set_password(&user.email.to_lowercase(), &user.name).await?;
|
||||||
|
} else {
|
||||||
|
Membership::confirm_user_invitations(&user.uuid, &mut conn).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.save(&mut conn).await?;
|
user.save(&mut conn).await?;
|
||||||
|
|
|
@ -254,10 +254,6 @@ async fn _sso_login(data: ConnectData, user_id: &mut Option<UserId>, conn: &mut
|
||||||
user.name = user_name;
|
user.name = user_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !CONFIG.mail_enabled() {
|
|
||||||
Membership::confirm_user_invitations(&user.uuid, conn).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
user.save(conn).await?;
|
user.save(conn).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -805,6 +805,8 @@ impl Membership {
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should be used only when email are disabled.
|
||||||
|
// In Organizations::send_invite status is set to Accepted only if the user has a password.
|
||||||
pub async fn confirm_user_invitations(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
|
pub async fn confirm_user_invitations(user_uuid: &UserId, conn: &mut DbConn) -> EmptyResult {
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
diesel::update(users_organizations::table)
|
diesel::update(users_organizations::table)
|
||||||
|
@ -814,13 +816,6 @@ impl Membership {
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.map_res("Error confirming invitations")
|
.map_res("Error confirming invitations")
|
||||||
}}
|
}}
|
||||||
.and_then(|updated| match updated {
|
|
||||||
1 => Ok(()),
|
|
||||||
count => err!(format!(
|
|
||||||
"Failed to update users_organizations to accepted for user ({}) was expecting invited status (updated row: {})).",
|
|
||||||
user_uuid, count
|
|
||||||
)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_any_state_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
|
pub async fn find_any_state_by_user(user_uuid: &UserId, conn: &mut DbConn) -> Vec<Self> {
|
||||||
|
|
Laden …
Tabelle hinzufügen
In neuem Issue referenzieren