mirror of
https://github.com/bitwarden/browser
synced 2026-02-07 20:24:01 +00:00
WIP
This commit is contained in:
@@ -1,6 +1,15 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from "@angular/core";
|
||||
import {
|
||||
Component,
|
||||
DestroyRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ReactiveFormsModule, FormBuilder, Validators, FormControl } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { filter, firstValueFrom, Subject } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
@@ -10,6 +19,7 @@ import {
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@@ -32,6 +42,13 @@ import {
|
||||
ToastService,
|
||||
Translation,
|
||||
} from "@bitwarden/components";
|
||||
import { GeneratorServicesModule } from "@bitwarden/generator-components";
|
||||
import {
|
||||
CredentialGeneratorService,
|
||||
GenerateRequest,
|
||||
Profile,
|
||||
Type,
|
||||
} from "@bitwarden/generator-core";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
|
||||
import {
|
||||
DEFAULT_KDF_CONFIG,
|
||||
@@ -107,6 +124,7 @@ interface InputPasswordForm {
|
||||
ButtonModule,
|
||||
CheckboxModule,
|
||||
FormFieldModule,
|
||||
GeneratorServicesModule,
|
||||
IconButtonModule,
|
||||
InputModule,
|
||||
JslibModule,
|
||||
@@ -149,6 +167,9 @@ export class InputPasswordComponent implements OnInit {
|
||||
protected showErrorSummary = false;
|
||||
protected showPassword = false;
|
||||
|
||||
private generate$: Subject<GenerateRequest> = new Subject();
|
||||
private account$ = this.accountService.activeAccount$.pipe(filter((acc) => acc != null));
|
||||
|
||||
protected formGroup = this.formBuilder.nonNullable.group<InputPasswordForm>(
|
||||
{
|
||||
newPassword: this.formBuilder.nonNullable.control("", [
|
||||
@@ -194,11 +215,22 @@ export class InputPasswordComponent implements OnInit {
|
||||
private policyService: PolicyService,
|
||||
private toastService: ToastService,
|
||||
private validationService: ValidationService,
|
||||
private credentialGeneratorService: CredentialGeneratorService,
|
||||
private accountService: AccountService,
|
||||
private destroy$: DestroyRef,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.addFormFieldsIfNecessary();
|
||||
this.setButtonText();
|
||||
this.credentialGeneratorService
|
||||
.generate$({ on$: this.generate$, account$: this.account$ })
|
||||
.pipe(takeUntilDestroyed(this.destroy$))
|
||||
.subscribe((generated) => {
|
||||
this.formGroup.patchValue({
|
||||
newPassword: generated.credential,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private addFormFieldsIfNecessary() {
|
||||
@@ -634,10 +666,13 @@ export class InputPasswordComponent implements OnInit {
|
||||
}
|
||||
|
||||
protected async generatePassword() {
|
||||
const options = (await this.passwordGenerationService.getOptions())?.[0] ?? {};
|
||||
this.formGroup.patchValue({
|
||||
newPassword: await this.passwordGenerationService.generatePassword(options),
|
||||
});
|
||||
const request: GenerateRequest = {
|
||||
type: Type.password,
|
||||
profile: Profile.masterPassword,
|
||||
source: "master-password",
|
||||
};
|
||||
|
||||
this.generate$.next(request);
|
||||
|
||||
if (!this.passwordStrengthComponent) {
|
||||
throw new Error("PasswordStrengthComponent is not initialized");
|
||||
|
||||
@@ -31,8 +31,7 @@ export const Profile = Object.freeze({
|
||||
* @remarks these are the options displayed on the generator tab
|
||||
*/
|
||||
account: "account",
|
||||
|
||||
// FIXME: consider adding a profile for bitwarden's master password
|
||||
masterPassword: "masterPassword",
|
||||
});
|
||||
|
||||
/** Credential generation algorithms grouped by purpose. */
|
||||
|
||||
@@ -5,6 +5,7 @@ import { deepFreeze } from "@bitwarden/common/tools/util";
|
||||
|
||||
import { PasswordRandomizer, SdkPasswordRandomizer } from "../../engine";
|
||||
import { DynamicPasswordPolicyConstraints, passwordLeastPrivilege } from "../../policies";
|
||||
import { masterPasswordReducer } from "../../policies/master-password-policy-reducer";
|
||||
import { GeneratorDependencyProvider } from "../../providers";
|
||||
import { CredentialGenerator, PasswordGeneratorSettings } from "../../types";
|
||||
import { Algorithm, Profile, Type } from "../data";
|
||||
@@ -111,6 +112,80 @@ const password: GeneratorMetadata<PasswordGeneratorSettings> = deepFreeze({
|
||||
},
|
||||
},
|
||||
},
|
||||
[Profile.masterPassword]: {
|
||||
type: "core",
|
||||
storage: {
|
||||
key: "passwordGeneratorSettings",
|
||||
target: "object",
|
||||
format: "plain",
|
||||
classifier: new PublicClassifier<PasswordGeneratorSettings>([
|
||||
"length",
|
||||
"ambiguous",
|
||||
"uppercase",
|
||||
"minUppercase",
|
||||
"lowercase",
|
||||
"minLowercase",
|
||||
"number",
|
||||
"minNumber",
|
||||
"special",
|
||||
"minSpecial",
|
||||
]),
|
||||
state: GENERATOR_DISK,
|
||||
initial: {
|
||||
length: 14,
|
||||
ambiguous: true,
|
||||
uppercase: true,
|
||||
minUppercase: 1,
|
||||
lowercase: true,
|
||||
minLowercase: 1,
|
||||
number: true,
|
||||
minNumber: 1,
|
||||
special: false,
|
||||
minSpecial: 0,
|
||||
},
|
||||
options: {
|
||||
deserializer(value) {
|
||||
return value;
|
||||
},
|
||||
clearOn: ["logout"],
|
||||
},
|
||||
},
|
||||
constraints: {
|
||||
type: PolicyType.MasterPassword,
|
||||
default: {
|
||||
length: {
|
||||
min: 5,
|
||||
max: 128,
|
||||
recommendation: 14,
|
||||
},
|
||||
minNumber: {
|
||||
min: 0,
|
||||
max: 9,
|
||||
},
|
||||
minSpecial: {
|
||||
min: 0,
|
||||
max: 9,
|
||||
},
|
||||
},
|
||||
create(policies, context) {
|
||||
const initial = {
|
||||
minLength: 0,
|
||||
useUppercase: false,
|
||||
useLowercase: true,
|
||||
useNumbers: false,
|
||||
numberCount: 0,
|
||||
useSpecial: false,
|
||||
specialCount: 0,
|
||||
};
|
||||
const policy = policies.reduce(masterPasswordReducer, initial);
|
||||
const constraints = new DynamicPasswordPolicyConstraints(
|
||||
policy,
|
||||
context.defaultConstraints,
|
||||
);
|
||||
return constraints;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
|
||||
import { PasswordGeneratorPolicy } from "../types";
|
||||
|
||||
export function masterPasswordReducer(acc: PasswordGeneratorPolicy, policy: Policy) {
|
||||
if (policy.type !== PolicyType.MasterPassword || !policy.enabled) {
|
||||
return acc;
|
||||
}
|
||||
return {
|
||||
minLength: Math.max(acc.minLength, policy.data.minLength ?? acc.minLength),
|
||||
useUppercase: policy.data.requireUpper || acc.useUppercase,
|
||||
useLowercase: policy.data.requireLower || acc.useLowercase,
|
||||
useNumbers: policy.data.requireNumbers || acc.useNumbers,
|
||||
numberCount: acc.numberCount,
|
||||
useSpecial: policy.data.requireSpecial || acc.useSpecial,
|
||||
specialCount: acc.specialCount,
|
||||
};
|
||||
}
|
||||
@@ -86,8 +86,15 @@ export class GeneratorProfileProvider {
|
||||
"initializing constraints$",
|
||||
);
|
||||
|
||||
// The problem is here, this just gets applicable policies to the current user, which the owner/admin may be exempt from if generating a pw for another user via account recovery.
|
||||
//const policies$ = profile.constraints.type
|
||||
// ? this.policyService.policiesByType$(profile.constraints.type, account.id)
|
||||
// : of([]);
|
||||
|
||||
const policies$ = profile.constraints.type
|
||||
? this.policyService.policiesByType$(profile.constraints.type, account.id)
|
||||
? this.policyService
|
||||
.policies$(account.id)
|
||||
.pipe(map((policies) => policies.filter((p) => p.type === profile.constraints.type)))
|
||||
: of([]);
|
||||
|
||||
const context: ProfileContext<Settings> = {
|
||||
|
||||
Reference in New Issue
Block a user