1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-27 04:03:00 +02:00

convert password generator to jslib

This commit is contained in:
Kyle Spearrin 2018-01-09 17:55:28 -05:00
parent 79aca025d0
commit eb031eda0f
4 changed files with 10 additions and 250 deletions

View File

@ -2,7 +2,7 @@ import BrowserApi from '../browser/browserApi';
import MainBackground from './main.background'; import MainBackground from './main.background';
import PasswordGenerationService from '../services/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib/abstractions';
import { UtilsService } from 'jslib/services/utils.service'; import { UtilsService } from 'jslib/services/utils.service';
@ -34,7 +34,7 @@ export default class CommandsBackground {
private async generatePasswordToClipboard() { private async generatePasswordToClipboard() {
const options = await this.passwordGenerationService.getOptions(); const options = await this.passwordGenerationService.getOptions();
const password = PasswordGenerationService.generatePassword(options); const password = await this.passwordGenerationService.generatePassword(options);
UtilsService.copyToClipboard(password); UtilsService.copyToClipboard(password);
this.passwordGenerationService.addHistory(password); this.passwordGenerationService.addHistory(password);

View File

@ -3,7 +3,10 @@ import BrowserApi from '../browser/browserApi';
import MainBackground from './main.background'; import MainBackground from './main.background';
import CipherService from '../services/cipher.service'; import CipherService from '../services/cipher.service';
import PasswordGenerationService from '../services/passwordGeneration.service';
import {
PasswordGenerationService,
} from 'jslib/abstractions';
import { UtilsService } from 'jslib/services/utils.service'; import { UtilsService } from 'jslib/services/utils.service';
@ -32,7 +35,7 @@ export default class ContextMenusBackground {
private async generatePasswordToClipboard() { private async generatePasswordToClipboard() {
const options = await this.passwordGenerationService.getOptions(); const options = await this.passwordGenerationService.getOptions();
const password = PasswordGenerationService.generatePassword(options); const password = this.passwordGenerationService.generatePassword(options);
UtilsService.copyToClipboard(password); UtilsService.copyToClipboard(password);
this.passwordGenerationService.addHistory(password); this.passwordGenerationService.addHistory(password);

View File

@ -4,6 +4,7 @@ import {
ApiService, ApiService,
AppIdService, AppIdService,
CryptoService, CryptoService,
PasswordGenerationService,
TokenService, TokenService,
TotpService, TotpService,
UserService, UserService,
@ -15,6 +16,7 @@ import {
AppIdService as AppIdServiceAbstraction, AppIdService as AppIdServiceAbstraction,
CryptoService as CryptoServiceAbstraction, CryptoService as CryptoServiceAbstraction,
MessagingService as MessagingServiceAbstraction, MessagingService as MessagingServiceAbstraction,
PasswordGenerationService as PasswordGenerationServiceAbstraction,
PlatformUtilsService as PlatformUtilsServiceAbstraction, PlatformUtilsService as PlatformUtilsServiceAbstraction,
StorageService as StorageServiceAbstraction, StorageService as StorageServiceAbstraction,
TokenService as TokenServiceAbstraction, TokenService as TokenServiceAbstraction,
@ -45,7 +47,6 @@ import EnvironmentService from '../services/environment.service';
import FolderService from '../services/folder.service'; import FolderService from '../services/folder.service';
import i18nService from '../services/i18n.service'; import i18nService from '../services/i18n.service';
import LockService from '../services/lock.service'; import LockService from '../services/lock.service';
import PasswordGenerationService from '../services/passwordGeneration.service';
import SettingsService from '../services/settings.service'; import SettingsService from '../services/settings.service';
import SyncService from '../services/sync.service'; import SyncService from '../services/sync.service';
@ -68,7 +69,7 @@ export default class MainBackground {
collectionService: CollectionService; collectionService: CollectionService;
lockService: LockService; lockService: LockService;
syncService: SyncService; syncService: SyncService;
passwordGenerationService: PasswordGenerationService; passwordGenerationService: PasswordGenerationServiceAbstraction;
totpService: TotpServiceAbstraction; totpService: TotpServiceAbstraction;
autofillService: AutofillService; autofillService: AutofillService;
containerService: ContainerService; containerService: ContainerService;

View File

@ -1,244 +0,0 @@
import {
CipherString,
PasswordHistory,
} from 'jslib/models/domain';
import { UtilsService } from 'jslib/services/utils.service';
import {
CryptoService,
StorageService,
} from 'jslib/abstractions';
const DefaultOptions = {
length: 14,
ambiguous: false,
number: true,
minNumber: 1,
uppercase: true,
minUppercase: 1,
lowercase: true,
minLowercase: 1,
special: false,
minSpecial: 1,
};
const Keys = {
options: 'passwordGenerationOptions',
history: 'generatedPasswordHistory',
};
const MaxPasswordsInHistory = 100;
export default class PasswordGenerationService {
static generatePassword(options: any): string {
// overload defaults with given options
const o = Object.assign({}, DefaultOptions, options);
// sanitize
if (o.uppercase && o.minUppercase < 0) {
o.minUppercase = 1;
}
if (o.lowercase && o.minLowercase < 0) {
o.minLowercase = 1;
}
if (o.number && o.minNumber < 0) {
o.minNumber = 1;
}
if (o.special && o.minSpecial < 0) {
o.minSpecial = 1;
}
if (!o.length || o.length < 1) {
o.length = 10;
}
const minLength: number = o.minUppercase + o.minLowercase + o.minNumber + o.minSpecial;
if (o.length < minLength) {
o.length = minLength;
}
const positions: string[] = [];
if (o.lowercase && o.minLowercase > 0) {
for (let i = 0; i < o.minLowercase; i++) {
positions.push('l');
}
}
if (o.uppercase && o.minUppercase > 0) {
for (let i = 0; i < o.minUppercase; i++) {
positions.push('u');
}
}
if (o.number && o.minNumber > 0) {
for (let i = 0; i < o.minNumber; i++) {
positions.push('n');
}
}
if (o.special && o.minSpecial > 0) {
for (let i = 0; i < o.minSpecial; i++) {
positions.push('s');
}
}
while (positions.length < o.length) {
positions.push('a');
}
// shuffle
positions.sort(() => {
return UtilsService.secureRandomNumber(0, 1) * 2 - 1;
});
// build out the char sets
let allCharSet = '';
let lowercaseCharSet = 'abcdefghijkmnopqrstuvwxyz';
if (o.ambiguous) {
lowercaseCharSet += 'l';
}
if (o.lowercase) {
allCharSet += lowercaseCharSet;
}
let uppercaseCharSet = 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
if (o.ambiguous) {
uppercaseCharSet += 'O';
}
if (o.uppercase) {
allCharSet += uppercaseCharSet;
}
let numberCharSet = '23456789';
if (o.ambiguous) {
numberCharSet += '01';
}
if (o.number) {
allCharSet += numberCharSet;
}
const specialCharSet = '!@#$%^&*';
if (o.special) {
allCharSet += specialCharSet;
}
let password = '';
for (let i = 0; i < o.length; i++) {
let positionChars: string;
switch (positions[i]) {
case 'l':
positionChars = lowercaseCharSet;
break;
case 'u':
positionChars = uppercaseCharSet;
break;
case 'n':
positionChars = numberCharSet;
break;
case 's':
positionChars = specialCharSet;
break;
case 'a':
positionChars = allCharSet;
break;
}
const randomCharIndex = UtilsService.secureRandomNumber(0, positionChars.length - 1);
password += positionChars.charAt(randomCharIndex);
}
return password;
}
optionsCache: any;
history: PasswordHistory[] = [];
constructor(private cryptoService: CryptoService,
private storageService: StorageService) {
storageService.get<PasswordHistory[]>(Keys.history).then((encrypted) => {
return this.decryptHistory(encrypted);
}).then((history) => {
this.history = history;
});
}
generatePassword(options: any) {
return PasswordGenerationService.generatePassword(options);
}
async getOptions() {
if (this.optionsCache == null) {
const options = await this.storageService.get(Keys.options);
if (options == null) {
this.optionsCache = DefaultOptions;
} else {
this.optionsCache = options;
}
}
return this.optionsCache;
}
async saveOptions(options: any) {
await this.storageService.save(Keys.options, options);
this.optionsCache = options;
}
getHistory() {
return this.history || new Array<PasswordHistory>();
}
async addHistory(password: string): Promise<any> {
// Prevent duplicates
if (this.matchesPrevious(password)) {
return;
}
this.history.push(new PasswordHistory(password, Date.now()));
// Remove old items.
if (this.history.length > MaxPasswordsInHistory) {
this.history.shift();
}
const newHistory = await this.encryptHistory();
return await this.storageService.save(Keys.history, newHistory);
}
async clear(): Promise<any> {
this.history = [];
return await this.storageService.remove(Keys.history);
}
private async encryptHistory(): Promise<PasswordHistory[]> {
if (this.history == null || this.history.length === 0) {
return Promise.resolve([]);
}
const promises = this.history.map(async (item) => {
const encrypted = await this.cryptoService.encrypt(item.password);
return new PasswordHistory(encrypted.encryptedString, item.date);
});
return await Promise.all(promises);
}
private async decryptHistory(history: PasswordHistory[]): Promise<PasswordHistory[]> {
if (history == null || history.length === 0) {
return Promise.resolve([]);
}
const promises = history.map(async (item) => {
const decrypted = await this.cryptoService.decrypt(new CipherString(item.password));
return new PasswordHistory(decrypted, item.date);
});
return await Promise.all(promises);
}
private matchesPrevious(password: string): boolean {
if (this.history == null || this.history.length === 0) {
return false;
}
return this.history[this.history.length - 1].password === password;
}
}