Apply Prettier (#581)

This commit is contained in:
Oscar Hinton 2021-12-16 13:36:21 +01:00 committed by GitHub
parent 8b2dfc6cdc
commit 193434461d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
589 changed files with 46650 additions and 41924 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

View File

@ -1,4 +1,5 @@
## Type of change
- [ ] Bug fix
- [ ] New feature development
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
@ -6,22 +7,22 @@
- [ ] Other
## Objective
<!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding-->
## Code changes
<!--Explain the changes you've made to each file or major component. This should help the reviewer understand your changes-->
<!--Also refer to any related changes or PRs in other repositories-->
* **file.ext:** Description of what was changed and why
- **file.ext:** Description of what was changed and why
## Testing requirements
<!--What functionality requires testing by QA? This includes testing new behavior and regression testing-->
## Before you submit
- [ ] I have checked for **linting** errors (`npm run lint`) (required)
- [ ] I have added **unit tests** where it makes sense to do so (encouraged but not required)
- [ ] This change requires a **documentation update** (notify the documentation team)

View File

@ -20,7 +20,6 @@ jobs:
- name: Print lines of code
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
build:
name: Build jslib
runs-on: ${{ matrix.os }}
@ -33,7 +32,7 @@ jobs:
- name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
with:
node-version: '16'
node-version: "16"
- name: Install node-gyp
run: |
@ -51,8 +50,8 @@ jobs:
- name: Install Node dependencies
run: npm install
# - name: Run linter
# run: npm run lint
- name: Run linter
run: npm run lint
- name: Build
run: npm run build

4
.vscode/launch.json vendored
View File

@ -10,9 +10,7 @@
"name": "Jasmine Individual Test",
"program": "${workspaceRoot}\\node_modules\\jasmine\\bin\\jasmine.js",
"preLaunchTask": "npm run build",
"args": [
"${workspaceFolder}/dist\\spec\\node\\services\\nodeCryptoFunction.service.spec.js"
]
"args": ["${workspaceFolder}/dist\\spec\\node\\services\\nodeCryptoFunction.service.spec.js"]
}
]
}

View File

@ -6,15 +6,11 @@ Please visit our [Community Forums](https://community.bitwarden.com/) for genera
Here is how you can get involved:
* **Request a new feature:** Go to the [Feature Requests category](https://community.bitwarden.com/c/feature-requests/) of the Community Forums. Please search existing feature requests before making a new one
* **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code
* **Report a bug or submit a bugfix:** Use Github issues and pull requests
* **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help)
* **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums
- **Request a new feature:** Go to the [Feature Requests category](https://community.bitwarden.com/c/feature-requests/) of the Community Forums. Please search existing feature requests before making a new one
- **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code
- **Report a bug or submit a bugfix:** Use Github issues and pull requests
- **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help)
- **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums
## Contributor Agreement
@ -22,9 +18,9 @@ Please sign the [Contributor Agreement](https://cla-assistant.io/bitwarden/jslib
## Pull Request Guidelines
* use `npm run lint` and fix any linting suggestions before submitting a pull request
* commit any pull requests against the `master` branch
* include a link to your Community Forums post
- use `npm run lint` and fix any linting suggestions before submitting a pull request
- commit any pull requests against the `master` branch
- include a link to your Community Forums post
# Introduction to jslib and git submodules
@ -33,36 +29,39 @@ jslib is a repository that contains shared code for all Bitwarden Typescript/Jav
If you haven't worked with submodules before, you should start by reading some basic guides (such as the [git scm chapter](https://git-scm.com/book/en/v2/Git-Tools-Submodules) or the [Atlassian tutorial](https://www.atlassian.com/git/tutorials/git-submodule)).
# Setting up your Local Dev environment for jslib
In order to easily develop local changes to jslib across each of the TypeScript/JavaScript clients, we recommend using symlinks for the submodule so that you only have to make the change once for it to be reflected across all your local repos.
## Prerequisites
1. git bash or other git command line
2. In order for this to work well, you need to use a consistent relative directory structure. Repos should be cloned in the following way:
* `./<your project(s) directory>`; we'll call this `/dev` ('cause why not)
* jslib - `git clone https://github.com/bitwarden/jslib.git` (/dev/jslib)
* web - `git clone --recurse-submodules https://github.com/bitwarden/web.git` (/dev/web)
* desktop - `git clone --recurse-submodules https://github.com/bitwarden/desktop.git` (/dev/desktop)
* browser - `git clone --recurse-submodules https://github.com/bitwarden/browser.git` (/dev/browser)
* cli - `git clone --recurse-submodules https://github.com/bitwarden/cli` (/dev/cli)
- `./<your project(s) directory>`; we'll call this `/dev` ('cause why not)
- jslib - `git clone https://github.com/bitwarden/jslib.git` (/dev/jslib)
- web - `git clone --recurse-submodules https://github.com/bitwarden/web.git` (/dev/web)
- desktop - `git clone --recurse-submodules https://github.com/bitwarden/desktop.git` (/dev/desktop)
- browser - `git clone --recurse-submodules https://github.com/bitwarden/browser.git` (/dev/browser)
- cli - `git clone --recurse-submodules https://github.com/bitwarden/cli` (/dev/cli)
You should notice web, desktop, browser and cli each reference jslib as a git submodule. If you've already cloned the repos but didn't use `--recurse-submodules` then you'll need to init the submodule with `npm run sub:init`.
## Configure Symlinks
Using `git clone` will make symlinks added to your repo be seen by git as plain text file paths. We need to prevent that. In the project root run, `git config core.symlinks true`.
For each project other than jslib, run the following:
* For macOS/Linux: `npm run symlink:mac`
* For Windows: `npm run symlink:win`
- For macOS/Linux: `npm run symlink:mac`
- For Windows: `npm run symlink:win`
Your client repos will now be pointing to your local jslib repo. You can now make changes in jslib and they will be immediately shared by the clients (just like they will be in production).
## Committing and pushing jslib changes
* You work on jslib like any other repo. Check out a new branch, make some commits, and push to remote when you're ready to submit a PR.
* Do not commit your jslib changes in the client repo. Your changes to the client and your changes to jslib should stay completely separate.
* When submitting a client PR that depends on a jslib PR, please include a link to the jslib PR so that the reviewer knows there are jslib changes.
- You work on jslib like any other repo. Check out a new branch, make some commits, and push to remote when you're ready to submit a PR.
- Do not commit your jslib changes in the client repo. Your changes to the client and your changes to jslib should stay completely separate.
- When submitting a client PR that depends on a jslib PR, please include a link to the jslib PR so that the reviewer knows there are jslib changes.
### Updating jslib on a feature branch
@ -70,8 +69,8 @@ If you've submitted a client PR and a jslib PR, your jslib PR will be approved a
1. If you've symlinked the client's jslib directory following the steps above, you'll need to delete that symlink and then run `npm run sub:init`.
2. Update the jslib submodule:
* if you're working on your own fork, run `git submodule update --remote --reference upstream`.
* if you're working on a branch on the official repo, run `npm run sub:update`
- if you're working on your own fork, run `git submodule update --remote --reference upstream`.
- if you're working on a branch on the official repo, run `npm run sub:update`
3. To check you've done this correctly, you can `cd` into your jslib directory and run `git log`. You should see your recent changes in the log. This will also show you the most recent commit hash, which should match the most recent commit hash on [Github](https://github.com/bitwarden/jslib).
4. Add your changes: `git add jslib`
5. Commit your changes: `git commit -m "update jslib version"`
@ -89,7 +88,8 @@ If you've made changes to jslib without needing to make any changes to the clien
4. Create a new PR to the client repo. Please include a link to your jslib PR so that reviewers know why you're updating jslib.
## Merge Conflicts
At times when you need to perform a `git merge master` into your feature or local branch, and there are conflicting version references to the *jslib* repo from your other clients, you will not be able to use the traditional merge or stage functions you would normally use for a file.
At times when you need to perform a `git merge master` into your feature or local branch, and there are conflicting version references to the _jslib_ repo from your other clients, you will not be able to use the traditional merge or stage functions you would normally use for a file.
To resolve you must use either `git reset` or update the index directly using `git update-index`. You can use (depending on whether you have symlink'd jslib) one of the following:

View File

@ -5,13 +5,14 @@
Common code referenced across Bitwarden JavaScript projects.
## Requirements
* [Node.js](https://nodejs.org) v16.13.1 or greater
* NPM v8
* Git
* node-gyp
- [Node.js](https://nodejs.org) v16.13.1 or greater
- NPM v8
- Git
- node-gyp
### Windows
* *Microsoft Build Tools 2015* in Visual Studio Installer
* [Windows 10 SDK 17134](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/)
either by downloading it seperately or through the Visual Studio Installer.
- _Microsoft Build Tools 2015_ in Visual Studio Installer
- [Windows 10 SDK 17134](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/)
either by downloading it seperately or through the Visual Studio Installer.

View File

@ -1,26 +1,18 @@
import {
Directive,
Input,
OnChanges,
SimpleChanges,
} from '@angular/core';
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
import {
CdkDragDrop,
moveItemInArray,
} from '@angular/cdk/drag-drop';
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
import { EventService } from 'jslib-common/abstractions/event.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
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 { 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 { 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 { Utils } from "jslib-common/misc/utils";
@Directive()
export class AddEditCustomFieldsComponent implements OnChanges {
@ -39,11 +31,14 @@ export class AddEditCustomFieldsComponent implements OnChanges {
constructor(private i18nService: I18nService, private eventService: EventService) {
this.addFieldTypeOptions = [
{ name: i18nService.t('cfTypeText'), value: FieldType.Text },
{ name: i18nService.t('cfTypeHidden'), value: FieldType.Hidden },
{ name: i18nService.t('cfTypeBoolean'), value: FieldType.Boolean },
{ name: i18nService.t("cfTypeText"), value: FieldType.Text },
{ name: i18nService.t("cfTypeHidden"), value: FieldType.Hidden },
{ name: i18nService.t("cfTypeBoolean"), value: FieldType.Boolean },
];
this.addFieldLinkedTypeOption = { name: this.i18nService.t('cfTypeLinked'), value: FieldType.Linked };
this.addFieldLinkedTypeOption = {
name: this.i18nService.t("cfTypeLinked"),
value: FieldType.Linked,
};
}
ngOnChanges(changes: SimpleChanges) {
@ -80,7 +75,7 @@ export class AddEditCustomFieldsComponent implements OnChanges {
}
toggleFieldValue(field: FieldView) {
const f = (field as any);
const f = field as any;
f.showValue = !f.showValue;
if (this.editMode && f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
@ -102,8 +97,9 @@ export class AddEditCustomFieldsComponent implements OnChanges {
const options: any = [];
this.cipher.linkedFieldOptions.forEach((linkedFieldOption, id) =>
options.push({ name: this.i18nService.t(linkedFieldOption.i18nKey), value: id }));
this.linkedFieldOptions = options.sort(Utils.getSortFunction(this.i18nService, 'name'));
options.push({ name: this.i18nService.t(linkedFieldOption.i18nKey), value: id })
);
this.linkedFieldOptions = options.sort(Utils.getSortFunction(this.i18nService, "name"));
}
private resetCipherLinkedFields() {
@ -113,12 +109,12 @@ export class AddEditCustomFieldsComponent implements OnChanges {
// Delete any Linked custom fields if the item type does not support them
if (this.cipher.linkedFieldOptions == null) {
this.cipher.fields = this.cipher.fields.filter(f => f.type !== FieldType.Linked);
this.cipher.fields = this.cipher.fields.filter((f) => f.type !== FieldType.Linked);
return;
}
this.cipher.fields
.filter(f => f.type === FieldType.Linked)
.forEach(f => f.linkedId = this.linkedFieldOptions[0].value);
.filter((f) => f.type === FieldType.Linked)
.forEach((f) => (f.linkedId = this.linkedFieldOptions[0].value));
}
}

View File

@ -1,45 +1,39 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
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 { 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';
import { EventService } from 'jslib-common/abstractions/event.service';
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 { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { OrganizationService } from 'jslib-common/abstractions/organization.service';
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.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 { AuditService } from "jslib-common/abstractions/audit.service";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CollectionService } from "jslib-common/abstractions/collection.service";
import { EventService } from "jslib-common/abstractions/event.service";
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 { MessagingService } from "jslib-common/abstractions/messaging.service";
import { OrganizationService } from "jslib-common/abstractions/organization.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.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 { Cipher } from 'jslib-common/models/domain/cipher';
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';
import { FolderView } from 'jslib-common/models/view/folderView';
import { IdentityView } from 'jslib-common/models/view/identityView';
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 { CardView } from "jslib-common/models/view/cardView";
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { FolderView } from "jslib-common/models/view/folderView";
import { IdentityView } from "jslib-common/models/view/identityView";
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';
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class AddEditComponent implements OnInit {
@ -86,66 +80,74 @@ export class AddEditComponent implements OnInit {
protected writeableCollections: CollectionView[];
private previousCipherId: string;
constructor(protected cipherService: CipherService, protected folderService: FolderService,
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService, protected stateService: StateService,
protected collectionService: CollectionService, protected messagingService: MessagingService,
protected eventService: EventService, protected policyService: PolicyService,
private logService: LogService, protected passwordRepromptService: PasswordRepromptService,
private organizationService: OrganizationService) {
constructor(
protected cipherService: CipherService,
protected folderService: FolderService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService,
protected stateService: StateService,
protected collectionService: CollectionService,
protected messagingService: MessagingService,
protected eventService: EventService,
protected policyService: PolicyService,
private logService: LogService,
protected passwordRepromptService: PasswordRepromptService,
private organizationService: OrganizationService
) {
this.typeOptions = [
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
{ name: i18nService.t('typeCard'), value: CipherType.Card },
{ name: i18nService.t('typeIdentity'), value: CipherType.Identity },
{ name: i18nService.t('typeSecureNote'), value: CipherType.SecureNote },
{ name: i18nService.t("typeLogin"), value: CipherType.Login },
{ name: i18nService.t("typeCard"), value: CipherType.Card },
{ name: i18nService.t("typeIdentity"), value: CipherType.Identity },
{ name: i18nService.t("typeSecureNote"), value: CipherType.SecureNote },
];
this.cardBrandOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: 'Visa', value: 'Visa' },
{ name: 'Mastercard', value: 'Mastercard' },
{ name: 'American Express', value: 'Amex' },
{ name: 'Discover', value: 'Discover' },
{ name: 'Diners Club', value: 'Diners Club' },
{ name: 'JCB', value: 'JCB' },
{ name: 'Maestro', value: 'Maestro' },
{ name: 'UnionPay', value: 'UnionPay' },
{ name: i18nService.t('other'), value: 'Other' },
{ name: "-- " + i18nService.t("select") + " --", value: null },
{ name: "Visa", value: "Visa" },
{ name: "Mastercard", value: "Mastercard" },
{ name: "American Express", value: "Amex" },
{ name: "Discover", value: "Discover" },
{ name: "Diners Club", value: "Diners Club" },
{ name: "JCB", value: "JCB" },
{ name: "Maestro", value: "Maestro" },
{ name: "UnionPay", value: "UnionPay" },
{ name: i18nService.t("other"), value: "Other" },
];
this.cardExpMonthOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: '01 - ' + i18nService.t('january'), value: '1' },
{ name: '02 - ' + i18nService.t('february'), value: '2' },
{ name: '03 - ' + i18nService.t('march'), value: '3' },
{ name: '04 - ' + i18nService.t('april'), value: '4' },
{ name: '05 - ' + i18nService.t('may'), value: '5' },
{ name: '06 - ' + i18nService.t('june'), value: '6' },
{ name: '07 - ' + i18nService.t('july'), value: '7' },
{ name: '08 - ' + i18nService.t('august'), value: '8' },
{ name: '09 - ' + i18nService.t('september'), value: '9' },
{ name: '10 - ' + i18nService.t('october'), value: '10' },
{ name: '11 - ' + i18nService.t('november'), value: '11' },
{ name: '12 - ' + i18nService.t('december'), value: '12' },
{ name: "-- " + i18nService.t("select") + " --", value: null },
{ name: "01 - " + i18nService.t("january"), value: "1" },
{ name: "02 - " + i18nService.t("february"), value: "2" },
{ name: "03 - " + i18nService.t("march"), value: "3" },
{ name: "04 - " + i18nService.t("april"), value: "4" },
{ name: "05 - " + i18nService.t("may"), value: "5" },
{ name: "06 - " + i18nService.t("june"), value: "6" },
{ name: "07 - " + i18nService.t("july"), value: "7" },
{ name: "08 - " + i18nService.t("august"), value: "8" },
{ name: "09 - " + i18nService.t("september"), value: "9" },
{ name: "10 - " + i18nService.t("october"), value: "10" },
{ name: "11 - " + i18nService.t("november"), value: "11" },
{ name: "12 - " + i18nService.t("december"), value: "12" },
];
this.identityTitleOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: i18nService.t('mr'), value: i18nService.t('mr') },
{ name: i18nService.t('mrs'), value: i18nService.t('mrs') },
{ name: i18nService.t('ms'), value: i18nService.t('ms') },
{ name: i18nService.t('dr'), value: i18nService.t('dr') },
{ name: "-- " + i18nService.t("select") + " --", value: null },
{ name: i18nService.t("mr"), value: i18nService.t("mr") },
{ name: i18nService.t("mrs"), value: i18nService.t("mrs") },
{ name: i18nService.t("ms"), value: i18nService.t("ms") },
{ name: i18nService.t("dr"), value: i18nService.t("dr") },
];
this.uriMatchOptions = [
{ name: i18nService.t('defaultMatchDetection'), value: null },
{ name: i18nService.t('baseDomain'), value: UriMatchType.Domain },
{ name: i18nService.t('host'), value: UriMatchType.Host },
{ name: i18nService.t('startsWith'), value: UriMatchType.StartsWith },
{ name: i18nService.t('regEx'), value: UriMatchType.RegularExpression },
{ name: i18nService.t('exact'), value: UriMatchType.Exact },
{ name: i18nService.t('never'), value: UriMatchType.Never },
{ name: i18nService.t("defaultMatchDetection"), value: null },
{ name: i18nService.t("baseDomain"), value: UriMatchType.Domain },
{ name: i18nService.t("host"), value: UriMatchType.Host },
{ name: i18nService.t("startsWith"), value: UriMatchType.StartsWith },
{ name: i18nService.t("regEx"), value: UriMatchType.RegularExpression },
{ name: i18nService.t("exact"), value: UriMatchType.Exact },
{ name: i18nService.t("never"), value: UriMatchType.Never },
];
this.autofillOnPageLoadOptions = [
{ name: i18nService.t('autoFillOnPageLoadUseDefault'), value: null },
{ name: i18nService.t('autoFillOnPageLoadYes'), value: true },
{ name: i18nService.t('autoFillOnPageLoadNo'), value: false },
{ name: i18nService.t("autoFillOnPageLoadUseDefault"), value: null },
{ name: i18nService.t("autoFillOnPageLoadYes"), value: true },
{ name: i18nService.t("autoFillOnPageLoadNo"), value: false },
];
}
@ -165,7 +167,7 @@ export class AddEditComponent implements OnInit {
}
const orgs = await this.organizationService.getAll();
orgs.sort(Utils.getSortFunction(this.i18nService, 'name')).forEach(o => {
orgs.sort(Utils.getSortFunction(this.i18nService, "name")).forEach((o) => {
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
this.ownershipOptions.push({ name: o.name, value: o.id });
}
@ -185,12 +187,12 @@ export class AddEditComponent implements OnInit {
this.editMode = true;
if (this.cloneMode) {
this.cloneMode = true;
this.title = this.i18nService.t('addItem');
this.title = this.i18nService.t("addItem");
} else {
this.title = this.i18nService.t('editItem');
this.title = this.i18nService.t("editItem");
}
} else {
this.title = this.i18nService.t('addItem');
this.title = this.i18nService.t("addItem");
}
const addEditCipherInfo: any = await this.stateService.getAddEditCipherInfo();
@ -207,7 +209,7 @@ export class AddEditComponent implements OnInit {
// Adjust Cipher Name if Cloning
if (this.cloneMode) {
this.cipher.name += ' - ' + this.i18nService.t('clone');
this.cipher.name += " - " + this.i18nService.t("clone");
// If not allowing personal ownership, update cipher's org Id to prompt downstream changes
if (this.cipher.organizationId == null && !this.allowPersonal) {
this.cipher.organizationId = this.organizationId;
@ -230,8 +232,12 @@ export class AddEditComponent implements OnInit {
if (this.cipher != null && (!this.editMode || addEditCipherInfo != null || this.cloneMode)) {
await this.organizationChanged();
if (this.collectionIds != null && this.collectionIds.length > 0 && this.collections.length > 0) {
this.collections.forEach(c => {
if (
this.collectionIds != null &&
this.collectionIds.length > 0 &&
this.collections.length > 0
) {
this.collections.forEach((c) => {
if (this.collectionIds.indexOf(c.id) > -1) {
(c as any).checked = true;
}
@ -253,28 +259,44 @@ export class AddEditComponent implements OnInit {
return this.restore();
}
if (this.cipher.name == null || this.cipher.name === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('nameRequired'));
if (this.cipher.name == null || this.cipher.name === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("nameRequired")
);
return false;
}
if ((!this.editMode || this.cloneMode) && !this.allowPersonal && this.cipher.organizationId == null) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('personalOwnershipSubmitError'));
if (
(!this.editMode || this.cloneMode) &&
!this.allowPersonal &&
this.cipher.organizationId == null
) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("personalOwnershipSubmitError")
);
return false;
}
if ((!this.editMode || this.cloneMode) && this.cipher.type === CipherType.Login &&
this.cipher.login.uris != null && this.cipher.login.uris.length === 1 &&
(this.cipher.login.uris[0].uri == null || this.cipher.login.uris[0].uri === '')) {
if (
(!this.editMode || this.cloneMode) &&
this.cipher.type === CipherType.Login &&
this.cipher.login.uris != null &&
this.cipher.login.uris.length === 1 &&
(this.cipher.login.uris[0].uri == null || this.cipher.login.uris[0].uri === "")
) {
this.cipher.login.uris = null;
}
// Allows saving of selected collections during "Add" and "Clone" flows
if ((!this.editMode || this.cloneMode) && this.cipher.organizationId != null) {
this.cipher.collectionIds = this.collections == null ? [] :
this.collections.filter(c => (c as any).checked).map(c => c.id);
this.cipher.collectionIds =
this.collections == null
? []
: this.collections.filter((c) => (c as any).checked).map((c) => c.id);
}
// Clear current Cipher Id to trigger "Add" cipher flow
@ -287,10 +309,13 @@ export class AddEditComponent implements OnInit {
this.formPromise = this.saveCipher(cipher);
await this.formPromise;
this.cipher.id = cipher.id;
this.platformUtilsService.showToast('success', null,
this.i18nService.t(this.editMode && !this.cloneMode ? 'editedItem' : 'addedItem'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem")
);
this.onSavedCipher.emit(this.cipher);
this.messagingService.send(this.editMode && !this.cloneMode ? 'editedCipher' : 'addedCipher');
this.messagingService.send(this.editMode && !this.cloneMode ? "editedCipher" : "addedCipher");
return true;
} catch (e) {
this.logService.error(e);
@ -344,8 +369,14 @@ export class AddEditComponent implements OnInit {
async delete(): Promise<boolean> {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeleteItemConfirmation' : 'deleteItemConfirmation'),
this.i18nService.t('deleteItem'), this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t(
this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation"
),
this.i18nService.t("deleteItem"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -353,10 +384,15 @@ export class AddEditComponent implements OnInit {
try {
this.deletePromise = this.deleteCipher();
await this.deletePromise;
this.platformUtilsService.showToast('success', null,
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem")
);
this.onDeletedCipher.emit(this.cipher);
this.messagingService.send(this.cipher.isDeleted ? 'permanentlyDeletedCipher' : 'deletedCipher');
this.messagingService.send(
this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher"
);
} catch (e) {
this.logService.error(e);
}
@ -370,8 +406,12 @@ export class AddEditComponent implements OnInit {
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('restoreItemConfirmation'), this.i18nService.t('restoreItem'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("restoreItemConfirmation"),
this.i18nService.t("restoreItem"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -379,9 +419,9 @@ export class AddEditComponent implements OnInit {
try {
this.restorePromise = this.restoreCipher();
await this.restorePromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('restoredItem'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem"));
this.onRestoredCipher.emit(this.cipher);
this.messagingService.send('restoredCipher');
this.messagingService.send("restoredCipher");
} catch (e) {
this.logService.error(e);
}
@ -390,10 +430,17 @@ export class AddEditComponent implements OnInit {
}
async generatePassword(): Promise<boolean> {
if (this.cipher.login != null && this.cipher.login.password != null && this.cipher.login.password.length) {
if (
this.cipher.login != null &&
this.cipher.login.password != null &&
this.cipher.login.password.length
) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('overwritePasswordConfirmation'), this.i18nService.t('overwritePassword'),
this.i18nService.t('yes'), this.i18nService.t('no'));
this.i18nService.t("overwritePasswordConfirmation"),
this.i18nService.t("overwritePassword"),
this.i18nService.t("yes"),
this.i18nService.t("no")
);
if (!confirmed) {
return false;
}
@ -405,7 +452,7 @@ export class AddEditComponent implements OnInit {
togglePassword() {
this.showPassword = !this.showPassword;
document.getElementById('loginPassword').focus();
document.getElementById("loginPassword").focus();
if (this.editMode && this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
}
@ -420,28 +467,30 @@ export class AddEditComponent implements OnInit {
toggleCardCode() {
this.showCardCode = !this.showCardCode;
document.getElementById('cardCode').focus();
document.getElementById("cardCode").focus();
if (this.editMode && this.showCardCode) {
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
}
}
toggleUriOptions(uri: LoginUriView) {
const u = (uri as any);
const u = uri as any;
u.showOptions = u.showOptions == null && uri.match != null ? false : !u.showOptions;
}
loginUriMatchChanged(uri: LoginUriView) {
const u = (uri as any);
const u = uri as any;
u.showOptions = u.showOptions == null ? true : u.showOptions;
}
async organizationChanged() {
if (this.writeableCollections != null) {
this.writeableCollections.forEach(c => (c as any).checked = false);
this.writeableCollections.forEach((c) => ((c as any).checked = false));
}
if (this.cipher.organizationId != null) {
this.collections = this.writeableCollections.filter(c => c.organizationId === this.cipher.organizationId);
this.collections = this.writeableCollections.filter(
(c) => c.organizationId === this.cipher.organizationId
);
const org = await this.organizationService.get(this.cipher.organizationId);
if (org != null) {
this.cipher.organizationUseTotp = org.useTotp;
@ -456,7 +505,11 @@ export class AddEditComponent implements OnInit {
return;
}
if (this.cipher.login == null || this.cipher.login.password == null || this.cipher.login.password === '') {
if (
this.cipher.login == null ||
this.cipher.login.password == null ||
this.cipher.login.password === ""
) {
return;
}
@ -465,10 +518,13 @@ export class AddEditComponent implements OnInit {
this.checkPasswordPromise = null;
if (matches > 0) {
this.platformUtilsService.showToast('warning', null,
this.i18nService.t('passwordExposed', matches.toString()));
this.platformUtilsService.showToast(
"warning",
null,
this.i18nService.t("passwordExposed", matches.toString())
);
} else {
this.platformUtilsService.showToast('success', null, this.i18nService.t('passwordSafe'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe"));
}
}
@ -483,7 +539,7 @@ export class AddEditComponent implements OnInit {
protected async loadCollections() {
const allCollections = await this.collectionService.getAllDecrypted();
return allCollections.filter(c => !c.readOnly);
return allCollections.filter((c) => !c.readOnly);
}
protected loadCipher() {
@ -499,7 +555,8 @@ export class AddEditComponent implements OnInit {
}
protected deleteCipher() {
return this.cipher.isDeleted ? this.cipherService.deleteWithServer(this.cipher.id)
return this.cipher.isDeleted
? this.cipherService.deleteWithServer(this.cipher.id)
: this.cipherService.softDeleteWithServer(this.cipher.id);
}

View File

@ -1,24 +1,18 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { ApiService } from 'jslib-common/abstractions/api.service';
import { CipherService } from 'jslib-common/abstractions/cipher.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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { ApiService } from "jslib-common/abstractions/api.service";
import { CipherService } from "jslib-common/abstractions/cipher.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 { 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 { 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';
import { AttachmentView } from "jslib-common/models/view/attachmentView";
import { CipherView } from "jslib-common/models/view/cipherView";
@Directive()
export class AttachmentsComponent implements OnInit {
@ -32,14 +26,20 @@ export class AttachmentsComponent implements OnInit {
hasUpdatedKey: boolean;
canAccessAttachments: boolean;
formPromise: Promise<any>;
deletePromises: { [id: string]: Promise<any>; } = {};
reuploadPromises: { [id: string]: Promise<any>; } = {};
deletePromises: { [id: string]: Promise<any> } = {};
reuploadPromises: { [id: string]: Promise<any> } = {};
emergencyAccessId?: string = null;
constructor(protected cipherService: CipherService, protected i18nService: I18nService,
protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService, protected win: Window,
protected logService: LogService, protected stateService: StateService) { }
constructor(
protected cipherService: CipherService,
protected i18nService: I18nService,
protected cryptoService: CryptoService,
protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService,
protected win: Window,
protected logService: LogService,
protected stateService: StateService
) {}
async ngOnInit() {
await this.init();
@ -47,22 +47,32 @@ export class AttachmentsComponent implements OnInit {
async submit() {
if (!this.hasUpdatedKey) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('updateKey'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("updateKey")
);
return;
}
const fileEl = document.getElementById('file') as HTMLInputElement;
const fileEl = document.getElementById("file") as HTMLInputElement;
const files = fileEl.files;
if (files == null || files.length === 0) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('selectFile'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("selectFile")
);
return;
}
if (files[0].size > 524288000) { // 500 MB
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('maxFileSize'));
if (files[0].size > 524288000) {
// 500 MB
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("maxFileSize")
);
return;
}
@ -70,7 +80,7 @@ export class AttachmentsComponent implements OnInit {
this.formPromise = this.saveCipherAttachment(files[0]);
this.cipherDomain = await this.formPromise;
this.cipher = await this.cipherDomain.decrypt();
this.platformUtilsService.showToast('success', null, this.i18nService.t('attachmentSaved'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("attachmentSaved"));
this.onUploadedAttachment.emit();
} catch (e) {
this.logService.error(e);
@ -78,9 +88,9 @@ export class AttachmentsComponent implements OnInit {
// reset file input
// ref: https://stackoverflow.com/a/20552042
fileEl.type = '';
fileEl.type = 'file';
fileEl.value = '';
fileEl.type = "";
fileEl.type = "file";
fileEl.value = "";
}
async delete(attachment: AttachmentView) {
@ -89,8 +99,12 @@ export class AttachmentsComponent implements OnInit {
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('deleteAttachmentConfirmation'), this.i18nService.t('deleteAttachment'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("deleteAttachmentConfirmation"),
this.i18nService.t("deleteAttachment"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return;
}
@ -98,7 +112,7 @@ export class AttachmentsComponent implements OnInit {
try {
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
await this.deletePromises[attachment.id];
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedAttachment'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedAttachment"));
const i = this.cipher.attachments.indexOf(attachment);
if (i > -1) {
this.cipher.attachments.splice(i, 1);
@ -112,21 +126,27 @@ export class AttachmentsComponent implements OnInit {
}
async download(attachment: AttachmentView) {
const a = (attachment as any);
const a = attachment as any;
if (a.downloading) {
return;
}
if (!this.canAccessAttachments) {
this.platformUtilsService.showToast('error', this.i18nService.t('premiumRequired'),
this.i18nService.t('premiumRequiredDesc'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("premiumRequired"),
this.i18nService.t("premiumRequiredDesc")
);
return;
}
let url: string;
try {
const attachmentDownloadResponse = await this.apiService.getAttachmentData(this.cipher.id, attachment.id,
this.emergencyAccessId);
const attachmentDownloadResponse = await this.apiService.getAttachmentData(
this.cipher.id,
attachment.id,
this.emergencyAccessId
);
url = attachmentDownloadResponse.url;
} catch (e) {
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
@ -139,21 +159,23 @@ export class AttachmentsComponent implements OnInit {
}
a.downloading = true;
const response = await fetch(new Request(url, { cache: 'no-store' }));
const response = await fetch(new Request(url, { cache: "no-store" }));
if (response.status !== 200) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
a.downloading = false;
return;
}
try {
const buf = await response.arrayBuffer();
const key = attachment.key != null ? attachment.key :
await this.cryptoService.getOrgKey(this.cipher.organizationId);
const key =
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
} catch (e) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}
a.downloading = false;
@ -169,23 +191,32 @@ export class AttachmentsComponent implements OnInit {
if (!this.canAccessAttachments) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'),
this.i18nService.t('learnMore'), this.i18nService.t('cancel'));
this.i18nService.t("premiumRequiredDesc"),
this.i18nService.t("premiumRequired"),
this.i18nService.t("learnMore"),
this.i18nService.t("cancel")
);
if (confirmed) {
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=purchase');
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=purchase");
}
} else if (!this.hasUpdatedKey) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('updateKey'), this.i18nService.t('featureUnavailable'),
this.i18nService.t('learnMore'), this.i18nService.t('cancel'), 'warning');
this.i18nService.t("updateKey"),
this.i18nService.t("featureUnavailable"),
this.i18nService.t("learnMore"),
this.i18nService.t("cancel"),
"warning"
);
if (confirmed) {
this.platformUtilsService.launchUri('https://help.bitwarden.com/article/update-encryption-key/');
this.platformUtilsService.launchUri(
"https://help.bitwarden.com/article/update-encryption-key/"
);
}
}
}
protected async reuploadCipherAttachment(attachment: AttachmentView, admin: boolean) {
const a = (attachment as any);
const a = attachment as any;
if (attachment.key != null || a.downloading || this.reuploadPromises[attachment.id] != null) {
return;
}
@ -194,9 +225,9 @@ export class AttachmentsComponent implements OnInit {
this.reuploadPromises[attachment.id] = Promise.resolve().then(async () => {
// 1. Download
a.downloading = true;
const response = await fetch(new Request(attachment.url, { cache: 'no-store' }));
const response = await fetch(new Request(attachment.url, { cache: "no-store" }));
if (response.status !== 200) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
a.downloading = false;
return;
}
@ -204,17 +235,23 @@ export class AttachmentsComponent implements OnInit {
try {
// 2. Resave
const buf = await response.arrayBuffer();
const key = attachment.key != null ? attachment.key :
await this.cryptoService.getOrgKey(this.cipher.organizationId);
const key =
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
this.cipherDomain = await this.cipherService.saveAttachmentRawWithServer(
this.cipherDomain, attachment.fileName, decBuf, admin);
this.cipherDomain,
attachment.fileName,
decBuf,
admin
);
this.cipher = await this.cipherDomain.decrypt();
// 3. Delete old
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
await this.deletePromises[attachment.id];
const foundAttachment = this.cipher.attachments.filter(a2 => a2.id === attachment.id);
const foundAttachment = this.cipher.attachments.filter((a2) => a2.id === attachment.id);
if (foundAttachment.length > 0) {
const i = this.cipher.attachments.indexOf(foundAttachment[0]);
if (i > -1) {
@ -222,10 +259,14 @@ export class AttachmentsComponent implements OnInit {
}
}
this.platformUtilsService.showToast('success', null, this.i18nService.t('attachmentSaved'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("attachmentSaved")
);
this.onReuploadedAttachment.emit();
} catch (e) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}
a.downloading = false;

View File

@ -1,27 +1,23 @@
import {
Component,
Input,
OnChanges,
OnInit,
} from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { Component, Input, OnChanges, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
@Component({
selector: 'app-avatar',
template: '<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
'[ngClass]="{\'rounded-circle\': circle}">',
selector: "app-avatar",
template:
'<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
"[ngClass]=\"{'rounded-circle': circle}\">",
})
export class AvatarComponent implements OnChanges, OnInit {
@Input() data: string;
@Input() email: string;
@Input() size = 45;
@Input() charCount = 2;
@Input() textColor = '#ffffff';
@Input() textColor = "#ffffff";
@Input() fontSize = 20;
@Input() fontWeight = 300;
@Input() dynamic = false;
@ -29,8 +25,11 @@ export class AvatarComponent implements OnChanges, OnInit {
src: string;
constructor(public sanitizer: DomSanitizer, private cryptoFunctionService: CryptoFunctionService,
private stateService: StateService) { }
constructor(
public sanitizer: DomSanitizer,
private cryptoFunctionService: CryptoFunctionService,
private stateService: StateService
) {}
ngOnInit() {
if (!this.dynamic) {
@ -47,9 +46,12 @@ export class AvatarComponent implements OnChanges, OnInit {
private async generate() {
const enableGravatars = await this.stateService.getEnableGravitars();
if (enableGravatars && this.email != null) {
const hashBytes = await this.cryptoFunctionService.hash(this.email.toLowerCase().trim(), 'md5');
const hashBytes = await this.cryptoFunctionService.hash(
this.email.toLowerCase().trim(),
"md5"
);
const hash = Utils.fromBufferToHex(hashBytes).toLowerCase();
this.src = 'https://www.gravatar.com/avatar/' + hash + '?s=' + this.size + '&r=pg&d=retro';
this.src = "https://www.gravatar.com/avatar/" + hash + "?s=" + this.size + "&r=pg&d=retro";
} else {
let chars: string = null;
const upperData = this.data.toUpperCase();
@ -70,9 +72,9 @@ export class AvatarComponent implements OnChanges, OnInit {
const color = this.stringToColor(upperData);
const svg = this.getSvg(this.size, color);
svg.appendChild(charObj);
const html = window.document.createElement('div').appendChild(svg).outerHTML;
const html = window.document.createElement("div").appendChild(svg).outerHTML;
const svgHtml = window.btoa(unescape(encodeURIComponent(html)));
this.src = 'data:image/svg+xml;base64,' + svgHtml;
this.src = "data:image/svg+xml;base64," + svgHtml;
}
}
@ -82,19 +84,19 @@ export class AvatarComponent implements OnChanges, OnInit {
// tslint:disable-next-line
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
let color = '#';
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);
const value = (hash >> (i * 8)) & 0xff;
color += ("00" + value.toString(16)).substr(-2);
}
return color;
}
private getFirstLetters(data: string, count: number): string {
const parts = data.split(' ');
const parts = data.split(" ");
if (parts.length > 1) {
let text = '';
let text = "";
for (let i = 0; i < count; i++) {
text += this.unicodeSafeSubstring(parts[i], 1);
}
@ -104,35 +106,38 @@ export class AvatarComponent implements OnChanges, OnInit {
}
private getSvg(size: number, color: string): HTMLElement {
const svgTag = window.document.createElement('svg');
svgTag.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svgTag.setAttribute('pointer-events', 'none');
svgTag.setAttribute('width', size.toString());
svgTag.setAttribute('height', size.toString());
const svgTag = window.document.createElement("svg");
svgTag.setAttribute("xmlns", "http://www.w3.org/2000/svg");
svgTag.setAttribute("pointer-events", "none");
svgTag.setAttribute("width", size.toString());
svgTag.setAttribute("height", size.toString());
svgTag.style.backgroundColor = color;
svgTag.style.width = size + 'px';
svgTag.style.height = size + 'px';
svgTag.style.width = size + "px";
svgTag.style.height = size + "px";
return svgTag;
}
private getCharText(character: string): HTMLElement {
const textTag = window.document.createElement('text');
textTag.setAttribute('text-anchor', 'middle');
textTag.setAttribute('y', '50%');
textTag.setAttribute('x', '50%');
textTag.setAttribute('dy', '0.35em');
textTag.setAttribute('pointer-events', 'auto');
textTag.setAttribute('fill', this.textColor);
textTag.setAttribute('font-family', '"Open Sans","Helvetica Neue",Helvetica,Arial,' +
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"');
const textTag = window.document.createElement("text");
textTag.setAttribute("text-anchor", "middle");
textTag.setAttribute("y", "50%");
textTag.setAttribute("x", "50%");
textTag.setAttribute("dy", "0.35em");
textTag.setAttribute("pointer-events", "auto");
textTag.setAttribute("fill", this.textColor);
textTag.setAttribute(
"font-family",
'"Open Sans","Helvetica Neue",Helvetica,Arial,' +
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"'
);
textTag.textContent = character;
textTag.style.fontWeight = this.fontWeight.toString();
textTag.style.fontSize = this.fontSize + 'px';
textTag.style.fontSize = this.fontSize + "px";
return textTag;
}
private unicodeSafeSubstring(str: string, count: number) {
const characters = str.match(/./ug);
return characters != null ? characters.slice(0, count).join('') : '';
const characters = str.match(/./gu);
return characters != null ? characters.slice(0, count).join("") : "";
}
}

View File

@ -1,26 +1,34 @@
<div #callout class="callout callout-{{calloutStyle}}" [ngClass]="{'clickable': clickable}"
[attr.role]="useAlertRole ? 'alert' : null">
<div
#callout
class="callout callout-{{ calloutStyle }}"
[ngClass]="{ clickable: clickable }"
[attr.role]="useAlertRole ? 'alert' : null"
>
<h3 class="callout-heading" *ngIf="title">
<i class="fa {{icon}}" *ngIf="icon" aria-hidden="true"></i>
{{title}}
<i class="fa {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
{{ title }}
</h3>
<div class="enforced-policy-options" *ngIf="enforcedPolicyOptions">
{{enforcedPolicyMessage}}
{{ enforcedPolicyMessage }}
<ul>
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
{{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
{{ "policyInEffectMinComplexity" | i18n: getPasswordScoreAlertDisplay() }}
</li>
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
{{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
{{ "policyInEffectMinLength" | i18n: enforcedPolicyOptions?.minLength.toString() }}
</li>
<li *ngIf="enforcedPolicyOptions?.requireUpper">
{{'policyInEffectUppercase' | i18n}}</li>
{{ "policyInEffectUppercase" | i18n }}
</li>
<li *ngIf="enforcedPolicyOptions?.requireLower">
{{'policyInEffectLowercase' | i18n}}</li>
{{ "policyInEffectLowercase" | i18n }}
</li>
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
{{'policyInEffectNumbers' | i18n}}</li>
{{ "policyInEffectNumbers" | i18n }}
</li>
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
{{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}</li>
{{ "policyInEffectSpecial" | i18n: "!@#$%^&*" }}
</li>
</ul>
</div>
<ng-content></ng-content>

View File

@ -1,19 +1,15 @@
import {
Component,
Input,
OnInit,
} from '@angular/core';
import { Component, Input, OnInit } from "@angular/core";
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
@Component({
selector: 'app-callout',
templateUrl: 'callout.component.html',
selector: "app-callout",
templateUrl: "callout.component.html",
})
export class CalloutComponent implements OnInit {
@Input() type = 'info';
@Input() type = "info";
@Input() icon: string;
@Input() title: string;
@Input() clickable: boolean;
@ -23,61 +19,61 @@ export class CalloutComponent implements OnInit {
calloutStyle: string;
constructor(private i18nService: I18nService) { }
constructor(private i18nService: I18nService) {}
ngOnInit() {
this.calloutStyle = this.type;
if (this.enforcedPolicyMessage === undefined) {
this.enforcedPolicyMessage = this.i18nService.t('masterPasswordPolicyInEffect');
this.enforcedPolicyMessage = this.i18nService.t("masterPasswordPolicyInEffect");
}
if (this.type === 'warning' || this.type === 'danger') {
if (this.type === 'danger') {
this.calloutStyle = 'danger';
if (this.type === "warning" || this.type === "danger") {
if (this.type === "danger") {
this.calloutStyle = "danger";
}
if (this.title === undefined) {
this.title = this.i18nService.t('warning');
this.title = this.i18nService.t("warning");
}
if (this.icon === undefined) {
this.icon = 'fa-warning';
this.icon = "fa-warning";
}
} else if (this.type === 'error') {
this.calloutStyle = 'danger';
} else if (this.type === "error") {
this.calloutStyle = "danger";
if (this.title === undefined) {
this.title = this.i18nService.t('error');
this.title = this.i18nService.t("error");
}
if (this.icon === undefined) {
this.icon = 'fa-bolt';
this.icon = "fa-bolt";
}
} else if (this.type === 'tip') {
this.calloutStyle = 'success';
} else if (this.type === "tip") {
this.calloutStyle = "success";
if (this.title === undefined) {
this.title = this.i18nService.t('tip');
this.title = this.i18nService.t("tip");
}
if (this.icon === undefined) {
this.icon = 'fa-lightbulb-o';
this.icon = "fa-lightbulb-o";
}
}
}
getPasswordScoreAlertDisplay() {
if (this.enforcedPolicyOptions == null) {
return '';
return "";
}
let str: string;
switch (this.enforcedPolicyOptions.minComplexity) {
case 4:
str = this.i18nService.t('strong');
str = this.i18nService.t("strong");
break;
case 3:
str = this.i18nService.t('good');
str = this.i18nService.t("good");
break;
default:
str = this.i18nService.t('weak');
str = this.i18nService.t("weak");
break;
}
return str + ' (' + this.enforcedPolicyOptions.minComplexity + ')';
return str + " (" + this.enforcedPolicyOptions.minComplexity + ")";
}
}

View File

@ -1,12 +1,12 @@
import { Directive, Input } from '@angular/core';
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 { 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 { CaptchaIFrame } from "jslib-common/misc/captcha_iframe";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
@Directive()
export abstract class CaptchaProtectedComponent {
@ -14,19 +14,27 @@ export abstract class CaptchaProtectedComponent {
captchaToken: string = null;
captcha: CaptchaIFrame;
constructor(protected environmentService: EnvironmentService, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService) { }
constructor(
protected environmentService: EnvironmentService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService
) {}
async setupCaptcha() {
const webVaultUrl = this.environmentService.getWebVaultUrl();
this.captcha = new CaptchaIFrame(window, webVaultUrl,
this.i18nService, (token: string) => {
this.captcha = new CaptchaIFrame(
window,
webVaultUrl,
this.i18nService,
(token: string) => {
this.captchaToken = token;
}, (error: string) => {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), error);
}, (info: string) => {
this.platformUtilsService.showToast('info', this.i18nService.t('info'), info);
},
(error: string) => {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), error);
},
(info: string) => {
this.platformUtilsService.showToast("info", this.i18nService.t("info"), info);
}
);
}
@ -35,7 +43,7 @@ export abstract class CaptchaProtectedComponent {
return !Utils.isNullOrWhitespace(this.captchaSiteKey);
}
protected handleCaptchaRequired(response: { captchaSiteKey: string; }): boolean {
protected handleCaptchaRequired(response: { captchaSiteKey: string }): boolean {
if (Utils.isNullOrWhitespace(response.captchaSiteKey)) {
return false;
}

View File

@ -1,18 +1,18 @@
import { Directive, OnInit } from '@angular/core';
import { Directive, OnInit } from "@angular/core";
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { I18nService } from 'jslib-common/abstractions/i18n.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 { CryptoService } from "jslib-common/abstractions/crypto.service";
import { I18nService } from "jslib-common/abstractions/i18n.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 { EncString } from 'jslib-common/models/domain/encString';
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
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';
import { KdfType } from "jslib-common/enums/kdfType";
@Directive()
export class ChangePasswordComponent implements OnInit {
@ -28,10 +28,15 @@ export class ChangePasswordComponent implements OnInit {
private masterPasswordStrengthTimeout: any;
constructor(protected i18nService: I18nService, protected cryptoService: CryptoService,
protected messagingService: MessagingService, protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService, protected policyService: PolicyService,
protected stateService: StateService) { }
constructor(
protected i18nService: I18nService,
protected cryptoService: CryptoService,
protected messagingService: MessagingService,
protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService,
protected policyService: PolicyService,
protected stateService: StateService
) {}
async ngOnInit() {
this.email = await this.stateService.getEmail();
@ -39,11 +44,11 @@ export class ChangePasswordComponent implements OnInit {
}
async submit() {
if (!await this.strongPassword()) {
if (!(await this.strongPassword())) {
return;
}
if (!await this.setupSubmitActions()) {
if (!(await this.setupSubmitActions())) {
return;
}
@ -54,8 +59,12 @@ export class ChangePasswordComponent implements OnInit {
if (this.kdfIterations == null) {
this.kdfIterations = await this.stateService.getKdfIterations();
}
const key = await this.cryptoService.makeKey(this.masterPassword, email.trim().toLowerCase(),
this.kdf, this.kdfIterations);
const key = await this.cryptoService.makeKey(
this.masterPassword,
email.trim().toLowerCase(),
this.kdf,
this.kdfIterations
);
const masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, key);
let encKey: [SymmetricCryptoKey, EncString] = null;
@ -75,45 +84,69 @@ export class ChangePasswordComponent implements OnInit {
return true;
}
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]) {
async performSubmitActions(
masterPasswordHash: string,
key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]
) {
// Override in sub-class
}
async strongPassword(): Promise<boolean> {
if (this.masterPassword == null || this.masterPassword === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassRequired'));
if (this.masterPassword == null || this.masterPassword === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassRequired")
);
return false;
}
if (this.masterPassword.length < 8) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassLength'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassLength")
);
return false;
}
if (this.masterPassword !== this.masterPasswordRetype) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassDoesntMatch'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassDoesntMatch")
);
return false;
}
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
this.getPasswordStrengthUserInput());
const strengthResult = this.passwordGenerationService.passwordStrength(
this.masterPassword,
this.getPasswordStrengthUserInput()
);
if (this.enforcedPolicyOptions != null &&
if (
this.enforcedPolicyOptions != null &&
!this.policyService.evaluateMasterPassword(
strengthResult.score,
this.masterPassword,
this.enforcedPolicyOptions)) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPasswordPolicyRequirementsNotMet'));
this.enforcedPolicyOptions
)
) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPasswordPolicyRequirementsNotMet")
);
return false;
}
if (strengthResult != null && strengthResult.score < 3) {
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
'warning');
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("weakMasterPasswordDesc"),
this.i18nService.t("weakMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!result) {
return false;
}
@ -127,25 +160,37 @@ export class ChangePasswordComponent implements OnInit {
clearTimeout(this.masterPasswordStrengthTimeout);
}
this.masterPasswordStrengthTimeout = setTimeout(() => {
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
this.getPasswordStrengthUserInput());
const strengthResult = this.passwordGenerationService.passwordStrength(
this.masterPassword,
this.getPasswordStrengthUserInput()
);
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
}, 300);
}
async logOut() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('logOutConfirmation'),
this.i18nService.t('logOut'), this.i18nService.t('logOut'), this.i18nService.t('cancel'));
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("logOutConfirmation"),
this.i18nService.t("logOut"),
this.i18nService.t("logOut"),
this.i18nService.t("cancel")
);
if (confirmed) {
this.messagingService.send('logout');
this.messagingService.send("logout");
}
}
private getPasswordStrengthUserInput() {
let userInput: string[] = [];
const atPosition = this.email.indexOf('@');
const atPosition = this.email.indexOf("@");
if (atPosition > -1) {
userInput = userInput.concat(this.email.substr(0, atPosition).trim().toLowerCase().split(/[^A-Za-z0-9]/));
userInput = userInput.concat(
this.email
.substr(0, atPosition)
.trim()
.toLowerCase()
.split(/[^A-Za-z0-9]/)
);
}
return userInput;
}

View File

@ -1,13 +1,8 @@
import {
Directive,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, Output } from "@angular/core";
import { SearchService } from 'jslib-common/abstractions/search.service';
import { SearchService } from "jslib-common/abstractions/search.service";
import { CipherView } from 'jslib-common/models/view/cipherView';
import { CipherView } from "jslib-common/models/view/cipherView";
@Directive()
export class CiphersComponent {
@ -28,7 +23,7 @@ export class CiphersComponent {
private searchTimeout: any = null;
constructor(protected searchService: SearchService) { }
constructor(protected searchService: SearchService) {}
async load(filter: (cipher: CipherView) => boolean = null, deleted: boolean = false) {
this.deleted = deleted || false;
@ -87,9 +82,13 @@ export class CiphersComponent {
return !this.searchPending && this.searchService.isSearchable(this.searchText);
}
protected deletedFilter: (cipher: CipherView) => boolean = c => c.isDeleted === this.deleted;
protected deletedFilter: (cipher: CipherView) => boolean = (c) => c.isDeleted === this.deleted;
protected async doSearch(indexedCiphers?: CipherView[]) {
this.ciphers = await this.searchService.searchCiphers(this.searchText, [this.filter, this.deletedFilter], indexedCiphers);
this.ciphers = await this.searchService.searchCiphers(
this.searchText,
[this.filter, this.deletedFilter],
indexedCiphers
);
}
}

View File

@ -1,21 +1,15 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
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 { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { CipherView } from 'jslib-common/models/view/cipherView';
import { CollectionView } from 'jslib-common/models/view/collectionView';
import { CipherView } from "jslib-common/models/view/cipherView";
import { CollectionView } from "jslib-common/models/view/collectionView";
import { Cipher } from 'jslib-common/models/domain/cipher';
import { Cipher } from "jslib-common/models/domain/cipher";
@Directive()
export class CollectionsComponent implements OnInit {
@ -30,8 +24,13 @@ export class CollectionsComponent implements OnInit {
protected cipherDomain: Cipher;
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService, protected cipherService: CipherService, private logService: LogService) { }
constructor(
protected collectionService: CollectionService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService,
protected cipherService: CipherService,
private logService: LogService
) {}
async ngOnInit() {
await this.load();
@ -43,9 +42,9 @@ export class CollectionsComponent implements OnInit {
this.cipher = await this.cipherDomain.decrypt();
this.collections = await this.loadCollections();
this.collections.forEach(c => (c as any).checked = false);
this.collections.forEach((c) => ((c as any).checked = false));
if (this.collectionIds != null) {
this.collections.forEach(c => {
this.collections.forEach((c) => {
(c as any).checked = this.collectionIds != null && this.collectionIds.indexOf(c.id) > -1;
});
}
@ -53,11 +52,14 @@ export class CollectionsComponent implements OnInit {
async submit() {
const selectedCollectionIds = this.collections
.filter(c => !!(c as any).checked)
.map(c => c.id);
.filter((c) => !!(c as any).checked)
.map((c) => c.id);
if (!this.allowSelectNone && selectedCollectionIds.length === 0) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('selectOneCollection'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("selectOneCollection")
);
return;
}
this.cipherDomain.collectionIds = selectedCollectionIds;
@ -65,7 +67,7 @@ export class CollectionsComponent implements OnInit {
this.formPromise = this.saveCollections();
await this.formPromise;
this.onSavedCollections.emit();
this.platformUtilsService.showToast('success', null, this.i18nService.t('editedItem'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("editedItem"));
} catch (e) {
this.logService.error(e);
}
@ -81,7 +83,9 @@ export class CollectionsComponent implements OnInit {
protected async loadCollections() {
const allCollections = await this.collectionService.getAllDecrypted();
return allCollections.filter(c => !c.readOnly && c.organizationId === this.cipher.organizationId);
return allCollections.filter(
(c) => !c.readOnly && c.organizationId === this.cipher.organizationId
);
}
protected saveCollections() {

View File

@ -1,12 +1,8 @@
import {
Directive,
EventEmitter,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Output } 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 { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
@Directive()
export class EnvironmentComponent {
@ -20,17 +16,19 @@ export class EnvironmentComponent {
baseUrl: string;
showCustom = false;
constructor(protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
protected i18nService: I18nService) {
constructor(
protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService,
protected i18nService: I18nService
) {
const urls = this.environmentService.getUrls();
this.baseUrl = urls.base || '';
this.webVaultUrl = urls.webVault || '';
this.apiUrl = urls.api || '';
this.identityUrl = urls.identity || '';
this.iconsUrl = urls.icons || '';
this.notificationsUrl = urls.notifications || '';
this.baseUrl = urls.base || "";
this.webVaultUrl = urls.webVault || "";
this.apiUrl = urls.api || "";
this.identityUrl = urls.identity || "";
this.iconsUrl = urls.icons || "";
this.notificationsUrl = urls.notifications || "";
}
async submit() {
@ -51,7 +49,7 @@ export class EnvironmentComponent {
this.iconsUrl = resUrls.icons;
this.notificationsUrl = resUrls.notifications;
this.platformUtilsService.showToast('success', null, this.i18nService.t('environmentSaved'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("environmentSaved"));
this.saved();
}

View File

@ -1,22 +1,17 @@
import {
Directive,
EventEmitter,
OnInit,
Output,
} from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Directive, EventEmitter, OnInit, Output } from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EventService } from 'jslib-common/abstractions/event.service';
import { ExportService } from 'jslib-common/abstractions/export.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 { PolicyService } from 'jslib-common/abstractions/policy.service';
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EventService } from "jslib-common/abstractions/event.service";
import { ExportService } from "jslib-common/abstractions/export.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 { 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';
import { EventType } from "jslib-common/enums/eventType";
import { PolicyType } from "jslib-common/enums/policyType";
@Directive()
export class ExportComponent implements OnInit {
@ -26,40 +21,53 @@ export class ExportComponent implements OnInit {
disabledByPolicy: boolean = false;
exportForm = this.fb.group({
format: ['json'],
secret: [''],
format: ["json"],
secret: [""],
});
formatOptions = [
{ name: '.json', value: 'json' },
{ name: '.csv', value: 'csv' },
{ name: '.json (Encrypted)', value: 'encrypted_json' },
{ name: ".json", value: "json" },
{ name: ".csv", value: "csv" },
{ name: ".json (Encrypted)", value: "encrypted_json" },
];
constructor(protected cryptoService: CryptoService, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, protected exportService: ExportService,
protected eventService: EventService, private policyService: PolicyService, protected win: Window,
private logService: LogService, private userVerificationService: UserVerificationService,
private fb: FormBuilder) { }
constructor(
protected cryptoService: CryptoService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected exportService: ExportService,
protected eventService: EventService,
private policyService: PolicyService,
protected win: Window,
private logService: LogService,
private userVerificationService: UserVerificationService,
private fb: FormBuilder
) {}
async ngOnInit() {
await this.checkExportDisabled();
}
async checkExportDisabled() {
this.disabledByPolicy = await this.policyService.policyAppliesToUser(PolicyType.DisablePersonalVaultExport);
this.disabledByPolicy = await this.policyService.policyAppliesToUser(
PolicyType.DisablePersonalVaultExport
);
if (this.disabledByPolicy) {
this.exportForm.disable();
}
}
get encryptedFormat() {
return this.format === 'encrypted_json';
return this.format === "encrypted_json";
}
async submit() {
if (this.disabledByPolicy) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('personalVaultExportPolicyInEffect'));
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("personalVaultExportPolicyInEffect")
);
return;
}
@ -68,11 +76,11 @@ export class ExportComponent implements OnInit {
return;
}
const secret = this.exportForm.get('secret').value;
const secret = this.exportForm.get("secret").value;
try {
await this.userVerificationService.verifyUser(secret);
} catch (e) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
return;
}
@ -82,7 +90,7 @@ export class ExportComponent implements OnInit {
this.downloadFile(data);
this.saved();
await this.collectEvent();
this.exportForm.get('secret').setValue('');
this.exportForm.get("secret").setValue("");
} catch (e) {
this.logService.error(e);
}
@ -91,16 +99,24 @@ export class ExportComponent implements OnInit {
async warningDialog() {
if (this.encryptedFormat) {
return await this.platformUtilsService.showDialog(
'<p>' + this.i18nService.t('encExportKeyWarningDesc') +
'<p>' + this.i18nService.t('encExportAccountWarningDesc'),
this.i18nService.t('confirmVaultExport'), this.i18nService.t('exportVault'),
this.i18nService.t('cancel'), 'warning',
true);
"<p>" +
this.i18nService.t("encExportKeyWarningDesc") +
"<p>" +
this.i18nService.t("encExportAccountWarningDesc"),
this.i18nService.t("confirmVaultExport"),
this.i18nService.t("exportVault"),
this.i18nService.t("cancel"),
"warning",
true
);
} else {
return await this.platformUtilsService.showDialog(
this.i18nService.t('exportWarningDesc'),
this.i18nService.t('confirmVaultExport'), this.i18nService.t('exportVault'),
this.i18nService.t('cancel'), 'warning');
this.i18nService.t("exportWarningDesc"),
this.i18nService.t("confirmVaultExport"),
this.i18nService.t("exportVault"),
this.i18nService.t("cancel"),
"warning"
);
}
}
@ -114,13 +130,13 @@ export class ExportComponent implements OnInit {
protected getFileName(prefix?: string) {
let extension = this.format;
if (this.format === 'encrypted_json') {
if (this.format === "encrypted_json") {
if (prefix == null) {
prefix = 'encrypted';
prefix = "encrypted";
} else {
prefix = 'encrypted_' + prefix;
prefix = "encrypted_" + prefix;
}
extension = 'json';
extension = "json";
}
return this.exportService.getFileName(prefix, extension);
}
@ -130,11 +146,11 @@ export class ExportComponent implements OnInit {
}
get format() {
return this.exportForm.get('format').value;
return this.exportForm.get("format").value;
}
private downloadFile(csv: string): void {
const fileName = this.getFileName();
this.platformUtilsService.saveFile(this.win, csv, { type: 'text/plain' }, fileName);
this.platformUtilsService.saveFile(this.win, csv, { type: "text/plain" }, fileName);
}
}

View File

@ -1,17 +1,11 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
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 { 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';
import { FolderView } from "jslib-common/models/view/folderView";
@Directive()
export class FolderAddEditComponent implements OnInit {
@ -25,17 +19,24 @@ export class FolderAddEditComponent implements OnInit {
formPromise: Promise<any>;
deletePromise: Promise<any>;
constructor(protected folderService: FolderService, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, private logService: LogService) { }
constructor(
protected folderService: FolderService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
private logService: LogService
) {}
async ngOnInit() {
await this.init();
}
async submit(): Promise<boolean> {
if (this.folder.name == null || this.folder.name === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('nameRequired'));
if (this.folder.name == null || this.folder.name === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("nameRequired")
);
return false;
}
@ -43,8 +44,11 @@ export class FolderAddEditComponent implements OnInit {
const folder = await this.folderService.encrypt(this.folder);
this.formPromise = this.folderService.saveWithServer(folder);
await this.formPromise;
this.platformUtilsService.showToast('success', null,
this.i18nService.t(this.editMode ? 'editedFolder' : 'addedFolder'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder")
);
this.onSavedFolder.emit(this.folder);
return true;
} catch (e) {
@ -56,8 +60,12 @@ export class FolderAddEditComponent implements OnInit {
async delete(): Promise<boolean> {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('deleteFolderConfirmation'), this.i18nService.t('deleteFolder'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("deleteFolderConfirmation"),
this.i18nService.t("deleteFolder"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -65,7 +73,7 @@ export class FolderAddEditComponent implements OnInit {
try {
this.deletePromise = this.folderService.deleteWithServer(this.folder.id);
await this.deletePromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedFolder'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedFolder"));
this.onDeletedFolder.emit(this.folder);
} catch (e) {
this.logService.error(e);
@ -79,11 +87,11 @@ export class FolderAddEditComponent implements OnInit {
if (this.editMode) {
this.editMode = true;
this.title = this.i18nService.t('editFolder');
this.title = this.i18nService.t("editFolder");
const folder = await this.folderService.get(this.folderId);
this.folder = await folder.decrypt();
} else {
this.title = this.i18nService.t('addFolder');
this.title = this.i18nService.t("addFolder");
}
}
}

View File

@ -1,20 +1,15 @@
import {
Directive,
EventEmitter,
Input,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, Output } from "@angular/core";
import { CipherType } from 'jslib-common/enums/cipherType';
import { CipherType } from "jslib-common/enums/cipherType";
import { CollectionView } from 'jslib-common/models/view/collectionView';
import { FolderView } from 'jslib-common/models/view/folderView';
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 { 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 { CollectionService } from "jslib-common/abstractions/collection.service";
import { FolderService } from "jslib-common/abstractions/folder.service";
import { StateService } from "jslib-common/abstractions/state.service";
@Directive()
export class GroupingsComponent {
@ -48,8 +43,11 @@ export class GroupingsComponent {
private collapsedGroupings: Set<string>;
constructor(protected collectionService: CollectionService, protected folderService: FolderService,
protected stateService: StateService) { }
constructor(
protected collectionService: CollectionService,
protected folderService: FolderService,
protected stateService: StateService
) {}
async load(setLoaded = true) {
const collapsedGroupings = await this.stateService.getCollapsedGroupings();
@ -73,7 +71,7 @@ export class GroupingsComponent {
}
const collections = await this.collectionService.getAllDecrypted();
if (organizationId != null) {
this.collections = collections.filter(c => c.organizationId === organizationId);
this.collections = collections.filter((c) => c.organizationId === organizationId);
} else {
this.collections = collections;
}
@ -143,7 +141,7 @@ export class GroupingsComponent {
this.selectedCollectionId = null;
}
async collapse(grouping: FolderView | CollectionView, idPrefix = '') {
async collapse(grouping: FolderView | CollectionView, idPrefix = "") {
if (grouping.id == null) {
return;
}
@ -156,7 +154,7 @@ export class GroupingsComponent {
await this.stateService.setCollapsedGroupings(this.collapsedGroupings);
}
isCollapsed(grouping: FolderView | CollectionView, idPrefix = '') {
isCollapsed(grouping: FolderView | CollectionView, idPrefix = "") {
return this.collapsedGroupings.has(idPrefix + grouping.id);
}
}

View File

@ -1,39 +1,49 @@
import { Router } from '@angular/router';
import { Router } from "@angular/router";
import { PasswordHintRequest } from 'jslib-common/models/request/passwordHintRequest';
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 { 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";
export class HintComponent {
email: string = '';
email: string = "";
formPromise: Promise<any>;
protected successRoute = 'login';
protected successRoute = "login";
protected onSuccessfulSubmit: () => void;
constructor(protected router: Router, protected i18nService: I18nService,
protected apiService: ApiService, protected platformUtilsService: PlatformUtilsService,
private logService: LogService) { }
constructor(
protected router: Router,
protected i18nService: I18nService,
protected apiService: ApiService,
protected platformUtilsService: PlatformUtilsService,
private logService: LogService
) {}
async submit() {
if (this.email == null || this.email === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('emailRequired'));
if (this.email == null || this.email === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("emailRequired")
);
return;
}
if (this.email.indexOf('@') === -1) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidEmail'));
if (this.email.indexOf("@") === -1) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidEmail")
);
return;
}
try {
this.formPromise = this.apiService.postPasswordHint(new PasswordHintRequest(this.email));
await this.formPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('masterPassSent'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("masterPassSent"));
if (this.onSuccessfulSubmit != null) {
this.onSuccessfulSubmit();
} else if (this.router != null) {

View File

@ -1,4 +1,4 @@
<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="" />
<i class="fa fa-fw fa-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
</div>

View File

@ -1,30 +1,26 @@
import {
Component,
Input,
OnChanges,
} from '@angular/core';
import { Component, Input, OnChanges } from "@angular/core";
import { CipherType } from 'jslib-common/enums/cipherType';
import { CipherType } from "jslib-common/enums/cipherType";
import { CipherView } from 'jslib-common/models/view/cipherView';
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 { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
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),
"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),
};
@Component({
selector: 'app-vault-icon',
templateUrl: 'icon.component.html',
selector: "app-vault-icon",
templateUrl: "icon.component.html",
})
export class IconComponent implements OnChanges {
@Input() cipher: CipherView;
@ -55,17 +51,17 @@ export class IconComponent implements OnChanges {
protected load() {
switch (this.cipher.type) {
case CipherType.Login:
this.icon = 'fa-globe';
this.icon = "fa-globe";
this.setLoginIcon();
break;
case CipherType.SecureNote:
this.icon = 'fa-sticky-note-o';
this.icon = "fa-sticky-note-o";
break;
case CipherType.Card:
this.icon = 'fa-credit-card';
this.icon = "fa-credit-card";
break;
case CipherType.Identity:
this.icon = 'fa-id-card-o';
this.icon = "fa-id-card-o";
break;
default:
break;
@ -77,23 +73,27 @@ export class IconComponent implements OnChanges {
let hostnameUri = this.cipher.login.uri;
let isWebsite = false;
if (hostnameUri.indexOf('androidapp://') === 0) {
this.icon = 'fa-android';
if (hostnameUri.indexOf("androidapp://") === 0) {
this.icon = "fa-android";
this.image = null;
} else if (hostnameUri.indexOf('iosapp://') === 0) {
this.icon = 'fa-apple';
} else if (hostnameUri.indexOf("iosapp://") === 0) {
this.icon = "fa-apple";
this.image = null;
} else if (this.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
hostnameUri = 'http://' + hostnameUri;
} else if (
this.imageEnabled &&
hostnameUri.indexOf("://") === -1 &&
hostnameUri.indexOf(".") > -1
) {
hostnameUri = "http://" + hostnameUri;
isWebsite = true;
} else if (this.imageEnabled) {
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
isWebsite = hostnameUri.indexOf("http") === 0 && hostnameUri.indexOf(".") > -1;
}
if (this.imageEnabled && isWebsite) {
try {
this.image = this.iconsUrl + '/' + Utils.getHostname(hostnameUri) + '/icon.png';
this.fallbackImage = 'images/fa-globe.png';
this.image = this.iconsUrl + "/" + Utils.getHostname(hostnameUri) + "/icon.png";
this.fallbackImage = "images/fa-globe.png";
} catch (e) {
// Ignore error since the fallback icon will be shown if image is null.
}

View File

@ -1,70 +1,84 @@
import { Directive, NgZone, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { take } from 'rxjs/operators';
import { Directive, NgZone, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { take } from "rxjs/operators";
import { ApiService } from 'jslib-common/abstractions/api.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { LogService } from 'jslib-common/abstractions/log.service';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { LogService } from "jslib-common/abstractions/log.service";
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 { EncString } from "jslib-common/models/domain/encString";
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
import { SecretVerificationRequest } from 'jslib-common/models/request/secretVerificationRequest';
import { SecretVerificationRequest } from "jslib-common/models/request/secretVerificationRequest";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
import { HashPurpose } from 'jslib-common/enums/hashPurpose';
import { KeySuffixOptions } from 'jslib-common/enums/keySuffixOptions';
import { HashPurpose } from "jslib-common/enums/hashPurpose";
import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
@Directive()
export class LockComponent implements OnInit {
masterPassword: string = '';
pin: string = '';
masterPassword: string = "";
pin: string = "";
showPassword: boolean = false;
email: string;
pinLock: boolean = false;
webVaultHostname: string = '';
webVaultHostname: string = "";
formPromise: Promise<any>;
supportsBiometric: boolean;
biometricLock: boolean;
biometricText: string;
hideInput: boolean;
protected successRoute: string = 'vault';
protected successRoute: string = "vault";
protected onSuccessfulSubmit: () => Promise<void>;
private invalidPinAttempts = 0;
private pinSet: [boolean, boolean];
constructor(protected router: Router, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, protected messagingService: MessagingService,
protected cryptoService: CryptoService, protected vaultTimeoutService: VaultTimeoutService,
protected environmentService: EnvironmentService, protected stateService: StateService,
protected apiService: ApiService, private logService: LogService,
private keyConnectorService: KeyConnectorService, protected ngZone: NgZone) { }
constructor(
protected router: Router,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected messagingService: MessagingService,
protected cryptoService: CryptoService,
protected vaultTimeoutService: VaultTimeoutService,
protected environmentService: EnvironmentService,
protected stateService: StateService,
protected apiService: ApiService,
private logService: LogService,
private keyConnectorService: KeyConnectorService,
protected ngZone: NgZone
) {}
async ngOnInit() {
this.stateService.activeAccount.subscribe(async _userId => {
this.stateService.activeAccount.subscribe(async (_userId) => {
await this.load();
});
}
async submit() {
if (this.pinLock && (this.pin == null || this.pin === '')) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('pinRequired'));
if (this.pinLock && (this.pin == null || this.pin === "")) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("pinRequired")
);
return;
}
if (!this.pinLock && (this.masterPassword == null || this.masterPassword === '')) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassRequired'));
if (!this.pinLock && (this.masterPassword == null || this.masterPassword === "")) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassRequired")
);
return;
}
@ -75,17 +89,30 @@ export class LockComponent implements OnInit {
let failed = true;
try {
if (this.pinSet[0]) {
const key = await this.cryptoService.makeKeyFromPin(this.pin, this.email, kdf, kdfIterations,
await this.stateService.getDecryptedPinProtected());
const key = await this.cryptoService.makeKeyFromPin(
this.pin,
this.email,
kdf,
kdfIterations,
await this.stateService.getDecryptedPinProtected()
);
const encKey = await this.cryptoService.getEncKey(key);
const protectedPin = await this.stateService.getProtectedPin();
const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey);
const decPin = await this.cryptoService.decryptToUtf8(
new EncString(protectedPin),
encKey
);
failed = decPin !== this.pin;
if (!failed) {
await this.setKeyAndContinue(key);
}
} else {
const key = await this.cryptoService.makeKeyFromPin(this.pin, this.email, kdf, kdfIterations);
const key = await this.cryptoService.makeKeyFromPin(
this.pin,
this.email,
kdf,
kdfIterations
);
failed = false;
await this.setKeyAndContinue(key);
}
@ -96,14 +123,22 @@ export class LockComponent implements OnInit {
if (failed) {
this.invalidPinAttempts++;
if (this.invalidPinAttempts >= 5) {
this.messagingService.send('logout');
this.messagingService.send("logout");
return;
}
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidPin'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidPin")
);
}
} else {
const key = await this.cryptoService.makeKey(this.masterPassword, this.email, kdf, kdfIterations);
const key = await this.cryptoService.makeKey(
this.masterPassword,
this.email,
kdf,
kdfIterations
);
const storedKeyHash = await this.cryptoService.getKeyHash();
let passwordValid = false;
@ -112,15 +147,21 @@ export class LockComponent implements OnInit {
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, key);
} else {
const request = new SecretVerificationRequest();
const serverKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
HashPurpose.ServerAuthorization);
const serverKeyHash = await this.cryptoService.hashPassword(
this.masterPassword,
key,
HashPurpose.ServerAuthorization
);
request.masterPasswordHash = serverKeyHash;
try {
this.formPromise = this.apiService.postAccountVerifyPassword(request);
await this.formPromise;
passwordValid = true;
const localKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
HashPurpose.LocalAuthorization);
const localKeyHash = await this.cryptoService.hashPassword(
this.masterPassword,
key,
HashPurpose.LocalAuthorization
);
await this.cryptoService.setKeyHash(localKeyHash);
} catch (e) {
this.logService.error(e);
@ -131,23 +172,40 @@ export class LockComponent implements OnInit {
if (this.pinSet[0]) {
const protectedPin = await this.stateService.getProtectedPin();
const encKey = await this.cryptoService.getEncKey(key);
const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey);
const pinKey = await this.cryptoService.makePinKey(decPin, this.email, kdf, kdfIterations);
await this.stateService.setDecryptedPinProtected(await this.cryptoService.encrypt(key.key, pinKey));
const decPin = await this.cryptoService.decryptToUtf8(
new EncString(protectedPin),
encKey
);
const pinKey = await this.cryptoService.makePinKey(
decPin,
this.email,
kdf,
kdfIterations
);
await this.stateService.setDecryptedPinProtected(
await this.cryptoService.encrypt(key.key, pinKey)
);
}
await this.setKeyAndContinue(key);
} else {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidMasterPassword'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidMasterPassword")
);
}
}
}
async logOut() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('logOutConfirmation'),
this.i18nService.t('logOut'), this.i18nService.t('logOut'), this.i18nService.t('cancel'));
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("logOutConfirmation"),
this.i18nService.t("logOut"),
this.i18nService.t("logOut"),
this.i18nService.t("cancel")
);
if (confirmed) {
this.messagingService.send('logout');
this.messagingService.send("logout");
}
}
@ -167,7 +225,7 @@ export class LockComponent implements OnInit {
togglePassword() {
this.showPassword = !this.showPassword;
const input = document.getElementById(this.pinLock ? 'pin' : 'masterPassword');
const input = document.getElementById(this.pinLock ? "pin" : "masterPassword");
if (this.ngZone.isStable) {
input.focus();
} else {
@ -185,7 +243,7 @@ export class LockComponent implements OnInit {
await this.stateService.setEverBeenUnlocked(true);
const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.setDisableFavicon(!!disableFavicon);
this.messagingService.send('unlocked');
this.messagingService.send("unlocked");
if (this.onSuccessfulSubmit != null) {
await this.onSuccessfulSubmit();
} else if (this.router != null) {
@ -195,10 +253,14 @@ export class LockComponent implements OnInit {
private async load() {
this.pinSet = await this.vaultTimeoutService.isPinLockSet();
this.pinLock = (this.pinSet[0] && (await this.stateService.getDecryptedPinProtected()) != null) || this.pinSet[1];
this.pinLock =
(this.pinSet[0] && (await this.stateService.getDecryptedPinProtected()) != null) ||
this.pinSet[1];
this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
this.biometricLock = await this.vaultTimeoutService.isBiometricLockSet() &&
(await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric) || !this.platformUtilsService.supportsSecureStorage());
this.biometricLock =
(await this.vaultTimeoutService.isBiometricLockSet()) &&
((await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric)) ||
!this.platformUtilsService.supportsSecureStorage());
this.biometricText = await this.stateService.getBiometricText();
this.email = await this.stateService.getEmail();
const usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
@ -210,7 +272,8 @@ export class LockComponent implements OnInit {
}
const webVaultUrl = this.environmentService.getWebVaultUrl();
const vaultUrl = webVaultUrl === 'https://vault.bitwarden.com' ? 'https://bitwarden.com' : webVaultUrl;
const vaultUrl =
webVaultUrl === "https://vault.bitwarden.com" ? "https://bitwarden.com" : webVaultUrl;
this.webVaultHostname = Utils.getHostname(vaultUrl);
}
}

View File

@ -1,35 +1,30 @@
import {
Directive,
Input,
NgZone,
OnInit,
} from '@angular/core';
import { Directive, Input, NgZone, OnInit } from "@angular/core";
import { Router } from '@angular/router';
import { Router } from "@angular/router";
import { take } from 'rxjs/operators';
import { take } from "rxjs/operators";
import { AuthResult } from 'jslib-common/models/domain/authResult';
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';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
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 { AuthService } from "jslib-common/abstractions/auth.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
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 { Utils } from "jslib-common/misc/utils";
import { CaptchaProtectedComponent } from './captchaProtected.component';
import { CaptchaProtectedComponent } from "./captchaProtected.component";
@Directive()
export class LoginComponent extends CaptchaProtectedComponent implements OnInit {
@Input() email: string = '';
@Input() email: string = "";
@Input() rememberEmail = true;
masterPassword: string = '';
masterPassword: string = "";
showPassword: boolean = false;
formPromise: Promise<AuthResult>;
onSuccessfulLogin: () => Promise<any>;
@ -37,27 +32,33 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
protected twoFactorRoute = '2fa';
protected successRoute = 'vault';
protected forcePasswordResetRoute = 'update-temp-password';
protected twoFactorRoute = "2fa";
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
constructor(protected authService: AuthService, protected router: Router,
platformUtilsService: PlatformUtilsService, i18nService: I18nService,
protected stateService: StateService, environmentService: EnvironmentService,
constructor(
protected authService: AuthService,
protected router: Router,
platformUtilsService: PlatformUtilsService,
i18nService: I18nService,
protected stateService: StateService,
environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, protected logService: LogService,
protected ngZone: NgZone) {
protected cryptoFunctionService: CryptoFunctionService,
protected logService: LogService,
protected ngZone: NgZone
) {
super(environmentService, i18nService, platformUtilsService);
}
async ngOnInit() {
if (this.email == null || this.email === '') {
if (this.email == null || this.email === "") {
this.email = await this.stateService.getRememberedEmail();
if (this.email == null) {
this.email = '';
this.email = "";
}
}
this.rememberEmail = await this.stateService.getRememberedEmail() != null;
this.rememberEmail = (await this.stateService.getRememberedEmail()) != null;
if (Utils.isBrowser && !Utils.isNode) {
this.focusInput();
}
@ -66,19 +67,28 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
async submit() {
await this.setupCaptcha();
if (this.email == null || this.email === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('emailRequired'));
if (this.email == null || this.email === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("emailRequired")
);
return;
}
if (this.email.indexOf('@') === -1) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidEmail'));
if (this.email.indexOf("@") === -1) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidEmail")
);
return;
}
if (this.masterPassword == null || this.masterPassword === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassRequired'));
if (this.masterPassword == null || this.masterPassword === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassRequired")
);
return;
}
@ -124,16 +134,18 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
togglePassword() {
this.showPassword = !this.showPassword;
if (this.ngZone.isStable) {
document.getElementById('masterPassword').focus();
document.getElementById("masterPassword").focus();
} else {
this.ngZone.onStable.pipe(take(1)).subscribe(() => document.getElementById('masterPassword').focus());
this.ngZone.onStable
.pipe(take(1))
.subscribe(() => document.getElementById("masterPassword").focus());
}
}
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
// Generate necessary sso params
const passwordOptions: any = {
type: 'password',
type: "password",
length: 64,
uppercase: true,
lowercase: true,
@ -142,7 +154,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
};
const state = await this.passwordGenerationService.generatePassword(passwordOptions);
const ssoCodeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
const codeVerifierHash = await this.cryptoFunctionService.hash(ssoCodeVerifier, 'sha256');
const codeVerifierHash = await this.cryptoFunctionService.hash(ssoCodeVerifier, "sha256");
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
// Save sso params
@ -153,12 +165,22 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
const webUrl = this.environmentService.getWebVaultUrl();
// Launch browser
this.platformUtilsService.launchUri(webUrl + '/#/sso?clientId=' + clientId +
'&redirectUri=' + encodeURIComponent(ssoRedirectUri) +
'&state=' + state + '&codeChallenge=' + codeChallenge);
this.platformUtilsService.launchUri(
webUrl +
"/#/sso?clientId=" +
clientId +
"&redirectUri=" +
encodeURIComponent(ssoRedirectUri) +
"&state=" +
state +
"&codeChallenge=" +
codeChallenge
);
}
protected focusInput() {
document.getElementById(this.email == null || this.email === '' ? 'email' : 'masterPassword').focus();
document
.getElementById(this.email == null || this.email === "" ? "email" : "masterPassword")
.focus();
}
}

View File

@ -7,35 +7,37 @@ import {
OnDestroy,
Type,
ViewChild,
ViewContainerRef
} from '@angular/core';
ViewContainerRef,
} from "@angular/core";
import {
ConfigurableFocusTrap,
ConfigurableFocusTrapFactory,
} from '@angular/cdk/a11y';
import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from "@angular/cdk/a11y";
import { ModalService } from '../../services/modal.service';
import { ModalService } from "../../services/modal.service";
import { ModalRef } from './modal.ref';
import { ModalRef } from "./modal.ref";
@Component({
selector: 'app-modal',
template: '<ng-template #modalContent></ng-template>',
selector: "app-modal",
template: "<ng-template #modalContent></ng-template>",
})
export class DynamicModalComponent implements AfterViewInit, OnDestroy {
componentRef: ComponentRef<any>;
@ViewChild('modalContent', { read: ViewContainerRef, static: true }) modalContentRef: ViewContainerRef;
@ViewChild("modalContent", { read: ViewContainerRef, static: true })
modalContentRef: ViewContainerRef;
childComponentType: Type<any>;
setComponentParameters: (component: any) => void;
private focusTrap: ConfigurableFocusTrap;
constructor(private modalService: ModalService, private cd: ChangeDetectorRef,
private el: ElementRef<HTMLElement>, private focusTrapFactory: ConfigurableFocusTrapFactory,
public modalRef: ModalRef) { }
constructor(
private modalService: ModalService,
private cd: ChangeDetectorRef,
private el: ElementRef<HTMLElement>,
private focusTrapFactory: ConfigurableFocusTrapFactory,
public modalRef: ModalRef
) {}
ngAfterViewInit() {
this.loadChildComponent(this.childComponentType);
@ -45,8 +47,10 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
this.cd.detectChanges();
this.modalRef.created(this.el.nativeElement);
this.focusTrap = this.focusTrapFactory.create(this.el.nativeElement.querySelector('.modal-dialog'));
if (this.el.nativeElement.querySelector('[appAutoFocus]') == null) {
this.focusTrap = this.focusTrapFactory.create(
this.el.nativeElement.querySelector(".modal-dialog")
);
if (this.el.nativeElement.querySelector("[appAutoFocus]") == null) {
this.focusTrap.focusFirstTabbableElementWhenReady();
}
}
@ -70,7 +74,7 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
}
getFocus() {
const autoFocusEl = this.el.nativeElement.querySelector('[appAutoFocus]') as HTMLElement;
const autoFocusEl = this.el.nativeElement.querySelector("[appAutoFocus]") as HTMLElement;
autoFocusEl?.focus();
}
}

View File

@ -1,9 +1,4 @@
import {
InjectFlags,
InjectionToken,
Injector,
Type
} from '@angular/core';
import { InjectFlags, InjectionToken, Injector, Type } from "@angular/core";
export class ModalInjector implements Injector {
constructor(private _parentInjector: Injector, private _additionalTokens: WeakMap<any, any>) {}

View File

@ -1,8 +1,7 @@
import { Observable, Subject } from 'rxjs';
import { first } from 'rxjs/operators';
import { Observable, Subject } from "rxjs";
import { first } from "rxjs/operators";
export class ModalRef {
onCreated: Observable<HTMLElement>; // Modal added to the DOM.
onClose: Observable<any>; // Initiated close.
onClosed: Observable<any>; // Modal was closed (Remove element from DOM)

View File

@ -1,18 +1,21 @@
import { Directive, OnInit } from '@angular/core';
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 { 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';
import { GeneratedPasswordHistory } from "jslib-common/models/domain/generatedPasswordHistory";
@Directive()
export class PasswordGeneratorHistoryComponent implements OnInit {
history: GeneratedPasswordHistory[] = [];
constructor(protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService,
private win: Window) { }
constructor(
protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService,
private win: Window
) {}
async ngOnInit() {
this.history = await this.passwordGenerationService.getHistory();
@ -26,7 +29,10 @@ export class PasswordGeneratorHistoryComponent implements OnInit {
copy(password: string) {
const copyOptions = this.win != null ? { window: this.win } : null;
this.platformUtilsService.copyToClipboard(password, copyOptions);
this.platformUtilsService.showToast('info', null,
this.i18nService.t('valueCopied', this.i18nService.t('password')));
this.platformUtilsService.showToast(
"info",
null,
this.i18nService.t("valueCopied", this.i18nService.t("password"))
);
}
}

View File

@ -1,16 +1,10 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
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 { 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';
import { PasswordGeneratorPolicyOptions } from "jslib-common/models/domain/passwordGeneratorPolicyOptions";
@Directive()
export class PasswordGeneratorComponent implements OnInit {
@ -19,17 +13,20 @@ export class PasswordGeneratorComponent implements OnInit {
passTypeOptions: any[];
options: any = {};
password: string = '-';
password: string = "-";
showOptions = false;
avoidAmbiguous = false;
enforcedPolicyOptions: PasswordGeneratorPolicyOptions;
constructor(protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService,
private win: Window) {
constructor(
protected passwordGenerationService: PasswordGenerationService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService,
private win: Window
) {
this.passTypeOptions = [
{ name: i18nService.t('password'), value: 'password' },
{ name: i18nService.t('passphrase'), value: 'passphrase' },
{ name: i18nService.t("password"), value: "password" },
{ name: i18nService.t("passphrase"), value: "passphrase" },
];
}
@ -38,7 +35,7 @@ export class PasswordGeneratorComponent implements OnInit {
this.options = optionsResponse[0];
this.enforcedPolicyOptions = optionsResponse[1];
this.avoidAmbiguous = !this.options.ambiguous;
this.options.type = this.options.type === 'passphrase' ? 'passphrase' : 'password';
this.options.type = this.options.type === "passphrase" ? "passphrase" : "password";
this.password = await this.passwordGenerationService.generatePassword(this.options);
await this.passwordGenerationService.addHistory(this.password);
}
@ -70,8 +67,11 @@ export class PasswordGeneratorComponent implements OnInit {
copy() {
const copyOptions = this.win != null ? { window: this.win } : null;
this.platformUtilsService.copyToClipboard(this.password, copyOptions);
this.platformUtilsService.showToast('info', null,
this.i18nService.t('valueCopied', this.i18nService.t('password')));
this.platformUtilsService.showToast(
"info",
null,
this.i18nService.t("valueCopied", this.i18nService.t("password"))
);
}
select() {
@ -86,10 +86,15 @@ export class PasswordGeneratorComponent implements OnInit {
// Application level normalize options depedent on class variables
this.options.ambiguous = !this.avoidAmbiguous;
if (!this.options.uppercase && !this.options.lowercase && !this.options.number && !this.options.special) {
if (
!this.options.uppercase &&
!this.options.lowercase &&
!this.options.number &&
!this.options.special
) {
this.options.lowercase = true;
if (this.win != null) {
const lowercase = this.win.document.querySelector('#lowercase') as HTMLInputElement;
const lowercase = this.win.document.querySelector("#lowercase") as HTMLInputElement;
if (lowercase) {
lowercase.checked = true;
}

View File

@ -1,18 +1,22 @@
import { Directive, OnInit } from '@angular/core';
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 { 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';
import { PasswordHistoryView } from "jslib-common/models/view/passwordHistoryView";
@Directive()
export class PasswordHistoryComponent implements OnInit {
cipherId: string;
history: PasswordHistoryView[] = [];
constructor(protected cipherService: CipherService, protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService, private win: Window) { }
constructor(
protected cipherService: CipherService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService,
private win: Window
) {}
async ngOnInit() {
await this.init();
@ -21,8 +25,11 @@ export class PasswordHistoryComponent implements OnInit {
copy(password: string) {
const copyOptions = this.win != null ? { window: this.win } : null;
this.platformUtilsService.copyToClipboard(password, copyOptions);
this.platformUtilsService.showToast('info', null,
this.i18nService.t('valueCopied', this.i18nService.t('password')));
this.platformUtilsService.showToast(
"info",
null,
this.i18nService.t("valueCopied", this.i18nService.t("password"))
);
}
protected async init() {

View File

@ -1,27 +1,33 @@
import { Directive } from '@angular/core';
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';
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()
export class PasswordRepromptComponent {
showPassword = false;
masterPassword = '';
masterPassword = "";
constructor(private modalRef: ModalRef, private cryptoService: CryptoService, private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService) {}
constructor(
private modalRef: ModalRef,
private cryptoService: CryptoService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService
) {}
togglePassword() {
this.showPassword = !this.showPassword;
}
async submit() {
if (!await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null)) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidMasterPassword'));
if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidMasterPassword")
);
return;
}

View File

@ -1,10 +1,10 @@
import { Directive, OnInit } from '@angular/core';
import { Directive, OnInit } from "@angular/core";
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 { StateService } from 'jslib-common/abstractions/state.service';
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 { StateService } from "jslib-common/abstractions/state.service";
@Directive()
export class PremiumComponent implements OnInit {
@ -12,9 +12,13 @@ export class PremiumComponent implements OnInit {
price: number = 10;
refreshPromise: Promise<any>;
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService, private logService: LogService,
protected stateService: StateService) { }
constructor(
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService,
private logService: LogService,
protected stateService: StateService
) {}
async ngOnInit() {
this.isPremium = await this.stateService.getCanAccessPremium();
@ -24,7 +28,7 @@ export class PremiumComponent implements OnInit {
try {
this.refreshPromise = this.apiService.refreshIdentityToken();
await this.refreshPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('refreshComplete'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("refreshComplete"));
this.isPremium = await this.stateService.getCanAccessPremium();
} catch (e) {
this.logService.error(e);
@ -32,18 +36,26 @@ export class PremiumComponent implements OnInit {
}
async purchase() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumPurchaseAlert'),
this.i18nService.t('premiumPurchase'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("premiumPurchaseAlert"),
this.i18nService.t("premiumPurchase"),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
if (confirmed) {
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=purchase');
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=purchase");
}
}
async manage() {
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumManageAlert'),
this.i18nService.t('premiumManage'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("premiumManageAlert"),
this.i18nService.t("premiumManage"),
this.i18nService.t("yes"),
this.i18nService.t("cancel")
);
if (confirmed) {
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=manage');
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=manage");
}
}
}

View File

@ -1,31 +1,31 @@
import { Directive, OnInit } from '@angular/core';
import { Router } from '@angular/router';
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 { 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';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
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 { KdfType } from "jslib-common/enums/kdfType";
import { CaptchaProtectedComponent } from './captchaProtected.component';
import { CaptchaProtectedComponent } from "./captchaProtected.component";
@Directive()
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
name: string = '';
email: string = '';
masterPassword: string = '';
confirmMasterPassword: string = '';
hint: string = '';
name: string = "";
email: string = "";
masterPassword: string = "";
confirmMasterPassword: string = "";
hint: string = "";
showPassword: boolean = false;
formPromise: Promise<any>;
masterPasswordScore: number;
@ -33,15 +33,21 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
showTerms = true;
acceptPolicies: boolean = false;
protected successRoute = 'login';
protected successRoute = "login";
private masterPasswordStrengthTimeout: any;
constructor(protected authService: AuthService, protected router: Router,
i18nService: I18nService, protected cryptoService: CryptoService,
protected apiService: ApiService, protected stateService: StateService,
constructor(
protected authService: AuthService,
protected router: Router,
i18nService: I18nService,
protected cryptoService: CryptoService,
protected apiService: ApiService,
protected stateService: StateService,
platformUtilsService: PlatformUtilsService,
protected passwordGenerationService: PasswordGenerationService, environmentService: EnvironmentService,
protected logService: LogService) {
protected passwordGenerationService: PasswordGenerationService,
environmentService: EnvironmentService,
protected logService: LogService
) {
super(environmentService, i18nService, platformUtilsService);
this.showTerms = !platformUtilsService.isSelfHost();
}
@ -57,89 +63,131 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
get masterPasswordScoreColor() {
switch (this.masterPasswordScore) {
case 4:
return 'success';
return "success";
case 3:
return 'primary';
return "primary";
case 2:
return 'warning';
return "warning";
default:
return 'danger';
return "danger";
}
}
get masterPasswordScoreText() {
switch (this.masterPasswordScore) {
case 4:
return this.i18nService.t('strong');
return this.i18nService.t("strong");
case 3:
return this.i18nService.t('good');
return this.i18nService.t("good");
case 2:
return this.i18nService.t('weak');
return this.i18nService.t("weak");
default:
return this.masterPasswordScore != null ? this.i18nService.t('weak') : null;
return this.masterPasswordScore != null ? this.i18nService.t("weak") : null;
}
}
async submit() {
if (!this.acceptPolicies && this.showTerms) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('acceptPoliciesError'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("acceptPoliciesError")
);
return;
}
if (this.email == null || this.email === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('emailRequired'));
if (this.email == null || this.email === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("emailRequired")
);
return;
}
if (this.email.indexOf('@') === -1) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('invalidEmail'));
if (this.email.indexOf("@") === -1) {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("invalidEmail")
);
return;
}
if (this.masterPassword == null || this.masterPassword === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassRequired'));
if (this.masterPassword == null || this.masterPassword === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassRequired")
);
return;
}
if (this.masterPassword.length < 8) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassLength'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassLength")
);
return;
}
if (this.masterPassword !== this.confirmMasterPassword) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('masterPassDoesntMatch'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("masterPassDoesntMatch")
);
return;
}
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
this.getPasswordStrengthUserInput());
const strengthResult = this.passwordGenerationService.passwordStrength(
this.masterPassword,
this.getPasswordStrengthUserInput()
);
if (strengthResult != null && strengthResult.score < 3) {
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
'warning');
const result = await this.platformUtilsService.showDialog(
this.i18nService.t("weakMasterPasswordDesc"),
this.i18nService.t("weakMasterPassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!result) {
return;
}
}
if (this.hint === this.masterPassword) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), this.i18nService.t('hintEqualsPassword'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("hintEqualsPassword")
);
return;
}
this.name = this.name === '' ? null : this.name;
this.name = this.name === "" ? null : this.name;
this.email = this.email.trim().toLowerCase();
const kdf = KdfType.PBKDF2_SHA256;
const useLowerKdf = this.platformUtilsService.isIE();
const kdfIterations = useLowerKdf ? 10000 : 100000;
const key = await this.cryptoService.makeKey(this.masterPassword, this.email, kdf, kdfIterations);
const key = await this.cryptoService.makeKey(
this.masterPassword,
this.email,
kdf,
kdfIterations
);
const encKey = await this.cryptoService.makeEncKey(key);
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
const request = new RegisterRequest(this.email, this.name, hashedPassword,
this.hint, encKey[1].encryptedString, kdf, kdfIterations, this.referenceData, this.captchaToken);
const request = new RegisterRequest(
this.email,
this.name,
hashedPassword,
this.hint,
encKey[1].encryptedString,
kdf,
kdfIterations,
this.referenceData,
this.captchaToken
);
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
const orgInvite = await this.stateService.getOrganizationInvitation();
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
@ -158,7 +206,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
throw e;
}
}
this.platformUtilsService.showToast('success', null, this.i18nService.t('newAccountCreated'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("newAccountCreated"));
this.router.navigate([this.successRoute], { queryParams: { email: this.email } });
} catch (e) {
this.logService.error(e);
@ -167,7 +215,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
togglePassword(confirmField: boolean) {
this.showPassword = !this.showPassword;
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
}
updatePasswordStrength() {
@ -175,20 +223,28 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
clearTimeout(this.masterPasswordStrengthTimeout);
}
this.masterPasswordStrengthTimeout = setTimeout(() => {
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
this.getPasswordStrengthUserInput());
const strengthResult = this.passwordGenerationService.passwordStrength(
this.masterPassword,
this.getPasswordStrengthUserInput()
);
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
}, 300);
}
private getPasswordStrengthUserInput() {
let userInput: string[] = [];
const atPosition = this.email.indexOf('@');
const atPosition = this.email.indexOf("@");
if (atPosition > -1) {
userInput = userInput.concat(this.email.substr(0, atPosition).trim().toLowerCase().split(/[^A-Za-z0-9]/));
userInput = userInput.concat(
this.email
.substr(0, atPosition)
.trim()
.toLowerCase()
.split(/[^A-Za-z0-9]/)
);
}
if (this.name != null && this.name !== '') {
userInput = userInput.concat(this.name.trim().toLowerCase().split(' '));
if (this.name != null && this.name !== "") {
userInput = userInput.concat(this.name.trim().toLowerCase().split(" "));
}
return userInput;
}

View File

@ -1,21 +1,17 @@
import {
Directive,
OnInit,
} from '@angular/core';
import { Router } from '@angular/router';
import { Directive, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { ApiService } from 'jslib-common/abstractions/api.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
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';
import { Organization } from "jslib-common/models/domain/organization";
@Directive()
export class RemovePasswordComponent implements OnInit {
actionPromise: Promise<any>;
continuing: boolean = false;
leaving: boolean = false;
@ -24,10 +20,15 @@ export class RemovePasswordComponent implements OnInit {
organization: Organization;
email: string;
constructor(private router: Router, private stateService: StateService,
private apiService: ApiService, private syncService: SyncService,
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
private keyConnectorService: KeyConnectorService) { }
constructor(
private router: Router,
private stateService: StateService,
private apiService: ApiService,
private syncService: SyncService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private keyConnectorService: KeyConnectorService
) {}
async ngOnInit() {
this.organization = await this.keyConnectorService.getManagingOrganization();
@ -42,18 +43,26 @@ export class RemovePasswordComponent implements OnInit {
try {
await this.actionPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('removedMasterPassword'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("removedMasterPassword")
);
await this.keyConnectorService.removeConvertAccountRequired();
this.router.navigate(['']);
this.router.navigate([""]);
} catch (e) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
}
}
async leave() {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('leaveOrganizationConfirmation'), this.organization.name,
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("leaveOrganizationConfirmation"),
this.organization.name,
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -64,11 +73,11 @@ export class RemovePasswordComponent implements OnInit {
return this.syncService.fullSync(true);
});
await this.actionPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('leftOrganization'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization"));
await this.keyConnectorService.removeConvertAccountRequired();
this.router.navigate(['']);
this.router.navigate([""]);
} catch (e) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e);
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e);
}
}
}

View File

@ -1,30 +1,24 @@
import { DatePipe } from '@angular/common';
import {
Directive,
EventEmitter,
Input,
OnInit,
Output
} from '@angular/core';
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 { 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';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
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 { EnvironmentService } from "jslib-common/abstractions/environment.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 { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
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 { SendFileView } from 'jslib-common/models/view/sendFileView';
import { SendTextView } from 'jslib-common/models/view/sendTextView';
import { SendView } from 'jslib-common/models/view/sendView';
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';
import { EncArrayBuffer } from "jslib-common/models/domain/encArrayBuffer";
import { Send } from "jslib-common/models/domain/send";
@Directive()
export class AddEditComponent implements OnInit {
@ -55,21 +49,27 @@ export class AddEditComponent implements OnInit {
private sendLinkBaseUrl: string;
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService, protected datePipe: DatePipe,
protected sendService: SendService, protected messagingService: MessagingService,
protected policyService: PolicyService, private logService: LogService,
protected stateService: StateService) {
constructor(
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService,
protected datePipe: DatePipe,
protected sendService: SendService,
protected messagingService: MessagingService,
protected policyService: PolicyService,
private logService: LogService,
protected stateService: StateService
) {
this.typeOptions = [
{ name: i18nService.t('sendTypeFile'), value: SendType.File },
{ name: i18nService.t('sendTypeText'), value: SendType.Text },
{ name: i18nService.t("sendTypeFile"), value: SendType.File },
{ name: i18nService.t("sendTypeText"), value: SendType.Text },
];
this.sendLinkBaseUrl = this.environmentService.getSendUrl();
}
get link(): string {
if (this.send.id != null && this.send.accessId != null) {
return this.sendLinkBaseUrl + this.send.accessId + '/' + this.send.urlB64Key;
return this.sendLinkBaseUrl + this.send.accessId + "/" + this.send.urlB64Key;
}
return null;
}
@ -91,22 +91,20 @@ export class AddEditComponent implements OnInit {
}
get title(): string {
return this.i18nService.t(
this.editMode ?
'editSend' :
'createSend'
);
return this.i18nService.t(this.editMode ? "editSend" : "createSend");
}
setDates(event: {deletionDate: string, expirationDate: string}) {
setDates(event: { deletionDate: string; expirationDate: string }) {
this.deletionDate = event.deletionDate;
this.expirationDate = event.expirationDate;
}
async load() {
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
this.disableHideEmail = await this.policyService.policyAppliesToUser(PolicyType.SendOptions,
p => p.data.disableHideEmail);
this.disableHideEmail = await this.policyService.policyAppliesToUser(
PolicyType.SendOptions,
(p) => p.data.disableHideEmail
);
this.canAccessPremium = await this.stateService.getCanAccessPremium();
this.emailVerified = await this.stateService.getEmailVerified();
@ -128,46 +126,58 @@ export class AddEditComponent implements OnInit {
}
}
this.hasPassword = this.send.password != null && this.send.password.trim() !== '';
this.hasPassword = this.send.password != null && this.send.password.trim() !== "";
}
async submit(): Promise<boolean> {
if (this.disableSend) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('sendDisabledWarning'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("sendDisabledWarning")
);
return false;
}
if (this.send.name == null || this.send.name === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('nameRequired'));
if (this.send.name == null || this.send.name === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("nameRequired")
);
return false;
}
let file: File = null;
if (this.send.type === SendType.File && !this.editMode) {
const fileEl = document.getElementById('file') as HTMLInputElement;
const fileEl = document.getElementById("file") as HTMLInputElement;
const files = fileEl.files;
if (files == null || files.length === 0) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('selectFile'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("selectFile")
);
return;
}
file = files[0];
if (files[0].size > 524288000) { // 500 MB
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('maxFileSize'));
if (files[0].size > 524288000) {
// 500 MB
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("maxFileSize")
);
return;
}
}
if (this.password != null && this.password.trim() === '') {
if (this.password != null && this.password.trim() === "") {
this.password = null;
}
this.formPromise = this.encryptSend(file)
.then(async encSend => {
this.formPromise = this.encryptSend(file).then(async (encSend) => {
const uploadPromise = this.sendService.saveWithServer(encSend);
await uploadPromise;
if (this.send.id == null) {
@ -180,12 +190,20 @@ export class AddEditComponent implements OnInit {
if (this.copyLink && this.link != null) {
const copySuccess = await this.copyLinkToClipboard(this.link);
if (copySuccess ?? true) {
this.platformUtilsService.showToast('success', null,
this.i18nService.t(this.editMode ? 'editedSend' : 'createdSend'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.editMode ? "editedSend" : "createdSend")
);
} else {
await this.platformUtilsService.showDialog(
this.i18nService.t(this.editMode ? 'editedSend' : 'createdSend'), null,
this.i18nService.t('ok'), null, 'success', null);
this.i18nService.t(this.editMode ? "editedSend" : "createdSend"),
null,
this.i18nService.t("ok"),
null,
"success",
null
);
await this.copyLinkToClipboard(this.link);
}
}
@ -208,9 +226,12 @@ export class AddEditComponent implements OnInit {
return false;
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('deleteSendConfirmation'),
this.i18nService.t('deleteSend'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("deleteSendConfirmation"),
this.i18nService.t("deleteSend"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -218,7 +239,7 @@ export class AddEditComponent implements OnInit {
try {
this.deletePromise = this.sendService.deleteWithServer(this.send.id);
await this.deletePromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend"));
await this.load();
this.onDeletedSend.emit(this.send);
return true;
@ -233,10 +254,10 @@ export class AddEditComponent implements OnInit {
if (this.send.type === SendType.File && !this.alertShown) {
if (!this.canAccessPremium) {
this.alertShown = true;
this.messagingService.send('premiumRequired');
this.messagingService.send("premiumRequired");
} else if (!this.emailVerified) {
this.alertShown = true;
this.messagingService.send('emailVerificationRequired');
this.messagingService.send("emailVerificationRequired");
}
}
}
@ -259,7 +280,8 @@ export class AddEditComponent implements OnInit {
sendData[0].deletionDate = null;
}
try {
sendData[0].expirationDate = this.expirationDate == null ? null : new Date(this.expirationDate);
sendData[0].expirationDate =
this.expirationDate == null ? null : new Date(this.expirationDate);
} catch {
sendData[0].expirationDate = null;
}
@ -269,6 +291,6 @@ export class AddEditComponent implements OnInit {
protected togglePasswordVisible() {
this.showPassword = !this.showPassword;
document.getElementById('password').focus();
document.getElementById("password").focus();
}
}

View File

@ -1,34 +1,28 @@
import { DatePipe } from '@angular/common';
import {
Directive,
EventEmitter,
Input,
OnInit,
Output
} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { DatePipe } from "@angular/common";
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
// Different BrowserPath = different controls.
enum BrowserPath {
// Native datetime-locale.
// We are happy.
Default = 'default',
Default = "default",
// Native date and time inputs, but no datetime-locale.
// We use individual date and time inputs and create a datetime programatically on submit.
Firefox = 'firefox',
Firefox = "firefox",
// No native date, time, or datetime-locale inputs.
// We use a polyfill for dates and a dropdown for times.
Safari = 'safari',
Safari = "safari",
}
enum DateField {
DeletionDate = 'deletion',
ExpriationDate = 'expiration',
DeletionDate = "deletion",
ExpriationDate = "expiration",
}
// Value = hours
@ -57,7 +51,7 @@ export class EffluxDatesComponent implements OnInit {
@Input() readonly editMode: boolean;
@Input() readonly disabled: boolean;
@Output() datesChanged = new EventEmitter<{deletionDate: string, expirationDate: string}>();
@Output() datesChanged = new EventEmitter<{ deletionDate: string; expirationDate: string }>();
get browserPath(): BrowserPath {
if (this.platformUtilsService.isFirefox()) {
@ -80,49 +74,49 @@ export class EffluxDatesComponent implements OnInit {
});
deletionDatePresets: any[] = [
{ name: this.i18nService.t('oneHour'), value: DatePreset.OneHour },
{ name: this.i18nService.t('oneDay'), value: DatePreset.OneDay },
{ name: this.i18nService.t('days', '2'), value: DatePreset.TwoDays },
{ name: this.i18nService.t('days', '3'), value: DatePreset.ThreeDays },
{ name: this.i18nService.t('days', '7'), value: DatePreset.SevenDays },
{ name: this.i18nService.t('days', '30'), value: DatePreset.ThirtyDays },
{ name: this.i18nService.t('custom'), value: DatePreset.Custom },
{ name: this.i18nService.t("oneHour"), value: DatePreset.OneHour },
{ name: this.i18nService.t("oneDay"), value: DatePreset.OneDay },
{ name: this.i18nService.t("days", "2"), value: DatePreset.TwoDays },
{ name: this.i18nService.t("days", "3"), value: DatePreset.ThreeDays },
{ name: this.i18nService.t("days", "7"), value: DatePreset.SevenDays },
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
{ name: this.i18nService.t("custom"), value: DatePreset.Custom },
];
expirationDatePresets: any[] = [
{ name: this.i18nService.t('never'), value: DatePreset.Never },
{ name: this.i18nService.t("never"), value: DatePreset.Never },
].concat([...this.deletionDatePresets]);
get selectedDeletionDatePreset(): FormControl {
return this.datesForm.get('selectedDeletionDatePreset') as FormControl;
return this.datesForm.get("selectedDeletionDatePreset") as FormControl;
}
get selectedExpirationDatePreset(): FormControl {
return this.datesForm.get('selectedExpirationDatePreset') as FormControl;
return this.datesForm.get("selectedExpirationDatePreset") as FormControl;
}
get defaultDeletionDateTime(): FormControl {
return this.datesForm.get('defaultDeletionDateTime') as FormControl;
return this.datesForm.get("defaultDeletionDateTime") as FormControl;
}
get defaultExpirationDateTime(): FormControl {
return this.datesForm.get('defaultExpirationDateTime') as FormControl;
return this.datesForm.get("defaultExpirationDateTime") as FormControl;
}
get fallbackDeletionDate(): FormControl {
return this.datesForm.get('fallbackDeletionDate') as FormControl;
return this.datesForm.get("fallbackDeletionDate") as FormControl;
}
get fallbackDeletionTime(): FormControl {
return this.datesForm.get('fallbackDeletionTime') as FormControl;
return this.datesForm.get("fallbackDeletionTime") as FormControl;
}
get fallbackExpirationDate(): FormControl {
return this.datesForm.get('fallbackExpirationDate') as FormControl;
return this.datesForm.get("fallbackExpirationDate") as FormControl;
}
get fallbackExpirationTime(): FormControl {
return this.datesForm.get('fallbackExpirationTime') as FormControl;
return this.datesForm.get("fallbackExpirationTime") as FormControl;
}
// Should be able to call these at any time and compute a submitable value
@ -135,14 +129,15 @@ export class EffluxDatesComponent implements OnInit {
switch (this.browserPath) {
case BrowserPath.Safari:
case BrowserPath.Firefox:
return this.fallbackDeletionDate.value + 'T' + this.fallbackDeletionTime.value;
return this.fallbackDeletionDate.value + "T" + this.fallbackDeletionTime.value;
default:
return this.defaultDeletionDateTime.value;
}
default:
const now = new Date();
const miliseconds = now.setTime(now.getTime() +
(this.selectedDeletionDatePreset.value as number * 60 * 60 * 1000)) ;
const miliseconds = now.setTime(
now.getTime() + (this.selectedDeletionDatePreset.value as number) * 60 * 60 * 1000
);
return new Date(miliseconds).toString();
}
}
@ -155,11 +150,13 @@ export class EffluxDatesComponent implements OnInit {
switch (this.browserPath) {
case BrowserPath.Safari:
case BrowserPath.Firefox:
if ((!this.fallbackExpirationDate.value || !this.fallbackExpirationTime.value) &&
this.editMode) {
if (
(!this.fallbackExpirationDate.value || !this.fallbackExpirationTime.value) &&
this.editMode
) {
return null;
}
return this.fallbackExpirationDate.value + 'T' + this.fallbackExpirationTime.value;
return this.fallbackExpirationDate.value + "T" + this.fallbackExpirationTime.value;
default:
if (!this.defaultExpirationDateTime.value) {
return null;
@ -168,8 +165,9 @@ export class EffluxDatesComponent implements OnInit {
}
default:
const now = new Date();
const miliseconds = now.setTime(now.getTime() +
(this.selectedExpirationDatePreset.value as number * 60 * 60 * 1000));
const miliseconds = now.setTime(
now.getTime() + (this.selectedExpirationDatePreset.value as number) * 60 * 60 * 1000
);
return new Date(miliseconds).toString();
}
}
@ -189,9 +187,11 @@ export class EffluxDatesComponent implements OnInit {
return nextWeek;
}
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected datePipe: DatePipe) {
}
constructor(
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected datePipe: DatePipe
) {}
ngOnInit(): void {
this.setInitialFormValues();
@ -235,16 +235,23 @@ export class EffluxDatesComponent implements OnInit {
this.fallbackDeletionDate.setValue(this.initialDeletionDate.toISOString().slice(0, 10));
this.fallbackDeletionTime.setValue(this.initialDeletionDate.toTimeString().slice(0, 5));
if (this.initialExpirationDate != null) {
this.fallbackExpirationDate.setValue(this.initialExpirationDate.toISOString().slice(0, 10));
this.fallbackExpirationTime.setValue(this.initialExpirationDate.toTimeString().slice(0, 5));
this.fallbackExpirationDate.setValue(
this.initialExpirationDate.toISOString().slice(0, 10)
);
this.fallbackExpirationTime.setValue(
this.initialExpirationDate.toTimeString().slice(0, 5)
);
}
break;
case BrowserPath.Default:
if (this.initialExpirationDate) {
this.defaultExpirationDateTime.setValue(
this.datePipe.transform(new Date(this.initialExpirationDate), 'yyyy-MM-ddTHH:mm'));
this.datePipe.transform(new Date(this.initialExpirationDate), "yyyy-MM-ddTHH:mm")
);
}
this.defaultDeletionDateTime.setValue(this.datePipe.transform(new Date(this.initialDeletionDate), 'yyyy-MM-ddTHH:mm'));
this.defaultDeletionDateTime.setValue(
this.datePipe.transform(new Date(this.initialDeletionDate), "yyyy-MM-ddTHH:mm")
);
break;
}
} else {
@ -254,7 +261,9 @@ export class EffluxDatesComponent implements OnInit {
switch (this.browserPath) {
case BrowserPath.Safari:
this.fallbackDeletionDate.setValue(this.nextWeek.toISOString().slice(0, 10));
this.fallbackDeletionTime.setValue(this.safariTimePresetOptions(DateField.DeletionDate)[1].twentyFourHour);
this.fallbackDeletionTime.setValue(
this.safariTimePresetOptions(DateField.DeletionDate)[1].twentyFourHour
);
break;
default:
break;
@ -282,10 +291,10 @@ export class EffluxDatesComponent implements OnInit {
// add prepending 0s to single digit hours/minutes
if (h < 10) {
hour = '0' + hour;
hour = "0" + hour;
}
if (m < 10) {
minutes = '0' + minutes;
minutes = "0" + minutes;
}
// build time strings and push to relevant sort groups
@ -324,14 +333,18 @@ export class EffluxDatesComponent implements OnInit {
// example: if the Send was created with a different client
if (field === DateField.ExpriationDate && this.initialExpirationDate != null && this.editMode) {
const previousValue: TimeOption = {
twelveHour: this.datePipe.transform(this.initialExpirationDate, 'hh:mm a'),
twentyFourHour: this.datePipe.transform(this.initialExpirationDate, 'HH:mm'),
twelveHour: this.datePipe.transform(this.initialExpirationDate, "hh:mm a"),
twentyFourHour: this.datePipe.transform(this.initialExpirationDate, "HH:mm"),
};
return [previousValue, { twelveHour: null, twentyFourHour: null }, ...validTimes];
} else if (field === DateField.DeletionDate && this.initialDeletionDate != null && this.editMode) {
} else if (
field === DateField.DeletionDate &&
this.initialDeletionDate != null &&
this.editMode
) {
const previousValue: TimeOption = {
twelveHour: this.datePipe.transform(this.initialDeletionDate, 'hh:mm a'),
twentyFourHour: this.datePipe.transform(this.initialDeletionDate, 'HH:mm'),
twelveHour: this.datePipe.transform(this.initialDeletionDate, "hh:mm a"),
twentyFourHour: this.datePipe.transform(this.initialDeletionDate, "HH:mm"),
};
return [previousValue, ...validTimes];
} else {

View File

@ -1,25 +1,20 @@
import {
Directive,
NgZone,
OnInit,
} from '@angular/core';
import { Directive, NgZone, OnInit } from "@angular/core";
import { PolicyType } from 'jslib-common/enums/policyType';
import { SendType } from 'jslib-common/enums/sendType';
import { PolicyType } from "jslib-common/enums/policyType";
import { SendType } from "jslib-common/enums/sendType";
import { SendView } from 'jslib-common/models/view/sendView';
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';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
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 { EnvironmentService } from "jslib-common/abstractions/environment.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 { PolicyService } from "jslib-common/abstractions/policy.service";
import { SearchService } from "jslib-common/abstractions/search.service";
import { SendService } from "jslib-common/abstractions/send.service";
@Directive()
export class SendComponent implements OnInit {
disableSend = false;
sendType = SendType;
loaded = false;
@ -44,10 +39,16 @@ export class SendComponent implements OnInit {
private searchTimeout: any;
constructor(protected sendService: SendService, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
protected ngZone: NgZone, protected searchService: SearchService,
protected policyService: PolicyService, private logService: LogService) { }
constructor(
protected sendService: SendService,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService,
protected ngZone: NgZone,
protected searchService: SearchService,
protected policyService: PolicyService,
private logService: LogService
) {}
async ngOnInit() {
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
@ -94,14 +95,14 @@ export class SendComponent implements OnInit {
}
if (timeout == null) {
this.hasSearched = this.searchService.isSearchable(this.searchText);
this.filteredSends = this.sends.filter(s => this.filter == null || this.filter(s));
this.filteredSends = this.sends.filter((s) => this.filter == null || this.filter(s));
this.applyTextSearch();
return;
}
this.searchPending = true;
this.searchTimeout = setTimeout(async () => {
this.hasSearched = this.searchService.isSearchable(this.searchText);
this.filteredSends = this.sends.filter(s => this.filter == null || this.filter(s));
this.filteredSends = this.sends.filter((s) => this.filter == null || this.filter(s));
this.applyTextSearch();
this.searchPending = false;
}, timeout);
@ -111,9 +112,13 @@ export class SendComponent implements OnInit {
if (this.actionPromise != null || s.password == null) {
return;
}
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('removePasswordConfirmation'),
this.i18nService.t('removePassword'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t("removePasswordConfirmation"),
this.i18nService.t("removePassword"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -125,7 +130,7 @@ export class SendComponent implements OnInit {
this.onSuccessfulRemovePassword();
} else {
// Default actions
this.platformUtilsService.showToast('success', null, this.i18nService.t('removedPassword'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("removedPassword"));
await this.load();
}
} catch (e) {
@ -139,9 +144,12 @@ export class SendComponent implements OnInit {
return false;
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('deleteSendConfirmation'),
this.i18nService.t('deleteSend'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("deleteSendConfirmation"),
this.i18nService.t("deleteSend"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
@ -154,7 +162,7 @@ export class SendComponent implements OnInit {
this.onSuccessfulDelete();
} else {
// Default actions
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend"));
await this.refresh();
}
} catch (e) {
@ -166,10 +174,13 @@ export class SendComponent implements OnInit {
copy(s: SendView) {
const sendLinkBaseUrl = this.environmentService.getSendUrl();
const link = sendLinkBaseUrl + s.accessId + '/' + s.urlB64Key;
const link = sendLinkBaseUrl + s.accessId + "/" + s.urlB64Key;
this.platformUtilsService.copyToClipboard(link);
this.platformUtilsService.showToast('success', null,
this.i18nService.t('valueCopied', this.i18nService.t('sendLink')));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("valueCopied", this.i18nService.t("sendLink"))
);
}
searchTextChanged() {
@ -185,7 +196,7 @@ export class SendComponent implements OnInit {
selectType(type: SendType) {
this.clearSelections();
this.selectedType = type;
this.applyFilter(s => s.type === type);
this.applyFilter((s) => s.type === type);
}
clearSelections() {

View File

@ -1,61 +1,73 @@
import { Directive } from '@angular/core';
import {
ActivatedRoute,
Router
} from '@angular/router';
import { Directive } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from 'rxjs/operators';
import { first } from "rxjs/operators";
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 { 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 { SyncService } from 'jslib-common/abstractions/sync.service';
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 { 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 { SyncService } from "jslib-common/abstractions/sync.service";
import { EncString } from 'jslib-common/models/domain/encString';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
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 { 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 { ChangePasswordComponent as BaseChangePasswordComponent } from "./change-password.component";
import { HashPurpose } from 'jslib-common/enums/hashPurpose';
import { KdfType } from 'jslib-common/enums/kdfType';
import { HashPurpose } from "jslib-common/enums/hashPurpose";
import { KdfType } from "jslib-common/enums/kdfType";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class SetPasswordComponent extends BaseChangePasswordComponent {
syncLoading: boolean = true;
showPassword: boolean = false;
hint: string = '';
hint: string = "";
identifier: string = null;
orgId: string;
resetPasswordAutoEnroll = false;
onSuccessfulChangePassword: () => Promise<any>;
successRoute = 'vault';
successRoute = "vault";
constructor(i18nService: I18nService, cryptoService: CryptoService,
messagingService: MessagingService, passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService, policyService: PolicyService,
protected router: Router, private apiService: ApiService,
private syncService: SyncService, private route: ActivatedRoute, stateService: StateService) {
super(i18nService, cryptoService, messagingService, passwordGenerationService,
platformUtilsService, policyService, stateService);
constructor(
i18nService: I18nService,
cryptoService: CryptoService,
messagingService: MessagingService,
passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService,
policyService: PolicyService,
protected router: Router,
private apiService: ApiService,
private syncService: SyncService,
private route: ActivatedRoute,
stateService: StateService
) {
super(
i18nService,
cryptoService,
messagingService,
passwordGenerationService,
platformUtilsService,
policyService,
stateService
);
}
async ngOnInit() {
await this.syncService.fullSync(true);
this.syncLoading = false;
this.route.queryParams.pipe(first()).subscribe(async qParams => {
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.identifier != null) {
this.identifier = qParams.identifier;
}
@ -68,7 +80,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
this.orgId = response.id;
this.resetPasswordAutoEnroll = response.resetPasswordEnabled;
} catch {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}
}
@ -82,8 +94,11 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
return true;
}
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]) {
async performSubmitActions(
masterPasswordHash: string,
key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]
) {
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
const request = new SetPasswordRequest(
masterPasswordHash,
@ -96,24 +111,34 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
);
try {
if (this.resetPasswordAutoEnroll) {
this.formPromise = this.apiService.setPassword(request).then(async () => {
this.formPromise = this.apiService
.setPassword(request)
.then(async () => {
await this.onSetPasswordSuccess(key, encKey, keys);
return this.apiService.getOrganizationKeys(this.orgId);
}).then(async response => {
})
.then(async (response) => {
if (response == null) {
throw new Error(this.i18nService.t('resetPasswordOrgKeysError'));
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
}
const userId = await this.stateService.getUserId();
const publicKey = Utils.fromB64ToArray(response.publicKey);
// RSA Encrypt user's encKey.key with organization public key
const userEncKey = await this.cryptoService.getEncKey();
const encryptedKey = await this.cryptoService.rsaEncrypt(userEncKey.key, publicKey.buffer);
const encryptedKey = await this.cryptoService.rsaEncrypt(
userEncKey.key,
publicKey.buffer
);
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
return this.apiService.putOrganizationUserResetPasswordEnrollment(this.orgId, userId, resetRequest);
return this.apiService.putOrganizationUserResetPasswordEnrollment(
this.orgId,
userId,
resetRequest
);
});
} else {
this.formPromise = this.apiService.setPassword(request).then(async () => {
@ -129,24 +154,31 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
this.router.navigate([this.successRoute]);
}
} catch {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}
}
togglePassword(confirmField: boolean) {
this.showPassword = !this.showPassword;
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
}
private async onSetPasswordSuccess(key: SymmetricCryptoKey, encKey: [SymmetricCryptoKey, EncString], keys: [string, EncString]) {
private async onSetPasswordSuccess(
key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString],
keys: [string, EncString]
) {
await this.stateService.setKdfType(this.kdf);
await this.stateService.setKdfIterations(this.kdfIterations);
await this.cryptoService.setKey(key);
await this.cryptoService.setEncKey(encKey[1].encryptedString);
await this.cryptoService.setEncPrivateKey(keys[1].encryptedString);
const localKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
HashPurpose.LocalAuthorization);
const localKeyHash = await this.cryptoService.hashPassword(
this.masterPassword,
key,
HashPurpose.LocalAuthorization
);
await this.cryptoService.setKeyHash(localKeyHash);
}
}

View File

@ -1,28 +1,30 @@
import {
Directive,
OnInit
} from '@angular/core';
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 { 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 { Utils } from "jslib-common/misc/utils";
import { ModalRef } from './modal/modal.ref';
import { ModalRef } from "./modal/modal.ref";
@Directive()
export class SetPinComponent implements OnInit {
pin = '';
pin = "";
showPin = false;
masterPassOnRestart = true;
showMasterPassOnRestart = true;
constructor(private modalRef: ModalRef, private cryptoService: CryptoService,
private keyConnectorService: KeyConnectorService, private stateService: StateService) { }
constructor(
private modalRef: ModalRef,
private cryptoService: CryptoService,
private keyConnectorService: KeyConnectorService,
private stateService: StateService
) {}
async ngOnInit() {
this.showMasterPassOnRestart = this.masterPassOnRestart = !await this.keyConnectorService.getUsesKeyConnector();
this.showMasterPassOnRestart = this.masterPassOnRestart =
!(await this.keyConnectorService.getUsesKeyConnector());
}
toggleVisibility() {

View File

@ -1,27 +1,22 @@
import {
Directive,
Input,
OnInit,
} from '@angular/core';
import { Directive, Input, OnInit } from "@angular/core";
import {
AbstractControl,
ControlValueAccessor,
FormBuilder,
ValidationErrors,
Validator
} from '@angular/forms';
Validator,
} from "@angular/forms";
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service';
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';
import { PolicyType } from "jslib-common/enums/policyType";
import { Policy } from "jslib-common/models/domain/policy";
@Directive()
export class VaultTimeoutInputComponent implements ControlValueAccessor, Validator, OnInit {
get showCustom() {
return this.form.get('vaultTimeout').value === VaultTimeoutInputComponent.CUSTOM_VALUE;
return this.form.get("vaultTimeout").value === VaultTimeoutInputComponent.CUSTOM_VALUE;
}
static CUSTOM_VALUE = -100;
@ -34,7 +29,7 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
}),
});
@Input() vaultTimeouts: { name: string; value: number; }[];
@Input() vaultTimeouts: { name: string; value: number }[];
vaultTimeoutPolicy: Policy;
vaultTimeoutPolicyHours: number;
vaultTimeoutPolicyMinutes: number;
@ -42,8 +37,11 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
private onChange: (vaultTimeout: number) => void;
private validatorChange: () => void;
constructor(private fb: FormBuilder, private policyService: PolicyService, private i18nService: I18nService) {
}
constructor(
private fb: FormBuilder,
private policyService: PolicyService,
private i18nService: I18nService
) {}
async ngOnInit() {
if (await this.policyService.policyAppliesToUser(PolicyType.MaximumVaultTimeout)) {
@ -53,7 +51,8 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
this.vaultTimeoutPolicyHours = Math.floor(this.vaultTimeoutPolicy.data.minutes / 60);
this.vaultTimeoutPolicyMinutes = this.vaultTimeoutPolicy.data.minutes % 60;
this.vaultTimeouts = this.vaultTimeouts.filter(t =>
this.vaultTimeouts = this.vaultTimeouts.filter(
(t) =>
t.value <= this.vaultTimeoutPolicy.data.minutes &&
(t.value > 0 || t.value === VaultTimeoutInputComponent.CUSTOM_VALUE) &&
t.value != null
@ -61,12 +60,12 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
this.validatorChange();
}
this.form.valueChanges.subscribe(async value => {
this.form.valueChanges.subscribe(async (value) => {
this.onChange(this.getVaultTimeout(value));
});
// Assign the previous value to the custom fields
this.form.get('vaultTimeout').valueChanges.subscribe(value => {
this.form.get("vaultTimeout").valueChanges.subscribe((value) => {
if (value !== VaultTimeoutInputComponent.CUSTOM_VALUE) {
return;
}
@ -82,7 +81,10 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
}
ngOnChanges() {
this.vaultTimeouts.push({ name: this.i18nService.t('custom'), value: VaultTimeoutInputComponent.CUSTOM_VALUE });
this.vaultTimeouts.push({
name: this.i18nService.t("custom"),
value: VaultTimeoutInputComponent.CUSTOM_VALUE,
});
}
getVaultTimeout(value: any) {
@ -98,7 +100,7 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
return;
}
if (this.vaultTimeouts.every(p => p.value !== value)) {
if (this.vaultTimeouts.every((p) => p.value !== value)) {
this.form.setValue({
vaultTimeout: VaultTimeoutInputComponent.CUSTOM_VALUE,
custom: {
@ -122,7 +124,7 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
registerOnTouched(onTouched: any): void {}
// tslint:disable-next-line
setDisabledState?(isDisabled: boolean): void { }
setDisabledState?(isDisabled: boolean): void {}
validate(control: AbstractControl): ValidationErrors {
if (this.vaultTimeoutPolicy && this.vaultTimeoutPolicy?.data?.minutes < control.value) {

View File

@ -1,25 +1,19 @@
import {
Directive,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
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 { 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 { Organization } from 'jslib-common/models/domain/organization';
import { CipherView } from 'jslib-common/models/view/cipherView';
import { CollectionView } from 'jslib-common/models/view/collectionView';
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';
import { Utils } from "jslib-common/misc/utils";
@Directive()
export class ShareComponent implements OnInit {
@ -34,9 +28,14 @@ export class ShareComponent implements OnInit {
protected writeableCollections: CollectionView[] = [];
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService, protected cipherService: CipherService,
private logService: LogService, protected organizationService: OrganizationService) { }
constructor(
protected collectionService: CollectionService,
protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService,
protected cipherService: CipherService,
private logService: LogService,
protected organizationService: OrganizationService
) {}
async ngOnInit() {
await this.load();
@ -44,10 +43,11 @@ export class ShareComponent implements OnInit {
async load() {
const allCollections = await this.collectionService.getAllDecrypted();
this.writeableCollections = allCollections.map(c => c).filter(c => !c.readOnly);
this.writeableCollections = allCollections.map((c) => c).filter((c) => !c.readOnly);
const orgs = await this.organizationService.getAll();
this.organizations = orgs.sort(Utils.getSortFunction(this.i18nService, 'name'))
.filter(o => o.enabled && o.status === OrganizationUserStatusType.Confirmed);
this.organizations = orgs
.sort(Utils.getSortFunction(this.i18nService, "name"))
.filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed);
const cipherDomain = await this.cipherService.get(this.cipherId);
this.cipher = await cipherDomain.decrypt();
@ -58,34 +58,45 @@ export class ShareComponent implements OnInit {
}
filterCollections() {
this.writeableCollections.forEach(c => (c as any).checked = false);
this.writeableCollections.forEach((c) => ((c as any).checked = false));
if (this.organizationId == null || this.writeableCollections.length === 0) {
this.collections = [];
} else {
this.collections = this.writeableCollections.filter(c => c.organizationId === this.organizationId);
this.collections = this.writeableCollections.filter(
(c) => c.organizationId === this.organizationId
);
}
}
async submit(): Promise<boolean> {
const selectedCollectionIds = this.collections
.filter(c => !!(c as any).checked)
.map(c => c.id);
.filter((c) => !!(c as any).checked)
.map((c) => c.id);
if (selectedCollectionIds.length === 0) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('selectOneCollection'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("selectOneCollection")
);
return;
}
const cipherDomain = await this.cipherService.get(this.cipherId);
const cipherView = await cipherDomain.decrypt();
const orgName = this.organizations.find(o => o.id === this.organizationId)?.name ?? this.i18nService.t('organization');
const orgName =
this.organizations.find((o) => o.id === this.organizationId)?.name ??
this.i18nService.t("organization");
try {
this.formPromise = this.cipherService.shareWithServer(cipherView, this.organizationId,
selectedCollectionIds).then(async () => {
this.formPromise = this.cipherService
.shareWithServer(cipherView, this.organizationId, selectedCollectionIds)
.then(async () => {
this.onSharedCipher.emit();
this.platformUtilsService.showToast('success', null,
this.i18nService.t('movedItemToOrg', cipherView.name, orgName));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("movedItemToOrg", cipherView.name, orgName)
);
});
await this.formPromise;
return true;

View File

@ -1,24 +1,21 @@
import { Directive } from '@angular/core';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { Directive } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
import { first } from 'rxjs/operators';
import { first } from "rxjs/operators";
import { ApiService } from 'jslib-common/abstractions/api.service';
import { AuthService } from 'jslib-common/abstractions/auth.service';
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
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 { Utils } from "jslib-common/misc/utils";
import { AuthResult } from 'jslib-common/models/domain/authResult';
import { AuthResult } from "jslib-common/models/domain/authResult";
@Directive()
export class SsoComponent {
@ -33,34 +30,54 @@ export class SsoComponent {
onSuccessfulLoginChangePasswordNavigate: () => Promise<any>;
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
protected twoFactorRoute = '2fa';
protected successRoute = 'lock';
protected changePasswordRoute = 'set-password';
protected forcePasswordResetRoute = 'update-temp-password';
protected twoFactorRoute = "2fa";
protected successRoute = "lock";
protected changePasswordRoute = "set-password";
protected forcePasswordResetRoute = "update-temp-password";
protected clientId: string;
protected redirectUri: string;
protected state: string;
protected codeChallenge: string;
constructor(protected authService: AuthService, protected router: Router,
protected i18nService: I18nService, protected route: ActivatedRoute,
protected stateService: StateService, protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService, protected cryptoFunctionService: CryptoFunctionService,
protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationService,
protected logService: LogService) { }
constructor(
protected authService: AuthService,
protected router: Router,
protected i18nService: I18nService,
protected route: ActivatedRoute,
protected stateService: StateService,
protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService,
protected cryptoFunctionService: CryptoFunctionService,
protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService,
protected logService: LogService
) {}
async ngOnInit() {
this.route.queryParams.pipe(first()).subscribe(async qParams => {
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
if (qParams.code != null && qParams.state != null) {
const codeVerifier = await this.stateService.getSsoCodeVerifier();
const state = await this.stateService.getSsoState();
await this.stateService.setSsoCodeVerifier(null);
await this.stateService.setSsoState(null);
if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
await this.logIn(qParams.code, codeVerifier, this.getOrgIdentifierFromState(qParams.state));
if (
qParams.code != null &&
codeVerifier != null &&
state != null &&
this.checkState(state, qParams.state)
) {
await this.logIn(
qParams.code,
codeVerifier,
this.getOrgIdentifierFromState(qParams.state)
);
}
} else if (qParams.clientId != null && qParams.redirectUri != null && qParams.state != null &&
qParams.codeChallenge != null) {
} else if (
qParams.clientId != null &&
qParams.redirectUri != null &&
qParams.state != null &&
qParams.codeChallenge != null
) {
this.redirectUri = qParams.redirectUri;
this.state = qParams.state;
this.codeChallenge = qParams.codeChallenge;
@ -78,20 +95,26 @@ export class SsoComponent {
}
async preValidate(): Promise<boolean> {
if (this.identifier == null || this.identifier === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('ssoValidationFailed'),
this.i18nService.t('ssoIdentifierRequired'));
if (this.identifier == null || this.identifier === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("ssoValidationFailed"),
this.i18nService.t("ssoIdentifierRequired")
);
return false;
}
return await this.apiService.preValidateSso(this.identifier);
}
protected async buildAuthorizeUrl(returnUri?: string, includeUserIdentifier?: boolean): Promise<string> {
protected async buildAuthorizeUrl(
returnUri?: string,
includeUserIdentifier?: boolean
): Promise<string> {
let codeChallenge = this.codeChallenge;
let state = this.state;
const passwordOptions: any = {
type: 'password',
type: "password",
length: 64,
uppercase: true,
lowercase: true,
@ -101,7 +124,7 @@ export class SsoComponent {
if (codeChallenge == null) {
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, 'sha256');
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, "sha256");
codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.stateService.setSsoCodeVerifier(codeVerifier);
}
@ -119,12 +142,23 @@ export class SsoComponent {
// Save state (regardless of new or existing)
await this.stateService.setSsoState(state);
let authorizeUrl = this.environmentService.getIdentityUrl() + '/connect/authorize?' +
'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' +
'response_type=code&scope=api offline_access&' +
'state=' + state + '&code_challenge=' + codeChallenge + '&' +
'code_challenge_method=S256&response_mode=query&' +
'domain_hint=' + encodeURIComponent(this.identifier);
let authorizeUrl =
this.environmentService.getIdentityUrl() +
"/connect/authorize?" +
"client_id=" +
this.clientId +
"&redirect_uri=" +
encodeURIComponent(this.redirectUri) +
"&" +
"response_type=code&scope=api offline_access&" +
"state=" +
state +
"&code_challenge=" +
codeChallenge +
"&" +
"code_challenge_method=S256&response_mode=query&" +
"domain_hint=" +
encodeURIComponent(this.identifier);
if (includeUserIdentifier) {
const userIdentifier = await this.apiService.getSsoUserIdentifier();
@ -137,7 +171,12 @@ export class SsoComponent {
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
this.loggingIn = true;
try {
this.formPromise = this.authService.logInSso(code, codeVerifier, this.redirectUri, orgIdFromState);
this.formPromise = this.authService.logInSso(
code,
codeVerifier,
this.redirectUri,
orgIdFromState
);
const response = await this.formPromise;
if (response.twoFactor) {
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
@ -146,7 +185,7 @@ export class SsoComponent {
this.router.navigate([this.twoFactorRoute], {
queryParams: {
identifier: orgIdFromState,
sso: 'true',
sso: "true",
},
});
}
@ -180,8 +219,12 @@ export class SsoComponent {
}
} catch (e) {
this.logService.error(e);
if (e.message === 'Unable to reach key connector') {
this.platformUtilsService.showToast('error', null, this.i18nService.t('ssoKeyConnectorUnavailable'));
if (e.message === "Unable to reach key connector") {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("ssoKeyConnectorUnavailable")
);
}
}
this.loggingIn = false;
@ -192,7 +235,7 @@ export class SsoComponent {
return null;
}
const stateSplit = state.split('_identifier=');
const stateSplit = state.split("_identifier=");
return stateSplit.length > 1 ? stateSplit[1] : null;
}
@ -204,8 +247,8 @@ export class SsoComponent {
return false;
}
const stateSplit = state.split('_identifier=');
const checkStateSplit = checkState.split('_identifier=');
const stateSplit = state.split("_identifier=");
const checkStateSplit = checkState.split("_identifier=");
return stateSplit[0] === checkStateSplit[0];
}
}

View File

@ -1,18 +1,25 @@
import { animate, state, style, transition, trigger } from "@angular/animations";
import { CommonModule } from "@angular/common";
import { Component, ModuleWithProviders, NgModule } from "@angular/core";
import {
animate,
state,
style,
transition,
trigger
} from '@angular/animations';
import { CommonModule } from '@angular/common';
import { Component, ModuleWithProviders, NgModule } from '@angular/core';
import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, ToastPackage, ToastrService, TOAST_CONFIG } from 'ngx-toastr';
DefaultNoComponentGlobalConfig,
GlobalConfig,
Toast as BaseToast,
ToastPackage,
ToastrService,
TOAST_CONFIG,
} from "ngx-toastr";
@Component({
selector: '[toast-component2]',
selector: "[toast-component2]",
template: `
<button *ngIf="options.closeButton" (click)="remove()" type="button" class="toast-close-button" aria-label="Close">
<button
*ngIf="options.closeButton"
(click)="remove()"
type="button"
class="toast-close-button"
aria-label="Close"
>
<span aria-hidden="true">&times;</span>
</button>
<div class="icon">
@ -22,11 +29,20 @@ import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, Toast
<div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
{{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
</div>
<div *ngIf="message && options.enableHtml" role="alertdialog" aria-live="polite"
[class]="options.messageClass" [innerHTML]="message">
</div>
<div *ngIf="message && !options.enableHtml" role="alertdialog" aria-live="polite"
[class]="options.messageClass" [attr.aria-label]="message">
<div
*ngIf="message && options.enableHtml"
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[innerHTML]="message"
></div>
<div
*ngIf="message && !options.enableHtml"
role="alertdialog"
aria-live="polite"
[class]="options.messageClass"
[attr.aria-label]="message"
>
{{ message }}
</div>
</div>
@ -35,18 +51,12 @@ import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, Toast
</div>
`,
animations: [
trigger('flyInOut', [
state('inactive', style({ opacity: 0 })),
state('active', style({ opacity: 1 })),
state('removed', style({ opacity: 0 })),
transition(
'inactive => active',
animate('{{ easeTime }}ms {{ easing }}')
),
transition(
'active => removed',
animate('{{ easeTime }}ms {{ easing }}')
),
trigger("flyInOut", [
state("inactive", style({ opacity: 0 })),
state("active", style({ opacity: 1 })),
state("removed", style({ opacity: 0 })),
transition("inactive => active", animate("{{ easeTime }}ms {{ easing }}")),
transition("active => removed", animate("{{ easeTime }}ms {{ easing }}")),
]),
],
preserveWhitespaces: false,
@ -60,7 +70,7 @@ export class BitwardenToast extends BaseToast {
export const BitwardenToastGlobalConfig: GlobalConfig = {
...DefaultNoComponentGlobalConfig,
toastComponent: BitwardenToast,
};
};
@NgModule({
imports: [CommonModule],

View File

@ -1,16 +1,11 @@
import {
Directive,
EventEmitter,
OnInit,
Output,
} from '@angular/core';
import { Router } from '@angular/router';
import { Directive, EventEmitter, OnInit, Output } from "@angular/core";
import { Router } from "@angular/router";
import { TwoFactorProviderType } from 'jslib-common/enums/twoFactorProviderType';
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 { AuthService } from "jslib-common/abstractions/auth.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
@Directive()
export class TwoFactorOptionsComponent implements OnInit {
@ -19,9 +14,13 @@ export class TwoFactorOptionsComponent implements OnInit {
providers: any[] = [];
constructor(protected authService: AuthService, protected router: Router,
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected win: Window) { }
constructor(
protected authService: AuthService,
protected router: Router,
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected win: Window
) {}
ngOnInit() {
this.providers = this.authService.getSupportedTwoFactorProviders(this.win);
@ -32,7 +31,7 @@ export class TwoFactorOptionsComponent implements OnInit {
}
recover() {
this.platformUtilsService.launchUri('https://help.bitwarden.com/article/lost-two-step-device/');
this.platformUtilsService.launchUri("https://help.bitwarden.com/article/lost-two-step-device/");
this.onRecoverSelected.emit();
}
}

View File

@ -1,34 +1,31 @@
import { Directive, OnDestroy, OnInit } from '@angular/core';
import { Directive, OnDestroy, OnInit } from "@angular/core";
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { ActivatedRoute, Router } from "@angular/router";
import { first } from 'rxjs/operators';
import { first } from "rxjs/operators";
import { TwoFactorProviderType } from 'jslib-common/enums/twoFactorProviderType';
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { TwoFactorEmailRequest } from 'jslib-common/models/request/twoFactorEmailRequest';
import { TwoFactorEmailRequest } from "jslib-common/models/request/twoFactorEmailRequest";
import { AuthResult } from 'jslib-common/models/domain/authResult';
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';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { AuthService } from "jslib-common/abstractions/auth.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.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 { StateService } from "jslib-common/abstractions/state.service";
import { TwoFactorProviders } from 'jslib-common/services/auth.service';
import { TwoFactorProviders } from "jslib-common/services/auth.service";
import * as DuoWebSDK from 'duo_web_sdk';
import { WebAuthnIFrame } from 'jslib-common/misc/webauthn_iframe';
import * as DuoWebSDK from "duo_web_sdk";
import { WebAuthnIFrame } from "jslib-common/misc/webauthn_iframe";
@Directive()
export class TwoFactorComponent implements OnInit, OnDestroy {
token: string = '';
token: string = "";
remember: boolean = false;
webAuthnReady: boolean = false;
webAuthnNewTab: boolean = false;
@ -37,7 +34,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
selectedProviderType: TwoFactorProviderType = TwoFactorProviderType.Authenticator;
webAuthnSupported: boolean = false;
webAuthn: WebAuthnIFrame = null;
title: string = '';
title: string = "";
twoFactorEmail: string = null;
formPromise: Promise<any>;
emailPromise: Promise<any>;
@ -49,14 +46,21 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
return `publickey-credentials-get ${this.environmentService.getWebVaultUrl()}`;
}
protected loginRoute = 'login';
protected successRoute = 'vault';
protected loginRoute = "login";
protected successRoute = "vault";
constructor(protected authService: AuthService, protected router: Router,
protected i18nService: I18nService, protected apiService: ApiService,
protected platformUtilsService: PlatformUtilsService, protected win: Window,
protected environmentService: EnvironmentService, protected stateService: StateService,
protected route: ActivatedRoute, protected logService: LogService) {
constructor(
protected authService: AuthService,
protected router: Router,
protected i18nService: I18nService,
protected apiService: ApiService,
protected platformUtilsService: PlatformUtilsService,
protected win: Window,
protected environmentService: EnvironmentService,
protected stateService: StateService,
protected route: ActivatedRoute,
protected logService: LogService
) {
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
}
@ -66,33 +70,42 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
return;
}
this.route.queryParams.pipe(first()).subscribe(qParams => {
this.route.queryParams.pipe(first()).subscribe((qParams) => {
if (qParams.identifier != null) {
this.identifier = qParams.identifier;
}
});
if (this.needsLock) {
this.successRoute = 'lock';
this.successRoute = "lock";
}
if (this.win != null && this.webAuthnSupported) {
const webVaultUrl = this.environmentService.getWebVaultUrl();
this.webAuthn = new WebAuthnIFrame(this.win, webVaultUrl, this.webAuthnNewTab, this.platformUtilsService,
this.i18nService, (token: string) => {
this.webAuthn = new WebAuthnIFrame(
this.win,
webVaultUrl,
this.webAuthnNewTab,
this.platformUtilsService,
this.i18nService,
(token: string) => {
this.token = token;
this.submit();
}, (error: string) => {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), error);
}, (info: string) => {
if (info === 'ready') {
},
(error: string) => {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), error);
},
(info: string) => {
if (info === "ready") {
this.webAuthnReady = true;
}
}
);
}
this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(this.webAuthnSupported);
this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(
this.webAuthnSupported
);
await this.init();
}
@ -103,7 +116,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
async init() {
if (this.selectedProviderType == null) {
this.title = this.i18nService.t('loginUnavailable');
this.title = this.i18nService.t("loginUnavailable");
return;
}
@ -147,9 +160,12 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
async submit() {
if (this.token == null || this.token === '') {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
this.i18nService.t('verificationCodeRequired'));
if (this.token == null || this.token === "") {
this.platformUtilsService.showToast(
"error",
this.i18nService.t("errorOccurred"),
this.i18nService.t("verificationCodeRequired")
);
return;
}
@ -159,9 +175,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
} else {
return;
}
} else if (this.selectedProviderType === TwoFactorProviderType.Email ||
this.selectedProviderType === TwoFactorProviderType.Authenticator) {
this.token = this.token.replace(' ', '').trim();
} else if (
this.selectedProviderType === TwoFactorProviderType.Email ||
this.selectedProviderType === TwoFactorProviderType.Authenticator
) {
this.token = this.token.replace(" ", "").trim();
}
try {
@ -174,7 +192,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
async doSubmit() {
this.formPromise = this.authService.logInTwoFactor(this.selectedProviderType, this.token, this.remember);
this.formPromise = this.authService.logInTwoFactor(
this.selectedProviderType,
this.token,
this.remember
);
const response: AuthResult = await this.formPromise;
const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.setDisableFavicon(!!disableFavicon);
@ -182,10 +204,10 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
this.onSuccessfulLogin();
}
if (response.resetMasterPassword) {
this.successRoute = 'set-password';
this.successRoute = "set-password";
}
if (response.forcePasswordReset) {
this.successRoute = 'update-temp-password';
this.successRoute = "update-temp-password";
}
if (this.onSuccessfulLoginNavigate != null) {
this.onSuccessfulLoginNavigate();
@ -214,8 +236,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
this.emailPromise = this.apiService.postTwoFactorEmail(request);
await this.emailPromise;
if (doToast) {
this.platformUtilsService.showToast('success', null,
this.i18nService.t('verificationCodeEmailSent', this.twoFactorEmail));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("verificationCodeEmailSent", this.twoFactorEmail)
);
}
} catch (e) {
this.logService.error(e);
@ -242,7 +267,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
}
get authing(): boolean {
return this.authService.authingWithPassword() || this.authService.authingWithSso() || this.authService.authingWithApiKey();
return (
this.authService.authingWithPassword() ||
this.authService.authingWithSso() ||
this.authService.authingWithApiKey()
);
}
get needsLock(): boolean {

View File

@ -1,23 +1,23 @@
import { Directive } from '@angular/core';
import { Directive } from "@angular/core";
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 { SyncService } from 'jslib-common/abstractions/sync.service';
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 { SyncService } from "jslib-common/abstractions/sync.service";
import { ChangePasswordComponent as BaseChangePasswordComponent } from './change-password.component';
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 { 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 { UpdateTempPasswordRequest } from "jslib-common/models/request/updateTempPasswordRequest";
@Directive()
export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
@ -28,13 +28,27 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
onSuccessfulChangePassword: () => Promise<any>;
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService, policyService: PolicyService,
cryptoService: CryptoService, messagingService: MessagingService,
private apiService: ApiService, stateService: StateService,
private syncService: SyncService, private logService: LogService) {
super(i18nService, cryptoService, messagingService, passwordGenerationService,
platformUtilsService, policyService, stateService);
constructor(
i18nService: I18nService,
platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService,
policyService: PolicyService,
cryptoService: CryptoService,
messagingService: MessagingService,
private apiService: ApiService,
stateService: StateService,
private syncService: SyncService,
private logService: LogService
) {
super(
i18nService,
cryptoService,
messagingService,
passwordGenerationService,
platformUtilsService,
policyService,
stateService
);
}
async ngOnInit() {
@ -44,7 +58,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
togglePassword(confirmField: boolean) {
this.showPassword = !this.showPassword;
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
}
async setupSubmitActions(): Promise<boolean> {
@ -57,18 +71,22 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
async submit() {
// Validation
if (!await this.strongPassword()) {
if (!(await this.strongPassword())) {
return;
}
if (!await this.setupSubmitActions()) {
if (!(await this.setupSubmitActions())) {
return;
}
try {
// Create new key and hash new password
const newKey = await this.cryptoService.makeKey(this.masterPassword, this.email.trim().toLowerCase(),
this.kdf, this.kdfIterations);
const newKey = await this.cryptoService.makeKey(
this.masterPassword,
this.email.trim().toLowerCase(),
this.kdf,
this.kdfIterations
);
const newPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, newKey);
// Grab user's current enc key
@ -83,8 +101,11 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
}
}
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]) {
async performSubmitActions(
masterPasswordHash: string,
key: SymmetricCryptoKey,
encKey: [SymmetricCryptoKey, EncString]
) {
try {
// Create request
const request = new UpdateTempPasswordRequest();
@ -95,12 +116,16 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
// Update user's password
this.formPromise = this.apiService.putUpdateTempPassword(request);
await this.formPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('updatedMasterPassword'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t("updatedMasterPassword")
);
if (this.onSuccessfulChangePassword != null) {
this.onSuccessfulChangePassword();
} else {
this.messagingService.send('logout');
this.messagingService.send("logout");
}
} catch (e) {
this.logService.error(e);

View File

@ -1,25 +1,46 @@
<ng-container *ngIf="!usesKeyConnector">
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control"
[formControl]="secret" required appAutofocus appInputVerbatim>
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
<input
id="masterPassword"
type="password"
name="MasterPasswordHash"
class="form-control"
[formControl]="secret"
required
appAutofocus
appInputVerbatim
/>
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
</ng-container>
<ng-container *ngIf="usesKeyConnector">
<div class="form-group">
<label class="d-block">{{'sendVerificationCode' | i18n}}</label>
<button type="button" class="btn btn-outline-secondary" (click)="requestOTP()" [disabled]="disableRequestOTP">
{{'sendCode' | i18n}}
<label class="d-block">{{ "sendVerificationCode" | i18n }}</label>
<button
type="button"
class="btn btn-outline-secondary"
(click)="requestOTP()"
[disabled]="disableRequestOTP"
>
{{ "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>
{{'codeSent' | i18n}}
{{ "codeSent" | i18n }}
</span>
</div>
<div class="form-group">
<label for="verificationCode">{{'verificationCode' | i18n}}</label>
<input id="verificationCode" type="input" name="verificationCode" class="form-control"
[formControl]="secret" required appAutofocus appInputVerbatim>
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
<label for="verificationCode">{{ "verificationCode" | i18n }}</label>
<input
id="verificationCode"
type="input"
name="verificationCode"
class="form-control"
[formControl]="secret"
required
appAutofocus
appInputVerbatim
/>
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
</div>
</ng-container>

View File

@ -1,29 +1,17 @@
import {
animate,
style,
transition,
trigger,
} from '@angular/animations';
import {
Component,
OnInit,
} from '@angular/core';
import {
ControlValueAccessor,
FormControl,
NG_VALUE_ACCESSOR,
} from '@angular/forms';
import { animate, style, transition, trigger } from "@angular/animations";
import { Component, OnInit } from "@angular/core";
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from "@angular/forms";
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
import { VerificationType } from 'jslib-common/enums/verificationType';
import { VerificationType } from "jslib-common/enums/verificationType";
import { Verification } from 'jslib-common/types/verification';
import { Verification } from "jslib-common/types/verification";
@Component({
selector: 'app-verify-master-password',
templateUrl: 'verify-master-password.component.html',
selector: "app-verify-master-password",
templateUrl: "verify-master-password.component.html",
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -32,11 +20,8 @@ import { Verification } from 'jslib-common/types/verification';
},
],
animations: [
trigger('sent', [
transition(':enter', [
style({ opacity: 0 }),
animate('100ms', style({ opacity: 1 })),
]),
trigger("sent", [
transition(":enter", [style({ opacity: 0 }), animate("100ms", style({ opacity: 1 }))]),
]),
],
})
@ -45,18 +30,20 @@ export class VerifyMasterPasswordComponent implements ControlValueAccessor, OnIn
disableRequestOTP: boolean = false;
sentCode: boolean = false;
secret = new FormControl('');
secret = new FormControl("");
private onChange: (value: Verification) => void;
constructor(private keyConnectorService: KeyConnectorService,
private userVerificationService: UserVerificationService) { }
constructor(
private keyConnectorService: KeyConnectorService,
private userVerificationService: UserVerificationService
) {}
async ngOnInit() {
this.usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
this.processChanges(this.secret.value);
this.secret.valueChanges.subscribe(secret => this.processChanges(secret));
this.secret.valueChanges.subscribe((secret) => this.processChanges(secret));
}
async requestOTP() {

View File

@ -1,15 +1,12 @@
import {
Directive,
Input,
} from '@angular/core';
import { Directive, Input } from "@angular/core";
import { EventType } from 'jslib-common/enums/eventType';
import { FieldType } from 'jslib-common/enums/fieldType';
import { EventType } from "jslib-common/enums/eventType";
import { FieldType } from "jslib-common/enums/fieldType";
import { EventService } from 'jslib-common/abstractions/event.service';
import { EventService } from "jslib-common/abstractions/event.service";
import { CipherView } from 'jslib-common/models/view/cipherView';
import { FieldView } from 'jslib-common/models/view/fieldView';
import { CipherView } from "jslib-common/models/view/cipherView";
import { FieldView } from "jslib-common/models/view/fieldView";
@Directive()
export class ViewCustomFieldsComponent {
@ -19,14 +16,14 @@ export class ViewCustomFieldsComponent {
fieldType = FieldType;
constructor(private eventService: EventService) { }
constructor(private eventService: EventService) {}
async toggleFieldValue(field: FieldView) {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
const f = (field as any);
const f = field as any;
f.showValue = !f.showValue;
if (f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);

View File

@ -7,34 +7,34 @@ import {
OnDestroy,
OnInit,
Output,
} from '@angular/core';
} 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 { 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';
import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { EventService } from 'jslib-common/abstractions/event.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
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 { ApiService } from "jslib-common/abstractions/api.service";
import { AuditService } from "jslib-common/abstractions/audit.service";
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
import { CipherService } from "jslib-common/abstractions/cipher.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { EventService } from "jslib-common/abstractions/event.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
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 { ErrorResponse } from 'jslib-common/models/response/errorResponse';
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';
import { AttachmentView } from "jslib-common/models/view/attachmentView";
import { CipherView } from "jslib-common/models/view/cipherView";
import { LoginUriView } from "jslib-common/models/view/loginUriView";
const BroadcasterSubscriptionId = 'ViewComponent';
const BroadcasterSubscriptionId = "ViewComponent";
@Directive()
export class ViewComponent implements OnDestroy, OnInit {
@ -62,20 +62,30 @@ export class ViewComponent implements OnDestroy, OnInit {
private previousCipherId: string;
private passwordReprompted: boolean = false;
constructor(protected cipherService: CipherService, protected totpService: TotpService,
protected tokenService: TokenService, protected i18nService: I18nService,
protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService, protected win: Window,
protected broadcasterService: BroadcasterService, protected ngZone: NgZone,
protected changeDetectorRef: ChangeDetectorRef, protected eventService: EventService,
protected apiService: ApiService, protected passwordRepromptService: PasswordRepromptService,
private logService: LogService, protected stateService: StateService) { }
constructor(
protected cipherService: CipherService,
protected totpService: TotpService,
protected tokenService: TokenService,
protected i18nService: I18nService,
protected cryptoService: CryptoService,
protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService,
protected win: Window,
protected broadcasterService: BroadcasterService,
protected ngZone: NgZone,
protected changeDetectorRef: ChangeDetectorRef,
protected eventService: EventService,
protected apiService: ApiService,
protected passwordRepromptService: PasswordRepromptService,
private logService: LogService,
protected stateService: StateService
) {}
ngOnInit() {
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
this.ngZone.run(async () => {
switch (message.command) {
case 'syncCompleted':
case "syncCompleted":
if (message.successfully) {
await this.load();
this.changeDetectorRef.detectChanges();
@ -98,8 +108,11 @@ export class ViewComponent implements OnDestroy, OnInit {
this.cipher = await cipher.decrypt();
this.canAccessPremium = await this.stateService.getCanAccessPremium();
if (this.cipher.type === CipherType.Login && this.cipher.login.totp &&
(cipher.organizationUseTotp || this.canAccessPremium)) {
if (
this.cipher.type === CipherType.Login &&
this.cipher.login.totp &&
(cipher.organizationUseTotp || this.canAccessPremium)
) {
await this.totpUpdateCode();
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
await this.totpTick(interval);
@ -143,21 +156,30 @@ export class ViewComponent implements OnDestroy, OnInit {
}
async delete(): Promise<boolean> {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeleteItemConfirmation' : 'deleteItemConfirmation'),
this.i18nService.t('deleteItem'), this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t(
this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation"
),
this.i18nService.t("deleteItem"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
try {
await this.deleteCipher();
this.platformUtilsService.showToast('success', null,
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
this.platformUtilsService.showToast(
"success",
null,
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem")
);
this.onDeletedCipher.emit(this.cipher);
} catch (e) {
this.logService.error(e);
@ -172,15 +194,19 @@ export class ViewComponent implements OnDestroy, OnInit {
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('restoreItemConfirmation'), this.i18nService.t('restoreItem'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
this.i18nService.t("restoreItemConfirmation"),
this.i18nService.t("restoreItem"),
this.i18nService.t("yes"),
this.i18nService.t("no"),
"warning"
);
if (!confirmed) {
return false;
}
try {
await this.restoreCipher();
this.platformUtilsService.showToast('success', null, this.i18nService.t('restoredItem'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem"));
this.onRestoredCipher.emit(this.cipher);
} catch (e) {
this.logService.error(e);
@ -190,7 +216,7 @@ export class ViewComponent implements OnDestroy, OnInit {
}
async togglePassword() {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
@ -201,7 +227,7 @@ export class ViewComponent implements OnDestroy, OnInit {
}
async toggleCardNumber() {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
@ -212,7 +238,7 @@ export class ViewComponent implements OnDestroy, OnInit {
}
async toggleCardCode() {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
@ -223,7 +249,11 @@ export class ViewComponent implements OnDestroy, OnInit {
}
async checkPassword() {
if (this.cipher.login == null || this.cipher.login.password == null || this.cipher.login.password === '') {
if (
this.cipher.login == null ||
this.cipher.login.password == null ||
this.cipher.login.password === ""
) {
return;
}
@ -231,10 +261,13 @@ export class ViewComponent implements OnDestroy, OnInit {
const matches = await this.checkPasswordPromise;
if (matches > 0) {
this.platformUtilsService.showToast('warning', null,
this.i18nService.t('passwordExposed', matches.toString()));
this.platformUtilsService.showToast(
"warning",
null,
this.i18nService.t("passwordExposed", matches.toString())
);
} else {
this.platformUtilsService.showToast('success', null, this.i18nService.t('passwordSafe'));
this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe"));
}
}
@ -255,46 +288,58 @@ export class ViewComponent implements OnDestroy, OnInit {
return;
}
if (this.passwordRepromptService.protectedFields().includes(aType) && !await this.promptPassword()) {
if (
this.passwordRepromptService.protectedFields().includes(aType) &&
!(await this.promptPassword())
) {
return;
}
const copyOptions = this.win != null ? { window: this.win } : null;
this.platformUtilsService.copyToClipboard(value, copyOptions);
this.platformUtilsService.showToast('info', null,
this.i18nService.t('valueCopied', this.i18nService.t(typeI18nKey)));
this.platformUtilsService.showToast(
"info",
null,
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey))
);
if (typeI18nKey === 'password') {
if (typeI18nKey === "password") {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipherId);
} else if (typeI18nKey === 'securityCode') {
} else if (typeI18nKey === "securityCode") {
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
} else if (aType === 'H_Field') {
} else if (aType === "H_Field") {
this.eventService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
}
}
setTextDataOnDrag(event: DragEvent, data: string) {
event.dataTransfer.setData('text', data);
event.dataTransfer.setData("text", data);
}
async downloadAttachment(attachment: AttachmentView) {
if (!await this.promptPassword()) {
if (!(await this.promptPassword())) {
return;
}
const a = (attachment as any);
const a = attachment as any;
if (a.downloading) {
return;
}
if (this.cipher.organizationId == null && !this.canAccessPremium) {
this.platformUtilsService.showToast('error', this.i18nService.t('premiumRequired'),
this.i18nService.t('premiumRequiredDesc'));
this.platformUtilsService.showToast(
"error",
this.i18nService.t("premiumRequired"),
this.i18nService.t("premiumRequiredDesc")
);
return;
}
let url: string;
try {
const attachmentDownloadResponse = await this.apiService.getAttachmentData(this.cipher.id, attachment.id);
const attachmentDownloadResponse = await this.apiService.getAttachmentData(
this.cipher.id,
attachment.id
);
url = attachmentDownloadResponse.url;
} catch (e) {
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
@ -307,28 +352,31 @@ export class ViewComponent implements OnDestroy, OnInit {
}
a.downloading = true;
const response = await fetch(new Request(url, { cache: 'no-store' }));
const response = await fetch(new Request(url, { cache: "no-store" }));
if (response.status !== 200) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
a.downloading = false;
return;
}
try {
const buf = await response.arrayBuffer();
const key = attachment.key != null ? attachment.key :
await this.cryptoService.getOrgKey(this.cipher.organizationId);
const key =
attachment.key != null
? attachment.key
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
} catch (e) {
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
}
a.downloading = false;
}
protected deleteCipher() {
return this.cipher.isDeleted ? this.cipherService.deleteWithServer(this.cipher.id)
return this.cipher.isDeleted
? this.cipherService.deleteWithServer(this.cipher.id)
: this.cipherService.softDeleteWithServer(this.cipher.id);
}
@ -341,7 +389,7 @@ export class ViewComponent implements OnDestroy, OnInit {
return true;
}
return this.passwordReprompted = await this.passwordRepromptService.showPasswordPrompt();
return (this.passwordReprompted = await this.passwordRepromptService.showPasswordPrompt());
}
private cleanUp() {
@ -357,7 +405,11 @@ export class ViewComponent implements OnDestroy, OnInit {
}
private async totpUpdateCode() {
if (this.cipher == null || this.cipher.type !== CipherType.Login || this.cipher.login.totp == null) {
if (
this.cipher == null ||
this.cipher.type !== CipherType.Login ||
this.cipher.login.totp == null
) {
if (this.totpInterval) {
clearInterval(this.totpInterval);
}
@ -368,7 +420,8 @@ export class ViewComponent implements OnDestroy, OnInit {
if (this.totpCode != null) {
if (this.totpCode.length > 4) {
const half = Math.floor(this.totpCode.length / 2);
this.totpCodeFormatted = this.totpCode.substring(0, half) + ' ' + this.totpCode.substring(half);
this.totpCodeFormatted =
this.totpCode.substring(0, half) + " " + this.totpCode.substring(half);
} else {
this.totpCodeFormatted = this.totpCode;
}
@ -385,7 +438,7 @@ export class ViewComponent implements OnDestroy, OnInit {
const mod = epoch % intervalSeconds;
this.totpSec = intervalSeconds - mod;
this.totpDash = +(Math.round((((78.6 / intervalSeconds) * mod) + 'e+2') as any) + 'e-2');
this.totpDash = +(Math.round(((78.6 / intervalSeconds) * mod + "e+2") as any) + "e-2");
this.totpLow = this.totpSec <= 7;
if (mod === 0) {
await this.totpUpdateCode();

View File

@ -1,12 +1,7 @@
import {
Directive,
ElementRef,
Input,
Renderer2,
} from '@angular/core';
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
@Directive({
selector: '[appA11yTitle]',
selector: "[appA11yTitle]",
})
export class A11yTitleDirective {
@Input() set appA11yTitle(title: string) {
@ -15,14 +10,14 @@ export class A11yTitleDirective {
private title: string;
constructor(private el: ElementRef, private renderer: Renderer2) { }
constructor(private el: ElementRef, private renderer: Renderer2) {}
ngOnInit() {
if (!this.el.nativeElement.hasAttribute('title')) {
this.renderer.setAttribute(this.el.nativeElement, 'title', this.title);
if (!this.el.nativeElement.hasAttribute("title")) {
this.renderer.setAttribute(this.el.nativeElement, "title", this.title);
}
if (!this.el.nativeElement.hasAttribute('aria-label')) {
this.renderer.setAttribute(this.el.nativeElement, 'aria-label', this.title);
if (!this.el.nativeElement.hasAttribute("aria-label")) {
this.renderer.setAttribute(this.el.nativeElement, "aria-label", this.title);
}
}
}

View File

@ -1,23 +1,21 @@
import {
Directive,
ElementRef,
Input,
OnChanges,
} from '@angular/core';
import { LogService } from 'jslib-common/abstractions/log.service';
import { Directive, ElementRef, Input, OnChanges } from "@angular/core";
import { LogService } from "jslib-common/abstractions/log.service";
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
import { ValidationService } from '../services/validation.service';
import { ValidationService } from "../services/validation.service";
@Directive({
selector: '[appApiAction]',
selector: "[appApiAction]",
})
export class ApiActionDirective implements OnChanges {
@Input() appApiAction: Promise<any>;
constructor(private el: ElementRef, private validationService: ValidationService,
private logService: LogService) { }
constructor(
private el: ElementRef,
private validationService: ValidationService,
private logService: LogService
) {}
ngOnChanges(changes: any) {
if (this.appApiAction == null || this.appApiAction.then == null) {
@ -26,17 +24,23 @@ export class ApiActionDirective implements OnChanges {
this.el.nativeElement.loading = true;
this.appApiAction.then((response: any) => {
this.appApiAction.then(
(response: any) => {
this.el.nativeElement.loading = false;
}, (e: any) => {
},
(e: any) => {
this.el.nativeElement.loading = false;
if ((e instanceof ErrorResponse || e.constructor.name === 'ErrorResponse') && (e as ErrorResponse).captchaRequired) {
this.logService.error('Captcha required error response: ' + e.getSingleMessage());
if (
(e instanceof ErrorResponse || e.constructor.name === "ErrorResponse") &&
(e as ErrorResponse).captchaRequired
) {
this.logService.error("Captcha required error response: " + e.getSingleMessage());
return;
}
this.logService?.error(`Received API exception: ${e}`);
this.validationService.showError(e);
});
}
);
}
}

View File

@ -1,25 +1,20 @@
import {
Directive,
ElementRef,
Input,
NgZone,
} from '@angular/core';
import { Directive, ElementRef, Input, NgZone } from "@angular/core";
import { take } from 'rxjs/operators';
import { take } from "rxjs/operators";
import { Utils } from 'jslib-common/misc/utils';
import { Utils } from "jslib-common/misc/utils";
@Directive({
selector: '[appAutofocus]',
selector: "[appAutofocus]",
})
export class AutofocusDirective {
@Input() set appAutofocus(condition: boolean | string) {
this.autofocus = condition === '' || condition === true;
this.autofocus = condition === "" || condition === true;
}
private autofocus: boolean;
constructor(private el: ElementRef, private ngZone: NgZone) { }
constructor(private el: ElementRef, private ngZone: NgZone) {}
ngOnInit() {
if (!Utils.isMobileBrowser && this.autofocus) {

View File

@ -1,17 +1,12 @@
import {
Directive,
ElementRef,
HostListener,
} from '@angular/core';
import { Directive, ElementRef, HostListener } from "@angular/core";
@Directive({
selector: '[appBlurClick]',
selector: "[appBlurClick]",
})
export class BlurClickDirective {
constructor(private el: ElementRef) {
}
constructor(private el: ElementRef) {}
@HostListener('click') onClick() {
@HostListener("click") onClick() {
this.el.nativeElement.blur();
}
}

View File

@ -1,12 +1,7 @@
import {
Directive,
ElementRef,
HostListener,
OnInit,
} from '@angular/core';
import { Directive, ElementRef, HostListener, OnInit } from "@angular/core";
@Directive({
selector: '[appBoxRow]',
selector: "[appBoxRow]",
})
export class BoxRowDirective implements OnInit {
el: HTMLElement = null;
@ -17,30 +12,43 @@ export class BoxRowDirective implements OnInit {
}
ngOnInit(): void {
this.formEls = Array.from(this.el.querySelectorAll('input:not([type="hidden"]), select, textarea'));
this.formEls.forEach(formEl => {
formEl.addEventListener('focus', (event: Event) => {
this.el.classList.add('active');
}, false);
this.formEls = Array.from(
this.el.querySelectorAll('input:not([type="hidden"]), select, textarea')
);
this.formEls.forEach((formEl) => {
formEl.addEventListener(
"focus",
(event: Event) => {
this.el.classList.add("active");
},
false
);
formEl.addEventListener('blur', (event: Event) => {
this.el.classList.remove('active');
}, false);
formEl.addEventListener(
"blur",
(event: Event) => {
this.el.classList.remove("active");
},
false
);
});
}
@HostListener('click', ['$event']) onClick(event: Event) {
@HostListener("click", ["$event"]) onClick(event: Event) {
const target = event.target as HTMLElement;
if (target !== this.el && !target.classList.contains('progress') &&
!target.classList.contains('progress-bar')) {
if (
target !== this.el &&
!target.classList.contains("progress") &&
!target.classList.contains("progress-bar")
) {
return;
}
if (this.formEls.length > 0) {
const formEl = (this.formEls[0] as HTMLElement);
if (formEl.tagName.toLowerCase() === 'input') {
const inputEl = (formEl as HTMLInputElement);
if (inputEl.type != null && inputEl.type.toLowerCase() === 'checkbox') {
const formEl = this.formEls[0] as HTMLElement;
if (formEl.tagName.toLowerCase() === "input") {
const inputEl = formEl as HTMLInputElement;
if (inputEl.type != null && inputEl.type.toLowerCase() === "checkbox") {
inputEl.click();
return;
}

View File

@ -2,11 +2,8 @@ import {
CdkFixedSizeVirtualScroll,
FixedSizeVirtualScrollStrategy,
VIRTUAL_SCROLL_STRATEGY,
} from '@angular/cdk/scrolling';
import {
Directive,
forwardRef,
} from '@angular/core';
} from "@angular/cdk/scrolling";
import { Directive, forwardRef } from "@angular/core";
// Custom virtual scroll strategy for cdk-virtual-scroll
// Uses a sample list item to set the itemSize for FixedSizeVirtualScrollStrategy
@ -15,7 +12,12 @@ export class CipherListVirtualScrollStrategy extends FixedSizeVirtualScrollStrat
private checkItemSizeCallback: any;
private timeout: any;
constructor(itemSize: number, minBufferPx: number, maxBufferPx: number, checkItemSizeCallback: any) {
constructor(
itemSize: number,
minBufferPx: number,
maxBufferPx: number,
checkItemSizeCallback: any
) {
super(itemSize, minBufferPx, maxBufferPx);
this.checkItemSizeCallback = checkItemSizeCallback;
}
@ -34,29 +36,41 @@ export function _cipherListVirtualScrollStrategyFactory(cipherListDir: CipherLis
}
@Directive({
selector: 'cdk-virtual-scroll-viewport[itemSize]',
providers: [{
selector: "cdk-virtual-scroll-viewport[itemSize]",
providers: [
{
provide: VIRTUAL_SCROLL_STRATEGY,
useFactory: _cipherListVirtualScrollStrategyFactory,
deps: [forwardRef(() => CipherListVirtualScroll)],
}],
},
],
})
export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll {
_scrollStrategy: CipherListVirtualScrollStrategy;
constructor() {
super();
this._scrollStrategy = new CipherListVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx,
this.checkAndUpdateItemSize);
this._scrollStrategy = new CipherListVirtualScrollStrategy(
this.itemSize,
this.minBufferPx,
this.maxBufferPx,
this.checkAndUpdateItemSize
);
}
checkAndUpdateItemSize = () => {
const sampleItem = document.querySelector('cdk-virtual-scroll-viewport .virtual-scroll-item') as HTMLElement;
const sampleItem = document.querySelector(
"cdk-virtual-scroll-viewport .virtual-scroll-item"
) as HTMLElement;
const newItemSize = sampleItem?.offsetHeight;
if (newItemSize != null && newItemSize !== this.itemSize) {
this.itemSize = newItemSize;
this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
}
this._scrollStrategy.updateItemAndBufferSize(
this.itemSize,
this.minBufferPx,
this.maxBufferPx
);
}
};
}

View File

@ -1,20 +1,14 @@
import {
Directive,
ElementRef,
HostListener,
Input,
} from '@angular/core';
import { Directive, ElementRef, HostListener, Input } from "@angular/core";
@Directive({
selector: '[appFallbackSrc]',
selector: "[appFallbackSrc]",
})
export class FallbackSrcDirective {
@Input('appFallbackSrc') appFallbackSrc: string;
@Input("appFallbackSrc") appFallbackSrc: string;
constructor(private el: ElementRef) {
}
constructor(private el: ElementRef) {}
@HostListener('error') onError() {
@HostListener("error") onError() {
this.el.nativeElement.src = this.appFallbackSrc;
}
}

View File

@ -1,37 +1,32 @@
import {
Directive,
ElementRef,
Input,
Renderer2,
} from '@angular/core';
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
@Directive({
selector: '[appInputVerbatim]',
selector: "[appInputVerbatim]",
})
export class InputVerbatimDirective {
@Input() set appInputVerbatim(condition: boolean | string) {
this.disableComplete = condition === '' || condition === true;
this.disableComplete = condition === "" || condition === true;
}
private disableComplete: boolean;
constructor(private el: ElementRef, private renderer: Renderer2) { }
constructor(private el: ElementRef, private renderer: Renderer2) {}
ngOnInit() {
if (this.disableComplete && !this.el.nativeElement.hasAttribute('autocomplete')) {
this.renderer.setAttribute(this.el.nativeElement, 'autocomplete', 'off');
if (this.disableComplete && !this.el.nativeElement.hasAttribute("autocomplete")) {
this.renderer.setAttribute(this.el.nativeElement, "autocomplete", "off");
}
if (!this.el.nativeElement.hasAttribute('autocapitalize')) {
this.renderer.setAttribute(this.el.nativeElement, 'autocapitalize', 'none');
if (!this.el.nativeElement.hasAttribute("autocapitalize")) {
this.renderer.setAttribute(this.el.nativeElement, "autocapitalize", "none");
}
if (!this.el.nativeElement.hasAttribute('autocorrect')) {
this.renderer.setAttribute(this.el.nativeElement, 'autocorrect', 'none');
if (!this.el.nativeElement.hasAttribute("autocorrect")) {
this.renderer.setAttribute(this.el.nativeElement, "autocorrect", "none");
}
if (!this.el.nativeElement.hasAttribute('spellcheck')) {
this.renderer.setAttribute(this.el.nativeElement, 'spellcheck', 'false');
if (!this.el.nativeElement.hasAttribute("spellcheck")) {
this.renderer.setAttribute(this.el.nativeElement, "spellcheck", "false");
}
if (!this.el.nativeElement.hasAttribute('inputmode')) {
this.renderer.setAttribute(this.el.nativeElement, 'inputmode', 'verbatim');
if (!this.el.nativeElement.hasAttribute("inputmode")) {
this.renderer.setAttribute(this.el.nativeElement, "inputmode", "verbatim");
}
}
}

View File

@ -1,22 +1,18 @@
import {
Directive,
ElementRef,
HostListener,
} from '@angular/core';
import { Directive, ElementRef, HostListener } from "@angular/core";
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
@Directive({
selector: '[appSelectCopy]',
selector: "[appSelectCopy]",
})
export class SelectCopyDirective {
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) { }
constructor(private el: ElementRef, private platformUtilsService: PlatformUtilsService) {}
@HostListener('copy') onCopy() {
@HostListener("copy") onCopy() {
if (window == null) {
return;
}
let copyText = '';
let copyText = "";
const selection = window.getSelection();
for (let i = 0; i < selection.rangeCount; i++) {
const range = selection.getRangeAt(i);
@ -30,7 +26,7 @@ export class SelectCopyDirective {
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
if (newLinePos > -1) {
const otherPart = text.substr(newLinePos).trim();
if (otherPart === '') {
if (otherPart === "") {
stringEndPos = newLinePos;
}
}

View File

@ -1,13 +1,10 @@
import {
Directive,
HostListener,
} from '@angular/core';
import { Directive, HostListener } from "@angular/core";
@Directive({
selector: '[appStopClick]',
selector: "[appStopClick]",
})
export class StopClickDirective {
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
$event.preventDefault();
}
}

View File

@ -1,13 +1,10 @@
import {
Directive,
HostListener,
} from '@angular/core';
import { Directive, HostListener } from "@angular/core";
@Directive({
selector: '[appStopProp]',
selector: "[appStopProp]",
})
export class StopPropDirective {
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
$event.stopPropagation();
}
}

View File

@ -1,20 +1,9 @@
import {
Directive,
ElementRef,
forwardRef,
HostListener,
Input,
Renderer2,
} from '@angular/core';
import {
ControlValueAccessor,
NgControl,
NG_VALUE_ACCESSOR,
} from '@angular/forms';
import { Directive, ElementRef, forwardRef, HostListener, Input, Renderer2 } from "@angular/core";
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from "@angular/forms";
// ref: https://juristr.com/blog/2018/02/ng-true-value-directive/
@Directive({
selector: 'input[type=checkbox][appTrueFalseValue]',
selector: "input[type=checkbox][appTrueFalseValue]",
providers: [
{
provide: NG_VALUE_ACCESSOR,
@ -27,18 +16,18 @@ export class TrueFalseValueDirective implements ControlValueAccessor {
@Input() trueValue = true;
@Input() falseValue = false;
constructor(private elementRef: ElementRef, private renderer: Renderer2) { }
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
@HostListener('change', ['$event'])
@HostListener("change", ["$event"])
onHostChange(ev: any) {
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
}
writeValue(obj: any): void {
if (obj === this.trueValue) {
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', true);
this.renderer.setProperty(this.elementRef.nativeElement, "checked", true);
} else {
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', false);
this.renderer.setProperty(this.elementRef.nativeElement, "checked", false);
}
}
@ -46,9 +35,15 @@ export class TrueFalseValueDirective implements ControlValueAccessor {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void { /* nothing */ }
registerOnTouched(fn: any): void {
/* nothing */
}
setDisabledState?(isDisabled: boolean): void { /* nothing */ }
setDisabledState?(isDisabled: boolean): void {
/* nothing */
}
private propagateChange = (_: any) => { /* nothing */ };
private propagateChange = (_: any) => {
/* nothing */
};
}

View File

@ -1,52 +1,49 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { Utils } from 'jslib-common/misc/utils';
import { Pipe, PipeTransform } from "@angular/core";
import { Utils } from "jslib-common/misc/utils";
/*
An updated pipe that sanitizes HTML, highlights numbers and special characters (in different colors each)
and handles Unicode / Emoji characters correctly.
*/
@Pipe({ name: 'colorPassword' })
@Pipe({ name: "colorPassword" })
export class ColorPasswordPipe implements PipeTransform {
transform(password: string) {
// Convert to an array to handle cases that stings have special characters, ie: emoji.
const passwordArray = Array.from(password);
let colorizedPassword = '';
let colorizedPassword = "";
for (let i = 0; i < passwordArray.length; i++) {
let character = passwordArray[i];
let isSpecial = false;
// Sanitize HTML first.
switch (character) {
case '&':
character = '&amp;';
case "&":
character = "&amp;";
isSpecial = true;
break;
case '<':
character = '&lt;';
case "<":
character = "&lt;";
isSpecial = true;
break;
case '>':
character = '&gt;';
case ">":
character = "&gt;";
isSpecial = true;
break;
case ' ':
character = '&nbsp;';
case " ":
character = "&nbsp;";
isSpecial = true;
break;
default:
break;
}
let type = 'letter';
let type = "letter";
if (character.match(Utils.regexpEmojiPresentation)) {
type = 'emoji';
type = "emoji";
} else if (isSpecial || character.match(/[^\w ]/)) {
type = 'special';
type = "special";
} else if (character.match(/\d/)) {
type = 'number';
type = "number";
}
colorizedPassword += '<span class="password-' + type + '">' + character + '</span>';
colorizedPassword += '<span class="password-' + type + '">' + character + "</span>";
}
return colorizedPassword;
}

View File

@ -1,15 +1,12 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { Pipe, PipeTransform } from "@angular/core";
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { I18nService } from "jslib-common/abstractions/i18n.service";
@Pipe({
name: 'i18n',
name: "i18n",
})
export class I18nPipe implements PipeTransform {
constructor(private i18nService: I18nService) { }
constructor(private i18nService: I18nService) {}
transform(id: string, p1?: string, p2?: string, p3?: string): string {
return this.i18nService.t(id, p1, p2, p3);

View File

@ -1,12 +1,9 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { Pipe, PipeTransform } from "@angular/core";
import { CipherView } from 'jslib-common/models/view/cipherView';
import { CipherView } from "jslib-common/models/view/cipherView";
@Pipe({
name: 'searchCiphers',
name: "searchCiphers",
})
export class SearchCiphersPipe implements PipeTransform {
transform(ciphers: CipherView[], searchText: string, deleted: boolean = false): CipherView[] {
@ -15,13 +12,13 @@ export class SearchCiphersPipe implements PipeTransform {
}
if (searchText == null || searchText.length < 2) {
return ciphers.filter(c => {
return ciphers.filter((c) => {
return deleted !== c.isDeleted;
});
}
searchText = searchText.trim().toLowerCase();
return ciphers.filter(c => {
return ciphers.filter((c) => {
if (deleted !== c.isDeleted) {
return false;
}

View File

@ -1,13 +1,16 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { Pipe, PipeTransform } from "@angular/core";
@Pipe({
name: 'search',
name: "search",
})
export class SearchPipe implements PipeTransform {
transform(items: any[], searchText: string, prop1?: string, prop2?: string, prop3?: string): any[] {
transform(
items: any[],
searchText: string,
prop1?: string,
prop2?: string,
prop3?: string
): any[] {
if (items == null || items.length === 0) {
return [];
}
@ -17,14 +20,26 @@ export class SearchPipe implements PipeTransform {
}
searchText = searchText.trim().toLowerCase();
return items.filter(i => {
if (prop1 != null && i[prop1] != null && i[prop1].toString().toLowerCase().indexOf(searchText) > -1) {
return items.filter((i) => {
if (
prop1 != null &&
i[prop1] != null &&
i[prop1].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
}
if (prop2 != null && i[prop2] != null && i[prop2].toString().toLowerCase().indexOf(searchText) > -1) {
if (
prop2 != null &&
i[prop2] != null &&
i[prop2].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
}
if (prop3 != null && i[prop3] != null && i[prop3].toString().toLowerCase().indexOf(searchText) > -1) {
if (
prop3 != null &&
i[prop3] != null &&
i[prop3].toString().toLowerCase().indexOf(searchText) > -1
) {
return true;
}
return false;

View File

@ -1,7 +1,4 @@
import {
Pipe,
PipeTransform,
} from '@angular/core';
import { Pipe, PipeTransform } from "@angular/core";
interface User {
name?: string;
@ -9,7 +6,7 @@ interface User {
}
@Pipe({
name: 'userName',
name: "userName",
})
export class UserNamePipe implements PipeTransform {
transform(user?: User): string {
@ -17,6 +14,6 @@ export class UserNamePipe implements PipeTransform {
return null;
}
return user.name == null || user.name.trim() === '' ? user.email : user.name;
return user.name == null || user.name.trim() === "" ? user.email : user.name;
}
}

View File

@ -1,90 +1,89 @@
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: italic;
font-weight: 300;
font-display: auto;
src: url(webfonts/Open_Sans-italic-300.woff) format('woff');
src: url(webfonts/Open_Sans-italic-300.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: italic;
font-weight: 400;
font-display: auto;
src: url(webfonts/Open_Sans-italic-400.woff) format('woff');
src: url(webfonts/Open_Sans-italic-400.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: italic;
font-weight: 600;
font-display: auto;
src: url(webfonts/Open_Sans-italic-600.woff) format('woff');
src: url(webfonts/Open_Sans-italic-600.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: italic;
font-weight: 700;
font-display: auto;
src: url(webfonts/Open_Sans-italic-700.woff) format('woff');
src: url(webfonts/Open_Sans-italic-700.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: italic;
font-weight: 800;
font-display: auto;
src: url(webfonts/Open_Sans-italic-800.woff) format('woff');
src: url(webfonts/Open_Sans-italic-800.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: normal;
font-weight: 300;
font-display: auto;
src: url(webfonts/Open_Sans-normal-300.woff) format('woff');
src: url(webfonts/Open_Sans-normal-300.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: normal;
font-weight: 400;
font-display: auto;
src: url(webfonts/Open_Sans-normal-400.woff) format('woff');
src: url(webfonts/Open_Sans-normal-400.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: normal;
font-weight: 600;
font-display: auto;
src: url(webfonts/Open_Sans-normal-600.woff) format('woff');
src: url(webfonts/Open_Sans-normal-600.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: normal;
font-weight: 700;
font-display: auto;
src: url(webfonts/Open_Sans-normal-700.woff) format('woff');
src: url(webfonts/Open_Sans-normal-700.woff) format("woff");
unicode-range: U+0-10FFFF;
}
@font-face {
font-family: 'Open Sans';
font-family: "Open Sans";
font-style: normal;
font-weight: 800;
font-display: auto;
src: url(webfonts/Open_Sans-normal-800.woff) format('woff');
src: url(webfonts/Open_Sans-normal-800.woff) format("woff");
unicode-range: U+0-10FFFF;
}

View File

@ -1,40 +1,42 @@
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
Router,
RouterStateSnapshot,
} from '@angular/router';
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { StateService } from "jslib-common/abstractions/state.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@Injectable()
export class AuthGuardService implements CanActivate {
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
private messagingService: MessagingService, private keyConnectorService: KeyConnectorService,
private stateService: StateService) { }
constructor(
private vaultTimeoutService: VaultTimeoutService,
private router: Router,
private messagingService: MessagingService,
private keyConnectorService: KeyConnectorService,
private stateService: StateService
) {}
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
const isAuthed = await this.stateService.getIsAuthenticated();
if (!isAuthed) {
this.messagingService.send('authBlocked');
this.messagingService.send("authBlocked");
return false;
}
const locked = await this.vaultTimeoutService.isLocked();
if (locked) {
if (routerState != null) {
this.messagingService.send('lockedUrl', { url: routerState.url });
this.messagingService.send("lockedUrl", { url: routerState.url });
}
this.router.navigate(['lock'], { queryParams: { promptBiometric: true }});
this.router.navigate(["lock"], { queryParams: { promptBiometric: true } });
return false;
}
if (!routerState.url.includes('remove-password') && await this.keyConnectorService.getConvertAccountRequired()) {
this.router.navigate(['/remove-password']);
if (
!routerState.url.includes("remove-password") &&
(await this.keyConnectorService.getConvertAccountRequired())
) {
this.router.navigate(["/remove-password"]);
return false;
}

View File

@ -1,7 +1,6 @@
import { Injectable } from '@angular/core';
import { Injectable } from "@angular/core";
import { BroadcasterService as BaseBroadcasterService } from 'jslib-common/services/broadcaster.service';
import { BroadcasterService as BaseBroadcasterService } from "jslib-common/services/broadcaster.service";
@Injectable()
export class BroadcasterService extends BaseBroadcasterService {
}
export class BroadcasterService extends BaseBroadcasterService {}

View File

@ -1,91 +1,85 @@
import {
Injector,
LOCALE_ID,
NgModule,
} from '@angular/core';
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 } 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';
import { AuthService as AuthServiceAbstraction } from 'jslib-common/abstractions/auth.service';
import { BroadcasterService as BroadcasterServiceAbstraction } from 'jslib-common/abstractions/broadcaster.service';
import { CipherService as CipherServiceAbstraction } from 'jslib-common/abstractions/cipher.service';
import { CollectionService as CollectionServiceAbstraction } from 'jslib-common/abstractions/collection.service';
import { CryptoService as CryptoServiceAbstraction } from 'jslib-common/abstractions/crypto.service';
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from 'jslib-common/abstractions/cryptoFunction.service';
import { EnvironmentService as EnvironmentServiceAbstraction } from 'jslib-common/abstractions/environment.service';
import { EventService as EventServiceAbstraction } from 'jslib-common/abstractions/event.service';
import { ExportService as ExportServiceAbstraction } from 'jslib-common/abstractions/export.service';
import { FileUploadService as FileUploadServiceAbstraction } from 'jslib-common/abstractions/fileUpload.service';
import { FolderService as FolderServiceAbstraction } from 'jslib-common/abstractions/folder.service';
import { I18nService as I18nServiceAbstraction } from 'jslib-common/abstractions/i18n.service';
import { KeyConnectorService as KeyConnectorServiceAbstraction } from 'jslib-common/abstractions/keyConnector.service';
import { LogService } from 'jslib-common/abstractions/log.service';
import { MessagingService as MessagingServiceAbstraction } from 'jslib-common/abstractions/messaging.service';
import { NotificationsService as NotificationsServiceAbstraction } from 'jslib-common/abstractions/notifications.service';
import { OrganizationService as OrganizationServiceAbstraction } from 'jslib-common/abstractions/organization.service';
import {
PasswordGenerationService as PasswordGenerationServiceAbstraction,
} from 'jslib-common/abstractions/passwordGeneration.service';
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService as PolicyServiceAbstraction } from 'jslib-common/abstractions/policy.service';
import { ProviderService as ProviderServiceAbstraction } from 'jslib-common/abstractions/provider.service';
import { SearchService as SearchServiceAbstraction } from 'jslib-common/abstractions/search.service';
import { SendService as SendServiceAbstraction } from 'jslib-common/abstractions/send.service';
import { SettingsService as SettingsServiceAbstraction } from 'jslib-common/abstractions/settings.service';
import { StateService as StateServiceAbstraction } from 'jslib-common/abstractions/state.service';
import { StateMigrationService as StateMigrationServiceAbstraction } from 'jslib-common/abstractions/stateMigration.service';
import { StorageService as StorageServiceAbstraction } from 'jslib-common/abstractions/storage.service';
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 { UserVerificationService as UserVerificationServiceAbstraction } from 'jslib-common/abstractions/userVerification.service';
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from 'jslib-common/abstractions/vaultTimeout.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";
import { AuthService as AuthServiceAbstraction } from "jslib-common/abstractions/auth.service";
import { BroadcasterService as BroadcasterServiceAbstraction } from "jslib-common/abstractions/broadcaster.service";
import { CipherService as CipherServiceAbstraction } from "jslib-common/abstractions/cipher.service";
import { CollectionService as CollectionServiceAbstraction } from "jslib-common/abstractions/collection.service";
import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service";
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service";
import { EventService as EventServiceAbstraction } from "jslib-common/abstractions/event.service";
import { ExportService as ExportServiceAbstraction } from "jslib-common/abstractions/export.service";
import { FileUploadService as FileUploadServiceAbstraction } from "jslib-common/abstractions/fileUpload.service";
import { FolderService as FolderServiceAbstraction } from "jslib-common/abstractions/folder.service";
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-common/abstractions/keyConnector.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service";
import { OrganizationService as OrganizationServiceAbstraction } from "jslib-common/abstractions/organization.service";
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "jslib-common/abstractions/passwordGeneration.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
import { PolicyService as PolicyServiceAbstraction } from "jslib-common/abstractions/policy.service";
import { ProviderService as ProviderServiceAbstraction } from "jslib-common/abstractions/provider.service";
import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service";
import { SendService as SendServiceAbstraction } from "jslib-common/abstractions/send.service";
import { SettingsService as SettingsServiceAbstraction } from "jslib-common/abstractions/settings.service";
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
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 { UserVerificationService as UserVerificationServiceAbstraction } from "jslib-common/abstractions/userVerification.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
import { AuthGuardService } from './auth-guard.service';
import { BroadcasterService } from './broadcaster.service';
import { LockGuardService } from './lock-guard.service';
import { ModalService } from './modal.service';
import { PasswordRepromptService } from './passwordReprompt.service';
import { UnauthGuardService } from './unauth-guard.service';
import { ValidationService } from './validation.service';
import { AuthGuardService } from "./auth-guard.service";
import { BroadcasterService } from "./broadcaster.service";
import { LockGuardService } from "./lock-guard.service";
import { ModalService } from "./modal.service";
import { PasswordRepromptService } from "./passwordReprompt.service";
import { UnauthGuardService } from "./unauth-guard.service";
import { ValidationService } from "./validation.service";
@NgModule({
declarations: [],
providers: [
{ provide: 'WINDOW', useValue: window },
{ provide: "WINDOW", useValue: window },
{
provide: LOCALE_ID,
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
@ -135,8 +129,9 @@ import { ValidationService } from './validation.service';
i18nService: I18nServiceAbstraction,
injector: Injector,
logService: LogService,
stateService: StateServiceAbstraction,
) => new CipherService(
stateService: StateServiceAbstraction
) =>
new CipherService(
cryptoService,
settingsService,
apiService,
@ -144,7 +139,7 @@ import { ValidationService } from './validation.service';
i18nService,
() => injector.get(SearchServiceAbstraction),
logService,
stateService,
stateService
),
deps: [
CryptoServiceAbstraction,
@ -172,11 +167,7 @@ import { ValidationService } from './validation.service';
{
provide: CollectionServiceAbstraction,
useClass: CollectionService,
deps: [
CryptoServiceAbstraction,
I18nServiceAbstraction,
StateServiceAbstraction,
],
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, StateServiceAbstraction],
},
{
provide: EnvironmentServiceAbstraction,
@ -186,11 +177,7 @@ import { ValidationService } from './validation.service';
{
provide: TotpServiceAbstraction,
useClass: TotpService,
deps: [
CryptoFunctionServiceAbstraction,
LogService,
StateServiceAbstraction,
],
deps: [CryptoFunctionServiceAbstraction, LogService, StateServiceAbstraction],
},
{ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StateServiceAbstraction] },
{
@ -206,18 +193,22 @@ import { ValidationService } from './validation.service';
{
provide: PasswordGenerationServiceAbstraction,
useClass: PasswordGenerationService,
deps: [
CryptoServiceAbstraction,
PolicyServiceAbstraction,
StateServiceAbstraction,
],
deps: [CryptoServiceAbstraction, PolicyServiceAbstraction, StateServiceAbstraction],
},
{
provide: ApiServiceAbstraction,
useFactory: (tokenService: TokenServiceAbstraction, platformUtilsService: PlatformUtilsServiceAbstraction,
environmentService: EnvironmentServiceAbstraction, messagingService: MessagingServiceAbstraction) =>
new ApiService(tokenService, platformUtilsService, environmentService,
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
useFactory: (
tokenService: TokenServiceAbstraction,
platformUtilsService: PlatformUtilsServiceAbstraction,
environmentService: EnvironmentServiceAbstraction,
messagingService: MessagingServiceAbstraction
) =>
new ApiService(
tokenService,
platformUtilsService,
environmentService,
async (expired: boolean) => messagingService.send("logout", { expired: expired })
),
deps: [
TokenServiceAbstraction,
PlatformUtilsServiceAbstraction,
@ -228,10 +219,7 @@ import { ValidationService } from './validation.service';
{
provide: FileUploadServiceAbstraction,
useClass: FileUploadService,
deps: [
LogService,
ApiServiceAbstraction,
],
deps: [LogService, ApiServiceAbstraction],
},
{
provide: SyncServiceAbstraction,
@ -249,8 +237,9 @@ import { ValidationService } from './validation.service';
keyConnectorService: KeyConnectorServiceAbstraction,
stateService: StateServiceAbstraction,
organizationService: OrganizationServiceAbstraction,
providerService: ProviderServiceAbstraction,
) => new SyncService(
providerService: ProviderServiceAbstraction
) =>
new SyncService(
apiService,
settingsService,
folderService,
@ -265,7 +254,8 @@ import { ValidationService } from './validation.service';
stateService,
organizationService,
providerService,
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
async (expired: boolean) => messagingService.send("logout", { expired: expired })
),
deps: [
ApiServiceAbstraction,
SettingsServiceAbstraction,
@ -302,8 +292,9 @@ import { ValidationService } from './validation.service';
tokenService: TokenServiceAbstraction,
policyService: PolicyServiceAbstraction,
keyConnectorService: KeyConnectorServiceAbstraction,
stateService: StateServiceAbstraction,
) => new VaultTimeoutService(
stateService: StateServiceAbstraction
) =>
new VaultTimeoutService(
cipherService,
folderService,
collectionService,
@ -316,7 +307,7 @@ import { ValidationService } from './validation.service';
keyConnectorService,
stateService,
null,
async () => messagingService.send('logout', { expired: false }),
async () => messagingService.send("logout", { expired: false })
),
deps: [
CipherServiceAbstraction,
@ -337,7 +328,7 @@ import { ValidationService } from './validation.service';
useClass: StateService,
deps: [
StorageServiceAbstraction,
'SECURE_STORAGE',
"SECURE_STORAGE",
LogService,
StateMigrationServiceAbstraction,
],
@ -345,10 +336,7 @@ import { ValidationService } from './validation.service';
{
provide: StateMigrationServiceAbstraction,
useClass: StateMigrationService,
deps: [
StorageServiceAbstraction,
'SECURE_STORAGE',
],
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
},
{
provide: ExportServiceAbstraction,
@ -363,11 +351,7 @@ import { ValidationService } from './validation.service';
{
provide: SearchServiceAbstraction,
useClass: SearchService,
deps: [
CipherServiceAbstraction,
LogService,
I18nServiceAbstraction,
],
deps: [CipherServiceAbstraction, LogService, I18nServiceAbstraction],
},
{
provide: NotificationsServiceAbstraction,
@ -379,16 +363,17 @@ import { ValidationService } from './validation.service';
environmentService: EnvironmentServiceAbstraction,
messagingService: MessagingServiceAbstraction,
logService: LogService,
stateService: StateServiceAbstraction,
) => new NotificationsService(
stateService: StateServiceAbstraction
) =>
new NotificationsService(
syncService,
appIdService,
apiService,
vaultTimeoutService,
environmentService,
async () => messagingService.send('logout', { expired: true }),
async () => messagingService.send("logout", { expired: true }),
logService,
stateService,
stateService
),
deps: [
SyncServiceAbstraction,
@ -404,7 +389,7 @@ import { ValidationService } from './validation.service';
{
provide: CryptoFunctionServiceAbstraction,
useClass: WebCryptoFunctionService,
deps: ['WINDOW', PlatformUtilsServiceAbstraction],
deps: ["WINDOW", PlatformUtilsServiceAbstraction],
},
{
provide: EventServiceAbstraction,
@ -420,11 +405,7 @@ import { ValidationService } from './validation.service';
{
provide: PolicyServiceAbstraction,
useClass: PolicyService,
deps: [
StateServiceAbstraction,
OrganizationServiceAbstraction,
ApiServiceAbstraction,
],
deps: [StateServiceAbstraction, OrganizationServiceAbstraction, ApiServiceAbstraction],
},
{
provide: SendServiceAbstraction,
@ -453,28 +434,19 @@ import { ValidationService } from './validation.service';
{
provide: UserVerificationServiceAbstraction,
useClass: UserVerificationService,
deps: [
CryptoServiceAbstraction,
I18nServiceAbstraction,
ApiServiceAbstraction,
],
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, ApiServiceAbstraction],
},
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
{
provide: OrganizationServiceAbstraction,
useClass: OrganizationService,
deps: [
StateServiceAbstraction,
],
deps: [StateServiceAbstraction],
},
{
provide: ProviderServiceAbstraction,
useClass: ProviderService,
deps: [
StateServiceAbstraction,
],
deps: [StateServiceAbstraction],
},
],
})
export class JslibServicesModule {
}
export class JslibServicesModule {}

View File

@ -1,25 +1,25 @@
import { Injectable } from '@angular/core';
import {
CanActivate,
Router,
} from '@angular/router';
import { Injectable } from "@angular/core";
import { CanActivate, Router } from "@angular/router";
import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { StateService } from "jslib-common/abstractions/state.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@Injectable()
export class LockGuardService implements CanActivate {
protected homepage = 'vault';
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
private stateService: StateService) { }
protected homepage = "vault";
constructor(
private vaultTimeoutService: VaultTimeoutService,
private router: Router,
private stateService: StateService
) {}
async canActivate() {
if (!await this.stateService.getIsAuthenticated()) {
this.router.navigate(['login']);
if (!(await this.stateService.getIsAuthenticated())) {
this.router.navigate(["login"]);
return false;
}
if (!await this.vaultTimeoutService.isLocked()) {
if (!(await this.vaultTimeoutService.isLocked())) {
this.router.navigate([this.homepage]);
return false;
}

View File

@ -7,13 +7,13 @@ import {
Injectable,
Injector,
Type,
ViewContainerRef
} from '@angular/core';
import { first } from 'rxjs/operators';
ViewContainerRef,
} from "@angular/core";
import { first } from "rxjs/operators";
import { DynamicModalComponent } from '../components/modal/dynamic-modal.component';
import { ModalInjector } from '../components/modal/modal-injector';
import { ModalRef } from '../components/modal/modal.ref';
import { DynamicModalComponent } from "../components/modal/dynamic-modal.component";
import { ModalInjector } from "../components/modal/modal-injector";
import { ModalRef } from "../components/modal/modal.ref";
export class ModalConfig<D = any> {
data?: D;
@ -28,10 +28,13 @@ export class ModalService {
// therefore modules needs to manually initialize their resolvers.
private factoryResolvers: Map<Type<any>, ComponentFactoryResolver> = new Map();
constructor(private componentFactoryResolver: ComponentFactoryResolver, private applicationRef: ApplicationRef,
private injector: Injector) {
document.addEventListener('keyup', event => {
if (event.key === 'Escape' && this.modalCount > 0) {
constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private applicationRef: ApplicationRef,
private injector: Injector
) {
document.addEventListener("keyup", (event) => {
if (event.key === "Escape" && this.modalCount > 0) {
this.topModal.instance.close();
}
});
@ -45,9 +48,11 @@ export class ModalService {
return this.modalList[this.modalCount - 1];
}
async openViewRef<T>(componentType: Type<T>, viewContainerRef: ViewContainerRef,
setComponentParameters: (component: T) => void = null): Promise<[ModalRef, T]> {
async openViewRef<T>(
componentType: Type<T>,
viewContainerRef: ViewContainerRef,
setComponentParameters: (component: T) => void = null
): Promise<[ModalRef, T]> {
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
modalComponentRef.instance.setComponentParameters = setComponentParameters;
@ -68,7 +73,10 @@ export class ModalService {
return modalRef;
}
registerComponentFactoryResolver<T>(componentType: Type<T>, componentFactoryResolver: ComponentFactoryResolver): void {
registerComponentFactoryResolver<T>(
componentType: Type<T>,
componentFactoryResolver: ComponentFactoryResolver
): void {
this.factoryResolvers.set(componentType, componentFactoryResolver);
}
@ -80,9 +88,11 @@ export class ModalService {
return this.componentFactoryResolver.resolveComponentFactory(componentType);
}
protected openInternal(componentType: Type<any>, config?: ModalConfig, attachToDom?: boolean):
[ModalRef, ComponentRef<DynamicModalComponent>] {
protected openInternal(
componentType: Type<any>,
config?: ModalConfig,
attachToDom?: boolean
): [ModalRef, ComponentRef<DynamicModalComponent>] {
const [modalRef, componentRef] = this.createModalComponent(config);
componentRef.instance.childComponentType = componentType;
@ -115,25 +125,27 @@ export class ModalService {
let backdrop: HTMLElement = null;
// Add backdrop, setup [data-dismiss] handler.
modalRef.onCreated.pipe(first()).subscribe(el => {
document.body.classList.add('modal-open');
modalRef.onCreated.pipe(first()).subscribe((el) => {
document.body.classList.add("modal-open");
const modalEl: HTMLElement = el.querySelector('.modal');
const dialogEl = modalEl.querySelector('.modal-dialog') as HTMLElement;
const modalEl: HTMLElement = el.querySelector(".modal");
const dialogEl = modalEl.querySelector(".modal-dialog") as HTMLElement;
backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop fade';
backdrop = document.createElement("div");
backdrop.className = "modal-backdrop fade";
backdrop.style.zIndex = `${this.modalCount}040`;
modalEl.prepend(backdrop);
dialogEl.addEventListener('click', (e: Event) => {
dialogEl.addEventListener("click", (e: Event) => {
e.stopPropagation();
});
dialogEl.style.zIndex = `${this.modalCount}050`;
const modals = Array.from(el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]'));
const modals = Array.from(
el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]')
);
for (const closeElement of modals) {
closeElement.addEventListener('click', event => {
closeElement.addEventListener("click", (event) => {
modalRef.close();
});
}
@ -144,19 +156,22 @@ export class ModalService {
modalRef.closed();
if (this.modalCount === 0) {
document.body.classList.remove('modal-open');
document.body.classList.remove("modal-open");
}
});
}
protected createModalComponent(config: ModalConfig): [ModalRef, ComponentRef<DynamicModalComponent>] {
protected createModalComponent(
config: ModalConfig
): [ModalRef, ComponentRef<DynamicModalComponent>] {
const modalRef = new ModalRef();
const map = new WeakMap();
map.set(ModalConfig, config);
map.set(ModalRef, modalRef);
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(DynamicModalComponent);
const componentFactory =
this.componentFactoryResolver.resolveComponentFactory(DynamicModalComponent);
const componentRef = componentFactory.create(new ModalInjector(this.injector, map));
return [modalRef, componentRef];

View File

@ -1,27 +1,30 @@
import { Injectable } from '@angular/core';
import { Injectable } from "@angular/core";
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
import { PasswordRepromptComponent } from '../components/password-reprompt.component';
import { ModalService } from './modal.service';
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
import { ModalService } from "./modal.service";
@Injectable()
export class PasswordRepromptService implements PasswordRepromptServiceAbstraction {
protected component = PasswordRepromptComponent;
constructor(private modalService: ModalService, private keyConnectorService: KeyConnectorService) { }
constructor(
private modalService: ModalService,
private keyConnectorService: KeyConnectorService
) {}
protectedFields() {
return ['TOTP', 'Password', 'H_Field', 'Card Number', 'Security Code'];
return ["TOTP", "Password", "H_Field", "Card Number", "Security Code"];
}
async showPasswordPrompt() {
if (!await this.enabled()) {
if (!(await this.enabled())) {
return true;
}
const ref = this.modalService.open(this.component, {allowMultipleModals: true});
const ref = this.modalService.open(this.component, { allowMultipleModals: true });
if (ref == null) {
return false;
@ -32,6 +35,6 @@ export class PasswordRepromptService implements PasswordRepromptServiceAbstracti
}
async enabled() {
return !await this.keyConnectorService.getUsesKeyConnector();
return !(await this.keyConnectorService.getUsesKeyConnector());
}
}

View File

@ -1,25 +1,24 @@
import { Injectable } from '@angular/core';
import {
CanActivate,
Router,
} from '@angular/router';
import { Injectable } from "@angular/core";
import { CanActivate, Router } from "@angular/router";
import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { StateService } from "jslib-common/abstractions/state.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
@Injectable()
export class UnauthGuardService implements CanActivate {
protected homepage = 'vault';
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
private stateService: StateService) { }
protected homepage = "vault";
constructor(
private vaultTimeoutService: VaultTimeoutService,
private router: Router,
private stateService: StateService
) {}
async canActivate() {
const isAuthed = await this.stateService.getIsAuthenticated();
if (isAuthed) {
const locked = await this.vaultTimeoutService.isLocked();
if (locked) {
this.router.navigate(['lock']);
this.router.navigate(["lock"]);
} else {
this.router.navigate([this.homepage]);
}

View File

@ -1,21 +1,24 @@
import { Injectable } from '@angular/core';
import { Injectable } from "@angular/core";
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
@Injectable()
export class ValidationService {
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService) { }
constructor(
private i18nService: I18nService,
private platformUtilsService: PlatformUtilsService
) {}
showError(data: any): string[] {
const defaultErrorMessage = this.i18nService.t('unexpectedError');
const defaultErrorMessage = this.i18nService.t("unexpectedError");
let errors: string[] = [];
if (data != null && typeof data === 'string') {
if (data != null && typeof data === "string") {
errors.push(data);
} else if (data == null || typeof data !== 'object') {
} else if (data == null || typeof data !== "object") {
errors.push(defaultErrorMessage);
} else if (data.validationErrors != null) {
errors = errors.concat((data as ErrorResponse).getAllMessages());
@ -24,9 +27,9 @@ export class ValidationService {
}
if (errors.length === 1) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), errors[0]);
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), errors[0]);
} else if (errors.length > 1) {
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), errors, {
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), errors, {
timeout: 5000 * errors.length,
});
}

View File

@ -14,17 +14,9 @@
"declarationDir": "dist/types",
"outDir": "dist",
"paths": {
"jslib-common/*": [
"../common/src/*"
]
"jslib-common/*": ["../common/src/*"]
}
},
"include": [
"src",
"spec"
],
"exclude": [
"node_modules",
"dist"
]
"include": ["src", "spec"],
"exclude": ["node_modules", "dist"]
}

View File

@ -1,170 +1,178 @@
import { PolicyType } from '../enums/policyType';
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
import { PolicyType } from "../enums/policyType";
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
import { AttachmentRequest } from '../models/request/attachmentRequest';
import { AttachmentRequest } from "../models/request/attachmentRequest";
import { BitPayInvoiceRequest } from '../models/request/bitPayInvoiceRequest';
import { CipherBulkDeleteRequest } from '../models/request/cipherBulkDeleteRequest';
import { CipherBulkMoveRequest } from '../models/request/cipherBulkMoveRequest';
import { CipherBulkRestoreRequest } from '../models/request/cipherBulkRestoreRequest';
import { CipherBulkShareRequest } from '../models/request/cipherBulkShareRequest';
import { CipherCollectionsRequest } from '../models/request/cipherCollectionsRequest';
import { CipherCreateRequest } from '../models/request/cipherCreateRequest';
import { CipherRequest } from '../models/request/cipherRequest';
import { CipherShareRequest } from '../models/request/cipherShareRequest';
import { CollectionRequest } from '../models/request/collectionRequest';
import { DeleteRecoverRequest } from '../models/request/deleteRecoverRequest';
import { EmailRequest } from '../models/request/emailRequest';
import { EmailTokenRequest } from '../models/request/emailTokenRequest';
import { EmergencyAccessAcceptRequest } from '../models/request/emergencyAccessAcceptRequest';
import { EmergencyAccessConfirmRequest } from '../models/request/emergencyAccessConfirmRequest';
import { EmergencyAccessInviteRequest } from '../models/request/emergencyAccessInviteRequest';
import { EmergencyAccessPasswordRequest } from '../models/request/emergencyAccessPasswordRequest';
import { EmergencyAccessUpdateRequest } from '../models/request/emergencyAccessUpdateRequest';
import { EventRequest } from '../models/request/eventRequest';
import { FolderRequest } from '../models/request/folderRequest';
import { GroupRequest } from '../models/request/groupRequest';
import { IapCheckRequest } from '../models/request/iapCheckRequest';
import { ImportCiphersRequest } from '../models/request/importCiphersRequest';
import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest';
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
import { KdfRequest } from '../models/request/kdfRequest';
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
import { KeysRequest } from '../models/request/keysRequest';
import { OrganizationSponsorshipCreateRequest } from '../models/request/organization/organizationSponsorshipCreateRequest';
import { OrganizationSponsorshipRedeemRequest } from '../models/request/organization/organizationSponsorshipRedeemRequest';
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
import { OrganizationSubscriptionUpdateRequest } from '../models/request/organizationSubscriptionUpdateRequest';
import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
import { OrganizationUserAcceptRequest } from '../models/request/organizationUserAcceptRequest';
import { OrganizationUserBulkConfirmRequest } from '../models/request/organizationUserBulkConfirmRequest';
import { OrganizationUserBulkRequest } from '../models/request/organizationUserBulkRequest';
import { OrganizationUserConfirmRequest } from '../models/request/organizationUserConfirmRequest';
import { OrganizationUserInviteRequest } from '../models/request/organizationUserInviteRequest';
import { OrganizationUserResetPasswordEnrollmentRequest } from '../models/request/organizationUserResetPasswordEnrollmentRequest';
import { OrganizationUserResetPasswordRequest } from '../models/request/organizationUserResetPasswordRequest';
import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizationUserUpdateGroupsRequest';
import { OrganizationUserUpdateRequest } from '../models/request/organizationUserUpdateRequest';
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
import { PasswordRequest } from '../models/request/passwordRequest';
import { PaymentRequest } from '../models/request/paymentRequest';
import { PolicyRequest } from '../models/request/policyRequest';
import { PreloginRequest } from '../models/request/preloginRequest';
import { ProviderAddOrganizationRequest } from '../models/request/provider/providerAddOrganizationRequest';
import { ProviderOrganizationCreateRequest } from '../models/request/provider/providerOrganizationCreateRequest';
import { ProviderSetupRequest } from '../models/request/provider/providerSetupRequest';
import { ProviderUpdateRequest } from '../models/request/provider/providerUpdateRequest';
import { ProviderUserAcceptRequest } from '../models/request/provider/providerUserAcceptRequest';
import { ProviderUserBulkConfirmRequest } from '../models/request/provider/providerUserBulkConfirmRequest';
import { ProviderUserBulkRequest } from '../models/request/provider/providerUserBulkRequest';
import { ProviderUserConfirmRequest } from '../models/request/provider/providerUserConfirmRequest';
import { ProviderUserInviteRequest } from '../models/request/provider/providerUserInviteRequest';
import { ProviderUserUpdateRequest } from '../models/request/provider/providerUserUpdateRequest';
import { RegisterRequest } from '../models/request/registerRequest';
import { SeatRequest } from '../models/request/seatRequest';
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
import { SendAccessRequest } from '../models/request/sendAccessRequest';
import { SendRequest } from '../models/request/sendRequest';
import { SetPasswordRequest } from '../models/request/setPasswordRequest';
import { StorageRequest } from '../models/request/storageRequest';
import { TaxInfoUpdateRequest } from '../models/request/taxInfoUpdateRequest';
import { TokenRequest } from '../models/request/tokenRequest';
import { TwoFactorEmailRequest } from '../models/request/twoFactorEmailRequest';
import { TwoFactorProviderRequest } from '../models/request/twoFactorProviderRequest';
import { TwoFactorRecoveryRequest } from '../models/request/twoFactorRecoveryRequest';
import { UpdateDomainsRequest } from '../models/request/updateDomainsRequest';
import { UpdateKeyRequest } from '../models/request/updateKeyRequest';
import { UpdateProfileRequest } from '../models/request/updateProfileRequest';
import { UpdateTempPasswordRequest } from '../models/request/updateTempPasswordRequest';
import { UpdateTwoFactorAuthenticatorRequest } from '../models/request/updateTwoFactorAuthenticatorRequest';
import { UpdateTwoFactorDuoRequest } from '../models/request/updateTwoFactorDuoRequest';
import { UpdateTwoFactorEmailRequest } from '../models/request/updateTwoFactorEmailRequest';
import { UpdateTwoFactorWebAuthnDeleteRequest } from '../models/request/updateTwoFactorWebAuthnDeleteRequest';
import { UpdateTwoFactorWebAuthnRequest } from '../models/request/updateTwoFactorWebAuthnRequest';
import { UpdateTwoFactorYubioOtpRequest } from '../models/request/updateTwoFactorYubioOtpRequest';
import { VerifyBankRequest } from '../models/request/verifyBankRequest';
import { VerifyDeleteRecoverRequest } from '../models/request/verifyDeleteRecoverRequest';
import { VerifyEmailRequest } from '../models/request/verifyEmailRequest';
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
import { CipherBulkMoveRequest } from "../models/request/cipherBulkMoveRequest";
import { CipherBulkRestoreRequest } from "../models/request/cipherBulkRestoreRequest";
import { CipherBulkShareRequest } from "../models/request/cipherBulkShareRequest";
import { CipherCollectionsRequest } from "../models/request/cipherCollectionsRequest";
import { CipherCreateRequest } from "../models/request/cipherCreateRequest";
import { CipherRequest } from "../models/request/cipherRequest";
import { CipherShareRequest } from "../models/request/cipherShareRequest";
import { CollectionRequest } from "../models/request/collectionRequest";
import { DeleteRecoverRequest } from "../models/request/deleteRecoverRequest";
import { EmailRequest } from "../models/request/emailRequest";
import { EmailTokenRequest } from "../models/request/emailTokenRequest";
import { EmergencyAccessAcceptRequest } from "../models/request/emergencyAccessAcceptRequest";
import { EmergencyAccessConfirmRequest } from "../models/request/emergencyAccessConfirmRequest";
import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessInviteRequest";
import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest";
import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest";
import { EventRequest } from "../models/request/eventRequest";
import { FolderRequest } from "../models/request/folderRequest";
import { GroupRequest } from "../models/request/groupRequest";
import { IapCheckRequest } from "../models/request/iapCheckRequest";
import { ImportCiphersRequest } from "../models/request/importCiphersRequest";
import { ImportDirectoryRequest } from "../models/request/importDirectoryRequest";
import { ImportOrganizationCiphersRequest } from "../models/request/importOrganizationCiphersRequest";
import { KdfRequest } from "../models/request/kdfRequest";
import { KeyConnectorUserKeyRequest } from "../models/request/keyConnectorUserKeyRequest";
import { KeysRequest } from "../models/request/keysRequest";
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organizationSponsorshipCreateRequest";
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organizationSponsorshipRedeemRequest";
import { OrganizationSsoRequest } from "../models/request/organization/organizationSsoRequest";
import { OrganizationCreateRequest } from "../models/request/organizationCreateRequest";
import { OrganizationImportRequest } from "../models/request/organizationImportRequest";
import { OrganizationKeysRequest } from "../models/request/organizationKeysRequest";
import { OrganizationSubscriptionUpdateRequest } from "../models/request/organizationSubscriptionUpdateRequest";
import { OrganizationTaxInfoUpdateRequest } from "../models/request/organizationTaxInfoUpdateRequest";
import { OrganizationUpdateRequest } from "../models/request/organizationUpdateRequest";
import { OrganizationUpgradeRequest } from "../models/request/organizationUpgradeRequest";
import { OrganizationUserAcceptRequest } from "../models/request/organizationUserAcceptRequest";
import { OrganizationUserBulkConfirmRequest } from "../models/request/organizationUserBulkConfirmRequest";
import { OrganizationUserBulkRequest } from "../models/request/organizationUserBulkRequest";
import { OrganizationUserConfirmRequest } from "../models/request/organizationUserConfirmRequest";
import { OrganizationUserInviteRequest } from "../models/request/organizationUserInviteRequest";
import { OrganizationUserResetPasswordEnrollmentRequest } from "../models/request/organizationUserResetPasswordEnrollmentRequest";
import { OrganizationUserResetPasswordRequest } from "../models/request/organizationUserResetPasswordRequest";
import { OrganizationUserUpdateGroupsRequest } from "../models/request/organizationUserUpdateGroupsRequest";
import { OrganizationUserUpdateRequest } from "../models/request/organizationUserUpdateRequest";
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
import { PasswordRequest } from "../models/request/passwordRequest";
import { PaymentRequest } from "../models/request/paymentRequest";
import { PolicyRequest } from "../models/request/policyRequest";
import { PreloginRequest } from "../models/request/preloginRequest";
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
import { ProviderSetupRequest } from "../models/request/provider/providerSetupRequest";
import { ProviderUpdateRequest } from "../models/request/provider/providerUpdateRequest";
import { ProviderUserAcceptRequest } from "../models/request/provider/providerUserAcceptRequest";
import { ProviderUserBulkConfirmRequest } from "../models/request/provider/providerUserBulkConfirmRequest";
import { ProviderUserBulkRequest } from "../models/request/provider/providerUserBulkRequest";
import { ProviderUserConfirmRequest } from "../models/request/provider/providerUserConfirmRequest";
import { ProviderUserInviteRequest } from "../models/request/provider/providerUserInviteRequest";
import { ProviderUserUpdateRequest } from "../models/request/provider/providerUserUpdateRequest";
import { RegisterRequest } from "../models/request/registerRequest";
import { SeatRequest } from "../models/request/seatRequest";
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
import { SelectionReadOnlyRequest } from "../models/request/selectionReadOnlyRequest";
import { SendAccessRequest } from "../models/request/sendAccessRequest";
import { SendRequest } from "../models/request/sendRequest";
import { SetPasswordRequest } from "../models/request/setPasswordRequest";
import { StorageRequest } from "../models/request/storageRequest";
import { TaxInfoUpdateRequest } from "../models/request/taxInfoUpdateRequest";
import { TokenRequest } from "../models/request/tokenRequest";
import { TwoFactorEmailRequest } from "../models/request/twoFactorEmailRequest";
import { TwoFactorProviderRequest } from "../models/request/twoFactorProviderRequest";
import { TwoFactorRecoveryRequest } from "../models/request/twoFactorRecoveryRequest";
import { UpdateDomainsRequest } from "../models/request/updateDomainsRequest";
import { UpdateKeyRequest } from "../models/request/updateKeyRequest";
import { UpdateProfileRequest } from "../models/request/updateProfileRequest";
import { UpdateTempPasswordRequest } from "../models/request/updateTempPasswordRequest";
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/updateTwoFactorAuthenticatorRequest";
import { UpdateTwoFactorDuoRequest } from "../models/request/updateTwoFactorDuoRequest";
import { UpdateTwoFactorEmailRequest } from "../models/request/updateTwoFactorEmailRequest";
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/updateTwoFactorWebAuthnDeleteRequest";
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/updateTwoFactorWebAuthnRequest";
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/updateTwoFactorYubioOtpRequest";
import { VerifyBankRequest } from "../models/request/verifyBankRequest";
import { VerifyDeleteRecoverRequest } from "../models/request/verifyDeleteRecoverRequest";
import { VerifyEmailRequest } from "../models/request/verifyEmailRequest";
import { ApiKeyResponse } from '../models/response/apiKeyResponse';
import { AttachmentResponse } from '../models/response/attachmentResponse';
import { AttachmentUploadDataResponse } from '../models/response/attachmentUploadDataResponse';
import { BillingResponse } from '../models/response/billingResponse';
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
import { CipherResponse } from '../models/response/cipherResponse';
import { ApiKeyResponse } from "../models/response/apiKeyResponse";
import { AttachmentResponse } from "../models/response/attachmentResponse";
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
import { BillingResponse } from "../models/response/billingResponse";
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
import { CipherResponse } from "../models/response/cipherResponse";
import {
CollectionGroupDetailsResponse,
CollectionResponse,
} from '../models/response/collectionResponse';
import { DomainsResponse } from '../models/response/domainsResponse';
} from "../models/response/collectionResponse";
import { DomainsResponse } from "../models/response/domainsResponse";
import {
EmergencyAccessGranteeDetailsResponse,
EmergencyAccessGrantorDetailsResponse,
EmergencyAccessTakeoverResponse,
EmergencyAccessViewResponse
} from '../models/response/emergencyAccessResponse';
import { EventResponse } from '../models/response/eventResponse';
import { FolderResponse } from '../models/response/folderResponse';
import {
GroupDetailsResponse,
GroupResponse,
} from '../models/response/groupResponse';
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
import { ListResponse } from '../models/response/listResponse';
import { OrganizationSsoResponse } from '../models/response/organization/organizationSsoResponse';
import { OrganizationAutoEnrollStatusResponse } from '../models/response/organizationAutoEnrollStatusResponse';
import { OrganizationKeysResponse } from '../models/response/organizationKeysResponse';
import { OrganizationResponse } from '../models/response/organizationResponse';
import { OrganizationSubscriptionResponse } from '../models/response/organizationSubscriptionResponse';
import { OrganizationUserBulkPublicKeyResponse } from '../models/response/organizationUserBulkPublicKeyResponse';
import { OrganizationUserBulkResponse } from '../models/response/organizationUserBulkResponse';
EmergencyAccessViewResponse,
} from "../models/response/emergencyAccessResponse";
import { EventResponse } from "../models/response/eventResponse";
import { FolderResponse } from "../models/response/folderResponse";
import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse";
import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse";
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
import { KeyConnectorUserKeyResponse } from "../models/response/keyConnectorUserKeyResponse";
import { ListResponse } from "../models/response/listResponse";
import { OrganizationSsoResponse } from "../models/response/organization/organizationSsoResponse";
import { OrganizationAutoEnrollStatusResponse } from "../models/response/organizationAutoEnrollStatusResponse";
import { OrganizationKeysResponse } from "../models/response/organizationKeysResponse";
import { OrganizationResponse } from "../models/response/organizationResponse";
import { OrganizationSubscriptionResponse } from "../models/response/organizationSubscriptionResponse";
import { OrganizationUserBulkPublicKeyResponse } from "../models/response/organizationUserBulkPublicKeyResponse";
import { OrganizationUserBulkResponse } from "../models/response/organizationUserBulkResponse";
import {
OrganizationUserDetailsResponse,
OrganizationUserResetPasswordDetailsReponse,
OrganizationUserUserDetailsResponse,
} from '../models/response/organizationUserResponse';
import { PaymentResponse } from '../models/response/paymentResponse';
import { PlanResponse } from '../models/response/planResponse';
import { PolicyResponse } from '../models/response/policyResponse';
import { PreloginResponse } from '../models/response/preloginResponse';
import { ProfileResponse } from '../models/response/profileResponse';
import { ProviderOrganizationOrganizationDetailsResponse, ProviderOrganizationResponse } from '../models/response/provider/providerOrganizationResponse';
import { ProviderResponse } from '../models/response/provider/providerResponse';
import { ProviderUserBulkPublicKeyResponse } from '../models/response/provider/providerUserBulkPublicKeyResponse';
import { ProviderUserBulkResponse } from '../models/response/provider/providerUserBulkResponse';
import { ProviderUserResponse, ProviderUserUserDetailsResponse } from '../models/response/provider/providerUserResponse';
import { SelectionReadOnlyResponse } from '../models/response/selectionReadOnlyResponse';
import { SendAccessResponse } from '../models/response/sendAccessResponse';
import { SendFileDownloadDataResponse } from '../models/response/sendFileDownloadDataResponse';
import { SendFileUploadDataResponse } from '../models/response/sendFileUploadDataResponse';
import { SendResponse } from '../models/response/sendResponse';
import { SubscriptionResponse } from '../models/response/subscriptionResponse';
import { SyncResponse } from '../models/response/syncResponse';
import { TaxInfoResponse } from '../models/response/taxInfoResponse';
import { TaxRateResponse } from '../models/response/taxRateResponse';
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
import { TwoFactorDuoResponse } from '../models/response/twoFactorDuoResponse';
import { TwoFactorEmailResponse } from '../models/response/twoFactorEmailResponse';
import { TwoFactorProviderResponse } from '../models/response/twoFactorProviderResponse';
import { TwoFactorRecoverResponse } from '../models/response/twoFactorRescoverResponse';
import { ChallengeResponse, TwoFactorWebAuthnResponse } from '../models/response/twoFactorWebAuthnResponse';
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
import { UserKeyResponse } from '../models/response/userKeyResponse';
} from "../models/response/organizationUserResponse";
import { PaymentResponse } from "../models/response/paymentResponse";
import { PlanResponse } from "../models/response/planResponse";
import { PolicyResponse } from "../models/response/policyResponse";
import { PreloginResponse } from "../models/response/preloginResponse";
import { ProfileResponse } from "../models/response/profileResponse";
import {
ProviderOrganizationOrganizationDetailsResponse,
ProviderOrganizationResponse,
} from "../models/response/provider/providerOrganizationResponse";
import { ProviderResponse } from "../models/response/provider/providerResponse";
import { ProviderUserBulkPublicKeyResponse } from "../models/response/provider/providerUserBulkPublicKeyResponse";
import { ProviderUserBulkResponse } from "../models/response/provider/providerUserBulkResponse";
import {
ProviderUserResponse,
ProviderUserUserDetailsResponse,
} from "../models/response/provider/providerUserResponse";
import { SelectionReadOnlyResponse } from "../models/response/selectionReadOnlyResponse";
import { SendAccessResponse } from "../models/response/sendAccessResponse";
import { SendFileDownloadDataResponse } from "../models/response/sendFileDownloadDataResponse";
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
import { SendResponse } from "../models/response/sendResponse";
import { SubscriptionResponse } from "../models/response/subscriptionResponse";
import { SyncResponse } from "../models/response/syncResponse";
import { TaxInfoResponse } from "../models/response/taxInfoResponse";
import { TaxRateResponse } from "../models/response/taxRateResponse";
import { TwoFactorAuthenticatorResponse } from "../models/response/twoFactorAuthenticatorResponse";
import { TwoFactorDuoResponse } from "../models/response/twoFactorDuoResponse";
import { TwoFactorEmailResponse } from "../models/response/twoFactorEmailResponse";
import { TwoFactorProviderResponse } from "../models/response/twoFactorProviderResponse";
import { TwoFactorRecoverResponse } from "../models/response/twoFactorRescoverResponse";
import {
ChallengeResponse,
TwoFactorWebAuthnResponse,
} from "../models/response/twoFactorWebAuthnResponse";
import { TwoFactorYubiKeyResponse } from "../models/response/twoFactorYubiKeyResponse";
import { UserKeyResponse } from "../models/response/userKeyResponse";
import { SendAccessView } from '../models/view/sendAccessView';
import { SendAccessView } from "../models/view/sendAccessView";
export abstract class ApiService {
postIdentityToken: (request: TokenRequest) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
postIdentityToken: (
request: TokenRequest
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
refreshIdentityToken: () => Promise<any>;
getProfile: () => Promise<ProfileResponse>;
@ -212,7 +220,11 @@ export abstract class ApiService {
deleteFolder: (id: string) => Promise<any>;
getSend: (id: string) => Promise<SendResponse>;
postSendAccess: (id: string, request: SendAccessRequest, apiUrl?: string) => Promise<SendAccessResponse>;
postSendAccess: (
id: string,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendAccessResponse>;
getSends: () => Promise<ListResponse<SendResponse>>;
postSend: (request: SendRequest) => Promise<SendResponse>;
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
@ -225,12 +237,20 @@ export abstract class ApiService {
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
putSendRemovePassword: (id: string) => Promise<SendResponse>;
deleteSend: (id: string) => Promise<any>;
getSendFileDownloadData: (send: SendAccessView, request: SendAccessRequest, apiUrl?: string) => Promise<SendFileDownloadDataResponse>;
getSendFileDownloadData: (
send: SendAccessView,
request: SendAccessRequest,
apiUrl?: string
) => Promise<SendFileDownloadDataResponse>;
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
getCipher: (id: string) => Promise<CipherResponse>;
getCipherAdmin: (id: string) => Promise<CipherResponse>;
getAttachmentData: (cipherId: string, attachmentId: string, emergencyAccessId?: string) => Promise<AttachmentResponse>;
getAttachmentData: (
cipherId: string,
attachmentId: string,
emergencyAccessId?: string
) => Promise<AttachmentResponse>;
getCiphersOrganization: (organizationId: string) => Promise<ListResponse<CipherResponse>>;
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
@ -248,14 +268,19 @@ export abstract class ApiService {
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
postImportOrganizationCiphers: (organizationId: string, request: ImportOrganizationCiphersRequest) => Promise<any>;
postImportOrganizationCiphers: (
organizationId: string,
request: ImportOrganizationCiphersRequest
) => Promise<any>;
putDeleteCipher: (id: string) => Promise<any>;
putDeleteCipherAdmin: (id: string) => Promise<any>;
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
putRestoreCipher: (id: string) => Promise<CipherResponse>;
putRestoreCipherAdmin: (id: string) => Promise<CipherResponse>;
putRestoreManyCiphers: (request: CipherBulkRestoreRequest) => Promise<ListResponse<CipherResponse>>;
putRestoreManyCiphers: (
request: CipherBulkRestoreRequest
) => Promise<ListResponse<CipherResponse>>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
@ -267,23 +292,51 @@ export abstract class ApiService {
* This method still exists for backward compatibility with old server versions.
*/
postCipherAttachmentAdminLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
postCipherAttachment: (id: string, request: AttachmentRequest) => Promise<AttachmentUploadDataResponse>;
postCipherAttachment: (
id: string,
request: AttachmentRequest
) => Promise<AttachmentUploadDataResponse>;
deleteCipherAttachment: (id: string, attachmentId: string) => Promise<any>;
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
postShareCipherAttachment: (id: string, attachmentId: string, data: FormData,
organizationId: string) => Promise<any>;
renewAttachmentUploadUrl: (id: string, attachmentId: string) => Promise<AttachmentUploadDataResponse>;
postShareCipherAttachment: (
id: string,
attachmentId: string,
data: FormData,
organizationId: string
) => Promise<any>;
renewAttachmentUploadUrl: (
id: string,
attachmentId: string
) => Promise<AttachmentUploadDataResponse>;
postAttachmentFile: (id: string, attachmentId: string, data: FormData) => Promise<any>;
getCollectionDetails: (organizationId: string, id: string) => Promise<CollectionGroupDetailsResponse>;
getCollectionDetails: (
organizationId: string,
id: string
) => Promise<CollectionGroupDetailsResponse>;
getUserCollections: () => Promise<ListResponse<CollectionResponse>>;
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
postCollection: (organizationId: string, request: CollectionRequest) => Promise<CollectionResponse>;
putCollectionUsers: (organizationId: string, id: string, request: SelectionReadOnlyRequest[]) => Promise<any>;
putCollection: (organizationId: string, id: string, request: CollectionRequest) => Promise<CollectionResponse>;
postCollection: (
organizationId: string,
request: CollectionRequest
) => Promise<CollectionResponse>;
putCollectionUsers: (
organizationId: string,
id: string,
request: SelectionReadOnlyRequest[]
) => Promise<any>;
putCollection: (
organizationId: string,
id: string,
request: CollectionRequest
) => Promise<CollectionResponse>;
deleteCollection: (organizationId: string, id: string) => Promise<any>;
deleteCollectionUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
deleteCollectionUser: (
organizationId: string,
id: string,
organizationUserId: string
) => Promise<any>;
getGroupDetails: (organizationId: string, id: string) => Promise<GroupDetailsResponse>;
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
@ -296,35 +349,83 @@ export abstract class ApiService {
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByToken: (organizationId: string, token: string, email: string, organizationUserId: string) =>
Promise<ListResponse<PolicyResponse>>;
putPolicy: (organizationId: string, type: PolicyType, request: PolicyRequest) => Promise<PolicyResponse>;
getPoliciesByToken: (
organizationId: string,
token: string,
email: string,
organizationUserId: string
) => Promise<ListResponse<PolicyResponse>>;
putPolicy: (
organizationId: string,
type: PolicyType,
request: PolicyRequest
) => Promise<PolicyResponse>;
getOrganizationUser: (organizationId: string, id: string) => Promise<OrganizationUserDetailsResponse>;
getOrganizationUser: (
organizationId: string,
id: string
) => Promise<OrganizationUserDetailsResponse>;
getOrganizationUserGroups: (organizationId: string, id: string) => Promise<string[]>;
getOrganizationUsers: (organizationId: string) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
getOrganizationUserResetPasswordDetails: (organizationId: string, id: string)
=> Promise<OrganizationUserResetPasswordDetailsReponse>;
postOrganizationUserInvite: (organizationId: string, request: OrganizationUserInviteRequest) => Promise<any>;
getOrganizationUsers: (
organizationId: string
) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
getOrganizationUserResetPasswordDetails: (
organizationId: string,
id: string
) => Promise<OrganizationUserResetPasswordDetailsReponse>;
postOrganizationUserInvite: (
organizationId: string,
request: OrganizationUserInviteRequest
) => Promise<any>;
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
postManyOrganizationUserReinvite: (organizationId: string, request: OrganizationUserBulkRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
postOrganizationUserAccept: (organizationId: string, id: string,
request: OrganizationUserAcceptRequest) => Promise<any>;
postOrganizationUserConfirm: (organizationId: string, id: string,
request: OrganizationUserConfirmRequest) => Promise<any>;
postOrganizationUsersPublicKey: (organizationId: string, request: OrganizationUserBulkRequest) =>
Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
postOrganizationUserBulkConfirm: (organizationId: string, request: OrganizationUserBulkConfirmRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
postManyOrganizationUserReinvite: (
organizationId: string,
request: OrganizationUserBulkRequest
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
postOrganizationUserAccept: (
organizationId: string,
id: string,
request: OrganizationUserAcceptRequest
) => Promise<any>;
postOrganizationUserConfirm: (
organizationId: string,
id: string,
request: OrganizationUserConfirmRequest
) => Promise<any>;
postOrganizationUsersPublicKey: (
organizationId: string,
request: OrganizationUserBulkRequest
) => Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
postOrganizationUserBulkConfirm: (
organizationId: string,
request: OrganizationUserBulkConfirmRequest
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
putOrganizationUser: (organizationId: string, id: string, request: OrganizationUserUpdateRequest) => Promise<any>;
putOrganizationUserGroups: (organizationId: string, id: string,
request: OrganizationUserUpdateGroupsRequest) => Promise<any>;
putOrganizationUserResetPasswordEnrollment: (organizationId: string, userId: string,
request: OrganizationUserResetPasswordEnrollmentRequest) => Promise<any>;
putOrganizationUserResetPassword: (organizationId: string, id: string,
request: OrganizationUserResetPasswordRequest) => Promise<any>;
putOrganizationUser: (
organizationId: string,
id: string,
request: OrganizationUserUpdateRequest
) => Promise<any>;
putOrganizationUserGroups: (
organizationId: string,
id: string,
request: OrganizationUserUpdateGroupsRequest
) => Promise<any>;
putOrganizationUserResetPasswordEnrollment: (
organizationId: string,
userId: string,
request: OrganizationUserResetPasswordEnrollmentRequest
) => Promise<any>;
putOrganizationUserResetPassword: (
organizationId: string,
id: string,
request: OrganizationUserResetPasswordRequest
) => Promise<any>;
deleteOrganizationUser: (organizationId: string, id: string) => Promise<any>;
deleteManyOrganizationUsers: (organizationId: string, request: OrganizationUserBulkRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
deleteManyOrganizationUsers: (
organizationId: string,
request: OrganizationUserBulkRequest
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
getSync: () => Promise<SyncResponse>;
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
@ -334,28 +435,45 @@ export abstract class ApiService {
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
getTwoFactorOrganizationProviders: (organizationId: string) => Promise<ListResponse<TwoFactorProviderResponse>>;
getTwoFactorAuthenticator: (request: SecretVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
getTwoFactorOrganizationProviders: (
organizationId: string
) => Promise<ListResponse<TwoFactorProviderResponse>>;
getTwoFactorAuthenticator: (
request: SecretVerificationRequest
) => Promise<TwoFactorAuthenticatorResponse>;
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
getTwoFactorOrganizationDuo: (organizationId: string,
request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
getTwoFactorOrganizationDuo: (
organizationId: string,
request: SecretVerificationRequest
) => Promise<TwoFactorDuoResponse>;
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
putTwoFactorAuthenticator: (
request: UpdateTwoFactorAuthenticatorRequest) => Promise<TwoFactorAuthenticatorResponse>;
request: UpdateTwoFactorAuthenticatorRequest
) => Promise<TwoFactorAuthenticatorResponse>;
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
putTwoFactorOrganizationDuo: (organizationId: string,
request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
putTwoFactorYubiKey: (request: UpdateTwoFactorYubioOtpRequest) => Promise<TwoFactorYubiKeyResponse>;
putTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnRequest) => Promise<TwoFactorWebAuthnResponse>;
deleteTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnDeleteRequest) => Promise<TwoFactorWebAuthnResponse>;
putTwoFactorOrganizationDuo: (
organizationId: string,
request: UpdateTwoFactorDuoRequest
) => Promise<TwoFactorDuoResponse>;
putTwoFactorYubiKey: (
request: UpdateTwoFactorYubioOtpRequest
) => Promise<TwoFactorYubiKeyResponse>;
putTwoFactorWebAuthn: (
request: UpdateTwoFactorWebAuthnRequest
) => Promise<TwoFactorWebAuthnResponse>;
deleteTwoFactorWebAuthn: (
request: UpdateTwoFactorWebAuthnDeleteRequest
) => Promise<TwoFactorWebAuthnResponse>;
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
putTwoFactorOrganizationDisable: (organizationId: string,
request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
putTwoFactorOrganizationDisable: (
organizationId: string,
request: TwoFactorProviderRequest
) => Promise<TwoFactorProviderResponse>;
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
@ -374,7 +492,10 @@ export abstract class ApiService {
postEmergencyAccessApprove: (id: string) => Promise<any>;
postEmergencyAccessReject: (id: string) => Promise<any>;
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
postEmergencyAccessPassword: (id: string, request: EmergencyAccessPasswordRequest) => Promise<any>;
postEmergencyAccessPassword: (
id: string,
request: EmergencyAccessPasswordRequest
) => Promise<any>;
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
getOrganization: (id: string) => Promise<OrganizationResponse>;
@ -382,19 +503,39 @@ export abstract class ApiService {
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
getOrganizationAutoEnrollStatus: (identifier: string) => Promise<OrganizationAutoEnrollStatusResponse>;
getOrganizationAutoEnrollStatus: (
identifier: string
) => Promise<OrganizationAutoEnrollStatusResponse>;
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
putOrganization: (id: string, request: OrganizationUpdateRequest) => Promise<OrganizationResponse>;
putOrganization: (
id: string,
request: OrganizationUpdateRequest
) => Promise<OrganizationResponse>;
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
postLeaveOrganization: (id: string) => Promise<any>;
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
postOrganizationApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
postOrganizationRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
postOrganizationSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
postOrganizationUpgrade: (id: string, request: OrganizationUpgradeRequest) => Promise<PaymentResponse>;
postOrganizationUpdateSubscription: (id: string, request: OrganizationSubscriptionUpdateRequest) => Promise<void>;
postOrganizationApiKey: (
id: string,
request: SecretVerificationRequest
) => Promise<ApiKeyResponse>;
postOrganizationRotateApiKey: (
id: string,
request: SecretVerificationRequest
) => Promise<ApiKeyResponse>;
postOrganizationSso: (
id: string,
request: OrganizationSsoRequest
) => Promise<OrganizationSsoResponse>;
postOrganizationUpgrade: (
id: string,
request: OrganizationUpgradeRequest
) => Promise<PaymentResponse>;
postOrganizationUpdateSubscription: (
id: string,
request: OrganizationSubscriptionUpdateRequest
) => Promise<void>;
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
@ -405,7 +546,10 @@ export abstract class ApiService {
getPlans: () => Promise<ListResponse<PlanResponse>>;
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
postOrganizationKeys: (id: string, request: OrganizationKeysRequest) => Promise<OrganizationKeysResponse>;
postOrganizationKeys: (
id: string,
request: OrganizationKeysRequest
) => Promise<OrganizationKeysResponse>;
postProviderSetup: (id: string, request: ProviderSetupRequest) => Promise<ProviderResponse>;
getProvider: (id: string) => Promise<ProviderResponse>;
@ -415,28 +559,84 @@ export abstract class ApiService {
getProviderUser: (providerId: string, id: string) => Promise<ProviderUserResponse>;
postProviderUserInvite: (providerId: string, request: ProviderUserInviteRequest) => Promise<any>;
postProviderUserReinvite: (providerId: string, id: string) => Promise<any>;
postManyProviderUserReinvite: (providerId: string, request: ProviderUserBulkRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
postProviderUserAccept: (providerId: string, id: string, request: ProviderUserAcceptRequest) => Promise<any>;
postProviderUserConfirm: (providerId: string, id: string, request: ProviderUserConfirmRequest) => Promise<any>;
postProviderUsersPublicKey: (providerId: string, request: ProviderUserBulkRequest) =>
Promise<ListResponse<ProviderUserBulkPublicKeyResponse>>;
postProviderUserBulkConfirm: (providerId: string, request: ProviderUserBulkConfirmRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
putProviderUser: (providerId: string, id: string, request: ProviderUserUpdateRequest) => Promise<any>;
postManyProviderUserReinvite: (
providerId: string,
request: ProviderUserBulkRequest
) => Promise<ListResponse<ProviderUserBulkResponse>>;
postProviderUserAccept: (
providerId: string,
id: string,
request: ProviderUserAcceptRequest
) => Promise<any>;
postProviderUserConfirm: (
providerId: string,
id: string,
request: ProviderUserConfirmRequest
) => Promise<any>;
postProviderUsersPublicKey: (
providerId: string,
request: ProviderUserBulkRequest
) => Promise<ListResponse<ProviderUserBulkPublicKeyResponse>>;
postProviderUserBulkConfirm: (
providerId: string,
request: ProviderUserBulkConfirmRequest
) => Promise<ListResponse<ProviderUserBulkResponse>>;
putProviderUser: (
providerId: string,
id: string,
request: ProviderUserUpdateRequest
) => Promise<any>;
deleteProviderUser: (organizationId: string, id: string) => Promise<any>;
deleteManyProviderUsers: (providerId: string, request: ProviderUserBulkRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
getProviderClients: (providerId: string) => Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>>;
postProviderAddOrganization: (providerId: string, request: ProviderAddOrganizationRequest) => Promise<any>;
postProviderCreateOrganization: (providerId: string, request: ProviderOrganizationCreateRequest) => Promise<ProviderOrganizationResponse>;
deleteManyProviderUsers: (
providerId: string,
request: ProviderUserBulkRequest
) => Promise<ListResponse<ProviderUserBulkResponse>>;
getProviderClients: (
providerId: string
) => Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>>;
postProviderAddOrganization: (
providerId: string,
request: ProviderAddOrganizationRequest
) => Promise<any>;
postProviderCreateOrganization: (
providerId: string,
request: ProviderOrganizationCreateRequest
) => Promise<ProviderOrganizationResponse>;
deleteProviderOrganization: (providerId: string, organizationId: string) => Promise<any>;
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsCipher: (id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsOrganization: (id: string, start: string, end: string,
token: string) => Promise<ListResponse<EventResponse>>;
getEventsOrganizationUser: (organizationId: string, id: string,
start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsProvider: (id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsProviderUser: (providerId: string, id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsCipher: (
id: string,
start: string,
end: string,
token: string
) => Promise<ListResponse<EventResponse>>;
getEventsOrganization: (
id: string,
start: string,
end: string,
token: string
) => Promise<ListResponse<EventResponse>>;
getEventsOrganizationUser: (
organizationId: string,
id: string,
start: string,
end: string,
token: string
) => Promise<ListResponse<EventResponse>>;
getEventsProvider: (
id: string,
start: string,
end: string,
token: string
) => Promise<ListResponse<EventResponse>>;
getEventsProviderUser: (
providerId: string,
id: string,
start: string,
end: string,
token: string
) => Promise<ListResponse<EventResponse>>;
postEventsCollect: (request: EventRequest[]) => Promise<any>;
deleteSsoUser: (organizationId: string) => Promise<any>;
@ -455,14 +655,23 @@ export abstract class ApiService {
preValidateSso: (identifier: string) => Promise<boolean>;
postCreateSponsorship: (sponsorshipOrgId: string, request: OrganizationSponsorshipCreateRequest) => Promise<void>;
postCreateSponsorship: (
sponsorshipOrgId: string,
request: OrganizationSponsorshipCreateRequest
) => Promise<void>;
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
postRedeemSponsorship: (sponsorshipToken: string, request: OrganizationSponsorshipRedeemRequest) => Promise<void>;
postRedeemSponsorship: (
sponsorshipToken: string,
request: OrganizationSponsorshipRedeemRequest
) => Promise<void>;
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
postUserKeyToKeyConnector: (keyConnectorUrl: string, request: KeyConnectorUserKeyRequest) => Promise<void>;
postUserKeyToKeyConnector: (
keyConnectorUrl: string,
request: KeyConnectorUserKeyRequest
) => Promise<void>;
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
}

View File

@ -1,4 +1,4 @@
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
export abstract class AuditService {
passwordLeaked: (password: string) => Promise<number>;

View File

@ -1,7 +1,7 @@
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
import { TwoFactorProviderType } from "../enums/twoFactorProviderType";
import { AuthResult } from '../models/domain/authResult';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { AuthResult } from "../models/domain/authResult";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
export abstract class AuthService {
email: string;
@ -11,20 +11,45 @@ export abstract class AuthService {
ssoRedirectUrl: string;
clientId: string;
clientSecret: string;
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string; }>;
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string }>;
selectedTwoFactorProviderType: TwoFactorProviderType;
logIn: (email: string, masterPassword: string, captchaToken?: string) => Promise<AuthResult>;
logInSso: (code: string, codeVerifier: string, redirectUrl: string, orgId: string) => Promise<AuthResult>;
logInSso: (
code: string,
codeVerifier: string,
redirectUrl: string,
orgId: string
) => Promise<AuthResult>;
logInApiKey: (clientId: string, clientSecret: string) => Promise<AuthResult>;
logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
remember?: boolean) => Promise<AuthResult>;
logInComplete: (email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string, remember?: boolean, captchaToken?: string) => Promise<AuthResult>;
logInSsoComplete: (code: string, codeVerifier: string, redirectUrl: string,
twoFactorProvider: TwoFactorProviderType, twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
logInApiKeyComplete: (clientId: string, clientSecret: string, twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
logInTwoFactor: (
twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string,
remember?: boolean
) => Promise<AuthResult>;
logInComplete: (
email: string,
masterPassword: string,
twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string,
remember?: boolean,
captchaToken?: string
) => Promise<AuthResult>;
logInSsoComplete: (
code: string,
codeVerifier: string,
redirectUrl: string,
twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string,
remember?: boolean
) => Promise<AuthResult>;
logInApiKeyComplete: (
clientId: string,
clientSecret: string,
twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string,
remember?: boolean
) => Promise<AuthResult>;
logOut: (callback: Function) => void;
getSupportedTwoFactorProviders: (win: Window) => any[];
getDefaultTwoFactorProvider: (webAuthnSupported: boolean) => TwoFactorProviderType;

View File

@ -1,26 +1,33 @@
import { CipherType } from '../enums/cipherType';
import { UriMatchType } from '../enums/uriMatchType';
import { CipherType } from "../enums/cipherType";
import { UriMatchType } from "../enums/uriMatchType";
import { CipherData } from '../models/data/cipherData';
import { CipherData } from "../models/data/cipherData";
import { Cipher } from '../models/domain/cipher';
import { Field } from '../models/domain/field';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { Cipher } from "../models/domain/cipher";
import { Field } from "../models/domain/field";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { CipherView } from '../models/view/cipherView';
import { FieldView } from '../models/view/fieldView';
import { CipherView } from "../models/view/cipherView";
import { FieldView } from "../models/view/fieldView";
export abstract class CipherService {
clearCache: (userId?: string) => Promise<void>;
encrypt: (model: CipherView, key?: SymmetricCryptoKey, originalCipher?: Cipher) => Promise<Cipher>;
encrypt: (
model: CipherView,
key?: SymmetricCryptoKey,
originalCipher?: Cipher
) => Promise<Cipher>;
encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise<Field[]>;
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;
get: (id: string) => Promise<Cipher>;
getAll: () => Promise<Cipher[]>;
getAllDecrypted: () => Promise<CipherView[]>;
getAllDecryptedForGrouping: (groupingId: string, folder?: boolean) => Promise<CipherView[]>;
getAllDecryptedForUrl: (url: string, includeOtherTypes?: CipherType[],
defaultMatch?: UriMatchType) => Promise<CipherView[]>;
getAllDecryptedForUrl: (
url: string,
includeOtherTypes?: CipherType[],
defaultMatch?: UriMatchType
) => Promise<CipherView[]>;
getAllFromApiForOrganization: (organizationId: string) => Promise<CipherView[]>;
getLastUsedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
getLastLaunchedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
@ -30,14 +37,30 @@ export abstract class CipherService {
updateLastLaunchedDate: (id: string) => Promise<void>;
saveNeverDomain: (domain: string) => Promise<void>;
saveWithServer: (cipher: Cipher) => Promise<any>;
shareWithServer: (cipher: CipherView, organizationId: string, collectionIds: string[]) => Promise<any>;
shareManyWithServer: (ciphers: CipherView[], organizationId: string, collectionIds: string[]) => Promise<any>;
saveAttachmentWithServer: (cipher: Cipher, unencryptedFile: any, admin?: boolean) => Promise<Cipher>;
saveAttachmentRawWithServer: (cipher: Cipher, filename: string, data: ArrayBuffer,
admin?: boolean) => Promise<Cipher>;
shareWithServer: (
cipher: CipherView,
organizationId: string,
collectionIds: string[]
) => Promise<any>;
shareManyWithServer: (
ciphers: CipherView[],
organizationId: string,
collectionIds: string[]
) => Promise<any>;
saveAttachmentWithServer: (
cipher: Cipher,
unencryptedFile: any,
admin?: boolean
) => Promise<Cipher>;
saveAttachmentRawWithServer: (
cipher: Cipher,
filename: string,
data: ArrayBuffer,
admin?: boolean
) => Promise<Cipher>;
saveCollectionsWithServer: (cipher: Cipher) => Promise<any>;
upsert: (cipher: CipherData | CipherData[]) => Promise<any>;
replace: (ciphers: { [id: string]: CipherData; }) => Promise<any>;
replace: (ciphers: { [id: string]: CipherData }) => Promise<any>;
clear: (userId: string) => Promise<any>;
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
@ -51,7 +74,9 @@ export abstract class CipherService {
softDelete: (id: string | string[]) => Promise<any>;
softDeleteWithServer: (id: string) => Promise<any>;
softDeleteManyWithServer: (ids: string[]) => Promise<any>;
restore: (cipher: { id: string, revisionDate: string; } | { id: string, revisionDate: string; }[]) => Promise<any>;
restore: (
cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[]
) => Promise<any>;
restoreWithServer: (id: string) => Promise<any>;
restoreManyWithServer: (ids: string[]) => Promise<any>;
}

View File

@ -1,9 +1,9 @@
import { CollectionData } from '../models/data/collectionData';
import { CollectionData } from "../models/data/collectionData";
import { Collection } from '../models/domain/collection';
import { TreeNode } from '../models/domain/treeNode';
import { Collection } from "../models/domain/collection";
import { TreeNode } from "../models/domain/treeNode";
import { CollectionView } from '../models/view/collectionView';
import { CollectionView } from "../models/view/collectionView";
export abstract class CollectionService {
clearCache: (userId?: string) => Promise<void>;
@ -15,7 +15,7 @@ export abstract class CollectionService {
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
upsert: (collection: CollectionData | CollectionData[]) => Promise<any>;
replace: (collections: { [id: string]: CollectionData; }) => Promise<any>;
replace: (collections: { [id: string]: CollectionData }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
}

View File

@ -1,21 +1,24 @@
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { EncString } from '../models/domain/encString';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { EncArrayBuffer } from "../models/domain/encArrayBuffer";
import { EncString } from "../models/domain/encString";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { ProfileOrganizationResponse } from '../models/response/profileOrganizationResponse';
import { ProfileProviderOrganizationResponse } from '../models/response/profileProviderOrganizationResponse';
import { ProfileProviderResponse } from '../models/response/profileProviderResponse';
import { ProfileOrganizationResponse } from "../models/response/profileOrganizationResponse";
import { ProfileProviderOrganizationResponse } from "../models/response/profileProviderOrganizationResponse";
import { ProfileProviderResponse } from "../models/response/profileProviderResponse";
import { HashPurpose } from '../enums/hashPurpose';
import { KdfType } from '../enums/kdfType';
import { KeySuffixOptions } from '../enums/keySuffixOptions';
import { HashPurpose } from "../enums/hashPurpose";
import { KdfType } from "../enums/kdfType";
import { KeySuffixOptions } from "../enums/keySuffixOptions";
export abstract class CryptoService {
setKey: (key: SymmetricCryptoKey) => Promise<any>;
setKeyHash: (keyHash: string) => Promise<void>;
setEncKey: (encKey: string) => Promise<void>;
setEncPrivateKey: (encPrivateKey: string) => Promise<void>;
setOrgKeys: (orgs: ProfileOrganizationResponse[], providerOrgs: ProfileProviderOrganizationResponse[]) => Promise<void>;
setOrgKeys: (
orgs: ProfileOrganizationResponse[],
providerOrgs: ProfileProviderOrganizationResponse[]
) => Promise<void>;
setProviderKeys: (orgs: ProfileProviderResponse[]) => Promise<void>;
getKey: (keySuffix?: KeySuffixOptions, userId?: string) => Promise<SymmetricCryptoKey>;
getKeyFromStorage: (keySuffix: KeySuffixOptions) => Promise<SymmetricCryptoKey>;
@ -41,16 +44,38 @@ export abstract class CryptoService {
clearPinProtectedKey: () => Promise<any>;
clearKeys: (userId?: string) => Promise<any>;
toggleKey: () => Promise<any>;
makeKey: (password: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise<SymmetricCryptoKey>;
makeKeyFromPin: (pin: string, salt: string, kdf: KdfType, kdfIterations: number,
protectedKeyCs?: EncString) => Promise<SymmetricCryptoKey>;
makeKey: (
password: string,
salt: string,
kdf: KdfType,
kdfIterations: number
) => Promise<SymmetricCryptoKey>;
makeKeyFromPin: (
pin: string,
salt: string,
kdf: KdfType,
kdfIterations: number,
protectedKeyCs?: EncString
) => Promise<SymmetricCryptoKey>;
makeShareKey: () => Promise<[EncString, SymmetricCryptoKey]>;
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
makePinKey: (pin: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise<SymmetricCryptoKey>;
makePinKey: (
pin: string,
salt: string,
kdf: KdfType,
kdfIterations: number
) => Promise<SymmetricCryptoKey>;
makeSendKey: (keyMaterial: ArrayBuffer) => Promise<SymmetricCryptoKey>;
hashPassword: (password: string, key: SymmetricCryptoKey, hashPurpose?: HashPurpose) => Promise<string>;
hashPassword: (
password: string,
key: SymmetricCryptoKey,
hashPurpose?: HashPurpose
) => Promise<string>;
makeEncKey: (key: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
remakeEncKey: (key: SymmetricCryptoKey, encKey?: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
remakeEncKey: (
key: SymmetricCryptoKey,
encKey?: SymmetricCryptoKey
) => Promise<[SymmetricCryptoKey, EncString]>;
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
rsaEncrypt: (data: ArrayBuffer, publicKey?: ArrayBuffer) => Promise<EncString>;

View File

@ -1,26 +1,61 @@
import { DecryptParameters } from '../models/domain/decryptParameters';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { DecryptParameters } from "../models/domain/decryptParameters";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
export abstract class CryptoFunctionService {
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
iterations: number) => Promise<ArrayBuffer>;
hkdf: (ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
outputByteSize: number, algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hkdfExpand: (prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5') => Promise<ArrayBuffer>;
hmac: (value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
pbkdf2: (
password: string | ArrayBuffer,
salt: string | ArrayBuffer,
algorithm: "sha256" | "sha512",
iterations: number
) => Promise<ArrayBuffer>;
hkdf: (
ikm: ArrayBuffer,
salt: string | ArrayBuffer,
info: string | ArrayBuffer,
outputByteSize: number,
algorithm: "sha256" | "sha512"
) => Promise<ArrayBuffer>;
hkdfExpand: (
prk: ArrayBuffer,
info: string | ArrayBuffer,
outputByteSize: number,
algorithm: "sha256" | "sha512"
) => Promise<ArrayBuffer>;
hash: (
value: string | ArrayBuffer,
algorithm: "sha1" | "sha256" | "sha512" | "md5"
) => Promise<ArrayBuffer>;
hmac: (
value: ArrayBuffer,
key: ArrayBuffer,
algorithm: "sha1" | "sha256" | "sha512"
) => Promise<ArrayBuffer>;
compare: (a: ArrayBuffer, b: ArrayBuffer) => Promise<boolean>;
hmacFast: (value: ArrayBuffer | string, key: ArrayBuffer | string, algorithm: 'sha1' | 'sha256' | 'sha512') =>
Promise<ArrayBuffer | string>;
hmacFast: (
value: ArrayBuffer | string,
key: ArrayBuffer | string,
algorithm: "sha1" | "sha256" | "sha512"
) => Promise<ArrayBuffer | string>;
compareFast: (a: ArrayBuffer | string, b: ArrayBuffer | string) => Promise<boolean>;
aesEncrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
aesDecryptFastParameters: (data: string, iv: string, mac: string, key: SymmetricCryptoKey) =>
DecryptParameters<ArrayBuffer | string>;
aesDecryptFastParameters: (
data: string,
iv: string,
mac: string,
key: SymmetricCryptoKey
) => DecryptParameters<ArrayBuffer | string>;
aesDecryptFast: (parameters: DecryptParameters<ArrayBuffer | string>) => Promise<string>;
aesDecrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
rsaEncrypt: (data: ArrayBuffer, publicKey: ArrayBuffer, algorithm: 'sha1' | 'sha256') => Promise<ArrayBuffer>;
rsaDecrypt: (data: ArrayBuffer, privateKey: ArrayBuffer, algorithm: 'sha1' | 'sha256') => Promise<ArrayBuffer>;
rsaEncrypt: (
data: ArrayBuffer,
publicKey: ArrayBuffer,
algorithm: "sha1" | "sha256"
) => Promise<ArrayBuffer>;
rsaDecrypt: (
data: ArrayBuffer,
privateKey: ArrayBuffer,
algorithm: "sha1" | "sha256"
) => Promise<ArrayBuffer>;
rsaExtractPublicKey: (privateKey: ArrayBuffer) => Promise<ArrayBuffer>;
rsaGenerateKeyPair: (length: 1024 | 2048 | 4096) => Promise<[ArrayBuffer, ArrayBuffer]>;
randomBytes: (length: number) => Promise<ArrayBuffer>;

View File

@ -1,4 +1,4 @@
import { Observable } from 'rxjs';
import { Observable } from "rxjs";
export type Urls = {
base?: string;

View File

@ -1,4 +1,4 @@
import { EventType } from '../enums/eventType';
import { EventType } from "../enums/eventType";
export abstract class EventService {
collect: (eventType: EventType, cipherId?: string, uploadImmediately?: boolean) => Promise<any>;

View File

@ -1,8 +1,11 @@
import { EventView } from '../models/view/eventView';
import { EventView } from "../models/view/eventView";
export abstract class ExportService {
getExport: (format?: 'csv' | 'json' | 'encrypted_json') => Promise<string>;
getOrganizationExport: (organizationId: string, format?: 'csv' | 'json' | 'encrypted_json') => Promise<string>;
getExport: (format?: "csv" | "json" | "encrypted_json") => Promise<string>;
getOrganizationExport: (
organizationId: string,
format?: "csv" | "json" | "encrypted_json"
) => Promise<string>;
getEventExport: (events: EventView[]) => Promise<string>;
getFileName: (prefix?: string, extension?: string) => string;
}

View File

@ -1,11 +1,18 @@
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { EncString } from '../models/domain/encString';
import { AttachmentUploadDataResponse } from '../models/response/attachmentUploadDataResponse';
import { SendFileUploadDataResponse } from '../models/response/sendFileUploadDataResponse';
import { EncArrayBuffer } from "../models/domain/encArrayBuffer";
import { EncString } from "../models/domain/encString";
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
export abstract class FileUploadService {
uploadSendFile: (uploadData: SendFileUploadDataResponse, fileName: EncString,
encryptedFileData: EncArrayBuffer) => Promise<any>;
uploadCipherAttachment: (admin: boolean, uploadData: AttachmentUploadDataResponse, fileName: EncString,
encryptedFileData: EncArrayBuffer) => Promise<any>;
uploadSendFile: (
uploadData: SendFileUploadDataResponse,
fileName: EncString,
encryptedFileData: EncArrayBuffer
) => Promise<any>;
uploadCipherAttachment: (
admin: boolean,
uploadData: AttachmentUploadDataResponse,
fileName: EncString,
encryptedFileData: EncArrayBuffer
) => Promise<any>;
}

View File

@ -1,10 +1,10 @@
import { FolderData } from '../models/data/folderData';
import { FolderData } from "../models/data/folderData";
import { Folder } from '../models/domain/folder';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { TreeNode } from '../models/domain/treeNode';
import { Folder } from "../models/domain/folder";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { TreeNode } from "../models/domain/treeNode";
import { FolderView } from '../models/view/folderView';
import { FolderView } from "../models/view/folderView";
export abstract class FolderService {
clearCache: (userId?: string) => Promise<void>;
@ -16,7 +16,7 @@ export abstract class FolderService {
getNested: (id: string) => Promise<TreeNode<FolderView>>;
saveWithServer: (folder: Folder) => Promise<any>;
upsert: (folder: FolderData | FolderData[]) => Promise<any>;
replace: (folders: { [id: string]: FolderData; }) => Promise<any>;
replace: (folders: { [id: string]: FolderData }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;

View File

@ -1,4 +1,4 @@
import { Importer } from '../importers/importer';
import { Importer } from "../importers/importer";
export interface ImportOption {
id: string;

View File

@ -1,4 +1,4 @@
import { Organization } from '../models/domain/organization';
import { Organization } from "../models/domain/organization";
export abstract class KeyConnectorService {
getAndSetKey: (url?: string) => Promise<void>;

View File

@ -1,4 +1,4 @@
import { LogLevelType } from '../enums/logLevelType';
import { LogLevelType } from "../enums/logLevelType";
export abstract class LogService {
debug: (message: string) => void;

View File

@ -1,11 +1,11 @@
import { OrganizationData } from '../models/data/organizationData';
import { OrganizationData } from "../models/data/organizationData";
import { Organization } from '../models/domain/organization';
import { Organization } from "../models/domain/organization";
export abstract class OrganizationService {
get: (id: string) => Promise<Organization>;
getByIdentifier: (identifier: string) => Promise<Organization>;
getAll: (userId?: string) => Promise<Organization[]>;
save: (orgs: {[id: string]: OrganizationData}) => Promise<any>;
save: (orgs: { [id: string]: OrganizationData }) => Promise<any>;
canManageSponsorships: () => Promise<boolean>;
}

View File

@ -1,13 +1,15 @@
import * as zxcvbn from 'zxcvbn';
import * as zxcvbn from "zxcvbn";
import { GeneratedPasswordHistory } from '../models/domain/generatedPasswordHistory';
import { PasswordGeneratorPolicyOptions } from '../models/domain/passwordGeneratorPolicyOptions';
import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory";
import { PasswordGeneratorPolicyOptions } from "../models/domain/passwordGeneratorPolicyOptions";
export abstract class PasswordGenerationService {
generatePassword: (options: any) => Promise<string>;
generatePassphrase: (options: any) => Promise<string>;
getOptions: () => Promise<[any, PasswordGeneratorPolicyOptions]>;
enforcePasswordGeneratorPoliciesOnOptions: (options: any) => Promise<[any, PasswordGeneratorPolicyOptions]>;
enforcePasswordGeneratorPoliciesOnOptions: (
options: any
) => Promise<[any, PasswordGeneratorPolicyOptions]>;
getPasswordGeneratorPolicyOptions: () => Promise<PasswordGeneratorPolicyOptions>;
saveOptions: (options: any) => Promise<any>;
getHistory: () => Promise<GeneratedPasswordHistory[]>;

View File

@ -1,5 +1,5 @@
import { DeviceType } from '../enums/deviceType';
import { ThemeType } from '../enums/themeType';
import { DeviceType } from "../enums/deviceType";
import { ThemeType } from "../enums/themeType";
interface ToastOptions {
timeout?: number;
@ -23,10 +23,20 @@ export abstract class PlatformUtilsService {
getApplicationVersion: () => Promise<string>;
supportsWebAuthn: (win: Window) => boolean;
supportsDuo: () => boolean;
showToast: (type: 'error' | 'success' | 'warning' | 'info', title: string, text: string | string[],
options?: ToastOptions) => void;
showDialog: (body: string, title?: string, confirmText?: string, cancelText?: string,
type?: string, bodyIsHtml?: boolean) => Promise<boolean>;
showToast: (
type: "error" | "success" | "warning" | "info",
title: string,
text: string | string[],
options?: ToastOptions
) => void;
showDialog: (
body: string,
title?: string,
confirmText?: string,
cancelText?: string,
type?: string,
bodyIsHtml?: boolean
) => Promise<boolean>;
isDev: () => boolean;
isSelfHost: () => boolean;
copyToClipboard: (text: string, options?: any) => void | boolean;
@ -34,7 +44,9 @@ export abstract class PlatformUtilsService {
supportsBiometric: () => Promise<boolean>;
authenticateBiometric: () => Promise<boolean>;
getDefaultSystemTheme: () => Promise<ThemeType.Light | ThemeType.Dark>;
onDefaultSystemThemeChange: (callback: ((theme: ThemeType.Light | ThemeType.Dark) => unknown)) => unknown;
onDefaultSystemThemeChange: (
callback: (theme: ThemeType.Light | ThemeType.Dark) => unknown
) => unknown;
getEffectiveTheme: () => Promise<ThemeType>;
supportsSecureStorage: () => boolean;
}

View File

@ -1,24 +1,34 @@
import { PolicyData } from '../models/data/policyData';
import { PolicyData } from "../models/data/policyData";
import { MasterPasswordPolicyOptions } from '../models/domain/masterPasswordPolicyOptions';
import { Policy } from '../models/domain/policy';
import { ResetPasswordPolicyOptions } from '../models/domain/resetPasswordPolicyOptions';
import { MasterPasswordPolicyOptions } from "../models/domain/masterPasswordPolicyOptions";
import { Policy } from "../models/domain/policy";
import { ResetPasswordPolicyOptions } from "../models/domain/resetPasswordPolicyOptions";
import { ListResponse } from '../models/response/listResponse';
import { PolicyResponse } from '../models/response/policyResponse';
import { ListResponse } from "../models/response/listResponse";
import { PolicyResponse } from "../models/response/policyResponse";
import { PolicyType } from '../enums/policyType';
import { PolicyType } from "../enums/policyType";
export abstract class PolicyService {
clearCache: () => void;
getAll: (type?: PolicyType, userId?: string) => Promise<Policy[]>;
getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise<Policy>;
replace: (policies: { [id: string]: PolicyData; }) => Promise<any>;
replace: (policies: { [id: string]: PolicyData }) => Promise<any>;
clear: (userId?: string) => Promise<any>;
getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise<MasterPasswordPolicyOptions>;
evaluateMasterPassword: (passwordStrength: number, newPassword: string,
enforcedPolicyOptions?: MasterPasswordPolicyOptions) => boolean;
getResetPasswordPolicyOptions: (policies: Policy[], orgId: string) => [ResetPasswordPolicyOptions, boolean];
evaluateMasterPassword: (
passwordStrength: number,
newPassword: string,
enforcedPolicyOptions?: MasterPasswordPolicyOptions
) => boolean;
getResetPasswordPolicyOptions: (
policies: Policy[],
orgId: string
) => [ResetPasswordPolicyOptions, boolean];
mapPoliciesFromToken: (policiesResponse: ListResponse<PolicyResponse>) => Policy[];
policyAppliesToUser: (policyType: PolicyType, policyFilter?: (policy: Policy) => boolean, userId?: string) => Promise<boolean>;
policyAppliesToUser: (
policyType: PolicyType,
policyFilter?: (policy: Policy) => boolean,
userId?: string
) => Promise<boolean>;
}

View File

@ -1,9 +1,9 @@
import { ProviderData } from '../models/data/providerData';
import { ProviderData } from "../models/data/providerData";
import { Provider } from '../models/domain/provider';
import { Provider } from "../models/domain/provider";
export abstract class ProviderService {
get: (id: string) => Promise<Provider>;
getAll: () => Promise<Provider[]>;
save: (providers: {[id: string]: ProviderData}) => Promise<any>;
save: (providers: { [id: string]: ProviderData }) => Promise<any>;
}

View File

@ -1,14 +1,16 @@
import { CipherView } from '../models/view/cipherView';
import { SendView } from '../models/view/sendView';
import { CipherView } from "../models/view/cipherView";
import { SendView } from "../models/view/sendView";
export abstract class SearchService {
indexedEntityId?: string = null;
clearIndex: () => void;
isSearchable: (query: string) => boolean;
indexCiphers: (indexedEntityGuid?: string, ciphersToIndex?: CipherView[]) => Promise<void>;
searchCiphers: (query: string,
filter?: ((cipher: CipherView) => boolean) | (((cipher: CipherView) => boolean)[]),
ciphers?: CipherView[]) => Promise<CipherView[]>;
searchCiphers: (
query: string,
filter?: ((cipher: CipherView) => boolean) | ((cipher: CipherView) => boolean)[],
ciphers?: CipherView[]
) => Promise<CipherView[]>;
searchCiphersBasic: (ciphers: CipherView[], query: string, deleted?: boolean) => CipherView[];
searchSends: (sends: SendView[], query: string) => SendView[];
}

View File

@ -1,20 +1,25 @@
import { SendData } from '../models/data/sendData';
import { SendData } from "../models/data/sendData";
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { Send } from '../models/domain/send';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { EncArrayBuffer } from "../models/domain/encArrayBuffer";
import { Send } from "../models/domain/send";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { SendView } from '../models/view/sendView';
import { SendView } from "../models/view/sendView";
export abstract class SendService {
clearCache: () => Promise<void>;
encrypt: (model: SendView, file: File | ArrayBuffer, password: string, key?: SymmetricCryptoKey) => Promise<[Send, EncArrayBuffer]>;
encrypt: (
model: SendView,
file: File | ArrayBuffer,
password: string,
key?: SymmetricCryptoKey
) => Promise<[Send, EncArrayBuffer]>;
get: (id: string) => Promise<Send>;
getAll: () => Promise<Send[]>;
getAllDecrypted: () => Promise<SendView[]>;
saveWithServer: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
upsert: (send: SendData | SendData[]) => Promise<any>;
replace: (sends: { [id: string]: SendData; }) => Promise<any>;
replace: (sends: { [id: string]: SendData }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;

Some files were not shown because too many files have changed in this diff Show More