1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-22 11:13:46 +00:00

added password generator tool

This commit is contained in:
Kyle Spearrin
2018-06-20 18:16:20 -04:00
parent 7979953f33
commit 367104f0a7
11 changed files with 262 additions and 8 deletions

View File

@@ -16,6 +16,7 @@ import { TwoFactorComponent } from './accounts/two-factor.component';
import { ExportComponent } from './tools/export.component';
import { ImportComponent } from './tools/import.component';
import { PasswordGeneratorComponent } from './tools/password-generator.component';
import { ToolsComponent } from './tools/tools.component';
import { VaultComponent } from './vault/vault.component';
@@ -45,9 +46,10 @@ const routes: Routes = [
path: 'tools',
component: ToolsComponent,
children: [
{ path: '', pathMatch: 'full', redirectTo: 'import' },
{ path: '', pathMatch: 'full', redirectTo: 'generator' },
{ path: 'import', component: ImportComponent, canActivate: [AuthGuardService] },
{ path: 'export', component: ExportComponent, canActivate: [AuthGuardService] },
{ path: 'generator', component: PasswordGeneratorComponent, canActivate: [AuthGuardService] },
],
},
],

View File

@@ -31,6 +31,8 @@ import { TwoFactorComponent } from './accounts/two-factor.component';
import { ExportComponent } from './tools/export.component';
import { ImportComponent } from './tools/import.component';
import { PasswordGeneratorHistoryComponent } from './tools/password-generator-history.component';
import { PasswordGeneratorComponent } from './tools/password-generator.component';
import { ToolsComponent } from './tools/tools.component';
import { AddEditComponent } from './vault/add-edit.component';
@@ -60,7 +62,6 @@ import { TrueFalseValueDirective } from 'jslib/angular/directives/true-false-val
import { I18nPipe } from 'jslib/angular/pipes/i18n.pipe';
import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
import { Folder } from 'jslib/models/domain';
@NgModule({
imports: [
@@ -106,6 +107,8 @@ import { Folder } from 'jslib/models/domain';
NavbarComponent,
OrganizationsComponent,
OrganizationLayoutComponent,
PasswordGeneratorComponent,
PasswordGeneratorHistoryComponent,
RegisterComponent,
SearchCiphersPipe,
ShareComponent,
@@ -127,6 +130,7 @@ import { Folder } from 'jslib/models/domain';
CollectionsComponent,
FolderAddEditComponent,
ModalComponent,
PasswordGeneratorHistoryComponent,
ShareComponent,
TwoFactorOptionsComponent,
],

View File

@@ -0,0 +1,38 @@
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title">{{'passwordHistory' | i18n}}</h2>
<button type="button" class="close" data-dismiss="modal" attr.aria-label="{{'close' | i18n}}">
<span aria-hidden="true">&times;</span>
</button>
</div>
<ul class="list-group list-group-flush" *ngIf="history.length">
<li class="list-group-item d-flex" *ngFor="let h of history">
<div>
<div class="password">{{h.password}}</div>
<small class="text-muted">{{h.date | date:'medium'}}</small>
</div>
<div class="ml-auto">
<button class="btn btn-link" appBlurClick title="{{'copyPassword' | i18n}}" (click)="copy(h.password)">
<i class="fa fa-lg fa-clipboard"></i>
</button>
</div>
</li>
</ul>
<div class="modal-body" *ngIf="!history.length">
{{'noPasswordsInList' | i18n}}
</div>
<div class="modal-footer">
<button appBlurClick type="button" class="btn btn-outline-secondary" data-dismiss="modal" title="{{'close' | i18n}}">
{{'close' | i18n}}
</button>
<div class="ml-auto">
<button appBlurClick type="button" (click)="clear()" class="btn btn-outline-danger" title="{{'clear' | i18n}}">
<i class="fa fa-trash-o fa-lg fa-fw"></i>
</button>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,24 @@
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { Component } from '@angular/core';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import {
PasswordGeneratorHistoryComponent as BasePasswordGeneratorHistoryComponent,
} from 'jslib/angular/components/password-generator-history.component';
@Component({
selector: 'app-password-generator-history',
templateUrl: 'password-generator-history.component.html',
})
export class PasswordGeneratorHistoryComponent extends BasePasswordGeneratorHistoryComponent {
constructor(passwordGenerationService: PasswordGenerationService, analytics: Angulartics2,
platformUtilsService: PlatformUtilsService, i18nService: I18nService,
toasterService: ToasterService) {
super(passwordGenerationService, analytics, platformUtilsService, i18nService, toasterService, window);
}
}

View File

@@ -0,0 +1,63 @@
<div class="page-header">
<h1>{{'passwordGenerator' | i18n}}</h1>
</div>
<div class="card card-password bg-light my-4">
<div class="card-body">
<span>{{password}}</span>
</div>
</div>
<h2>{{'options' | i18n}}</h2>
<div class="row">
<div class="form-group col-4">
<label for="length">{{'length' | i18n}}</label>
<input id="length" class="form-control" type="number" min="5" max="128" [(ngModel)]="options.length" (input)="saveOptions()">
<input id="lengthRange" class="mt-2" type="range" min="5" max="128" step="1" [(ngModel)]="options.length" (change)="sliderChanged()"
(input)="sliderInput()">
</div>
<div class="form-group col-4">
<label for="min-number">{{'minNumbers' | i18n}}</label>
<input id="min-number" class="form-control" type="number" min="0" max="9" (input)="saveOptions()" [(ngModel)]="options.minNumber">
</div>
<div class="form-group col-4">
<label for="min-special">{{'minSpecial' | i18n}}</label>
<input id="min-special" class="form-control" type="number" min="0" max="9" (input)="saveOptions()" [(ngModel)]="options.minSpecial">
</div>
</div>
<div class="form-group">
<div class="form-check">
<input id="uppercase" class="form-check-input" type="checkbox" (change)="saveOptions()" [(ngModel)]="options.uppercase">
<label for="uppercase" class="form-check-label">A-Z</label>
</div>
<div class="form-check">
<input id="lowercase" class="form-check-input" type="checkbox" (change)="saveOptions()" [(ngModel)]="options.lowercase">
<label for="lowercase" class="form-check-label">a-z</label>
</div>
<div class="form-check">
<input id="numbers" class="form-check-input" type="checkbox" (change)="saveOptions()" [(ngModel)]="options.number">
<label for="numbers" class="form-check-label">0-9</label>
</div>
<div class="form-check">
<input id="special" class="form-check-input" type="checkbox" (change)="saveOptions()" [(ngModel)]="options.special">
<label for="special" class="form-check-label">!@#$%^&amp;*</label>
</div>
<div class="form-check">
<input id="ambiguous" class="form-check-input" type="checkbox" (change)="saveOptions()" [(ngModel)]="avoidAmbiguous">
<label for="ambiguous" class="form-check-label">{{'ambiguous' | i18n}}</label>
</div>
</div>
<div class="d-flex">
<div>
<button type="button" class="btn btn-outline-primary" appBlurClick (click)="regenerate()">
{{'regeneratePassword' | i18n}}
</button>
<button type="button" class="btn btn-outline-primary" appBlurClick (click)="copy()">
{{'copyPassword' | i18n}}
</button>
</div>
<div class="ml-auto">
<button type="button" class="btn btn-link" appBlurClick (click)="history()">
{{'passwordHistory' | i18n}}
</button>
</div>
</div>
<ng-template #historyTemplate></ng-template>

View File

@@ -0,0 +1,50 @@
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import {
Component,
ComponentFactoryResolver,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import {
PasswordGeneratorComponent as BasePasswordGeneratorComponent,
} from 'jslib/angular/components/password-generator.component';
import { ModalComponent } from '../modal.component';
import { PasswordGeneratorHistoryComponent } from './password-generator-history.component';
@Component({
selector: 'app-password-generator',
templateUrl: 'password-generator.component.html',
})
export class PasswordGeneratorComponent extends BasePasswordGeneratorComponent {
@ViewChild('historyTemplate', { read: ViewContainerRef }) historyModalRef: ViewContainerRef;
private modal: ModalComponent = null;
constructor(passwordGenerationService: PasswordGenerationService, analytics: Angulartics2,
platformUtilsService: PlatformUtilsService, i18nService: I18nService,
toasterService: ToasterService, private componentFactoryResolver: ComponentFactoryResolver) {
super(passwordGenerationService, analytics, platformUtilsService, i18nService, toasterService, window);
}
history() {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.historyModalRef.createComponent(factory).instance;
this.modal.show<PasswordGeneratorHistoryComponent>(PasswordGeneratorHistoryComponent, this.historyModalRef);
this.modal.onClosed.subscribe(async () => {
this.modal = null;
});
}
}

View File

@@ -4,11 +4,15 @@
<div class="card">
<div class="card-header">Tools</div>
<div class="list-group list-group-flush">
<a routerLink="generator" class="list-group-item" routerLinkActive="active">
Password Generator
</a>
<a routerLink="import" class="list-group-item" routerLinkActive="active">
Import
</a>
<a routerLink="export" class="list-group-item" routerLinkActive="active">
Export</a>
Export
</a>
</div>
</div>
</div>

View File

@@ -12,6 +12,7 @@ import { AuditService } from 'jslib/abstractions/audit.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service';
import { TokenService } from 'jslib/abstractions/token.service';
@@ -38,7 +39,8 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
analytics: Angulartics2, toasterService: ToasterService,
auditService: AuditService, stateService: StateService,
private tokenService: TokenService, private totpService: TotpService) {
private tokenService: TokenService, private totpService: TotpService,
private passwordGenerationService: PasswordGenerationService) {
super(cipherService, folderService, i18nService, platformUtilsService, analytics,
toasterService, auditService, stateService);
}
@@ -83,6 +85,15 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
this.i18nService.t('valueCopied', this.i18nService.t(typeI18nKey)));
}
async generatePassword(): Promise<boolean> {
const confirmed = await super.generatePassword();
if (confirmed) {
const options = await this.passwordGenerationService.getOptions();
this.cipher.login.password = await this.passwordGenerationService.generatePassword(options);
}
return confirmed;
}
private cleanUp() {
if (this.totpInterval) {
window.clearInterval(this.totpInterval);