mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 05:43:41 +00:00
Merge branch 'master' into feature/flexible-collections
This commit is contained in:
@@ -1,40 +1,51 @@
|
||||
<label class="environment-selector-btn">
|
||||
<div class="environment-selector-btn">
|
||||
{{ "loggingInOn" | i18n }}:
|
||||
<a
|
||||
<button
|
||||
type="button"
|
||||
(click)="toggle(null)"
|
||||
cdkOverlayOrigin
|
||||
#trigger="cdkOverlayOrigin"
|
||||
aria-haspopup="menu"
|
||||
aria-haspopup="dialog"
|
||||
aria-controls="cdk-overlay-container"
|
||||
[ngSwitch]="selectedEnvironment"
|
||||
>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.US" class="text-primary">{{
|
||||
<span *ngSwitchCase="ServerEnvironmentType.US" class="text-primary">{{
|
||||
"usDomain" | i18n
|
||||
}}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.EU" class="text-primary">{{
|
||||
}}</span>
|
||||
<span *ngSwitchCase="ServerEnvironmentType.EU" class="text-primary">{{
|
||||
"euDomain" | i18n
|
||||
}}</label>
|
||||
<label *ngSwitchCase="ServerEnvironmentType.SelfHosted" class="text-primary">{{
|
||||
}}</span>
|
||||
<span *ngSwitchCase="ServerEnvironmentType.SelfHosted" class="text-primary">{{
|
||||
"selfHostedServer" | i18n
|
||||
}}</label>
|
||||
}}</span>
|
||||
<i class="bwi bwi-fw bwi-sm bwi-angle-down" aria-hidden="true"></i>
|
||||
</a>
|
||||
</label>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
(backdropClick)="close()"
|
||||
(detach)="close()"
|
||||
[cdkConnectedOverlayOpen]="isOpen"
|
||||
[cdkConnectedOverlayPositions]="overlayPosition"
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[cdkConnectedOverlayBackdropClass]="'cdk-overlay-transparent-backdrop'"
|
||||
(backdropClick)="isOpen = false"
|
||||
(detach)="close()"
|
||||
>
|
||||
<div class="box-content">
|
||||
<div class="environment-selector-dialog" [@transformPanel]="'open'" role="dialog">
|
||||
<div
|
||||
class="environment-selector-dialog"
|
||||
[@transformPanel]="'open'"
|
||||
cdkTrapFocus
|
||||
cdkTrapFocusAutoCapture
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.US)"
|
||||
[attr.aria-pressed]="selectedEnvironment === ServerEnvironmentType.US ? 'true' : 'false'"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check"
|
||||
@@ -51,6 +62,7 @@
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.EU)"
|
||||
[attr.aria-pressed]="selectedEnvironment === ServerEnvironmentType.EU ? 'true' : 'false'"
|
||||
*ngIf="euServerFlagEnabled"
|
||||
>
|
||||
<i
|
||||
@@ -68,6 +80,9 @@
|
||||
type="button"
|
||||
class="environment-selector-dialog-item"
|
||||
(click)="toggle(ServerEnvironmentType.SelfHosted)"
|
||||
[attr.aria-pressed]="
|
||||
selectedEnvironment === ServerEnvironmentType.SelfHosted ? 'true' : 'false'
|
||||
"
|
||||
>
|
||||
<i
|
||||
class="bwi bwi-fw bwi-sm bwi-check"
|
||||
|
||||
@@ -352,7 +352,7 @@ describe("SsoComponent", () => {
|
||||
describe("Given Trusted Device Encryption is enabled, user doesn't need to set a MP, and forcePasswordReset is required", () => {
|
||||
[
|
||||
ForceResetPasswordReason.AdminForcePasswordReset,
|
||||
ForceResetPasswordReason.WeakMasterPassword,
|
||||
// ForceResetPasswordReason.WeakMasterPassword, -- not possible in SSO flow as set client side
|
||||
].forEach((forceResetPasswordReason) => {
|
||||
const reasonString = ForceResetPasswordReason[forceResetPasswordReason];
|
||||
let authResult;
|
||||
@@ -449,7 +449,7 @@ describe("SsoComponent", () => {
|
||||
describe("Force Master Password Reset scenarios", () => {
|
||||
[
|
||||
ForceResetPasswordReason.AdminForcePasswordReset,
|
||||
ForceResetPasswordReason.WeakMasterPassword,
|
||||
// ForceResetPasswordReason.WeakMasterPassword, -- not possible in SSO flow as set client side
|
||||
].forEach((forceResetPasswordReason) => {
|
||||
const reasonString = ForceResetPasswordReason[forceResetPasswordReason];
|
||||
|
||||
|
||||
@@ -226,9 +226,9 @@ export class SsoComponent {
|
||||
return await this.handleChangePasswordRequired(orgIdentifier);
|
||||
}
|
||||
|
||||
// Users can be forced to reset their password via an admin or org policy
|
||||
// disallowing weak passwords
|
||||
if (authResult.forcePasswordReset !== ForceResetPasswordReason.None) {
|
||||
// Users enrolled in admin acct recovery can be forced to set a new password after
|
||||
// having the admin set a temp password for them
|
||||
if (authResult.forcePasswordReset == ForceResetPasswordReason.AdminForcePasswordReset) {
|
||||
return await this.handleForcePasswordReset(orgIdentifier);
|
||||
}
|
||||
|
||||
|
||||
@@ -282,8 +282,10 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
||||
return await this.handleChangePasswordRequired(orgIdentifier);
|
||||
}
|
||||
|
||||
// Users can be forced to reset their password via an admin or org policy
|
||||
// disallowing weak passwords
|
||||
// Users can be forced to reset their password via an admin or org policy disallowing weak passwords
|
||||
// Note: this is different from SSO component login flow as a user can
|
||||
// login with MP and then have to pass 2FA to finish login and we can actually
|
||||
// evaluate if they have a weak password at this time.
|
||||
if (authResult.forcePasswordReset !== ForceResetPasswordReason.None) {
|
||||
return await this.handleForcePasswordReset(orgIdentifier);
|
||||
}
|
||||
|
||||
@@ -154,8 +154,13 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
.policyAppliesToActiveUser$(PolicyType.SendOptions, (p) => p.data.disableHideEmail)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((policyAppliesToActiveUser) => {
|
||||
if ((this.disableHideEmail = policyAppliesToActiveUser)) {
|
||||
if (
|
||||
(this.disableHideEmail = policyAppliesToActiveUser) &&
|
||||
!this.formGroup.controls.hideEmail.value
|
||||
) {
|
||||
this.formGroup.controls.hideEmail.disable();
|
||||
} else {
|
||||
this.formGroup.controls.hideEmail.enable();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -207,9 +212,6 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
this.send = await send.decrypt();
|
||||
this.type = this.send.type;
|
||||
this.updateFormValues();
|
||||
if (this.send.hideEmail) {
|
||||
this.formGroup.controls.hideEmail.enable();
|
||||
}
|
||||
} else {
|
||||
this.send = new SendView();
|
||||
this.send.type = this.type;
|
||||
@@ -425,6 +427,10 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
"yyyy-MM-ddTHH:mm"
|
||||
),
|
||||
});
|
||||
|
||||
if (this.send.hideEmail) {
|
||||
this.formGroup.controls.hideEmail.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private async handleCopyLinkToClipboard() {
|
||||
|
||||
@@ -153,6 +153,7 @@ export abstract class LogInStrategy {
|
||||
const result = new AuthResult();
|
||||
result.resetMasterPassword = response.resetMasterPassword;
|
||||
|
||||
// Convert boolean to enum
|
||||
if (response.forcePasswordReset) {
|
||||
result.forcePasswordReset = ForceResetPasswordReason.AdminForcePasswordReset;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trus
|
||||
import { KeyConnectorService } from "../abstractions/key-connector.service";
|
||||
import { TokenService } from "../abstractions/token.service";
|
||||
import { TwoFactorService } from "../abstractions/two-factor.service";
|
||||
import { ForceResetPasswordReason } from "../models/domain/force-reset-password-reason";
|
||||
import { SsoLogInCredentials } from "../models/domain/log-in-credentials";
|
||||
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
||||
import { IdentityTokenResponse } from "../models/response/identity-token.response";
|
||||
@@ -73,6 +74,11 @@ export class SsoLogInStrategy extends LogInStrategy {
|
||||
this.email = ssoAuthResult.email;
|
||||
this.ssoEmail2FaSessionToken = ssoAuthResult.ssoEmail2FaSessionToken;
|
||||
|
||||
// Auth guard currently handles redirects for this.
|
||||
if (ssoAuthResult.forcePasswordReset == ForceResetPasswordReason.AdminForcePasswordReset) {
|
||||
await this.stateService.setForcePasswordResetReason(ssoAuthResult.forcePasswordReset);
|
||||
}
|
||||
|
||||
return ssoAuthResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
* This enum is used to determine if a user should be forced to reset their password
|
||||
* on login (server flag) or unlock via MP (client evaluation).
|
||||
*/
|
||||
export enum ForceResetPasswordReason {
|
||||
/**
|
||||
* A password reset should not be forced.
|
||||
@@ -6,12 +10,14 @@ export enum ForceResetPasswordReason {
|
||||
|
||||
/**
|
||||
* Occurs when an organization admin forces a user to reset their password.
|
||||
* Communicated via server flag.
|
||||
*/
|
||||
AdminForcePasswordReset,
|
||||
|
||||
/**
|
||||
* Occurs when a user logs in / unlocks their vault with a master password that does not meet an organization's
|
||||
* master password policy that is enforced on login/unlock.
|
||||
* Only set client side b/c server can't evaluate MP.
|
||||
*/
|
||||
WeakMasterPassword,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user