1
0
mirror of https://github.com/bitwarden/jslib synced 2026-01-08 19:43:15 +00:00

Merge branch 'master' of https://github.com/bitwarden/jslib into improve-hostname-and-domain-retrieval

This commit is contained in:
Daniel James Smith
2022-03-11 12:19:39 +01:00
492 changed files with 83679 additions and 5149 deletions

View File

@@ -15,9 +15,7 @@
"scripts": {
"clean": "rimraf dist/**/*",
"build": "npm run clean && tsc",
"build:watch": "npm run clean && tsc -watch",
"lint": "tslint 'src/**/*.ts' 'spec/**/*.ts'",
"lint:fix": "tslint 'src/**/*.ts' 'spec/**/*.ts' --fix"
"build:watch": "npm run clean && tsc -watch"
},
"devDependencies": {
"@types/duo_web_sdk": "^2.7.1",

View File

@@ -1,18 +1,14 @@
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
import { EventService } from "jslib-common/abstractions/event.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { CipherView } from "jslib-common/models/view/cipherView";
import { FieldView } from "jslib-common/models/view/fieldView";
import { CipherType } from "jslib-common/enums/cipherType";
import { EventType } from "jslib-common/enums/eventType";
import { FieldType } from "jslib-common/enums/fieldType";
import { Utils } from "jslib-common/misc/utils";
import { CipherView } from "jslib-common/models/view/cipherView";
import { FieldView } from "jslib-common/models/view/fieldView";
@Directive()
export class AddEditCustomFieldsComponent implements OnChanges {

View File

@@ -1,13 +1,5 @@
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType";
import { EventType } from "jslib-common/enums/eventType";
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
import { PolicyType } from "jslib-common/enums/policyType";
import { SecureNoteType } from "jslib-common/enums/secureNoteType";
import { UriMatchType } from "jslib-common/enums/uriMatchType";
import { AuditService } from "jslib-common/abstractions/audit.service";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service";
@@ -21,9 +13,15 @@ import { PasswordRepromptService } from "jslib-common/abstractions/passwordRepro
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType";
import { EventType } from "jslib-common/enums/eventType";
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
import { PolicyType } from "jslib-common/enums/policyType";
import { SecureNoteType } from "jslib-common/enums/secureNoteType";
import { UriMatchType } from "jslib-common/enums/uriMatchType";
import { Utils } from "jslib-common/misc/utils";
import { Cipher } from "jslib-common/models/domain/cipher";
import { CardView } from "jslib-common/models/view/cardView";
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
@@ -33,11 +31,9 @@ import { LoginUriView } from "jslib-common/models/view/loginUriView";
import { LoginView } from "jslib-common/models/view/loginView";
import { SecureNoteView } from "jslib-common/models/view/secureNoteView";
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class AddEditComponent implements OnInit {
@Input() cloneMode: boolean = false;
@Input() cloneMode = false;
@Input() folderId: string = null;
@Input() cipherId: string;
@Input() type: CipherType;
@@ -52,7 +48,7 @@ export class AddEditComponent implements OnInit {
@Output() onEditCollections = new EventEmitter<CipherView>();
@Output() onGeneratePassword = new EventEmitter();
editMode: boolean = false;
editMode = false;
cipher: CipherView;
folders: FolderView[];
collections: CollectionView[] = [];
@@ -61,9 +57,9 @@ export class AddEditComponent implements OnInit {
deletePromise: Promise<any>;
restorePromise: Promise<any>;
checkPasswordPromise: Promise<number>;
showPassword: boolean = false;
showCardNumber: boolean = false;
showCardCode: boolean = false;
showPassword = false;
showCardNumber = false;
showCardCode = false;
cipherType = CipherType;
typeOptions: any[];
cardBrandOptions: any[];
@@ -74,8 +70,8 @@ export class AddEditComponent implements OnInit {
autofillOnPageLoadOptions: any[];
currentDate = new Date();
allowPersonal = true;
reprompt: boolean = false;
canUseReprompt: boolean = true;
reprompt = false;
canUseReprompt = true;
protected writeableCollections: CollectionView[];
private previousCipherId: string;

View File

@@ -7,10 +7,8 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Cipher } from "jslib-common/models/domain/cipher";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
import { AttachmentView } from "jslib-common/models/view/attachmentView";
import { CipherView } from "jslib-common/models/view/cipherView";
@@ -209,7 +207,7 @@ export class AttachmentsComponent implements OnInit {
);
if (confirmed) {
this.platformUtilsService.launchUri(
"https://help.bitwarden.com/article/update-encryption-key/"
"https://bitwarden.com/help/account-encryption-key/#rotate-your-encryption-key"
);
}
}

View File

@@ -3,13 +3,12 @@ import { DomSanitizer } from "@angular/platform-browser";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
@Component({
selector: "app-avatar",
template:
'<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
'<img *ngIf="src" [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
"[ngClass]=\"{'rounded-circle': circle}\">",
})
export class AvatarComponent implements OnChanges, OnInit {
@@ -81,12 +80,10 @@ export class AvatarComponent implements OnChanges, OnInit {
private stringToColor(str: string): string {
let hash = 0;
for (let i = 0; i < str.length; i++) {
// tslint:disable-next-line
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
let color = "#";
for (let i = 0; i < 3; i++) {
// tslint:disable-next-line
const value = (hash >> (i * 8)) & 0xff;
color += ("00" + value.toString(16)).substr(-2);
}

View File

@@ -5,7 +5,7 @@
[attr.role]="useAlertRole ? 'alert' : null"
>
<h3 class="callout-heading" *ngIf="title">
<i class="fa {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
<i class="bwi {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
{{ title }}
</h3>
<div class="enforced-policy-options" *ngIf="enforcedPolicyOptions">

View File

@@ -1,7 +1,6 @@
import { Component, Input, OnInit } from "@angular/core";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
@Component({
@@ -36,7 +35,7 @@ export class CalloutComponent implements OnInit {
this.title = this.i18nService.t("warning");
}
if (this.icon === undefined) {
this.icon = "fa-warning";
this.icon = "bwi-exclamation-triangle";
}
} else if (this.type === "error") {
this.calloutStyle = "danger";
@@ -44,7 +43,7 @@ export class CalloutComponent implements OnInit {
this.title = this.i18nService.t("error");
}
if (this.icon === undefined) {
this.icon = "fa-bolt";
this.icon = "bwi-error";
}
} else if (this.type === "tip") {
this.calloutStyle = "success";
@@ -52,7 +51,7 @@ export class CalloutComponent implements OnInit {
this.title = this.i18nService.t("tip");
}
if (this.icon === undefined) {
this.icon = "fa-lightbulb-o";
this.icon = "bwi-lightbulb";
}
}
}

View File

@@ -3,9 +3,7 @@ import { Directive, Input } from "@angular/core";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { CaptchaIFrame } from "jslib-common/misc/captcha_iframe";
import { Utils } from "jslib-common/misc/utils";
@Directive()

View File

@@ -7,13 +7,11 @@ import { PasswordGenerationService } from "jslib-common/abstractions/passwordGen
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { KdfType } from "jslib-common/enums/kdfType";
import { EncString } from "jslib-common/models/domain/encString";
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { KdfType } from "jslib-common/enums/kdfType";
@Directive()
export class ChangePasswordComponent implements OnInit {
masterPassword: string;
@@ -40,7 +38,7 @@ export class ChangePasswordComponent implements OnInit {
async ngOnInit() {
this.email = await this.stateService.getEmail();
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
this.enforcedPolicyOptions ??= await this.policyService.getMasterPasswordPolicyOptions();
}
async submit() {

View File

@@ -1,7 +1,6 @@
import { Directive, EventEmitter, Input, Output } from "@angular/core";
import { SearchService } from "jslib-common/abstractions/search.service";
import { CipherView } from "jslib-common/models/view/cipherView";
@Directive()
@@ -12,12 +11,12 @@ export class CiphersComponent {
@Output() onAddCipher = new EventEmitter();
@Output() onAddCipherOptions = new EventEmitter();
loaded: boolean = false;
loaded = false;
ciphers: CipherView[] = [];
searchText: string;
searchPlaceholder: string = null;
filter: (cipher: CipherView) => boolean = null;
deleted: boolean = false;
deleted = false;
protected searchPending = false;
@@ -25,13 +24,13 @@ export class CiphersComponent {
constructor(protected searchService: SearchService) {}
async load(filter: (cipher: CipherView) => boolean = null, deleted: boolean = false) {
async load(filter: (cipher: CipherView) => boolean = null, deleted = false) {
this.deleted = deleted || false;
await this.applyFilter(filter);
this.loaded = true;
}
async reload(filter: (cipher: CipherView) => boolean = null, deleted: boolean = false) {
async reload(filter: (cipher: CipherView) => boolean = null, deleted = false) {
this.loaded = false;
this.ciphers = [];
await this.load(filter, deleted);

View File

@@ -5,12 +5,10 @@ import { CollectionService } from "jslib-common/abstractions/collection.service"
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { Cipher } from "jslib-common/models/domain/cipher";
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { Cipher } from "jslib-common/models/domain/cipher";
@Directive()
export class CollectionsComponent implements OnInit {
@Input() cipherId: string;

View File

@@ -0,0 +1,5 @@
<ng-container *ngIf="show">
<app-callout type="info" title="{{ scopeConfig.title | i18n }}">
{{ scopeConfig.description | i18n: scopeConfig.scopeIdentifier }}
</app-callout>
</ng-container>

View File

@@ -0,0 +1,43 @@
import { Component, Input, OnInit } from "@angular/core";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { StateService } from "jslib-common/abstractions/state.service";
@Component({
selector: "app-export-scope-callout",
templateUrl: "export-scope-callout.component.html",
})
export class ExportScopeCalloutComponent implements OnInit {
@Input() organizationId: string = null;
show = false;
scopeConfig: {
title: string;
description: string;
scopeIdentifier: string;
};
constructor(
protected organizationService: OrganizationService,
protected stateService: StateService
) {}
async ngOnInit(): Promise<void> {
if (!(await this.organizationService.hasOrganizations())) {
return;
}
this.scopeConfig =
this.organizationId != null
? {
title: "exportingOrganizationVaultTitle",
description: "exportingOrganizationVaultDescription",
scopeIdentifier: (await this.organizationService.get(this.organizationId)).name,
}
: {
title: "exportingPersonalVaultTitle",
description: "exportingPersonalVaultDescription",
scopeIdentifier: await this.stateService.getEmail(),
};
this.show = true;
}
}

View File

@@ -9,7 +9,6 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { EventType } from "jslib-common/enums/eventType";
import { PolicyType } from "jslib-common/enums/policyType";
@@ -18,9 +17,9 @@ export class ExportComponent implements OnInit {
@Output() onSaved = new EventEmitter();
formPromise: Promise<string>;
disabledByPolicy: boolean = false;
disabledByPolicy = false;
exportForm = this.fb.group({
exportForm = this.formBuilder.group({
format: ["json"],
secret: [""],
});
@@ -41,7 +40,7 @@ export class ExportComponent implements OnInit {
protected win: Window,
private logService: LogService,
private userVerificationService: UserVerificationService,
private fb: FormBuilder
private formBuilder: FormBuilder
) {}
async ngOnInit() {

View File

@@ -4,7 +4,6 @@ import { FolderService } from "jslib-common/abstractions/folder.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { FolderView } from "jslib-common/models/view/folderView";
@Directive()
@@ -13,7 +12,7 @@ export class FolderAddEditComponent implements OnInit {
@Output() onSavedFolder = new EventEmitter<FolderView>();
@Output() onDeletedFolder = new EventEmitter<FolderView>();
editMode: boolean = false;
editMode = false;
folder: FolderView = new FolderView();
title: string;
formPromise: Promise<any>;

View File

@@ -1,15 +1,12 @@
import { Directive, EventEmitter, Input, Output } from "@angular/core";
import { CipherType } from "jslib-common/enums/cipherType";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { FolderView } from "jslib-common/models/view/folderView";
import { TreeNode } from "jslib-common/models/domain/treeNode";
import { CollectionService } from "jslib-common/abstractions/collection.service";
import { FolderService } from "jslib-common/abstractions/folder.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { CipherType } from "jslib-common/enums/cipherType";
import { TreeNode } from "jslib-common/models/domain/treeNode";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { FolderView } from "jslib-common/models/view/folderView";
@Directive()
export class GroupingsComponent {
@@ -31,13 +28,13 @@ export class GroupingsComponent {
nestedFolders: TreeNode<FolderView>[];
collections: CollectionView[];
nestedCollections: TreeNode<CollectionView>[];
loaded: boolean = false;
loaded = false;
cipherType = CipherType;
selectedAll: boolean = false;
selectedFavorites: boolean = false;
selectedTrash: boolean = false;
selectedAll = false;
selectedFavorites = false;
selectedTrash = false;
selectedType: CipherType = null;
selectedFolder: boolean = false;
selectedFolder = false;
selectedFolderId: string = null;
selectedCollectionId: string = null;
@@ -151,7 +148,7 @@ export class GroupingsComponent {
} else {
this.collapsedGroupings.add(id);
}
await this.stateService.setCollapsedGroupings(this.collapsedGroupings);
await this.stateService.setCollapsedGroupings(Array.from(this.collapsedGroupings));
}
isCollapsed(grouping: FolderView | CollectionView, idPrefix = "") {

View File

@@ -1,14 +1,13 @@
import { Router } from "@angular/router";
import { PasswordHintRequest } from "jslib-common/models/request/passwordHintRequest";
import { ApiService } from "jslib-common/abstractions/api.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PasswordHintRequest } from "jslib-common/models/request/passwordHintRequest";
export class HintComponent {
email: string = "";
email = "";
formPromise: Promise<any>;
protected successRoute = "login";

View File

@@ -1,4 +1,11 @@
<div class="icon" aria-hidden="true">
<img [src]="image" appFallbackSrc="{{ fallbackImage }}" *ngIf="imageEnabled && image" alt="" />
<i class="fa fa-fw fa-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
<img
[src]="image"
appFallbackSrc="{{ fallbackImage }}"
*ngIf="imageEnabled && image"
alt=""
decoding="async"
loading="lazy"
/>
<i class="bwi bwi-fw bwi-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
</div>

View File

@@ -1,21 +1,24 @@
import { Component, Input, OnChanges } from "@angular/core";
import { CipherType } from "jslib-common/enums/cipherType";
import { CipherView } from "jslib-common/models/view/cipherView";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { CipherType } from "jslib-common/enums/cipherType";
import { Utils } from "jslib-common/misc/utils";
import { CipherView } from "jslib-common/models/view/cipherView";
const IconMap: any = {
"fa-globe": String.fromCharCode(0xf0ac),
"fa-sticky-note-o": String.fromCharCode(0xf24a),
"fa-id-card-o": String.fromCharCode(0xf2c3),
"fa-credit-card": String.fromCharCode(0xf09d),
"fa-android": String.fromCharCode(0xf17b),
"fa-apple": String.fromCharCode(0xf179),
/**
* Provides a mapping from supported card brands to
* the filenames of icon that should be present in images/cards folder of clients.
*/
const cardIcons: Record<string, string> = {
Visa: "card-visa",
Mastercard: "card-mastercard",
Amex: "card-amex",
Discover: "card-discover",
"Diners Club": "card-diners-club",
JCB: "card-jcb",
Maestro: "card-maestro",
UnionPay: "card-union-pay",
};
@Component({
@@ -44,24 +47,21 @@ export class IconComponent implements OnChanges {
this.load();
}
get iconCode(): string {
return IconMap[this.icon];
}
protected load() {
switch (this.cipher.type) {
case CipherType.Login:
this.icon = "fa-globe";
this.icon = "bwi-globe";
this.setLoginIcon();
break;
case CipherType.SecureNote:
this.icon = "fa-sticky-note-o";
this.icon = "bwi-sticky-note";
break;
case CipherType.Card:
this.icon = "fa-credit-card";
this.icon = "bwi-credit-card";
this.setCardIcon();
break;
case CipherType.Identity:
this.icon = "fa-id-card-o";
this.icon = "bwi-id-card";
break;
default:
break;
@@ -74,10 +74,10 @@ export class IconComponent implements OnChanges {
let isWebsite = false;
if (hostnameUri.indexOf("androidapp://") === 0) {
this.icon = "fa-android";
this.icon = "bwi-android";
this.image = null;
} else if (hostnameUri.indexOf("iosapp://") === 0) {
this.icon = "fa-apple";
this.icon = "bwi-apple";
this.image = null;
} else if (
this.imageEnabled &&
@@ -93,7 +93,7 @@ export class IconComponent implements OnChanges {
if (this.imageEnabled && isWebsite) {
try {
this.image = this.iconsUrl + "/" + Utils.getHostname(hostnameUri) + "/icon.png";
this.fallbackImage = "images/fa-globe.png";
this.fallbackImage = "images/bwi-globe.png";
} catch (e) {
// Ignore error since the fallback icon will be shown if image is null.
}
@@ -102,4 +102,11 @@ export class IconComponent implements OnChanges {
this.image = null;
}
}
private setCardIcon() {
const brand = this.cipher.card.brand;
if (this.imageEnabled && brand in cardIcons) {
this.icon = "credit-card-icon " + cardIcons[brand];
}
}
}

View File

@@ -12,32 +12,28 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
import { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { SecretVerificationRequest } from "jslib-common/models/request/secretVerificationRequest";
import { Utils } from "jslib-common/misc/utils";
import { HashPurpose } from "jslib-common/enums/hashPurpose";
import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
import { Utils } from "jslib-common/misc/utils";
import { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { SecretVerificationRequest } from "jslib-common/models/request/secretVerificationRequest";
@Directive()
export class LockComponent implements OnInit {
masterPassword: string = "";
pin: string = "";
showPassword: boolean = false;
masterPassword = "";
pin = "";
showPassword = false;
email: string;
pinLock: boolean = false;
webVaultHostname: string = "";
pinLock = false;
webVaultHostname = "";
formPromise: Promise<any>;
supportsBiometric: boolean;
biometricLock: boolean;
biometricText: string;
hideInput: boolean;
protected successRoute: string = "vault";
protected successRoute = "vault";
protected onSuccessfulSubmit: () => Promise<void>;
private invalidPinAttempts = 0;
@@ -53,13 +49,15 @@ export class LockComponent implements OnInit {
protected environmentService: EnvironmentService,
protected stateService: StateService,
protected apiService: ApiService,
private logService: LogService,
protected logService: LogService,
private keyConnectorService: KeyConnectorService,
protected ngZone: NgZone
) {}
async ngOnInit() {
this.stateService.activeAccount.subscribe(async (_userId) => {
// Load the first and observe updates
await this.load();
this.stateService.activeAccount.subscribe(async () => {
await this.load();
});
}

View File

@@ -1,11 +1,7 @@
import { Directive, Input, NgZone, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { take } from "rxjs/operators";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
@@ -14,18 +10,19 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { PasswordLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { CaptchaProtectedComponent } from "./captchaProtected.component";
@Directive()
export class LoginComponent extends CaptchaProtectedComponent implements OnInit {
@Input() email: string = "";
@Input() email = "";
@Input() rememberEmail = true;
masterPassword: string = "";
showPassword: boolean = false;
masterPassword = "";
showPassword = false;
formPromise: Promise<AuthResult>;
onSuccessfulLogin: () => Promise<any>;
onSuccessfulLoginNavigate: () => Promise<any>;
@@ -35,6 +32,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
protected twoFactorRoute = "2fa";
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
protected alwaysRememberEmail = false;
constructor(
protected authService: AuthService,
@@ -58,7 +56,9 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.email = "";
}
}
this.rememberEmail = (await this.stateService.getRememberedEmail()) != null;
if (!this.alwaysRememberEmail) {
this.rememberEmail = (await this.stateService.getRememberedEmail()) != null;
}
if (Utils.isBrowser && !Utils.isNode) {
this.focusInput();
}
@@ -93,16 +93,22 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
}
try {
this.formPromise = this.authService.logIn(this.email, this.masterPassword, this.captchaToken);
const credentials = new PasswordLogInCredentials(
this.email,
this.masterPassword,
this.captchaToken,
null
);
this.formPromise = this.authService.logIn(credentials);
const response = await this.formPromise;
if (this.rememberEmail) {
if (this.rememberEmail || this.alwaysRememberEmail) {
await this.stateService.setRememberedEmail(this.email);
} else {
await this.stateService.setRememberedEmail(null);
}
if (this.handleCaptchaRequired(response)) {
return;
} else if (response.twoFactor) {
} else if (response.requiresTwoFactor) {
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
this.onSuccessfulLoginTwoFactorNavigate();
} else {

View File

@@ -1,3 +1,4 @@
import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from "@angular/cdk/a11y";
import {
AfterViewInit,
ChangeDetectorRef,
@@ -10,8 +11,6 @@ import {
ViewContainerRef,
} from "@angular/core";
import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from "@angular/cdk/a11y";
import { ModalService } from "../../services/modal.service";
import { ModalRef } from "./modal.ref";

View File

@@ -3,7 +3,6 @@ import { Directive, OnInit } from "@angular/core";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { GeneratedPasswordHistory } from "jslib-common/models/domain/generatedPasswordHistory";
@Directive()

View File

@@ -3,17 +3,16 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PasswordGeneratorPolicyOptions } from "jslib-common/models/domain/passwordGeneratorPolicyOptions";
@Directive()
export class PasswordGeneratorComponent implements OnInit {
@Input() showSelect: boolean = false;
@Input() showSelect = false;
@Output() onSelected = new EventEmitter<string>();
passTypeOptions: any[];
options: any = {};
password: string = "-";
password = "-";
showOptions = false;
avoidAmbiguous = false;
enforcedPolicyOptions: PasswordGeneratorPolicyOptions;
@@ -50,7 +49,7 @@ export class PasswordGeneratorComponent implements OnInit {
this.password = await this.passwordGenerationService.generatePassword(this.options);
}
async saveOptions(regenerate: boolean = true) {
async saveOptions(regenerate = true) {
this.normalizeOptions();
await this.passwordGenerationService.saveOptions(this.options);

View File

@@ -3,7 +3,6 @@ import { Directive, OnInit } from "@angular/core";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PasswordHistoryView } from "jslib-common/models/view/passwordHistoryView";
@Directive()

View File

@@ -3,6 +3,7 @@ import { Directive } from "@angular/core";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { ModalRef } from "./modal/modal.ref";
@Directive()

View File

@@ -8,8 +8,8 @@ import { StateService } from "jslib-common/abstractions/state.service";
@Directive()
export class PremiumComponent implements OnInit {
isPremium: boolean = false;
price: number = 10;
isPremium = false;
price = 10;
refreshPromise: Promise<any>;
constructor(

View File

@@ -1,10 +1,6 @@
import { Directive, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { KeysRequest } from "jslib-common/models/request/keysRequest";
import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest";
import { RegisterRequest } from "jslib-common/models/request/registerRequest";
import { ApiService } from "jslib-common/abstractions/api.service";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
@@ -14,24 +10,26 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { KdfType } from "jslib-common/enums/kdfType";
import { KeysRequest } from "jslib-common/models/request/keysRequest";
import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest";
import { RegisterRequest } from "jslib-common/models/request/registerRequest";
import { CaptchaProtectedComponent } from "./captchaProtected.component";
@Directive()
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
name: string = "";
email: string = "";
masterPassword: string = "";
confirmMasterPassword: string = "";
hint: string = "";
showPassword: boolean = false;
name = "";
email = "";
masterPassword = "";
confirmMasterPassword = "";
hint = "";
showPassword = false;
formPromise: Promise<any>;
masterPasswordScore: number;
referenceData: ReferenceEventRequest;
showTerms = true;
acceptPolicies: boolean = false;
acceptPolicies = false;
protected successRoute = "login";
private masterPasswordStrengthTimeout: any;

View File

@@ -7,16 +7,15 @@ import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.serv
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service";
import { Organization } from "jslib-common/models/domain/organization";
@Directive()
export class RemovePasswordComponent implements OnInit {
actionPromise: Promise<any>;
continuing: boolean = false;
leaving: boolean = false;
continuing = false;
leaving = false;
loading: boolean = true;
loading = true;
organization: Organization;
email: string;

View File

@@ -1,9 +1,6 @@
import { DatePipe } from "@angular/common";
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { PolicyType } from "jslib-common/enums/policyType";
import { SendType } from "jslib-common/enums/sendType";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
@@ -12,14 +9,14 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SendService } from "jslib-common/abstractions/send.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { PolicyType } from "jslib-common/enums/policyType";
import { SendType } from "jslib-common/enums/sendType";
import { EncArrayBuffer } from "jslib-common/models/domain/encArrayBuffer";
import { Send } from "jslib-common/models/domain/send";
import { SendFileView } from "jslib-common/models/view/sendFileView";
import { SendTextView } from "jslib-common/models/view/sendTextView";
import { SendView } from "jslib-common/models/view/sendView";
import { EncArrayBuffer } from "jslib-common/models/domain/encArrayBuffer";
import { Send } from "jslib-common/models/domain/send";
@Directive()
export class AddEditComponent implements OnInit {
@Input() sendId: string;

View File

@@ -133,12 +133,13 @@ export class EffluxDatesComponent implements OnInit {
default:
return this.defaultDeletionDateTime.value;
}
default:
default: {
const now = new Date();
const miliseconds = now.setTime(
now.getTime() + (this.selectedDeletionDatePreset.value as number) * 60 * 60 * 1000
);
return new Date(miliseconds).toString();
}
}
}
@@ -163,12 +164,13 @@ export class EffluxDatesComponent implements OnInit {
}
return this.defaultExpirationDateTime.value;
}
default:
default: {
const now = new Date();
const miliseconds = now.setTime(
now.getTime() + (this.selectedExpirationDatePreset.value as number) * 60 * 60 * 1000
);
return new Date(miliseconds).toString();
}
}
}
//

View File

@@ -1,10 +1,5 @@
import { Directive, NgZone, OnInit } from "@angular/core";
import { PolicyType } from "jslib-common/enums/policyType";
import { SendType } from "jslib-common/enums/sendType";
import { SendView } from "jslib-common/models/view/sendView";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
@@ -12,6 +7,9 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service";
import { PolicyType } from "jslib-common/enums/policyType";
import { SendType } from "jslib-common/enums/sendType";
import { SendView } from "jslib-common/models/view/sendView";
@Directive()
export class SendComponent implements OnInit {
@@ -20,7 +18,7 @@ export class SendComponent implements OnInit {
loaded = false;
loading = true;
refreshing = false;
expired: boolean = false;
expired = false;
type: SendType = null;
sends: SendView[] = [];
filteredSends: SendView[] = [];

View File

@@ -1,6 +1,5 @@
import { Directive } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { ApiService } from "jslib-common/abstractions/api.service";
@@ -12,26 +11,22 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service";
import { HashPurpose } from "jslib-common/enums/hashPurpose";
import { KdfType } from "jslib-common/enums/kdfType";
import { Utils } from "jslib-common/misc/utils";
import { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { KeysRequest } from "jslib-common/models/request/keysRequest";
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
import { SetPasswordRequest } from "jslib-common/models/request/setPasswordRequest";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
import { HashPurpose } from "jslib-common/enums/hashPurpose";
import { KdfType } from "jslib-common/enums/kdfType";
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class SetPasswordComponent extends BaseChangePasswordComponent {
syncLoading: boolean = true;
showPassword: boolean = false;
hint: string = "";
syncLoading = true;
showPassword = false;
hint = "";
identifier: string = null;
orgId: string;
resetPasswordAutoEnroll = false;
@@ -79,6 +74,8 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
const response = await this.apiService.getOrganizationAutoEnrollStatus(this.identifier);
this.orgId = response.id;
this.resetPasswordAutoEnroll = response.resetPasswordEnabled;
this.enforcedPolicyOptions =
await this.policyService.getMasterPasswordPoliciesForInvitedUsers(this.orgId);
} catch {
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}

View File

@@ -3,7 +3,6 @@ import { Directive, OnInit } from "@angular/core";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
import { ModalRef } from "./modal/modal.ref";

View File

@@ -9,7 +9,6 @@ import {
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { PolicyType } from "jslib-common/enums/policyType";
import { Policy } from "jslib-common/models/domain/policy";
@@ -21,9 +20,9 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
static CUSTOM_VALUE = -100;
form = this.fb.group({
form = this.formBuilder.group({
vaultTimeout: [null],
custom: this.fb.group({
custom: this.formBuilder.group({
hours: [null],
minutes: [null],
}),
@@ -38,7 +37,7 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
private validatorChange: () => void;
constructor(
private fb: FormBuilder,
private formBuilder: FormBuilder,
private policyService: PolicyService,
private i18nService: I18nService
) {}
@@ -120,11 +119,13 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
this.onChange = onChange;
}
// tslint:disable-next-line
registerOnTouched(onTouched: any): void {}
registerOnTouched(onTouched: any): void {
// Empty
}
// tslint:disable-next-line
setDisabledState?(isDisabled: boolean): void {}
setDisabledState?(isDisabled: boolean): void {
// Empty
}
validate(control: AbstractControl): ValidationErrors {
if (this.vaultTimeoutPolicy && this.vaultTimeoutPolicy?.data?.minutes < control.value) {

View File

@@ -1,20 +1,17 @@
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
import { Utils } from "jslib-common/misc/utils";
import { Organization } from "jslib-common/models/domain/organization";
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class ShareComponent implements OnInit {
@Input() cipherId: string;

View File

@@ -1,6 +1,5 @@
import { Directive } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from "rxjs/operators";
import { ApiService } from "jslib-common/abstractions/api.service";
@@ -12,10 +11,9 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { SsoLogInCredentials } from "jslib-common/models/domain/logInCredentials";
@Directive()
export class SsoComponent {
@@ -171,14 +169,15 @@ export class SsoComponent {
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
this.loggingIn = true;
try {
this.formPromise = this.authService.logInSso(
const credentials = new SsoLogInCredentials(
code,
codeVerifier,
this.redirectUri,
orgIdFromState
);
this.formPromise = this.authService.logIn(credentials);
const response = await this.formPromise;
if (response.twoFactor) {
if (response.requiresTwoFactor) {
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
this.onSuccessfulLoginTwoFactorNavigate();
} else {

View File

@@ -1,11 +1,10 @@
import { Directive, EventEmitter, OnInit, Output } from "@angular/core";
import { Router } from "@angular/router";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
@Directive()
export class TwoFactorOptionsComponent implements OnInit {
@@ -15,7 +14,7 @@ export class TwoFactorOptionsComponent implements OnInit {
providers: any[] = [];
constructor(
protected authService: AuthService,
protected twoFactorService: TwoFactorService,
protected router: Router,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
@@ -23,7 +22,7 @@ export class TwoFactorOptionsComponent implements OnInit {
) {}
ngOnInit() {
this.providers = this.authService.getSupportedTwoFactorProviders(this.win);
this.providers = this.twoFactorService.getSupportedProviders(this.win);
}
choose(p: any) {
@@ -31,7 +30,7 @@ export class TwoFactorOptionsComponent implements OnInit {
}
recover() {
this.platformUtilsService.launchUri("https://help.bitwarden.com/article/lost-two-step-device/");
this.platformUtilsService.launchUri("https://bitwarden.com/help/lost-two-step-device/");
this.onRecoverSelected.emit();
}
}

View File

@@ -1,15 +1,8 @@
import { Directive, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import * as DuoWebSDK from "duo_web_sdk";
import { first } from "rxjs/operators";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { TwoFactorEmailRequest } from "jslib-common/models/request/twoFactorEmailRequest";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { ApiService } from "jslib-common/abstractions/api.service";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
@@ -17,24 +10,27 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { TwoFactorProviders } from "jslib-common/services/auth.service";
import * as DuoWebSDK from "duo_web_sdk";
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { WebAuthnIFrame } from "jslib-common/misc/webauthn_iframe";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { TwoFactorEmailRequest } from "jslib-common/models/request/twoFactorEmailRequest";
import { TwoFactorProviders } from "jslib-common/services/twoFactor.service";
import { CaptchaProtectedComponent } from "./captchaProtected.component";
@Directive()
export class TwoFactorComponent implements OnInit, OnDestroy {
token: string = "";
remember: boolean = false;
webAuthnReady: boolean = false;
webAuthnNewTab: boolean = false;
export class TwoFactorComponent extends CaptchaProtectedComponent implements OnInit, OnDestroy {
token = "";
remember = false;
webAuthnReady = false;
webAuthnNewTab = false;
providers = TwoFactorProviders;
providerType = TwoFactorProviderType;
selectedProviderType: TwoFactorProviderType = TwoFactorProviderType.Authenticator;
webAuthnSupported: boolean = false;
webAuthnSupported = false;
webAuthn: WebAuthnIFrame = null;
title: string = "";
title = "";
twoFactorEmail: string = null;
formPromise: Promise<any>;
emailPromise: Promise<any>;
@@ -59,13 +55,15 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
protected environmentService: EnvironmentService,
protected stateService: StateService,
protected route: ActivatedRoute,
protected logService: LogService
protected logService: LogService,
protected twoFactorService: TwoFactorService
) {
super(environmentService, i18nService, platformUtilsService);
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
}
async ngOnInit() {
if (!this.authing || this.authService.twoFactorProvidersData == null) {
if (!this.authing || this.twoFactorService.getProviders() == null) {
this.router.navigate([this.loginRoute]);
return;
}
@@ -103,9 +101,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
);
}
this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(
this.webAuthnSupported
);
this.selectedProviderType = this.twoFactorService.getDefaultProvider(this.webAuthnSupported);
await this.init();
}
@@ -122,7 +118,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
this.cleanupWebAuthn();
this.title = (TwoFactorProviders as any)[this.selectedProviderType].name;
const providerData = this.authService.twoFactorProvidersData.get(this.selectedProviderType);
const providerData = this.twoFactorService.getProviders().get(this.selectedProviderType);
switch (this.selectedProviderType) {
case TwoFactorProviderType.WebAuthn:
if (!this.webAuthnNewTab) {
@@ -150,7 +146,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
break;
case TwoFactorProviderType.Email:
this.twoFactorEmail = providerData.Email;
if (this.authService.twoFactorProvidersData.size > 1) {
if (this.twoFactorService.getProviders().size > 1) {
await this.sendEmail(false);
}
break;
@@ -160,6 +156,8 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
async submit() {
await this.setupCaptcha();
if (this.token == null || this.token === "") {
this.platformUtilsService.showToast(
"error",
@@ -193,13 +191,19 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
async doSubmit() {
this.formPromise = this.authService.logInTwoFactor(
this.selectedProviderType,
this.token,
this.remember
{
provider: this.selectedProviderType,
token: this.token,
remember: this.remember,
},
this.captchaToken
);
const response: AuthResult = await this.formPromise;
const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.setDisableFavicon(!!disableFavicon);
if (this.handleCaptchaRequired(response)) {
return;
}
if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin();
}
@@ -250,7 +254,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
authWebAuthn() {
const providerData = this.authService.twoFactorProvidersData.get(this.selectedProviderType);
const providerData = this.twoFactorService.getProviders().get(this.selectedProviderType);
if (!this.webAuthnSupported || this.webAuthn == null) {
return;

View File

@@ -0,0 +1,127 @@
import { Directive } from "@angular/core";
import { Router } from "@angular/router";
import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { VerificationType } from "jslib-common/enums/verificationType";
import { EncString } from "jslib-common/models/domain/encString";
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { PasswordRequest } from "jslib-common/models/request/passwordRequest";
import { Verification } from "jslib-common/types/verification";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
@Directive()
export class UpdatePasswordComponent extends BaseChangePasswordComponent {
hint: string;
key: string;
enforcedPolicyOptions: MasterPasswordPolicyOptions;
showPassword = false;
currentMasterPassword: string;
onSuccessfulChangePassword: () => Promise<any>;
constructor(
protected router: Router,
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService,
policyService: PolicyService,
cryptoService: CryptoService,
messagingService: MessagingService,
private apiService: ApiService,
stateService: StateService,
private userVerificationService: UserVerificationService,
private logService: LogService
) {
super(
i18nService,
cryptoService,
messagingService,
passwordGenerationService,
platformUtilsService,
policyService,
stateService
);
}
togglePassword(confirmField: boolean) {
this.showPassword = !this.showPassword;
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
}
async cancel() {
await this.stateService.setOrganizationInvitation(null);
await this.stateService.setLoginRedirect(null);
this.router.navigate(["/vault"]);
}
async setupSubmitActions(): Promise<boolean> {
if (this.currentMasterPassword == null || this.currentMasterPassword === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassRequired")
);
return false;
}
const secret: Verification = {
type: VerificationType.MasterPassword,
secret: this.currentMasterPassword,
};
try {
await this.userVerificationService.verifyUser(secret);
} catch (e) {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
return false;
}
this.kdf = await this.stateService.getKdfType();
this.kdfIterations = await this.stateService.getKdfIterations();
return true;
}
async performSubmitActions(
masterPasswordHash: string,
key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]
) {
try {
// Create Request
const request = new PasswordRequest();
request.masterPasswordHash = await this.cryptoService.hashPassword(
this.currentMasterPassword,
null
);
request.newMasterPasswordHash = masterPasswordHash;
request.key = encKey[1].encryptedString;
// Update user's password
this.apiService.postPassword(request);
this.platformUtilsService.showToast(
"success",
this.i18nService.t("masterPasswordChanged"),
this.i18nService.t("logBackIn")
);
if (this.onSuccessfulChangePassword != null) {
this.onSuccessfulChangePassword();
} else {
this.messagingService.send("logout");
}
} catch (e) {
this.logService.error(e);
}
}
}

View File

@@ -10,21 +10,19 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { PolicyService } from "jslib-common/abstractions/policy.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { SyncService } from "jslib-common/abstractions/sync.service";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
import { EncString } from "jslib-common/models/domain/encString";
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { UpdateTempPasswordRequest } from "jslib-common/models/request/updateTempPasswordRequest";
import { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
@Directive()
export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
hint: string;
key: string;
enforcedPolicyOptions: MasterPasswordPolicyOptions;
showPassword: boolean = false;
showPassword = false;
onSuccessfulChangePassword: () => Promise<any>;

View File

@@ -24,7 +24,7 @@
{{ "sendCode" | i18n }}
</button>
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
<i class="bwi bwi-check-circle" aria-hidden="true"></i>
{{ "codeSent" | i18n }}
</span>
</div>

View File

@@ -4,9 +4,7 @@ import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from "@angular/f
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { VerificationType } from "jslib-common/enums/verificationType";
import { Verification } from "jslib-common/types/verification";
@Component({
@@ -26,9 +24,9 @@ import { Verification } from "jslib-common/types/verification";
],
})
export class VerifyMasterPasswordComponent implements ControlValueAccessor, OnInit {
usesKeyConnector: boolean = false;
disableRequestOTP: boolean = false;
sentCode: boolean = false;
usesKeyConnector = false;
disableRequestOTP = false;
sentCode = false;
secret = new FormControl("");

View File

@@ -1,10 +1,8 @@
import { Directive, Input } from "@angular/core";
import { EventService } from "jslib-common/abstractions/event.service";
import { EventType } from "jslib-common/enums/eventType";
import { FieldType } from "jslib-common/enums/fieldType";
import { EventService } from "jslib-common/abstractions/event.service";
import { CipherView } from "jslib-common/models/view/cipherView";
import { FieldView } from "jslib-common/models/view/fieldView";
@@ -25,8 +23,17 @@ export class ViewCustomFieldsComponent {
const f = field as any;
f.showValue = !f.showValue;
f.showCount = false;
if (f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
}
}
async toggleFieldCount(field: FieldView) {
if (!field.showValue) {
return;
}
field.showCount = !field.showCount;
}
}

View File

@@ -9,11 +9,6 @@ import {
Output,
} from "@angular/core";
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType";
import { EventType } from "jslib-common/enums/eventType";
import { FieldType } from "jslib-common/enums/fieldType";
import { ApiService } from "jslib-common/abstractions/api.service";
import { AuditService } from "jslib-common/abstractions/audit.service";
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
@@ -27,9 +22,11 @@ import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.se
import { StateService } from "jslib-common/abstractions/state.service";
import { TokenService } from "jslib-common/abstractions/token.service";
import { TotpService } from "jslib-common/abstractions/totp.service";
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
import { CipherType } from "jslib-common/enums/cipherType";
import { EventType } from "jslib-common/enums/eventType";
import { FieldType } from "jslib-common/enums/fieldType";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
import { AttachmentView } from "jslib-common/models/view/attachmentView";
import { CipherView } from "jslib-common/models/view/cipherView";
import { LoginUriView } from "jslib-common/models/view/loginUriView";
@@ -47,6 +44,7 @@ export class ViewComponent implements OnDestroy, OnInit {
cipher: CipherView;
showPassword: boolean;
showPasswordCount: boolean;
showCardNumber: boolean;
showCardCode: boolean;
canAccessPremium: boolean;
@@ -60,7 +58,7 @@ export class ViewComponent implements OnDestroy, OnInit {
private totpInterval: any;
private previousCipherId: string;
private passwordReprompted: boolean = false;
private passwordReprompted = false;
constructor(
protected cipherService: CipherService,
@@ -221,11 +219,20 @@ export class ViewComponent implements OnDestroy, OnInit {
}
this.showPassword = !this.showPassword;
this.showPasswordCount = false;
if (this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
}
}
async togglePasswordCount() {
if (!this.showPassword) {
return;
}
this.showPasswordCount = !this.showPasswordCount;
}
async toggleCardNumber() {
if (!(await this.promptPassword())) {
return;

View File

@@ -0,0 +1,26 @@
import { Directive, ElementRef, OnDestroy, OnInit } from "@angular/core";
import { NgControl } from "@angular/forms";
import { Subscription } from "rxjs";
@Directive({
selector: "[appA11yInvalid]",
})
export class A11yInvalidDirective implements OnDestroy, OnInit {
private sub: Subscription;
constructor(private el: ElementRef<HTMLInputElement>, private formControlDirective: NgControl) {}
ngOnInit() {
this.sub = this.formControlDirective.control.statusChanges.subscribe((status) => {
if (status === "INVALID") {
this.el.nativeElement.setAttribute("aria-invalid", "true");
} else if (status === "VALID") {
this.el.nativeElement.setAttribute("aria-invalid", "false");
}
});
}
ngOnDestroy() {
this.sub?.unsubscribe();
}
}

View File

@@ -1,6 +1,6 @@
import { Directive, ElementRef, Input, OnChanges } from "@angular/core";
import { LogService } from "jslib-common/abstractions/log.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
import { ValidationService } from "../services/validation.service";

View File

@@ -1,5 +1,4 @@
import { Directive, ElementRef, Input, NgZone } from "@angular/core";
import { take } from "rxjs/operators";
import { Utils } from "jslib-common/misc/utils";

View File

@@ -7,7 +7,7 @@ export class BoxRowDirective implements OnInit {
el: HTMLElement = null;
formEls: Element[];
constructor(private elRef: ElementRef) {
constructor(elRef: ElementRef) {
this.el = elRef.nativeElement;
}
@@ -18,7 +18,7 @@ export class BoxRowDirective implements OnInit {
this.formEls.forEach((formEl) => {
formEl.addEventListener(
"focus",
(event: Event) => {
() => {
this.el.classList.add("active");
},
false
@@ -26,7 +26,7 @@ export class BoxRowDirective implements OnInit {
formEl.addEventListener(
"blur",
(event: Event) => {
() => {
this.el.classList.remove("active");
},
false

View File

@@ -0,0 +1,12 @@
import { Directive, ElementRef, HostListener } from "@angular/core";
@Directive({
selector: "input[appInputStripSpaces]",
})
export class InputStripSpacesDirective {
constructor(private el: ElementRef<HTMLInputElement>) {}
@HostListener("input") onInput() {
this.el.nativeElement.value = this.el.nativeElement.value.replace(/ /g, "");
}
}

View File

@@ -0,0 +1,27 @@
import { Directive, OnInit, TemplateRef, ViewContainerRef } from "@angular/core";
import { StateService } from "jslib-common/abstractions/state.service";
/**
* Hides the element if the user has premium.
*/
@Directive({
selector: "[appNotPremium]",
})
export class NotPremiumDirective implements OnInit {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private stateService: StateService
) {}
async ngOnInit(): Promise<void> {
const premium = await this.stateService.getCanAccessPremium();
if (premium) {
this.viewContainer.clear();
} else {
this.viewContainer.createEmbeddedView(this.templateRef);
}
}
}

View File

@@ -0,0 +1,27 @@
import { Directive, OnInit, TemplateRef, ViewContainerRef } from "@angular/core";
import { StateService } from "jslib-common/abstractions/state.service";
/**
* Only shows the element if the user has premium.
*/
@Directive({
selector: "[appPremium]",
})
export class PremiumDirective implements OnInit {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private stateService: StateService
) {}
async ngOnInit(): Promise<void> {
const premium = await this.stateService.getCanAccessPremium();
if (premium) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
}

View File

@@ -1,5 +1,5 @@
import { Directive, ElementRef, forwardRef, HostListener, Input, Renderer2 } from "@angular/core";
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from "@angular/forms";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
// ref: https://juristr.com/blog/2018/02/ng-true-value-directive/
@Directive({

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

View File

@@ -0,0 +1,5 @@
export interface SelectOptions {
name: string;
value: any;
disabled?: boolean;
}

View File

@@ -0,0 +1,19 @@
import { Pipe } from "@angular/core";
import { ColorPasswordPipe } from "./color-password.pipe";
/*
An updated pipe that extends ColourPasswordPipe to include a character count
*/
@Pipe({ name: "colorPasswordCount" })
export class ColorPasswordCountPipe extends ColorPasswordPipe {
transform(password: string) {
const template = (character: string, type: string, index: number) =>
`<span class="password-character password-${type}">
${character}<span class="password-count">${index + 1}</span>
</span>`;
const colorizedPasswordCount = this.generateTemplate(password, template);
return colorizedPasswordCount;
}
}

View File

@@ -1,4 +1,5 @@
import { Pipe, PipeTransform } from "@angular/core";
import { Utils } from "jslib-common/misc/utils";
/*
@@ -8,6 +9,16 @@ import { Utils } from "jslib-common/misc/utils";
@Pipe({ name: "colorPassword" })
export class ColorPasswordPipe implements PipeTransform {
transform(password: string) {
const template = (character: string, type: string) =>
`<span class="password-${type}">${character}</span>`;
const colorizedPassword = this.generateTemplate(password, template);
return colorizedPassword;
}
protected generateTemplate(
password: string,
templateGenerator: (chararacter: string, type: string, index?: number) => string
) {
// Convert to an array to handle cases that stings have special characters, ie: emoji.
const passwordArray = Array.from(password);
let colorizedPassword = "";
@@ -43,7 +54,7 @@ export class ColorPasswordPipe implements PipeTransform {
} else if (character.match(/\d/)) {
type = "number";
}
colorizedPassword += '<span class="password-' + type + '">' + character + "</span>";
colorizedPassword += templateGenerator(character, type, i);
}
return colorizedPassword;
}

View File

@@ -6,7 +6,7 @@ import { CipherView } from "jslib-common/models/view/cipherView";
name: "searchCiphers",
})
export class SearchCiphersPipe implements PipeTransform {
transform(ciphers: CipherView[], searchText: string, deleted: boolean = false): CipherView[] {
transform(ciphers: CipherView[], searchText: string, deleted = false): CipherView[] {
if (ciphers == null || ciphers.length === 0) {
return [];
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,250 @@
$icomoon-font-family: "bwi-font" !default;
$icomoon-font-path: "~@bitwarden/jslib-angular/src/scss/bwicons/fonts/" !default;
// New font sheet? Update the font-face information below
@font-face {
font-family: "#{$icomoon-font-family}";
src: url($icomoon-font-path + "bwi-font.svg") format("svg"),
url($icomoon-font-path + "bwi-font.ttf") format("truetype"),
url($icomoon-font-path + "bwi-font.woff") format("woff"),
url($icomoon-font-path + "bwi-font.woff2") format("woff2");
font-weight: normal;
font-style: normal;
font-display: block;
}
// Base Class
.bwi {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: "#{$icomoon-font-family}" !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
display: inline-block;
/* Better Font Rendering */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Fixed Width Icons
.bwi-fw {
width: calc(18em / 14);
text-align: center;
}
// Sizing Changes
.bwi-sm {
font-size: 0.875em;
}
.bwi-lg {
font-size: calc(4em / 3);
line-height: calc(3em / 4);
vertical-align: -15%;
}
.bwi-2x {
font-size: 2em;
}
.bwi-3x {
font-size: 3em;
}
.bwi-4x {
font-size: 4em;
}
// Spin Animations
.bwi-spin {
animation: bwi-spin 2s infinite linear;
}
@keyframes bwi-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
// List Icons
.bwi-ul {
padding-left: 0;
margin-left: calc(30em / 14);
list-style-type: none;
> li {
position: relative;
}
}
.bwi-li {
position: absolute;
left: calc(-30em / 14);
width: calc(30em / 14);
top: calc(2em / 14);
text-align: center;
&.bwi-lg {
left: calc(-30em / 14) + calc(4em / 14);
}
}
// Rotation
.bwi-rotate-270 {
transform: rotate(270deg);
}
// For new icons - add their glyph name and value to the map below
$icons: (
"save-changes": "\e988",
"browser": "\e985",
"mobile": "\e986",
"cli": "\e987",
"providers": "\e983",
"vault": "\e984",
"folder-closed-f": "\e982",
"rocket": "\e9ee",
"ellipsis-h": "\e9ef",
"ellipsis-v": "\e9f0",
"safari": "\e974",
"opera": "\e975",
"firefox": "\e976",
"edge": "\e977",
"chrome": "\e978",
"star-f": "\e979",
"arrow-circle-up": "\e97a",
"arrow-circle-right": "\e97b",
"arrow-circle-left": "\e97c",
"arrow-circle-down": "\e97d",
"undo": "\e97e",
"bolt": "\e97f",
"puzzle": "\e980",
"rss": "\e973",
"dbl-angle-left": "\e970",
"dbl-angle-right": "\e971",
"hamburger": "\e972",
"bw-folder-open-f": "\e93e",
"desktop": "\e96a",
"angle-left": "\e96b",
"user": "\e900",
"user-f": "\e901",
"key": "\e902",
"share-square": "\e903",
"hashtag": "\e904",
"clone": "\e905",
"list-alt": "\e906",
"id-card": "\e907",
"credit-card": "\e908",
"globe": "\e909",
"sticky-note": "\e90a",
"folder": "\e90b",
"lock": "\e90c",
"lock-f": "\e90d",
"generate": "\e90e",
"generate-f": "\e90f",
"cog": "\e910",
"cog-f": "\e911",
"check-circle": "\e912",
"eye": "\e913",
"pencil-square": "\e914",
"bookmark": "\e915",
"files": "\e916",
"trash": "\e917",
"plus": "\e918",
"star": "\e919",
"list": "\e91a",
"angle-right": "\e91b",
"external-link": "\e91c",
"refresh": "\e91d",
"search": "\e91f",
"filter": "\e920",
"plus-circle": "\e921",
"user-circle": "\e922",
"question-circle": "\e923",
"cogs": "\e924",
"minus-circle": "\e925",
"send": "\e926",
"send-f": "\e927",
"download": "\e928",
"pencil": "\e929",
"sign-out": "\e92a",
"share": "\e92b",
"clock": "\e92c",
"angle-down": "\e92d",
"caret-down": "\e92e",
"square": "\e92f",
"collection": "\e930",
"bank": "\e931",
"shield": "\e932",
"stop": "\e933",
"plus-square": "\e934",
"save": "\e935",
"sign-in": "\e936",
"spinner": "\e937",
"dollar": "\e939",
"check": "\e93a",
"check-square": "\e93b",
"minus-square": "\e93c",
"close": "\e93d",
"share-arrow": "\e96c",
"paperclip": "\e93f",
"bitcoin": "\e940",
"cut": "\e941",
"frown": "\e942",
"folder-open": "\e943",
"bug": "\e946",
"chain-broken": "\e947",
"dashboard": "\e948",
"envelope": "\e949",
"exclamation-circle": "\e94a",
"exclamation-triangle": "\e94b",
"caret-right": "\e94c",
"file-pdf": "\e94e",
"file-text": "\e94f",
"info-circle": "\e952",
"lightbulb": "\e953",
"link": "\e954",
"linux": "\e956",
"long-arrow-right": "\e957",
"money": "\e958",
"play": "\e959",
"reddit": "\e95a",
"refresh-tab": "\e95b",
"sitemap": "\e95c",
"sliders": "\e95d",
"tag": "\e95e",
"thumb-tack": "\e95f",
"thumbs-up": "\e960",
"unlock": "\e962",
"users": "\e963",
"wrench": "\e965",
"ban": "\e967",
"camera": "\e968",
"chevron-up": "\e969",
"eye-slash": "\e96d",
"file": "\e96e",
"paste": "\e96f",
"github": "\e950",
"facebook": "\e94d",
"paypal": "\e938",
"google": "\e951",
"linkedin": "\e955",
"discourse": "\e91e",
"twitter": "\e961",
"youtube": "\e966",
"windows": "\e964",
"apple": "\e945",
"android": "\e944",
"error": "\e981",
"numbered-list": "\e989",
);
@each $name, $glyph in $icons {
.bwi-#{$name}:before {
content: $glyph;
}
}

View File

@@ -0,0 +1,44 @@
$card-icons-base: "~@bitwarden/jslib-angular/src/images/cards/";
$card-icons: (
"visa": $card-icons-base + "visa-light.png",
"amex": $card-icons-base + "amex-light.png",
"diners-club": $card-icons-base + "diners_club-light.png",
"discover": $card-icons-base + "discover-light.png",
"jcb": $card-icons-base + "jcb-light.png",
"maestro": $card-icons-base + "maestro-light.png",
"mastercard": $card-icons-base + "mastercard-light.png",
"union-pay": $card-icons-base + "union_pay-light.png",
);
$card-icons-dark: (
"visa": $card-icons-base + "visa-dark.png",
"amex": $card-icons-base + "amex-dark.png",
"diners-club": $card-icons-base + "diners_club-dark.png",
"discover": $card-icons-base + "discover-dark.png",
"jcb": $card-icons-base + "jcb-dark.png",
"maestro": $card-icons-base + "maestro-dark.png",
"mastercard": $card-icons-base + "mastercard-dark.png",
"union-pay": $card-icons-base + "union_pay-dark.png",
);
.credit-card-icon {
display: block; // Resolves the parent container being slighly to big
height: 19px;
width: 24px;
background-size: contain;
background-repeat: no-repeat;
}
@each $name, $url in $card-icons {
.card-#{$name} {
background-image: url("#{$url}");
}
}
@each $theme in $dark-icon-themes {
@each $name, $url in $card-icons-dark {
.#{$theme} .card-#{$name} {
background-image: url("#{$url}");
}
}
}

View File

@@ -1,36 +1,5 @@
import { Injector, LOCALE_ID, NgModule } from "@angular/core";
import { ApiService } from "jslib-common/services/api.service";
import { AppIdService } from "jslib-common/services/appId.service";
import { AuditService } from "jslib-common/services/audit.service";
import { AuthService } from "jslib-common/services/auth.service";
import { CipherService } from "jslib-common/services/cipher.service";
import { CollectionService } from "jslib-common/services/collection.service";
import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
import { CryptoService } from "jslib-common/services/crypto.service";
import { EnvironmentService } from "jslib-common/services/environment.service";
import { EventService } from "jslib-common/services/event.service";
import { ExportService } from "jslib-common/services/export.service";
import { FileUploadService } from "jslib-common/services/fileUpload.service";
import { FolderService } from "jslib-common/services/folder.service";
import { KeyConnectorService } from "jslib-common/services/keyConnector.service";
import { NotificationsService } from "jslib-common/services/notifications.service";
import { OrganizationService } from "jslib-common/services/organization.service";
import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service";
import { PolicyService } from "jslib-common/services/policy.service";
import { ProviderService } from "jslib-common/services/provider.service";
import { SearchService } from "jslib-common/services/search.service";
import { SendService } from "jslib-common/services/send.service";
import { SettingsService } from "jslib-common/services/settings.service";
import { StateService } from "jslib-common/services/state.service";
import { StateMigrationService } from "jslib-common/services/stateMigration.service";
import { SyncService } from "jslib-common/services/sync.service";
import { TokenService } from "jslib-common/services/token.service";
import { TotpService } from "jslib-common/services/totp.service";
import { UserVerificationService } from "jslib-common/services/userVerification.service";
import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service";
import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service";
import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service";
import { AppIdService as AppIdServiceAbstraction } from "jslib-common/abstractions/appId.service";
import { AuditService as AuditServiceAbstraction } from "jslib-common/abstractions/audit.service";
@@ -65,8 +34,43 @@ import { StorageService as StorageServiceAbstraction } from "jslib-common/abstra
import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
import { TotpService as TotpServiceAbstraction } from "jslib-common/abstractions/totp.service";
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
import { UserVerificationService as UserVerificationServiceAbstraction } from "jslib-common/abstractions/userVerification.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { Account } from "jslib-common/models/domain/account";
import { GlobalState } from "jslib-common/models/domain/globalState";
import { ApiService } from "jslib-common/services/api.service";
import { AppIdService } from "jslib-common/services/appId.service";
import { AuditService } from "jslib-common/services/audit.service";
import { AuthService } from "jslib-common/services/auth.service";
import { CipherService } from "jslib-common/services/cipher.service";
import { CollectionService } from "jslib-common/services/collection.service";
import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
import { CryptoService } from "jslib-common/services/crypto.service";
import { EnvironmentService } from "jslib-common/services/environment.service";
import { EventService } from "jslib-common/services/event.service";
import { ExportService } from "jslib-common/services/export.service";
import { FileUploadService } from "jslib-common/services/fileUpload.service";
import { FolderService } from "jslib-common/services/folder.service";
import { KeyConnectorService } from "jslib-common/services/keyConnector.service";
import { NotificationsService } from "jslib-common/services/notifications.service";
import { OrganizationService } from "jslib-common/services/organization.service";
import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service";
import { PolicyService } from "jslib-common/services/policy.service";
import { ProviderService } from "jslib-common/services/provider.service";
import { SearchService } from "jslib-common/services/search.service";
import { SendService } from "jslib-common/services/send.service";
import { SettingsService } from "jslib-common/services/settings.service";
import { StateService } from "jslib-common/services/state.service";
import { StateMigrationService } from "jslib-common/services/stateMigration.service";
import { SyncService } from "jslib-common/services/sync.service";
import { TokenService } from "jslib-common/services/token.service";
import { TotpService } from "jslib-common/services/totp.service";
import { TwoFactorService } from "jslib-common/services/twoFactor.service";
import { UserVerificationService } from "jslib-common/services/userVerification.service";
import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service";
import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service";
import { AuthGuardService } from "./auth-guard.service";
import { BroadcasterService } from "./broadcaster.service";
@@ -108,15 +112,14 @@ import { ValidationService } from "./validation.service";
ApiServiceAbstraction,
TokenServiceAbstraction,
AppIdServiceAbstraction,
I18nServiceAbstraction,
PlatformUtilsServiceAbstraction,
MessagingServiceAbstraction,
VaultTimeoutServiceAbstraction,
LogService,
CryptoFunctionServiceAbstraction,
KeyConnectorServiceAbstraction,
EnvironmentServiceAbstraction,
StateServiceAbstraction,
TwoFactorServiceAbstraction,
I18nServiceAbstraction,
],
},
{
@@ -307,7 +310,8 @@ import { ValidationService } from "./validation.service";
keyConnectorService,
stateService,
null,
async () => messagingService.send("logout", { expired: false })
async (userId?: string) =>
messagingService.send("logout", { expired: false, userId: userId })
),
deps: [
CipherServiceAbstraction,
@@ -325,7 +329,19 @@ import { ValidationService } from "./validation.service";
},
{
provide: StateServiceAbstraction,
useClass: StateService,
useFactory: (
storageService: StorageServiceAbstraction,
secureStorageService: StorageServiceAbstraction,
logService: LogService,
stateMigrationService: StateMigrationServiceAbstraction
) =>
new StateService(
storageService,
secureStorageService,
logService,
stateMigrationService,
new StateFactory(GlobalState, Account)
),
deps: [
StorageServiceAbstraction,
"SECURE_STORAGE",
@@ -335,7 +351,15 @@ import { ValidationService } from "./validation.service";
},
{
provide: StateMigrationServiceAbstraction,
useClass: StateMigrationService,
useFactory: (
storageService: StorageServiceAbstraction,
secureStorageService: StorageServiceAbstraction
) =>
new StateMigrationService(
storageService,
secureStorageService,
new StateFactory(GlobalState, Account)
),
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
},
{
@@ -429,6 +453,7 @@ import { ValidationService } from "./validation.service";
TokenServiceAbstraction,
LogService,
OrganizationServiceAbstraction,
CryptoFunctionServiceAbstraction,
],
},
{
@@ -447,6 +472,11 @@ import { ValidationService } from "./validation.service";
useClass: ProviderService,
deps: [StateServiceAbstraction],
},
{
provide: TwoFactorServiceAbstraction,
useClass: TwoFactorService,
deps: [I18nServiceAbstraction, PlatformUtilsServiceAbstraction],
},
],
})
export class JslibServicesModule {}

View File

@@ -7,6 +7,7 @@ import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.serv
@Injectable()
export class LockGuardService implements CanActivate {
protected homepage = "vault";
protected loginpage = "login";
constructor(
private vaultTimeoutService: VaultTimeoutService,
private router: Router,
@@ -14,16 +15,15 @@ export class LockGuardService implements CanActivate {
) {}
async canActivate() {
if (!(await this.stateService.getIsAuthenticated())) {
this.router.navigate(["login"]);
return false;
if (await this.vaultTimeoutService.isLocked()) {
return true;
}
if (!(await this.vaultTimeoutService.isLocked())) {
this.router.navigate([this.homepage]);
return false;
}
const redirectUrl = (await this.stateService.getIsAuthenticated())
? [this.homepage]
: [this.loginpage];
return true;
this.router.navigate(redirectUrl);
return false;
}
}

View File

@@ -17,7 +17,7 @@ import { ModalRef } from "../components/modal/modal.ref";
export class ModalConfig<D = any> {
data?: D;
allowMultipleModals: boolean = false;
allowMultipleModals = false;
}
@Injectable()
@@ -68,6 +68,7 @@ export class ModalService {
return;
}
// eslint-disable-next-line
const [modalRef, _] = this.openInternal(componentType, config, true);
return modalRef;
@@ -145,7 +146,7 @@ export class ModalService {
el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]')
);
for (const closeElement of modals) {
closeElement.addEventListener("click", (event) => {
closeElement.addEventListener("click", () => {
modalRef.close();
});
}

View File

@@ -4,6 +4,7 @@ import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.serv
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
import { ModalService } from "./modal.service";
@Injectable()

View File

@@ -2,7 +2,6 @@ import { Injectable } from "@angular/core";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
@Injectable()

View File

@@ -0,0 +1,9 @@
import { AbstractControl, ValidationErrors, Validators } from "@angular/forms";
/**
* Runs Validators.required on a field only if it's dirty. This prevents error messages from being displayed
* to the user prematurely.
*/
export function dirtyRequired(control: AbstractControl): ValidationErrors | null {
return control.dirty ? Validators.required(control) : null;
}

View File

@@ -1,18 +1,6 @@
{
"extends": "../shared/tsconfig",
"compilerOptions": {
"pretty": true,
"moduleResolution": "node",
"noImplicitAny": true,
"target": "ES6",
"module": "commonjs",
"lib": ["es5", "es6", "es7", "dom"],
"sourceMap": true,
"declaration": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declarationDir": "dist/types",
"outDir": "dist",
"paths": {
"jslib-common/*": ["../common/src/*"]
}