mirror of
https://github.com/bitwarden/jslib
synced 2025-12-10 05:13:41 +00:00
Apply prettier
This commit is contained in:
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
11
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,4 +1,5 @@
|
|||||||
## Type of change
|
## Type of change
|
||||||
|
|
||||||
- [ ] Bug fix
|
- [ ] Bug fix
|
||||||
- [ ] New feature development
|
- [ ] New feature development
|
||||||
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
||||||
@@ -6,22 +7,22 @@
|
|||||||
- [ ] Other
|
- [ ] Other
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
|
|
||||||
<!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding-->
|
<!--Describe what the purpose of this PR is. For example: what bug you're fixing or what new feature you're adding-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Code changes
|
## Code changes
|
||||||
|
|
||||||
<!--Explain the changes you've made to each file or major component. This should help the reviewer understand your 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-->
|
<!--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
|
## Testing requirements
|
||||||
|
|
||||||
<!--What functionality requires testing by QA? This includes testing new behavior and regression testing-->
|
<!--What functionality requires testing by QA? This includes testing new behavior and regression testing-->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Before you submit
|
## Before you submit
|
||||||
|
|
||||||
- [ ] I have checked for **linting** errors (`npm run lint`) (required)
|
- [ ] 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)
|
- [ ] 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)
|
- [ ] This change requires a **documentation update** (notify the documentation team)
|
||||||
|
|||||||
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
|||||||
- name: Print lines of code
|
- name: Print lines of code
|
||||||
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
||||||
|
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build jslib
|
name: Build jslib
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -33,7 +32,7 @@ jobs:
|
|||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: "16"
|
||||||
|
|
||||||
- name: Install node-gyp
|
- name: Install node-gyp
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,9 +10,7 @@
|
|||||||
"name": "Jasmine Individual Test",
|
"name": "Jasmine Individual Test",
|
||||||
"program": "${workspaceRoot}\\node_modules\\jasmine\\bin\\jasmine.js",
|
"program": "${workspaceRoot}\\node_modules\\jasmine\\bin\\jasmine.js",
|
||||||
"preLaunchTask": "npm run build",
|
"preLaunchTask": "npm run build",
|
||||||
"args": [
|
"args": ["${workspaceFolder}/dist\\spec\\node\\services\\nodeCryptoFunction.service.spec.js"]
|
||||||
"${workspaceFolder}/dist\\spec\\node\\services\\nodeCryptoFunction.service.spec.js"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,11 @@ Please visit our [Community Forums](https://community.bitwarden.com/) for genera
|
|||||||
|
|
||||||
Here is how you can get involved:
|
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
|
- **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
|
||||||
* **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)
|
||||||
* **Report a bug or submit a bugfix:** Use Github issues and pull requests
|
- **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums
|
||||||
|
|
||||||
* **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
|
## Contributor Agreement
|
||||||
|
|
||||||
@@ -22,9 +18,9 @@ Please sign the [Contributor Agreement](https://cla-assistant.io/bitwarden/jslib
|
|||||||
|
|
||||||
## Pull Request Guidelines
|
## Pull Request Guidelines
|
||||||
|
|
||||||
* use `npm run lint` and fix any linting suggestions before submitting a pull request
|
- use `npm run lint` and fix any linting suggestions before submitting a pull request
|
||||||
* commit any pull requests against the `master` branch
|
- commit any pull requests against the `master` branch
|
||||||
* include a link to your Community Forums post
|
- include a link to your Community Forums post
|
||||||
|
|
||||||
# Introduction to jslib and git submodules
|
# 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)).
|
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
|
# 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.
|
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
|
## Prerequisites
|
||||||
|
|
||||||
1. git bash or other git command line
|
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:
|
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)
|
- `./<your project(s) directory>`; we'll call this `/dev` ('cause why not)
|
||||||
* jslib - `git clone https://github.com/bitwarden/jslib.git` (/dev/jslib)
|
- jslib - `git clone https://github.com/bitwarden/jslib.git` (/dev/jslib)
|
||||||
* web - `git clone --recurse-submodules https://github.com/bitwarden/web.git` (/dev/web)
|
- 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)
|
- 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)
|
- 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)
|
- 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`.
|
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
|
## 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`.
|
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 each project other than jslib, run the following:
|
||||||
|
|
||||||
* For macOS/Linux: `npm run symlink:mac`
|
- For macOS/Linux: `npm run symlink:mac`
|
||||||
* For Windows: `npm run symlink:win`
|
- 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).
|
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
|
## 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.
|
- 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.
|
- 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.
|
- 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
|
### 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`.
|
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:
|
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 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 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).
|
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`
|
4. Add your changes: `git add jslib`
|
||||||
5. Commit your changes: `git commit -m "update jslib version"`
|
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.
|
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
|
## 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:
|
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:
|
||||||
|
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -5,13 +5,14 @@
|
|||||||
Common code referenced across Bitwarden JavaScript projects.
|
Common code referenced across Bitwarden JavaScript projects.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
* [Node.js](https://nodejs.org) v16.13.1 or greater
|
|
||||||
* NPM v8
|
- [Node.js](https://nodejs.org) v16.13.1 or greater
|
||||||
* Git
|
- NPM v8
|
||||||
* node-gyp
|
- Git
|
||||||
|
- node-gyp
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
* *Microsoft Build Tools 2015* in 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/)
|
- [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.
|
either by downloading it seperately or through the Visual Studio Installer.
|
||||||
|
|||||||
@@ -1,26 +1,18 @@
|
|||||||
import {
|
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
|
||||||
Directive,
|
|
||||||
Input,
|
|
||||||
OnChanges,
|
|
||||||
SimpleChanges,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import {
|
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
|
||||||
CdkDragDrop,
|
|
||||||
moveItemInArray,
|
|
||||||
} from '@angular/cdk/drag-drop';
|
|
||||||
|
|
||||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
import { EventService } from "jslib-common/abstractions/event.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { FieldView } from 'jslib-common/models/view/fieldView';
|
import { FieldView } from "jslib-common/models/view/fieldView";
|
||||||
|
|
||||||
import { CipherType } from 'jslib-common/enums/cipherType';
|
import { CipherType } from "jslib-common/enums/cipherType";
|
||||||
import { EventType } from 'jslib-common/enums/eventType';
|
import { EventType } from "jslib-common/enums/eventType";
|
||||||
import { FieldType } from 'jslib-common/enums/fieldType';
|
import { FieldType } from "jslib-common/enums/fieldType";
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class AddEditCustomFieldsComponent implements OnChanges {
|
export class AddEditCustomFieldsComponent implements OnChanges {
|
||||||
@@ -39,11 +31,14 @@ export class AddEditCustomFieldsComponent implements OnChanges {
|
|||||||
|
|
||||||
constructor(private i18nService: I18nService, private eventService: EventService) {
|
constructor(private i18nService: I18nService, private eventService: EventService) {
|
||||||
this.addFieldTypeOptions = [
|
this.addFieldTypeOptions = [
|
||||||
{ name: i18nService.t('cfTypeText'), value: FieldType.Text },
|
{ name: i18nService.t("cfTypeText"), value: FieldType.Text },
|
||||||
{ name: i18nService.t('cfTypeHidden'), value: FieldType.Hidden },
|
{ name: i18nService.t("cfTypeHidden"), value: FieldType.Hidden },
|
||||||
{ name: i18nService.t('cfTypeBoolean'), value: FieldType.Boolean },
|
{ 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) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
@@ -80,7 +75,7 @@ export class AddEditCustomFieldsComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleFieldValue(field: FieldView) {
|
toggleFieldValue(field: FieldView) {
|
||||||
const f = (field as any);
|
const f = field as any;
|
||||||
f.showValue = !f.showValue;
|
f.showValue = !f.showValue;
|
||||||
if (this.editMode && f.showValue) {
|
if (this.editMode && f.showValue) {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
|
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
|
||||||
@@ -102,8 +97,9 @@ export class AddEditCustomFieldsComponent implements OnChanges {
|
|||||||
|
|
||||||
const options: any = [];
|
const options: any = [];
|
||||||
this.cipher.linkedFieldOptions.forEach((linkedFieldOption, id) =>
|
this.cipher.linkedFieldOptions.forEach((linkedFieldOption, id) =>
|
||||||
options.push({ name: this.i18nService.t(linkedFieldOption.i18nKey), value: id }));
|
options.push({ name: this.i18nService.t(linkedFieldOption.i18nKey), value: id })
|
||||||
this.linkedFieldOptions = options.sort(Utils.getSortFunction(this.i18nService, 'name'));
|
);
|
||||||
|
this.linkedFieldOptions = options.sort(Utils.getSortFunction(this.i18nService, "name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetCipherLinkedFields() {
|
private resetCipherLinkedFields() {
|
||||||
@@ -113,12 +109,12 @@ export class AddEditCustomFieldsComponent implements OnChanges {
|
|||||||
|
|
||||||
// Delete any Linked custom fields if the item type does not support them
|
// Delete any Linked custom fields if the item type does not support them
|
||||||
if (this.cipher.linkedFieldOptions == null) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cipher.fields
|
this.cipher.fields
|
||||||
.filter(f => f.type === FieldType.Linked)
|
.filter((f) => f.type === FieldType.Linked)
|
||||||
.forEach(f => f.linkedId = this.linkedFieldOptions[0].value);
|
.forEach((f) => (f.linkedId = this.linkedFieldOptions[0].value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,39 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { CipherRepromptType } from 'jslib-common/enums/cipherRepromptType';
|
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
|
||||||
import { CipherType } from 'jslib-common/enums/cipherType';
|
import { CipherType } from "jslib-common/enums/cipherType";
|
||||||
import { EventType } from 'jslib-common/enums/eventType';
|
import { EventType } from "jslib-common/enums/eventType";
|
||||||
import { OrganizationUserStatusType } from 'jslib-common/enums/organizationUserStatusType';
|
import { OrganizationUserStatusType } from "jslib-common/enums/organizationUserStatusType";
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
import { SecureNoteType } from 'jslib-common/enums/secureNoteType';
|
import { SecureNoteType } from "jslib-common/enums/secureNoteType";
|
||||||
import { UriMatchType } from 'jslib-common/enums/uriMatchType';
|
import { UriMatchType } from "jslib-common/enums/uriMatchType";
|
||||||
|
|
||||||
import { AuditService } from 'jslib-common/abstractions/audit.service';
|
import { AuditService } from "jslib-common/abstractions/audit.service";
|
||||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
import { CollectionService } from "jslib-common/abstractions/collection.service";
|
||||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
import { EventService } from "jslib-common/abstractions/event.service";
|
||||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
import { FolderService } from "jslib-common/abstractions/folder.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { OrganizationService } from 'jslib-common/abstractions/organization.service';
|
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
||||||
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
|
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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 { CardView } from "jslib-common/models/view/cardView";
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
import { CollectionView } from "jslib-common/models/view/collectionView";
|
||||||
import { FolderView } from 'jslib-common/models/view/folderView';
|
import { FolderView } from "jslib-common/models/view/folderView";
|
||||||
import { IdentityView } from 'jslib-common/models/view/identityView';
|
import { IdentityView } from "jslib-common/models/view/identityView";
|
||||||
import { LoginUriView } from 'jslib-common/models/view/loginUriView';
|
import { LoginUriView } from "jslib-common/models/view/loginUriView";
|
||||||
import { LoginView } from 'jslib-common/models/view/loginView';
|
import { LoginView } from "jslib-common/models/view/loginView";
|
||||||
import { SecureNoteView } from 'jslib-common/models/view/secureNoteView';
|
import { SecureNoteView } from "jslib-common/models/view/secureNoteView";
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class AddEditComponent implements OnInit {
|
export class AddEditComponent implements OnInit {
|
||||||
@@ -86,66 +80,74 @@ export class AddEditComponent implements OnInit {
|
|||||||
protected writeableCollections: CollectionView[];
|
protected writeableCollections: CollectionView[];
|
||||||
private previousCipherId: string;
|
private previousCipherId: string;
|
||||||
|
|
||||||
constructor(protected cipherService: CipherService, protected folderService: FolderService,
|
constructor(
|
||||||
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
protected cipherService: CipherService,
|
||||||
protected auditService: AuditService, protected stateService: StateService,
|
protected folderService: FolderService,
|
||||||
protected collectionService: CollectionService, protected messagingService: MessagingService,
|
protected i18nService: I18nService,
|
||||||
protected eventService: EventService, protected policyService: PolicyService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
private logService: LogService, protected passwordRepromptService: PasswordRepromptService,
|
protected auditService: AuditService,
|
||||||
private organizationService: OrganizationService) {
|
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 = [
|
this.typeOptions = [
|
||||||
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
|
{ name: i18nService.t("typeLogin"), value: CipherType.Login },
|
||||||
{ name: i18nService.t('typeCard'), value: CipherType.Card },
|
{ name: i18nService.t("typeCard"), value: CipherType.Card },
|
||||||
{ name: i18nService.t('typeIdentity'), value: CipherType.Identity },
|
{ name: i18nService.t("typeIdentity"), value: CipherType.Identity },
|
||||||
{ name: i18nService.t('typeSecureNote'), value: CipherType.SecureNote },
|
{ name: i18nService.t("typeSecureNote"), value: CipherType.SecureNote },
|
||||||
];
|
];
|
||||||
this.cardBrandOptions = [
|
this.cardBrandOptions = [
|
||||||
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
|
{ name: "-- " + i18nService.t("select") + " --", value: null },
|
||||||
{ name: 'Visa', value: 'Visa' },
|
{ name: "Visa", value: "Visa" },
|
||||||
{ name: 'Mastercard', value: 'Mastercard' },
|
{ name: "Mastercard", value: "Mastercard" },
|
||||||
{ name: 'American Express', value: 'Amex' },
|
{ name: "American Express", value: "Amex" },
|
||||||
{ name: 'Discover', value: 'Discover' },
|
{ name: "Discover", value: "Discover" },
|
||||||
{ name: 'Diners Club', value: 'Diners Club' },
|
{ name: "Diners Club", value: "Diners Club" },
|
||||||
{ name: 'JCB', value: 'JCB' },
|
{ name: "JCB", value: "JCB" },
|
||||||
{ name: 'Maestro', value: 'Maestro' },
|
{ name: "Maestro", value: "Maestro" },
|
||||||
{ name: 'UnionPay', value: 'UnionPay' },
|
{ name: "UnionPay", value: "UnionPay" },
|
||||||
{ name: i18nService.t('other'), value: 'Other' },
|
{ name: i18nService.t("other"), value: "Other" },
|
||||||
];
|
];
|
||||||
this.cardExpMonthOptions = [
|
this.cardExpMonthOptions = [
|
||||||
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
|
{ name: "-- " + i18nService.t("select") + " --", value: null },
|
||||||
{ name: '01 - ' + i18nService.t('january'), value: '1' },
|
{ name: "01 - " + i18nService.t("january"), value: "1" },
|
||||||
{ name: '02 - ' + i18nService.t('february'), value: '2' },
|
{ name: "02 - " + i18nService.t("february"), value: "2" },
|
||||||
{ name: '03 - ' + i18nService.t('march'), value: '3' },
|
{ name: "03 - " + i18nService.t("march"), value: "3" },
|
||||||
{ name: '04 - ' + i18nService.t('april'), value: '4' },
|
{ name: "04 - " + i18nService.t("april"), value: "4" },
|
||||||
{ name: '05 - ' + i18nService.t('may'), value: '5' },
|
{ name: "05 - " + i18nService.t("may"), value: "5" },
|
||||||
{ name: '06 - ' + i18nService.t('june'), value: '6' },
|
{ name: "06 - " + i18nService.t("june"), value: "6" },
|
||||||
{ name: '07 - ' + i18nService.t('july'), value: '7' },
|
{ name: "07 - " + i18nService.t("july"), value: "7" },
|
||||||
{ name: '08 - ' + i18nService.t('august'), value: '8' },
|
{ name: "08 - " + i18nService.t("august"), value: "8" },
|
||||||
{ name: '09 - ' + i18nService.t('september'), value: '9' },
|
{ name: "09 - " + i18nService.t("september"), value: "9" },
|
||||||
{ name: '10 - ' + i18nService.t('october'), value: '10' },
|
{ name: "10 - " + i18nService.t("october"), value: "10" },
|
||||||
{ name: '11 - ' + i18nService.t('november'), value: '11' },
|
{ name: "11 - " + i18nService.t("november"), value: "11" },
|
||||||
{ name: '12 - ' + i18nService.t('december'), value: '12' },
|
{ name: "12 - " + i18nService.t("december"), value: "12" },
|
||||||
];
|
];
|
||||||
this.identityTitleOptions = [
|
this.identityTitleOptions = [
|
||||||
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
|
{ name: "-- " + i18nService.t("select") + " --", value: null },
|
||||||
{ name: i18nService.t('mr'), value: i18nService.t('mr') },
|
{ name: i18nService.t("mr"), value: i18nService.t("mr") },
|
||||||
{ name: i18nService.t('mrs'), value: i18nService.t('mrs') },
|
{ name: i18nService.t("mrs"), value: i18nService.t("mrs") },
|
||||||
{ name: i18nService.t('ms'), value: i18nService.t('ms') },
|
{ name: i18nService.t("ms"), value: i18nService.t("ms") },
|
||||||
{ name: i18nService.t('dr'), value: i18nService.t('dr') },
|
{ name: i18nService.t("dr"), value: i18nService.t("dr") },
|
||||||
];
|
];
|
||||||
this.uriMatchOptions = [
|
this.uriMatchOptions = [
|
||||||
{ name: i18nService.t('defaultMatchDetection'), value: null },
|
{ name: i18nService.t("defaultMatchDetection"), value: null },
|
||||||
{ name: i18nService.t('baseDomain'), value: UriMatchType.Domain },
|
{ name: i18nService.t("baseDomain"), value: UriMatchType.Domain },
|
||||||
{ name: i18nService.t('host'), value: UriMatchType.Host },
|
{ name: i18nService.t("host"), value: UriMatchType.Host },
|
||||||
{ name: i18nService.t('startsWith'), value: UriMatchType.StartsWith },
|
{ name: i18nService.t("startsWith"), value: UriMatchType.StartsWith },
|
||||||
{ name: i18nService.t('regEx'), value: UriMatchType.RegularExpression },
|
{ name: i18nService.t("regEx"), value: UriMatchType.RegularExpression },
|
||||||
{ name: i18nService.t('exact'), value: UriMatchType.Exact },
|
{ name: i18nService.t("exact"), value: UriMatchType.Exact },
|
||||||
{ name: i18nService.t('never'), value: UriMatchType.Never },
|
{ name: i18nService.t("never"), value: UriMatchType.Never },
|
||||||
];
|
];
|
||||||
this.autofillOnPageLoadOptions = [
|
this.autofillOnPageLoadOptions = [
|
||||||
{ name: i18nService.t('autoFillOnPageLoadUseDefault'), value: null },
|
{ name: i18nService.t("autoFillOnPageLoadUseDefault"), value: null },
|
||||||
{ name: i18nService.t('autoFillOnPageLoadYes'), value: true },
|
{ name: i18nService.t("autoFillOnPageLoadYes"), value: true },
|
||||||
{ name: i18nService.t('autoFillOnPageLoadNo'), value: false },
|
{ name: i18nService.t("autoFillOnPageLoadNo"), value: false },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +167,7 @@ export class AddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const orgs = await this.organizationService.getAll();
|
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) {
|
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
|
||||||
this.ownershipOptions.push({ name: o.name, value: o.id });
|
this.ownershipOptions.push({ name: o.name, value: o.id });
|
||||||
}
|
}
|
||||||
@@ -185,12 +187,12 @@ export class AddEditComponent implements OnInit {
|
|||||||
this.editMode = true;
|
this.editMode = true;
|
||||||
if (this.cloneMode) {
|
if (this.cloneMode) {
|
||||||
this.cloneMode = true;
|
this.cloneMode = true;
|
||||||
this.title = this.i18nService.t('addItem');
|
this.title = this.i18nService.t("addItem");
|
||||||
} else {
|
} else {
|
||||||
this.title = this.i18nService.t('editItem');
|
this.title = this.i18nService.t("editItem");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.title = this.i18nService.t('addItem');
|
this.title = this.i18nService.t("addItem");
|
||||||
}
|
}
|
||||||
|
|
||||||
const addEditCipherInfo: any = await this.stateService.getAddEditCipherInfo();
|
const addEditCipherInfo: any = await this.stateService.getAddEditCipherInfo();
|
||||||
@@ -207,7 +209,7 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
// Adjust Cipher Name if Cloning
|
// Adjust Cipher Name if Cloning
|
||||||
if (this.cloneMode) {
|
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 not allowing personal ownership, update cipher's org Id to prompt downstream changes
|
||||||
if (this.cipher.organizationId == null && !this.allowPersonal) {
|
if (this.cipher.organizationId == null && !this.allowPersonal) {
|
||||||
this.cipher.organizationId = this.organizationId;
|
this.cipher.organizationId = this.organizationId;
|
||||||
@@ -230,8 +232,12 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
if (this.cipher != null && (!this.editMode || addEditCipherInfo != null || this.cloneMode)) {
|
if (this.cipher != null && (!this.editMode || addEditCipherInfo != null || this.cloneMode)) {
|
||||||
await this.organizationChanged();
|
await this.organizationChanged();
|
||||||
if (this.collectionIds != null && this.collectionIds.length > 0 && this.collections.length > 0) {
|
if (
|
||||||
this.collections.forEach(c => {
|
this.collectionIds != null &&
|
||||||
|
this.collectionIds.length > 0 &&
|
||||||
|
this.collections.length > 0
|
||||||
|
) {
|
||||||
|
this.collections.forEach((c) => {
|
||||||
if (this.collectionIds.indexOf(c.id) > -1) {
|
if (this.collectionIds.indexOf(c.id) > -1) {
|
||||||
(c as any).checked = true;
|
(c as any).checked = true;
|
||||||
}
|
}
|
||||||
@@ -253,28 +259,44 @@ export class AddEditComponent implements OnInit {
|
|||||||
return this.restore();
|
return this.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cipher.name == null || this.cipher.name === '') {
|
if (this.cipher.name == null || this.cipher.name === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('nameRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("nameRequired")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!this.editMode || this.cloneMode) && !this.allowPersonal && this.cipher.organizationId == null) {
|
if (
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
(!this.editMode || this.cloneMode) &&
|
||||||
this.i18nService.t('personalOwnershipSubmitError'));
|
!this.allowPersonal &&
|
||||||
|
this.cipher.organizationId == null
|
||||||
|
) {
|
||||||
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("personalOwnershipSubmitError")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!this.editMode || this.cloneMode) && this.cipher.type === CipherType.Login &&
|
if (
|
||||||
this.cipher.login.uris != null && this.cipher.login.uris.length === 1 &&
|
(!this.editMode || this.cloneMode) &&
|
||||||
(this.cipher.login.uris[0].uri == null || this.cipher.login.uris[0].uri === '')) {
|
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;
|
this.cipher.login.uris = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allows saving of selected collections during "Add" and "Clone" flows
|
// Allows saving of selected collections during "Add" and "Clone" flows
|
||||||
if ((!this.editMode || this.cloneMode) && this.cipher.organizationId != null) {
|
if ((!this.editMode || this.cloneMode) && this.cipher.organizationId != null) {
|
||||||
this.cipher.collectionIds = this.collections == null ? [] :
|
this.cipher.collectionIds =
|
||||||
this.collections.filter(c => (c as any).checked).map(c => c.id);
|
this.collections == null
|
||||||
|
? []
|
||||||
|
: this.collections.filter((c) => (c as any).checked).map((c) => c.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear current Cipher Id to trigger "Add" cipher flow
|
// Clear current Cipher Id to trigger "Add" cipher flow
|
||||||
@@ -287,10 +309,13 @@ export class AddEditComponent implements OnInit {
|
|||||||
this.formPromise = this.saveCipher(cipher);
|
this.formPromise = this.saveCipher(cipher);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.cipher.id = cipher.id;
|
this.cipher.id = cipher.id;
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t(this.editMode && !this.cloneMode ? 'editedItem' : 'addedItem'));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem")
|
||||||
|
);
|
||||||
this.onSavedCipher.emit(this.cipher);
|
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;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -344,8 +369,14 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
async delete(): Promise<boolean> {
|
async delete(): Promise<boolean> {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeleteItemConfirmation' : 'deleteItemConfirmation'),
|
this.i18nService.t(
|
||||||
this.i18nService.t('deleteItem'), this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation"
|
||||||
|
),
|
||||||
|
this.i18nService.t("deleteItem"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -353,10 +384,15 @@ export class AddEditComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.deletePromise = this.deleteCipher();
|
this.deletePromise = this.deleteCipher();
|
||||||
await this.deletePromise;
|
await this.deletePromise;
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem")
|
||||||
|
);
|
||||||
this.onDeletedCipher.emit(this.cipher);
|
this.onDeletedCipher.emit(this.cipher);
|
||||||
this.messagingService.send(this.cipher.isDeleted ? 'permanentlyDeletedCipher' : 'deletedCipher');
|
this.messagingService.send(
|
||||||
|
this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher"
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@@ -370,8 +406,12 @@ export class AddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('restoreItemConfirmation'), this.i18nService.t('restoreItem'),
|
this.i18nService.t("restoreItemConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("restoreItem"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -379,9 +419,9 @@ export class AddEditComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.restorePromise = this.restoreCipher();
|
this.restorePromise = this.restoreCipher();
|
||||||
await this.restorePromise;
|
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.onRestoredCipher.emit(this.cipher);
|
||||||
this.messagingService.send('restoredCipher');
|
this.messagingService.send("restoredCipher");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@@ -390,10 +430,17 @@ export class AddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async generatePassword(): Promise<boolean> {
|
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(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('overwritePasswordConfirmation'), this.i18nService.t('overwritePassword'),
|
this.i18nService.t("overwritePasswordConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'));
|
this.i18nService.t("overwritePassword"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no")
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -405,7 +452,7 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
togglePassword() {
|
togglePassword() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById('loginPassword').focus();
|
document.getElementById("loginPassword").focus();
|
||||||
if (this.editMode && this.showPassword) {
|
if (this.editMode && this.showPassword) {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
|
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
|
||||||
}
|
}
|
||||||
@@ -420,28 +467,30 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
toggleCardCode() {
|
toggleCardCode() {
|
||||||
this.showCardCode = !this.showCardCode;
|
this.showCardCode = !this.showCardCode;
|
||||||
document.getElementById('cardCode').focus();
|
document.getElementById("cardCode").focus();
|
||||||
if (this.editMode && this.showCardCode) {
|
if (this.editMode && this.showCardCode) {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
|
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleUriOptions(uri: LoginUriView) {
|
toggleUriOptions(uri: LoginUriView) {
|
||||||
const u = (uri as any);
|
const u = uri as any;
|
||||||
u.showOptions = u.showOptions == null && uri.match != null ? false : !u.showOptions;
|
u.showOptions = u.showOptions == null && uri.match != null ? false : !u.showOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
loginUriMatchChanged(uri: LoginUriView) {
|
loginUriMatchChanged(uri: LoginUriView) {
|
||||||
const u = (uri as any);
|
const u = uri as any;
|
||||||
u.showOptions = u.showOptions == null ? true : u.showOptions;
|
u.showOptions = u.showOptions == null ? true : u.showOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
async organizationChanged() {
|
async organizationChanged() {
|
||||||
if (this.writeableCollections != null) {
|
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) {
|
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);
|
const org = await this.organizationService.get(this.cipher.organizationId);
|
||||||
if (org != null) {
|
if (org != null) {
|
||||||
this.cipher.organizationUseTotp = org.useTotp;
|
this.cipher.organizationUseTotp = org.useTotp;
|
||||||
@@ -456,7 +505,11 @@ export class AddEditComponent implements OnInit {
|
|||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,10 +518,13 @@ export class AddEditComponent implements OnInit {
|
|||||||
this.checkPasswordPromise = null;
|
this.checkPasswordPromise = null;
|
||||||
|
|
||||||
if (matches > 0) {
|
if (matches > 0) {
|
||||||
this.platformUtilsService.showToast('warning', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('passwordExposed', matches.toString()));
|
"warning",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("passwordExposed", matches.toString())
|
||||||
|
);
|
||||||
} else {
|
} 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() {
|
protected async loadCollections() {
|
||||||
const allCollections = await this.collectionService.getAllDecrypted();
|
const allCollections = await this.collectionService.getAllDecrypted();
|
||||||
return allCollections.filter(c => !c.readOnly);
|
return allCollections.filter((c) => !c.readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadCipher() {
|
protected loadCipher() {
|
||||||
@@ -499,7 +555,8 @@ export class AddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected deleteCipher() {
|
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);
|
: this.cipherService.softDeleteWithServer(this.cipher.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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 { ErrorResponse } from 'jslib-common/models/response/errorResponse';
|
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
|
||||||
|
|
||||||
import { AttachmentView } from 'jslib-common/models/view/attachmentView';
|
import { AttachmentView } from "jslib-common/models/view/attachmentView";
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class AttachmentsComponent implements OnInit {
|
export class AttachmentsComponent implements OnInit {
|
||||||
@@ -32,14 +26,20 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
hasUpdatedKey: boolean;
|
hasUpdatedKey: boolean;
|
||||||
canAccessAttachments: boolean;
|
canAccessAttachments: boolean;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
deletePromises: { [id: string]: Promise<any>; } = {};
|
deletePromises: { [id: string]: Promise<any> } = {};
|
||||||
reuploadPromises: { [id: string]: Promise<any>; } = {};
|
reuploadPromises: { [id: string]: Promise<any> } = {};
|
||||||
emergencyAccessId?: string = null;
|
emergencyAccessId?: string = null;
|
||||||
|
|
||||||
constructor(protected cipherService: CipherService, protected i18nService: I18nService,
|
constructor(
|
||||||
protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
|
protected cipherService: CipherService,
|
||||||
protected apiService: ApiService, protected win: Window,
|
protected i18nService: I18nService,
|
||||||
protected logService: LogService, protected stateService: StateService) { }
|
protected cryptoService: CryptoService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected apiService: ApiService,
|
||||||
|
protected win: Window,
|
||||||
|
protected logService: LogService,
|
||||||
|
protected stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.init();
|
await this.init();
|
||||||
@@ -47,22 +47,32 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (!this.hasUpdatedKey) {
|
if (!this.hasUpdatedKey) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('updateKey'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("updateKey")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileEl = document.getElementById('file') as HTMLInputElement;
|
const fileEl = document.getElementById("file") as HTMLInputElement;
|
||||||
const files = fileEl.files;
|
const files = fileEl.files;
|
||||||
if (files == null || files.length === 0) {
|
if (files == null || files.length === 0) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('selectFile'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("selectFile")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files[0].size > 524288000) { // 500 MB
|
if (files[0].size > 524288000) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
// 500 MB
|
||||||
this.i18nService.t('maxFileSize'));
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("maxFileSize")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +80,7 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
this.formPromise = this.saveCipherAttachment(files[0]);
|
this.formPromise = this.saveCipherAttachment(files[0]);
|
||||||
this.cipherDomain = await this.formPromise;
|
this.cipherDomain = await this.formPromise;
|
||||||
this.cipher = await this.cipherDomain.decrypt();
|
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();
|
this.onUploadedAttachment.emit();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -78,9 +88,9 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
|
|
||||||
// reset file input
|
// reset file input
|
||||||
// ref: https://stackoverflow.com/a/20552042
|
// ref: https://stackoverflow.com/a/20552042
|
||||||
fileEl.type = '';
|
fileEl.type = "";
|
||||||
fileEl.type = 'file';
|
fileEl.type = "file";
|
||||||
fileEl.value = '';
|
fileEl.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(attachment: AttachmentView) {
|
async delete(attachment: AttachmentView) {
|
||||||
@@ -89,8 +99,12 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('deleteAttachmentConfirmation'), this.i18nService.t('deleteAttachment'),
|
this.i18nService.t("deleteAttachmentConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("deleteAttachment"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -98,7 +112,7 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
|
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
|
||||||
await this.deletePromises[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);
|
const i = this.cipher.attachments.indexOf(attachment);
|
||||||
if (i > -1) {
|
if (i > -1) {
|
||||||
this.cipher.attachments.splice(i, 1);
|
this.cipher.attachments.splice(i, 1);
|
||||||
@@ -112,21 +126,27 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async download(attachment: AttachmentView) {
|
async download(attachment: AttachmentView) {
|
||||||
const a = (attachment as any);
|
const a = attachment as any;
|
||||||
if (a.downloading) {
|
if (a.downloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.canAccessAttachments) {
|
if (!this.canAccessAttachments) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('premiumRequired'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('premiumRequiredDesc'));
|
"error",
|
||||||
|
this.i18nService.t("premiumRequired"),
|
||||||
|
this.i18nService.t("premiumRequiredDesc")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
try {
|
try {
|
||||||
const attachmentDownloadResponse = await this.apiService.getAttachmentData(this.cipher.id, attachment.id,
|
const attachmentDownloadResponse = await this.apiService.getAttachmentData(
|
||||||
this.emergencyAccessId);
|
this.cipher.id,
|
||||||
|
attachment.id,
|
||||||
|
this.emergencyAccessId
|
||||||
|
);
|
||||||
url = attachmentDownloadResponse.url;
|
url = attachmentDownloadResponse.url;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
|
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
|
||||||
@@ -139,21 +159,23 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.downloading = true;
|
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) {
|
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;
|
a.downloading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const buf = await response.arrayBuffer();
|
const buf = await response.arrayBuffer();
|
||||||
const key = attachment.key != null ? attachment.key :
|
const key =
|
||||||
await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
attachment.key != null
|
||||||
|
? attachment.key
|
||||||
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
||||||
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
|
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||||
}
|
}
|
||||||
|
|
||||||
a.downloading = false;
|
a.downloading = false;
|
||||||
@@ -169,23 +191,32 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
|
|
||||||
if (!this.canAccessAttachments) {
|
if (!this.canAccessAttachments) {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('premiumRequiredDesc'), this.i18nService.t('premiumRequired'),
|
this.i18nService.t("premiumRequiredDesc"),
|
||||||
this.i18nService.t('learnMore'), this.i18nService.t('cancel'));
|
this.i18nService.t("premiumRequired"),
|
||||||
|
this.i18nService.t("learnMore"),
|
||||||
|
this.i18nService.t("cancel")
|
||||||
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=purchase');
|
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=purchase");
|
||||||
}
|
}
|
||||||
} else if (!this.hasUpdatedKey) {
|
} else if (!this.hasUpdatedKey) {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('updateKey'), this.i18nService.t('featureUnavailable'),
|
this.i18nService.t("updateKey"),
|
||||||
this.i18nService.t('learnMore'), this.i18nService.t('cancel'), 'warning');
|
this.i18nService.t("featureUnavailable"),
|
||||||
|
this.i18nService.t("learnMore"),
|
||||||
|
this.i18nService.t("cancel"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (confirmed) {
|
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) {
|
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) {
|
if (attachment.key != null || a.downloading || this.reuploadPromises[attachment.id] != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -194,9 +225,9 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
this.reuploadPromises[attachment.id] = Promise.resolve().then(async () => {
|
this.reuploadPromises[attachment.id] = Promise.resolve().then(async () => {
|
||||||
// 1. Download
|
// 1. Download
|
||||||
a.downloading = true;
|
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) {
|
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;
|
a.downloading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -204,17 +235,23 @@ export class AttachmentsComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
// 2. Resave
|
// 2. Resave
|
||||||
const buf = await response.arrayBuffer();
|
const buf = await response.arrayBuffer();
|
||||||
const key = attachment.key != null ? attachment.key :
|
const key =
|
||||||
await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
attachment.key != null
|
||||||
|
? attachment.key
|
||||||
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
||||||
this.cipherDomain = await this.cipherService.saveAttachmentRawWithServer(
|
this.cipherDomain = await this.cipherService.saveAttachmentRawWithServer(
|
||||||
this.cipherDomain, attachment.fileName, decBuf, admin);
|
this.cipherDomain,
|
||||||
|
attachment.fileName,
|
||||||
|
decBuf,
|
||||||
|
admin
|
||||||
|
);
|
||||||
this.cipher = await this.cipherDomain.decrypt();
|
this.cipher = await this.cipherDomain.decrypt();
|
||||||
|
|
||||||
// 3. Delete old
|
// 3. Delete old
|
||||||
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
|
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
|
||||||
await this.deletePromises[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) {
|
if (foundAttachment.length > 0) {
|
||||||
const i = this.cipher.attachments.indexOf(foundAttachment[0]);
|
const i = this.cipher.attachments.indexOf(foundAttachment[0]);
|
||||||
if (i > -1) {
|
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();
|
this.onReuploadedAttachment.emit();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||||
}
|
}
|
||||||
|
|
||||||
a.downloading = false;
|
a.downloading = false;
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
import {
|
import { Component, Input, OnChanges, OnInit } from "@angular/core";
|
||||||
Component,
|
import { DomSanitizer } from "@angular/platform-browser";
|
||||||
Input,
|
|
||||||
OnChanges,
|
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { DomSanitizer } from '@angular/platform-browser';
|
|
||||||
|
|
||||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-avatar',
|
selector: "app-avatar",
|
||||||
template: '<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
|
template:
|
||||||
'[ngClass]="{\'rounded-circle\': circle}">',
|
'<img [src]="sanitizer.bypassSecurityTrustResourceUrl(src)" title="{{data}}" ' +
|
||||||
|
"[ngClass]=\"{'rounded-circle': circle}\">",
|
||||||
})
|
})
|
||||||
export class AvatarComponent implements OnChanges, OnInit {
|
export class AvatarComponent implements OnChanges, OnInit {
|
||||||
@Input() data: string;
|
@Input() data: string;
|
||||||
@Input() email: string;
|
@Input() email: string;
|
||||||
@Input() size = 45;
|
@Input() size = 45;
|
||||||
@Input() charCount = 2;
|
@Input() charCount = 2;
|
||||||
@Input() textColor = '#ffffff';
|
@Input() textColor = "#ffffff";
|
||||||
@Input() fontSize = 20;
|
@Input() fontSize = 20;
|
||||||
@Input() fontWeight = 300;
|
@Input() fontWeight = 300;
|
||||||
@Input() dynamic = false;
|
@Input() dynamic = false;
|
||||||
@@ -29,8 +25,11 @@ export class AvatarComponent implements OnChanges, OnInit {
|
|||||||
|
|
||||||
src: string;
|
src: string;
|
||||||
|
|
||||||
constructor(public sanitizer: DomSanitizer, private cryptoFunctionService: CryptoFunctionService,
|
constructor(
|
||||||
private stateService: StateService) { }
|
public sanitizer: DomSanitizer,
|
||||||
|
private cryptoFunctionService: CryptoFunctionService,
|
||||||
|
private stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this.dynamic) {
|
if (!this.dynamic) {
|
||||||
@@ -47,9 +46,12 @@ export class AvatarComponent implements OnChanges, OnInit {
|
|||||||
private async generate() {
|
private async generate() {
|
||||||
const enableGravatars = await this.stateService.getEnableGravitars();
|
const enableGravatars = await this.stateService.getEnableGravitars();
|
||||||
if (enableGravatars && this.email != null) {
|
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();
|
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 {
|
} else {
|
||||||
let chars: string = null;
|
let chars: string = null;
|
||||||
const upperData = this.data.toUpperCase();
|
const upperData = this.data.toUpperCase();
|
||||||
@@ -70,9 +72,9 @@ export class AvatarComponent implements OnChanges, OnInit {
|
|||||||
const color = this.stringToColor(upperData);
|
const color = this.stringToColor(upperData);
|
||||||
const svg = this.getSvg(this.size, color);
|
const svg = this.getSvg(this.size, color);
|
||||||
svg.appendChild(charObj);
|
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)));
|
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
|
// tslint:disable-next-line
|
||||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
}
|
}
|
||||||
let color = '#';
|
let color = "#";
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
const value = (hash >> (i * 8)) & 0xFF;
|
const value = (hash >> (i * 8)) & 0xff;
|
||||||
color += ('00' + value.toString(16)).substr(-2);
|
color += ("00" + value.toString(16)).substr(-2);
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFirstLetters(data: string, count: number): string {
|
private getFirstLetters(data: string, count: number): string {
|
||||||
const parts = data.split(' ');
|
const parts = data.split(" ");
|
||||||
if (parts.length > 1) {
|
if (parts.length > 1) {
|
||||||
let text = '';
|
let text = "";
|
||||||
for (let i = 0; i < count; i++) {
|
for (let i = 0; i < count; i++) {
|
||||||
text += this.unicodeSafeSubstring(parts[i], 1);
|
text += this.unicodeSafeSubstring(parts[i], 1);
|
||||||
}
|
}
|
||||||
@@ -104,35 +106,38 @@ export class AvatarComponent implements OnChanges, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSvg(size: number, color: string): HTMLElement {
|
private getSvg(size: number, color: string): HTMLElement {
|
||||||
const svgTag = window.document.createElement('svg');
|
const svgTag = window.document.createElement("svg");
|
||||||
svgTag.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
|
svgTag.setAttribute("xmlns", "http://www.w3.org/2000/svg");
|
||||||
svgTag.setAttribute('pointer-events', 'none');
|
svgTag.setAttribute("pointer-events", "none");
|
||||||
svgTag.setAttribute('width', size.toString());
|
svgTag.setAttribute("width", size.toString());
|
||||||
svgTag.setAttribute('height', size.toString());
|
svgTag.setAttribute("height", size.toString());
|
||||||
svgTag.style.backgroundColor = color;
|
svgTag.style.backgroundColor = color;
|
||||||
svgTag.style.width = size + 'px';
|
svgTag.style.width = size + "px";
|
||||||
svgTag.style.height = size + 'px';
|
svgTag.style.height = size + "px";
|
||||||
return svgTag;
|
return svgTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCharText(character: string): HTMLElement {
|
private getCharText(character: string): HTMLElement {
|
||||||
const textTag = window.document.createElement('text');
|
const textTag = window.document.createElement("text");
|
||||||
textTag.setAttribute('text-anchor', 'middle');
|
textTag.setAttribute("text-anchor", "middle");
|
||||||
textTag.setAttribute('y', '50%');
|
textTag.setAttribute("y", "50%");
|
||||||
textTag.setAttribute('x', '50%');
|
textTag.setAttribute("x", "50%");
|
||||||
textTag.setAttribute('dy', '0.35em');
|
textTag.setAttribute("dy", "0.35em");
|
||||||
textTag.setAttribute('pointer-events', 'auto');
|
textTag.setAttribute("pointer-events", "auto");
|
||||||
textTag.setAttribute('fill', this.textColor);
|
textTag.setAttribute("fill", this.textColor);
|
||||||
textTag.setAttribute('font-family', '"Open Sans","Helvetica Neue",Helvetica,Arial,' +
|
textTag.setAttribute(
|
||||||
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"');
|
"font-family",
|
||||||
|
'"Open Sans","Helvetica Neue",Helvetica,Arial,' +
|
||||||
|
'sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"'
|
||||||
|
);
|
||||||
textTag.textContent = character;
|
textTag.textContent = character;
|
||||||
textTag.style.fontWeight = this.fontWeight.toString();
|
textTag.style.fontWeight = this.fontWeight.toString();
|
||||||
textTag.style.fontSize = this.fontSize + 'px';
|
textTag.style.fontSize = this.fontSize + "px";
|
||||||
return textTag;
|
return textTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unicodeSafeSubstring(str: string, count: number) {
|
private unicodeSafeSubstring(str: string, count: number) {
|
||||||
const characters = str.match(/./ug);
|
const characters = str.match(/./gu);
|
||||||
return characters != null ? characters.slice(0, count).join('') : '';
|
return characters != null ? characters.slice(0, count).join("") : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<div #callout class="callout callout-{{calloutStyle}}" [ngClass]="{'clickable': clickable}"
|
<div
|
||||||
[attr.role]="useAlertRole ? 'alert' : null">
|
#callout
|
||||||
|
class="callout callout-{{ calloutStyle }}"
|
||||||
|
[ngClass]="{ clickable: clickable }"
|
||||||
|
[attr.role]="useAlertRole ? 'alert' : null"
|
||||||
|
>
|
||||||
<h3 class="callout-heading" *ngIf="title">
|
<h3 class="callout-heading" *ngIf="title">
|
||||||
<i class="fa {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
|
<i class="fa {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
@@ -8,19 +12,23 @@
|
|||||||
{{ enforcedPolicyMessage }}
|
{{ enforcedPolicyMessage }}
|
||||||
<ul>
|
<ul>
|
||||||
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
|
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
|
||||||
{{'policyInEffectMinComplexity' | i18n : getPasswordScoreAlertDisplay()}}
|
{{ "policyInEffectMinComplexity" | i18n: getPasswordScoreAlertDisplay() }}
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
|
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
|
||||||
{{'policyInEffectMinLength' | i18n : enforcedPolicyOptions?.minLength.toString()}}
|
{{ "policyInEffectMinLength" | i18n: enforcedPolicyOptions?.minLength.toString() }}
|
||||||
</li>
|
</li>
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireUpper">
|
<li *ngIf="enforcedPolicyOptions?.requireUpper">
|
||||||
{{'policyInEffectUppercase' | i18n}}</li>
|
{{ "policyInEffectUppercase" | i18n }}
|
||||||
|
</li>
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireLower">
|
<li *ngIf="enforcedPolicyOptions?.requireLower">
|
||||||
{{'policyInEffectLowercase' | i18n}}</li>
|
{{ "policyInEffectLowercase" | i18n }}
|
||||||
|
</li>
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
|
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
|
||||||
{{'policyInEffectNumbers' | i18n}}</li>
|
{{ "policyInEffectNumbers" | i18n }}
|
||||||
|
</li>
|
||||||
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
|
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
|
||||||
{{'policyInEffectSpecial' | i18n : '!@#$%^&*'}}</li>
|
{{ "policyInEffectSpecial" | i18n: "!@#$%^&*" }}
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
import {
|
import { Component, Input, OnInit } from "@angular/core";
|
||||||
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({
|
@Component({
|
||||||
selector: 'app-callout',
|
selector: "app-callout",
|
||||||
templateUrl: 'callout.component.html',
|
templateUrl: "callout.component.html",
|
||||||
})
|
})
|
||||||
export class CalloutComponent implements OnInit {
|
export class CalloutComponent implements OnInit {
|
||||||
@Input() type = 'info';
|
@Input() type = "info";
|
||||||
@Input() icon: string;
|
@Input() icon: string;
|
||||||
@Input() title: string;
|
@Input() title: string;
|
||||||
@Input() clickable: boolean;
|
@Input() clickable: boolean;
|
||||||
@@ -29,55 +25,55 @@ export class CalloutComponent implements OnInit {
|
|||||||
this.calloutStyle = this.type;
|
this.calloutStyle = this.type;
|
||||||
|
|
||||||
if (this.enforcedPolicyMessage === undefined) {
|
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 === "warning" || this.type === "danger") {
|
||||||
if (this.type === 'danger') {
|
if (this.type === "danger") {
|
||||||
this.calloutStyle = 'danger';
|
this.calloutStyle = "danger";
|
||||||
}
|
}
|
||||||
if (this.title === undefined) {
|
if (this.title === undefined) {
|
||||||
this.title = this.i18nService.t('warning');
|
this.title = this.i18nService.t("warning");
|
||||||
}
|
}
|
||||||
if (this.icon === undefined) {
|
if (this.icon === undefined) {
|
||||||
this.icon = 'fa-warning';
|
this.icon = "fa-warning";
|
||||||
}
|
}
|
||||||
} else if (this.type === 'error') {
|
} else if (this.type === "error") {
|
||||||
this.calloutStyle = 'danger';
|
this.calloutStyle = "danger";
|
||||||
if (this.title === undefined) {
|
if (this.title === undefined) {
|
||||||
this.title = this.i18nService.t('error');
|
this.title = this.i18nService.t("error");
|
||||||
}
|
}
|
||||||
if (this.icon === undefined) {
|
if (this.icon === undefined) {
|
||||||
this.icon = 'fa-bolt';
|
this.icon = "fa-bolt";
|
||||||
}
|
}
|
||||||
} else if (this.type === 'tip') {
|
} else if (this.type === "tip") {
|
||||||
this.calloutStyle = 'success';
|
this.calloutStyle = "success";
|
||||||
if (this.title === undefined) {
|
if (this.title === undefined) {
|
||||||
this.title = this.i18nService.t('tip');
|
this.title = this.i18nService.t("tip");
|
||||||
}
|
}
|
||||||
if (this.icon === undefined) {
|
if (this.icon === undefined) {
|
||||||
this.icon = 'fa-lightbulb-o';
|
this.icon = "fa-lightbulb-o";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getPasswordScoreAlertDisplay() {
|
getPasswordScoreAlertDisplay() {
|
||||||
if (this.enforcedPolicyOptions == null) {
|
if (this.enforcedPolicyOptions == null) {
|
||||||
return '';
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
let str: string;
|
let str: string;
|
||||||
switch (this.enforcedPolicyOptions.minComplexity) {
|
switch (this.enforcedPolicyOptions.minComplexity) {
|
||||||
case 4:
|
case 4:
|
||||||
str = this.i18nService.t('strong');
|
str = this.i18nService.t("strong");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
str = this.i18nService.t('good');
|
str = this.i18nService.t("good");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
str = this.i18nService.t('weak');
|
str = this.i18nService.t("weak");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return str + ' (' + this.enforcedPolicyOptions.minComplexity + ')';
|
return str + " (" + this.enforcedPolicyOptions.minComplexity + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Directive()
|
||||||
export abstract class CaptchaProtectedComponent {
|
export abstract class CaptchaProtectedComponent {
|
||||||
@@ -14,19 +14,27 @@ export abstract class CaptchaProtectedComponent {
|
|||||||
captchaToken: string = null;
|
captchaToken: string = null;
|
||||||
captcha: CaptchaIFrame;
|
captcha: CaptchaIFrame;
|
||||||
|
|
||||||
constructor(protected environmentService: EnvironmentService, protected i18nService: I18nService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService) { }
|
protected environmentService: EnvironmentService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService
|
||||||
|
) {}
|
||||||
|
|
||||||
async setupCaptcha() {
|
async setupCaptcha() {
|
||||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||||
|
|
||||||
this.captcha = new CaptchaIFrame(window, webVaultUrl,
|
this.captcha = new CaptchaIFrame(
|
||||||
this.i18nService, (token: string) => {
|
window,
|
||||||
|
webVaultUrl,
|
||||||
|
this.i18nService,
|
||||||
|
(token: string) => {
|
||||||
this.captchaToken = token;
|
this.captchaToken = token;
|
||||||
}, (error: string) => {
|
},
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), error);
|
(error: string) => {
|
||||||
}, (info: string) => {
|
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), error);
|
||||||
this.platformUtilsService.showToast('info', this.i18nService.t('info'), info);
|
},
|
||||||
|
(info: string) => {
|
||||||
|
this.platformUtilsService.showToast("info", this.i18nService.t("info"), info);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -35,7 +43,7 @@ export abstract class CaptchaProtectedComponent {
|
|||||||
return !Utils.isNullOrWhitespace(this.captchaSiteKey);
|
return !Utils.isNullOrWhitespace(this.captchaSiteKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected handleCaptchaRequired(response: { captchaSiteKey: string; }): boolean {
|
protected handleCaptchaRequired(response: { captchaSiteKey: string }): boolean {
|
||||||
if (Utils.isNullOrWhitespace(response.captchaSiteKey)) {
|
if (Utils.isNullOrWhitespace(response.captchaSiteKey)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
import { EncString } from 'jslib-common/models/domain/encString';
|
import { EncString } from "jslib-common/models/domain/encString";
|
||||||
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
|
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
|
||||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { KdfType } from 'jslib-common/enums/kdfType';
|
import { KdfType } from "jslib-common/enums/kdfType";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class ChangePasswordComponent implements OnInit {
|
export class ChangePasswordComponent implements OnInit {
|
||||||
@@ -28,10 +28,15 @@ export class ChangePasswordComponent implements OnInit {
|
|||||||
|
|
||||||
private masterPasswordStrengthTimeout: any;
|
private masterPasswordStrengthTimeout: any;
|
||||||
|
|
||||||
constructor(protected i18nService: I18nService, protected cryptoService: CryptoService,
|
constructor(
|
||||||
protected messagingService: MessagingService, protected passwordGenerationService: PasswordGenerationService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService, protected policyService: PolicyService,
|
protected cryptoService: CryptoService,
|
||||||
protected stateService: StateService) { }
|
protected messagingService: MessagingService,
|
||||||
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected policyService: PolicyService,
|
||||||
|
protected stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.email = await this.stateService.getEmail();
|
this.email = await this.stateService.getEmail();
|
||||||
@@ -39,11 +44,11 @@ export class ChangePasswordComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (!await this.strongPassword()) {
|
if (!(await this.strongPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await this.setupSubmitActions()) {
|
if (!(await this.setupSubmitActions())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,8 +59,12 @@ export class ChangePasswordComponent implements OnInit {
|
|||||||
if (this.kdfIterations == null) {
|
if (this.kdfIterations == null) {
|
||||||
this.kdfIterations = await this.stateService.getKdfIterations();
|
this.kdfIterations = await this.stateService.getKdfIterations();
|
||||||
}
|
}
|
||||||
const key = await this.cryptoService.makeKey(this.masterPassword, email.trim().toLowerCase(),
|
const key = await this.cryptoService.makeKey(
|
||||||
this.kdf, this.kdfIterations);
|
this.masterPassword,
|
||||||
|
email.trim().toLowerCase(),
|
||||||
|
this.kdf,
|
||||||
|
this.kdfIterations
|
||||||
|
);
|
||||||
const masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, key);
|
const masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, key);
|
||||||
|
|
||||||
let encKey: [SymmetricCryptoKey, EncString] = null;
|
let encKey: [SymmetricCryptoKey, EncString] = null;
|
||||||
@@ -75,45 +84,69 @@ export class ChangePasswordComponent implements OnInit {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
|
async performSubmitActions(
|
||||||
encKey: [SymmetricCryptoKey, EncString]) {
|
masterPasswordHash: string,
|
||||||
|
key: SymmetricCryptoKey,
|
||||||
|
encKey: [SymmetricCryptoKey, EncString]
|
||||||
|
) {
|
||||||
// Override in sub-class
|
// Override in sub-class
|
||||||
}
|
}
|
||||||
|
|
||||||
async strongPassword(): Promise<boolean> {
|
async strongPassword(): Promise<boolean> {
|
||||||
if (this.masterPassword == null || this.masterPassword === '') {
|
if (this.masterPassword == null || this.masterPassword === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassRequired")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.masterPassword.length < 8) {
|
if (this.masterPassword.length < 8) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassLength'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassLength")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.masterPassword !== this.masterPasswordRetype) {
|
if (this.masterPassword !== this.masterPasswordRetype) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassDoesntMatch'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassDoesntMatch")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
|
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||||
this.getPasswordStrengthUserInput());
|
this.masterPassword,
|
||||||
|
this.getPasswordStrengthUserInput()
|
||||||
|
);
|
||||||
|
|
||||||
if (this.enforcedPolicyOptions != null &&
|
if (
|
||||||
|
this.enforcedPolicyOptions != null &&
|
||||||
!this.policyService.evaluateMasterPassword(
|
!this.policyService.evaluateMasterPassword(
|
||||||
strengthResult.score,
|
strengthResult.score,
|
||||||
this.masterPassword,
|
this.masterPassword,
|
||||||
this.enforcedPolicyOptions)) {
|
this.enforcedPolicyOptions
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
)
|
||||||
this.i18nService.t('masterPasswordPolicyRequirementsNotMet'));
|
) {
|
||||||
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPasswordPolicyRequirementsNotMet")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strengthResult != null && strengthResult.score < 3) {
|
if (strengthResult != null && strengthResult.score < 3) {
|
||||||
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
|
const result = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
|
this.i18nService.t("weakMasterPasswordDesc"),
|
||||||
'warning');
|
this.i18nService.t("weakMasterPassword"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -127,25 +160,37 @@ export class ChangePasswordComponent implements OnInit {
|
|||||||
clearTimeout(this.masterPasswordStrengthTimeout);
|
clearTimeout(this.masterPasswordStrengthTimeout);
|
||||||
}
|
}
|
||||||
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
||||||
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
|
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||||
this.getPasswordStrengthUserInput());
|
this.masterPassword,
|
||||||
|
this.getPasswordStrengthUserInput()
|
||||||
|
);
|
||||||
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
async logOut() {
|
async logOut() {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('logOutConfirmation'),
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('logOut'), this.i18nService.t('logOut'), this.i18nService.t('cancel'));
|
this.i18nService.t("logOutConfirmation"),
|
||||||
|
this.i18nService.t("logOut"),
|
||||||
|
this.i18nService.t("logOut"),
|
||||||
|
this.i18nService.t("cancel")
|
||||||
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.messagingService.send('logout');
|
this.messagingService.send("logout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPasswordStrengthUserInput() {
|
private getPasswordStrengthUserInput() {
|
||||||
let userInput: string[] = [];
|
let userInput: string[] = [];
|
||||||
const atPosition = this.email.indexOf('@');
|
const atPosition = this.email.indexOf("@");
|
||||||
if (atPosition > -1) {
|
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;
|
return userInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, Output } from "@angular/core";
|
||||||
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()
|
@Directive()
|
||||||
export class CiphersComponent {
|
export class CiphersComponent {
|
||||||
@@ -87,9 +82,13 @@ export class CiphersComponent {
|
|||||||
return !this.searchPending && this.searchService.isSearchable(this.searchText);
|
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[]) {
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
import { CollectionService } from "jslib-common/abstractions/collection.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
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()
|
@Directive()
|
||||||
export class CollectionsComponent implements OnInit {
|
export class CollectionsComponent implements OnInit {
|
||||||
@@ -30,8 +24,13 @@ export class CollectionsComponent implements OnInit {
|
|||||||
|
|
||||||
protected cipherDomain: Cipher;
|
protected cipherDomain: Cipher;
|
||||||
|
|
||||||
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected i18nService: I18nService, protected cipherService: CipherService, private logService: LogService) { }
|
protected collectionService: CollectionService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected cipherService: CipherService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.load();
|
await this.load();
|
||||||
@@ -43,9 +42,9 @@ export class CollectionsComponent implements OnInit {
|
|||||||
this.cipher = await this.cipherDomain.decrypt();
|
this.cipher = await this.cipherDomain.decrypt();
|
||||||
this.collections = await this.loadCollections();
|
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) {
|
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;
|
(c as any).checked = this.collectionIds != null && this.collectionIds.indexOf(c.id) > -1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -53,11 +52,14 @@ export class CollectionsComponent implements OnInit {
|
|||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
const selectedCollectionIds = this.collections
|
const selectedCollectionIds = this.collections
|
||||||
.filter(c => !!(c as any).checked)
|
.filter((c) => !!(c as any).checked)
|
||||||
.map(c => c.id);
|
.map((c) => c.id);
|
||||||
if (!this.allowSelectNone && selectedCollectionIds.length === 0) {
|
if (!this.allowSelectNone && selectedCollectionIds.length === 0) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('selectOneCollection'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("selectOneCollection")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cipherDomain.collectionIds = selectedCollectionIds;
|
this.cipherDomain.collectionIds = selectedCollectionIds;
|
||||||
@@ -65,7 +67,7 @@ export class CollectionsComponent implements OnInit {
|
|||||||
this.formPromise = this.saveCollections();
|
this.formPromise = this.saveCollections();
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.onSavedCollections.emit();
|
this.onSavedCollections.emit();
|
||||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('editedItem'));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("editedItem"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@@ -81,7 +83,9 @@ export class CollectionsComponent implements OnInit {
|
|||||||
|
|
||||||
protected async loadCollections() {
|
protected async loadCollections() {
|
||||||
const allCollections = await this.collectionService.getAllDecrypted();
|
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() {
|
protected saveCollections() {
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class EnvironmentComponent {
|
export class EnvironmentComponent {
|
||||||
@@ -20,17 +16,19 @@ export class EnvironmentComponent {
|
|||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
showCustom = false;
|
showCustom = false;
|
||||||
|
|
||||||
constructor(protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
|
constructor(
|
||||||
protected i18nService: I18nService) {
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected environmentService: EnvironmentService,
|
||||||
|
protected i18nService: I18nService
|
||||||
|
) {
|
||||||
const urls = this.environmentService.getUrls();
|
const urls = this.environmentService.getUrls();
|
||||||
|
|
||||||
this.baseUrl = urls.base || '';
|
this.baseUrl = urls.base || "";
|
||||||
this.webVaultUrl = urls.webVault || '';
|
this.webVaultUrl = urls.webVault || "";
|
||||||
this.apiUrl = urls.api || '';
|
this.apiUrl = urls.api || "";
|
||||||
this.identityUrl = urls.identity || '';
|
this.identityUrl = urls.identity || "";
|
||||||
this.iconsUrl = urls.icons || '';
|
this.iconsUrl = urls.icons || "";
|
||||||
this.notificationsUrl = urls.notifications || '';
|
this.notificationsUrl = urls.notifications || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
@@ -51,7 +49,7 @@ export class EnvironmentComponent {
|
|||||||
this.iconsUrl = resUrls.icons;
|
this.iconsUrl = resUrls.icons;
|
||||||
this.notificationsUrl = resUrls.notifications;
|
this.notificationsUrl = resUrls.notifications;
|
||||||
|
|
||||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('environmentSaved'));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("environmentSaved"));
|
||||||
this.saved();
|
this.saved();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,17 @@
|
|||||||
import {
|
import { Directive, EventEmitter, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
import { FormBuilder } from "@angular/forms";
|
||||||
EventEmitter,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { FormBuilder } from '@angular/forms';
|
|
||||||
|
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
import { EventService } from "jslib-common/abstractions/event.service";
|
||||||
import { ExportService } from 'jslib-common/abstractions/export.service';
|
import { ExportService } from "jslib-common/abstractions/export.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.service';
|
import { UserVerificationService } from "jslib-common/abstractions/userVerification.service";
|
||||||
|
|
||||||
import { EventType } from 'jslib-common/enums/eventType';
|
import { EventType } from "jslib-common/enums/eventType";
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class ExportComponent implements OnInit {
|
export class ExportComponent implements OnInit {
|
||||||
@@ -26,40 +21,53 @@ export class ExportComponent implements OnInit {
|
|||||||
disabledByPolicy: boolean = false;
|
disabledByPolicy: boolean = false;
|
||||||
|
|
||||||
exportForm = this.fb.group({
|
exportForm = this.fb.group({
|
||||||
format: ['json'],
|
format: ["json"],
|
||||||
secret: [''],
|
secret: [""],
|
||||||
});
|
});
|
||||||
|
|
||||||
formatOptions = [
|
formatOptions = [
|
||||||
{ name: '.json', value: 'json' },
|
{ name: ".json", value: "json" },
|
||||||
{ name: '.csv', value: 'csv' },
|
{ name: ".csv", value: "csv" },
|
||||||
{ name: '.json (Encrypted)', value: 'encrypted_json' },
|
{ name: ".json (Encrypted)", value: "encrypted_json" },
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(protected cryptoService: CryptoService, protected i18nService: I18nService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, protected exportService: ExportService,
|
protected cryptoService: CryptoService,
|
||||||
protected eventService: EventService, private policyService: PolicyService, protected win: Window,
|
protected i18nService: I18nService,
|
||||||
private logService: LogService, private userVerificationService: UserVerificationService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
private fb: FormBuilder) { }
|
protected exportService: ExportService,
|
||||||
|
protected eventService: EventService,
|
||||||
|
private policyService: PolicyService,
|
||||||
|
protected win: Window,
|
||||||
|
private logService: LogService,
|
||||||
|
private userVerificationService: UserVerificationService,
|
||||||
|
private fb: FormBuilder
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.checkExportDisabled();
|
await this.checkExportDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkExportDisabled() {
|
async checkExportDisabled() {
|
||||||
this.disabledByPolicy = await this.policyService.policyAppliesToUser(PolicyType.DisablePersonalVaultExport);
|
this.disabledByPolicy = await this.policyService.policyAppliesToUser(
|
||||||
|
PolicyType.DisablePersonalVaultExport
|
||||||
|
);
|
||||||
if (this.disabledByPolicy) {
|
if (this.disabledByPolicy) {
|
||||||
this.exportForm.disable();
|
this.exportForm.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get encryptedFormat() {
|
get encryptedFormat() {
|
||||||
return this.format === 'encrypted_json';
|
return this.format === "encrypted_json";
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.disabledByPolicy) {
|
if (this.disabledByPolicy) {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('personalVaultExportPolicyInEffect'));
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("personalVaultExportPolicyInEffect")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,11 +76,11 @@ export class ExportComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = this.exportForm.get('secret').value;
|
const secret = this.exportForm.get("secret").value;
|
||||||
try {
|
try {
|
||||||
await this.userVerificationService.verifyUser(secret);
|
await this.userVerificationService.verifyUser(secret);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
|
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +90,7 @@ export class ExportComponent implements OnInit {
|
|||||||
this.downloadFile(data);
|
this.downloadFile(data);
|
||||||
this.saved();
|
this.saved();
|
||||||
await this.collectEvent();
|
await this.collectEvent();
|
||||||
this.exportForm.get('secret').setValue('');
|
this.exportForm.get("secret").setValue("");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
}
|
}
|
||||||
@@ -91,16 +99,24 @@ export class ExportComponent implements OnInit {
|
|||||||
async warningDialog() {
|
async warningDialog() {
|
||||||
if (this.encryptedFormat) {
|
if (this.encryptedFormat) {
|
||||||
return await this.platformUtilsService.showDialog(
|
return await this.platformUtilsService.showDialog(
|
||||||
'<p>' + this.i18nService.t('encExportKeyWarningDesc') +
|
"<p>" +
|
||||||
'<p>' + this.i18nService.t('encExportAccountWarningDesc'),
|
this.i18nService.t("encExportKeyWarningDesc") +
|
||||||
this.i18nService.t('confirmVaultExport'), this.i18nService.t('exportVault'),
|
"<p>" +
|
||||||
this.i18nService.t('cancel'), 'warning',
|
this.i18nService.t("encExportAccountWarningDesc"),
|
||||||
true);
|
this.i18nService.t("confirmVaultExport"),
|
||||||
|
this.i18nService.t("exportVault"),
|
||||||
|
this.i18nService.t("cancel"),
|
||||||
|
"warning",
|
||||||
|
true
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return await this.platformUtilsService.showDialog(
|
return await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('exportWarningDesc'),
|
this.i18nService.t("exportWarningDesc"),
|
||||||
this.i18nService.t('confirmVaultExport'), this.i18nService.t('exportVault'),
|
this.i18nService.t("confirmVaultExport"),
|
||||||
this.i18nService.t('cancel'), 'warning');
|
this.i18nService.t("exportVault"),
|
||||||
|
this.i18nService.t("cancel"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,13 +130,13 @@ export class ExportComponent implements OnInit {
|
|||||||
|
|
||||||
protected getFileName(prefix?: string) {
|
protected getFileName(prefix?: string) {
|
||||||
let extension = this.format;
|
let extension = this.format;
|
||||||
if (this.format === 'encrypted_json') {
|
if (this.format === "encrypted_json") {
|
||||||
if (prefix == null) {
|
if (prefix == null) {
|
||||||
prefix = 'encrypted';
|
prefix = "encrypted";
|
||||||
} else {
|
} else {
|
||||||
prefix = 'encrypted_' + prefix;
|
prefix = "encrypted_" + prefix;
|
||||||
}
|
}
|
||||||
extension = 'json';
|
extension = "json";
|
||||||
}
|
}
|
||||||
return this.exportService.getFileName(prefix, extension);
|
return this.exportService.getFileName(prefix, extension);
|
||||||
}
|
}
|
||||||
@@ -130,11 +146,11 @@ export class ExportComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get format() {
|
get format() {
|
||||||
return this.exportForm.get('format').value;
|
return this.exportForm.get("format").value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private downloadFile(csv: string): void {
|
private downloadFile(csv: string): void {
|
||||||
const fileName = this.getFileName();
|
const fileName = this.getFileName();
|
||||||
this.platformUtilsService.saveFile(this.win, csv, { type: 'text/plain' }, fileName);
|
this.platformUtilsService.saveFile(this.win, csv, { type: "text/plain" }, fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
import { FolderService } from "jslib-common/abstractions/folder.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Directive()
|
||||||
export class FolderAddEditComponent implements OnInit {
|
export class FolderAddEditComponent implements OnInit {
|
||||||
@@ -25,17 +19,24 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
deletePromise: Promise<any>;
|
deletePromise: Promise<any>;
|
||||||
|
|
||||||
constructor(protected folderService: FolderService, protected i18nService: I18nService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, private logService: LogService) { }
|
protected folderService: FolderService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.init();
|
await this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit(): Promise<boolean> {
|
async submit(): Promise<boolean> {
|
||||||
if (this.folder.name == null || this.folder.name === '') {
|
if (this.folder.name == null || this.folder.name === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('nameRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("nameRequired")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,8 +44,11 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
const folder = await this.folderService.encrypt(this.folder);
|
const folder = await this.folderService.encrypt(this.folder);
|
||||||
this.formPromise = this.folderService.saveWithServer(folder);
|
this.formPromise = this.folderService.saveWithServer(folder);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t(this.editMode ? 'editedFolder' : 'addedFolder'));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder")
|
||||||
|
);
|
||||||
this.onSavedFolder.emit(this.folder);
|
this.onSavedFolder.emit(this.folder);
|
||||||
return true;
|
return true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -56,8 +60,12 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
|
|
||||||
async delete(): Promise<boolean> {
|
async delete(): Promise<boolean> {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('deleteFolderConfirmation'), this.i18nService.t('deleteFolder'),
|
this.i18nService.t("deleteFolderConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("deleteFolder"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -65,7 +73,7 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.deletePromise = this.folderService.deleteWithServer(this.folder.id);
|
this.deletePromise = this.folderService.deleteWithServer(this.folder.id);
|
||||||
await this.deletePromise;
|
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);
|
this.onDeletedFolder.emit(this.folder);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -79,11 +87,11 @@ export class FolderAddEditComponent implements OnInit {
|
|||||||
|
|
||||||
if (this.editMode) {
|
if (this.editMode) {
|
||||||
this.editMode = true;
|
this.editMode = true;
|
||||||
this.title = this.i18nService.t('editFolder');
|
this.title = this.i18nService.t("editFolder");
|
||||||
const folder = await this.folderService.get(this.folderId);
|
const folder = await this.folderService.get(this.folderId);
|
||||||
this.folder = await folder.decrypt();
|
this.folder = await folder.decrypt();
|
||||||
} else {
|
} else {
|
||||||
this.title = this.i18nService.t('addFolder');
|
this.title = this.i18nService.t("addFolder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, Output } from "@angular/core";
|
||||||
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 { CollectionView } from "jslib-common/models/view/collectionView";
|
||||||
import { FolderView } from 'jslib-common/models/view/folderView';
|
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 { CollectionService } from "jslib-common/abstractions/collection.service";
|
||||||
import { FolderService } from 'jslib-common/abstractions/folder.service';
|
import { FolderService } from "jslib-common/abstractions/folder.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class GroupingsComponent {
|
export class GroupingsComponent {
|
||||||
@@ -48,8 +43,11 @@ export class GroupingsComponent {
|
|||||||
|
|
||||||
private collapsedGroupings: Set<string>;
|
private collapsedGroupings: Set<string>;
|
||||||
|
|
||||||
constructor(protected collectionService: CollectionService, protected folderService: FolderService,
|
constructor(
|
||||||
protected stateService: StateService) { }
|
protected collectionService: CollectionService,
|
||||||
|
protected folderService: FolderService,
|
||||||
|
protected stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async load(setLoaded = true) {
|
async load(setLoaded = true) {
|
||||||
const collapsedGroupings = await this.stateService.getCollapsedGroupings();
|
const collapsedGroupings = await this.stateService.getCollapsedGroupings();
|
||||||
@@ -73,7 +71,7 @@ export class GroupingsComponent {
|
|||||||
}
|
}
|
||||||
const collections = await this.collectionService.getAllDecrypted();
|
const collections = await this.collectionService.getAllDecrypted();
|
||||||
if (organizationId != null) {
|
if (organizationId != null) {
|
||||||
this.collections = collections.filter(c => c.organizationId === organizationId);
|
this.collections = collections.filter((c) => c.organizationId === organizationId);
|
||||||
} else {
|
} else {
|
||||||
this.collections = collections;
|
this.collections = collections;
|
||||||
}
|
}
|
||||||
@@ -143,7 +141,7 @@ export class GroupingsComponent {
|
|||||||
this.selectedCollectionId = null;
|
this.selectedCollectionId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async collapse(grouping: FolderView | CollectionView, idPrefix = '') {
|
async collapse(grouping: FolderView | CollectionView, idPrefix = "") {
|
||||||
if (grouping.id == null) {
|
if (grouping.id == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -156,7 +154,7 @@ export class GroupingsComponent {
|
|||||||
await this.stateService.setCollapsedGroupings(this.collapsedGroupings);
|
await this.stateService.setCollapsedGroupings(this.collapsedGroupings);
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsed(grouping: FolderView | CollectionView, idPrefix = '') {
|
isCollapsed(grouping: FolderView | CollectionView, idPrefix = "") {
|
||||||
return this.collapsedGroupings.has(idPrefix + grouping.id);
|
return this.collapsedGroupings.has(idPrefix + grouping.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
export class HintComponent {
|
export class HintComponent {
|
||||||
email: string = '';
|
email: string = "";
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
|
|
||||||
protected successRoute = 'login';
|
protected successRoute = "login";
|
||||||
protected onSuccessfulSubmit: () => void;
|
protected onSuccessfulSubmit: () => void;
|
||||||
|
|
||||||
constructor(protected router: Router, protected i18nService: I18nService,
|
constructor(
|
||||||
protected apiService: ApiService, protected platformUtilsService: PlatformUtilsService,
|
protected router: Router,
|
||||||
private logService: LogService) { }
|
protected i18nService: I18nService,
|
||||||
|
protected apiService: ApiService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.email == null || this.email === '') {
|
if (this.email == null || this.email === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('emailRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("emailRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.email.indexOf('@') === -1) {
|
if (this.email.indexOf("@") === -1) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidEmail'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidEmail")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.formPromise = this.apiService.postPasswordHint(new PasswordHintRequest(this.email));
|
this.formPromise = this.apiService.postPasswordHint(new PasswordHintRequest(this.email));
|
||||||
await this.formPromise;
|
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) {
|
if (this.onSuccessfulSubmit != null) {
|
||||||
this.onSuccessfulSubmit();
|
this.onSuccessfulSubmit();
|
||||||
} else if (this.router != null) {
|
} else if (this.router != null) {
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
import {
|
import { Component, Input, OnChanges } from "@angular/core";
|
||||||
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 { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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 = {
|
const IconMap: any = {
|
||||||
'fa-globe': String.fromCharCode(0xf0ac),
|
"fa-globe": String.fromCharCode(0xf0ac),
|
||||||
'fa-sticky-note-o': String.fromCharCode(0xf24a),
|
"fa-sticky-note-o": String.fromCharCode(0xf24a),
|
||||||
'fa-id-card-o': String.fromCharCode(0xf2c3),
|
"fa-id-card-o": String.fromCharCode(0xf2c3),
|
||||||
'fa-credit-card': String.fromCharCode(0xf09d),
|
"fa-credit-card": String.fromCharCode(0xf09d),
|
||||||
'fa-android': String.fromCharCode(0xf17b),
|
"fa-android": String.fromCharCode(0xf17b),
|
||||||
'fa-apple': String.fromCharCode(0xf179),
|
"fa-apple": String.fromCharCode(0xf179),
|
||||||
};
|
};
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-vault-icon',
|
selector: "app-vault-icon",
|
||||||
templateUrl: 'icon.component.html',
|
templateUrl: "icon.component.html",
|
||||||
})
|
})
|
||||||
export class IconComponent implements OnChanges {
|
export class IconComponent implements OnChanges {
|
||||||
@Input() cipher: CipherView;
|
@Input() cipher: CipherView;
|
||||||
@@ -55,17 +51,17 @@ export class IconComponent implements OnChanges {
|
|||||||
protected load() {
|
protected load() {
|
||||||
switch (this.cipher.type) {
|
switch (this.cipher.type) {
|
||||||
case CipherType.Login:
|
case CipherType.Login:
|
||||||
this.icon = 'fa-globe';
|
this.icon = "fa-globe";
|
||||||
this.setLoginIcon();
|
this.setLoginIcon();
|
||||||
break;
|
break;
|
||||||
case CipherType.SecureNote:
|
case CipherType.SecureNote:
|
||||||
this.icon = 'fa-sticky-note-o';
|
this.icon = "fa-sticky-note-o";
|
||||||
break;
|
break;
|
||||||
case CipherType.Card:
|
case CipherType.Card:
|
||||||
this.icon = 'fa-credit-card';
|
this.icon = "fa-credit-card";
|
||||||
break;
|
break;
|
||||||
case CipherType.Identity:
|
case CipherType.Identity:
|
||||||
this.icon = 'fa-id-card-o';
|
this.icon = "fa-id-card-o";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -77,23 +73,27 @@ export class IconComponent implements OnChanges {
|
|||||||
let hostnameUri = this.cipher.login.uri;
|
let hostnameUri = this.cipher.login.uri;
|
||||||
let isWebsite = false;
|
let isWebsite = false;
|
||||||
|
|
||||||
if (hostnameUri.indexOf('androidapp://') === 0) {
|
if (hostnameUri.indexOf("androidapp://") === 0) {
|
||||||
this.icon = 'fa-android';
|
this.icon = "fa-android";
|
||||||
this.image = null;
|
this.image = null;
|
||||||
} else if (hostnameUri.indexOf('iosapp://') === 0) {
|
} else if (hostnameUri.indexOf("iosapp://") === 0) {
|
||||||
this.icon = 'fa-apple';
|
this.icon = "fa-apple";
|
||||||
this.image = null;
|
this.image = null;
|
||||||
} else if (this.imageEnabled && hostnameUri.indexOf('://') === -1 && hostnameUri.indexOf('.') > -1) {
|
} else if (
|
||||||
hostnameUri = 'http://' + hostnameUri;
|
this.imageEnabled &&
|
||||||
|
hostnameUri.indexOf("://") === -1 &&
|
||||||
|
hostnameUri.indexOf(".") > -1
|
||||||
|
) {
|
||||||
|
hostnameUri = "http://" + hostnameUri;
|
||||||
isWebsite = true;
|
isWebsite = true;
|
||||||
} else if (this.imageEnabled) {
|
} else if (this.imageEnabled) {
|
||||||
isWebsite = hostnameUri.indexOf('http') === 0 && hostnameUri.indexOf('.') > -1;
|
isWebsite = hostnameUri.indexOf("http") === 0 && hostnameUri.indexOf(".") > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.imageEnabled && isWebsite) {
|
if (this.imageEnabled && isWebsite) {
|
||||||
try {
|
try {
|
||||||
this.image = this.iconsUrl + '/' + Utils.getHostname(hostnameUri) + '/icon.png';
|
this.image = this.iconsUrl + "/" + Utils.getHostname(hostnameUri) + "/icon.png";
|
||||||
this.fallbackImage = 'images/fa-globe.png';
|
this.fallbackImage = "images/fa-globe.png";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore error since the fallback icon will be shown if image is null.
|
// Ignore error since the fallback icon will be shown if image is null.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +1,84 @@
|
|||||||
import { Directive, NgZone, OnInit } from '@angular/core';
|
import { Directive, 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 { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
import { EncString } from 'jslib-common/models/domain/encString';
|
import { EncString } from "jslib-common/models/domain/encString";
|
||||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
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 { HashPurpose } from "jslib-common/enums/hashPurpose";
|
||||||
import { KeySuffixOptions } from 'jslib-common/enums/keySuffixOptions';
|
import { KeySuffixOptions } from "jslib-common/enums/keySuffixOptions";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class LockComponent implements OnInit {
|
export class LockComponent implements OnInit {
|
||||||
masterPassword: string = '';
|
masterPassword: string = "";
|
||||||
pin: string = '';
|
pin: string = "";
|
||||||
showPassword: boolean = false;
|
showPassword: boolean = false;
|
||||||
email: string;
|
email: string;
|
||||||
pinLock: boolean = false;
|
pinLock: boolean = false;
|
||||||
webVaultHostname: string = '';
|
webVaultHostname: string = "";
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
supportsBiometric: boolean;
|
supportsBiometric: boolean;
|
||||||
biometricLock: boolean;
|
biometricLock: boolean;
|
||||||
biometricText: string;
|
biometricText: string;
|
||||||
hideInput: boolean;
|
hideInput: boolean;
|
||||||
|
|
||||||
protected successRoute: string = 'vault';
|
protected successRoute: string = "vault";
|
||||||
protected onSuccessfulSubmit: () => Promise<void>;
|
protected onSuccessfulSubmit: () => Promise<void>;
|
||||||
|
|
||||||
private invalidPinAttempts = 0;
|
private invalidPinAttempts = 0;
|
||||||
private pinSet: [boolean, boolean];
|
private pinSet: [boolean, boolean];
|
||||||
|
|
||||||
constructor(protected router: Router, protected i18nService: I18nService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, protected messagingService: MessagingService,
|
protected router: Router,
|
||||||
protected cryptoService: CryptoService, protected vaultTimeoutService: VaultTimeoutService,
|
protected i18nService: I18nService,
|
||||||
protected environmentService: EnvironmentService, protected stateService: StateService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected apiService: ApiService, private logService: LogService,
|
protected messagingService: MessagingService,
|
||||||
private keyConnectorService: KeyConnectorService, protected ngZone: NgZone) { }
|
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() {
|
async ngOnInit() {
|
||||||
this.stateService.activeAccount.subscribe(async _userId => {
|
this.stateService.activeAccount.subscribe(async (_userId) => {
|
||||||
await this.load();
|
await this.load();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.pinLock && (this.pin == null || this.pin === '')) {
|
if (this.pinLock && (this.pin == null || this.pin === "")) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('pinRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("pinRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.pinLock && (this.masterPassword == null || this.masterPassword === '')) {
|
if (!this.pinLock && (this.masterPassword == null || this.masterPassword === "")) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,17 +89,30 @@ export class LockComponent implements OnInit {
|
|||||||
let failed = true;
|
let failed = true;
|
||||||
try {
|
try {
|
||||||
if (this.pinSet[0]) {
|
if (this.pinSet[0]) {
|
||||||
const key = await this.cryptoService.makeKeyFromPin(this.pin, this.email, kdf, kdfIterations,
|
const key = await this.cryptoService.makeKeyFromPin(
|
||||||
await this.stateService.getDecryptedPinProtected());
|
this.pin,
|
||||||
|
this.email,
|
||||||
|
kdf,
|
||||||
|
kdfIterations,
|
||||||
|
await this.stateService.getDecryptedPinProtected()
|
||||||
|
);
|
||||||
const encKey = await this.cryptoService.getEncKey(key);
|
const encKey = await this.cryptoService.getEncKey(key);
|
||||||
const protectedPin = await this.stateService.getProtectedPin();
|
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;
|
failed = decPin !== this.pin;
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
await this.setKeyAndContinue(key);
|
await this.setKeyAndContinue(key);
|
||||||
}
|
}
|
||||||
} else {
|
} 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;
|
failed = false;
|
||||||
await this.setKeyAndContinue(key);
|
await this.setKeyAndContinue(key);
|
||||||
}
|
}
|
||||||
@@ -96,14 +123,22 @@ export class LockComponent implements OnInit {
|
|||||||
if (failed) {
|
if (failed) {
|
||||||
this.invalidPinAttempts++;
|
this.invalidPinAttempts++;
|
||||||
if (this.invalidPinAttempts >= 5) {
|
if (this.invalidPinAttempts >= 5) {
|
||||||
this.messagingService.send('logout');
|
this.messagingService.send("logout");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidPin'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidPin")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} 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();
|
const storedKeyHash = await this.cryptoService.getKeyHash();
|
||||||
|
|
||||||
let passwordValid = false;
|
let passwordValid = false;
|
||||||
@@ -112,15 +147,21 @@ export class LockComponent implements OnInit {
|
|||||||
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, key);
|
passwordValid = await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, key);
|
||||||
} else {
|
} else {
|
||||||
const request = new SecretVerificationRequest();
|
const request = new SecretVerificationRequest();
|
||||||
const serverKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
|
const serverKeyHash = await this.cryptoService.hashPassword(
|
||||||
HashPurpose.ServerAuthorization);
|
this.masterPassword,
|
||||||
|
key,
|
||||||
|
HashPurpose.ServerAuthorization
|
||||||
|
);
|
||||||
request.masterPasswordHash = serverKeyHash;
|
request.masterPasswordHash = serverKeyHash;
|
||||||
try {
|
try {
|
||||||
this.formPromise = this.apiService.postAccountVerifyPassword(request);
|
this.formPromise = this.apiService.postAccountVerifyPassword(request);
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
passwordValid = true;
|
passwordValid = true;
|
||||||
const localKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
|
const localKeyHash = await this.cryptoService.hashPassword(
|
||||||
HashPurpose.LocalAuthorization);
|
this.masterPassword,
|
||||||
|
key,
|
||||||
|
HashPurpose.LocalAuthorization
|
||||||
|
);
|
||||||
await this.cryptoService.setKeyHash(localKeyHash);
|
await this.cryptoService.setKeyHash(localKeyHash);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -131,23 +172,40 @@ export class LockComponent implements OnInit {
|
|||||||
if (this.pinSet[0]) {
|
if (this.pinSet[0]) {
|
||||||
const protectedPin = await this.stateService.getProtectedPin();
|
const protectedPin = await this.stateService.getProtectedPin();
|
||||||
const encKey = await this.cryptoService.getEncKey(key);
|
const encKey = await this.cryptoService.getEncKey(key);
|
||||||
const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey);
|
const decPin = await this.cryptoService.decryptToUtf8(
|
||||||
const pinKey = await this.cryptoService.makePinKey(decPin, this.email, kdf, kdfIterations);
|
new EncString(protectedPin),
|
||||||
await this.stateService.setDecryptedPinProtected(await this.cryptoService.encrypt(key.key, pinKey));
|
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);
|
await this.setKeyAndContinue(key);
|
||||||
} else {
|
} else {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidMasterPassword'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidMasterPassword")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async logOut() {
|
async logOut() {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('logOutConfirmation'),
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('logOut'), this.i18nService.t('logOut'), this.i18nService.t('cancel'));
|
this.i18nService.t("logOutConfirmation"),
|
||||||
|
this.i18nService.t("logOut"),
|
||||||
|
this.i18nService.t("logOut"),
|
||||||
|
this.i18nService.t("cancel")
|
||||||
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.messagingService.send('logout');
|
this.messagingService.send("logout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +225,7 @@ export class LockComponent implements OnInit {
|
|||||||
|
|
||||||
togglePassword() {
|
togglePassword() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
const input = document.getElementById(this.pinLock ? 'pin' : 'masterPassword');
|
const input = document.getElementById(this.pinLock ? "pin" : "masterPassword");
|
||||||
if (this.ngZone.isStable) {
|
if (this.ngZone.isStable) {
|
||||||
input.focus();
|
input.focus();
|
||||||
} else {
|
} else {
|
||||||
@@ -185,7 +243,7 @@ export class LockComponent implements OnInit {
|
|||||||
await this.stateService.setEverBeenUnlocked(true);
|
await this.stateService.setEverBeenUnlocked(true);
|
||||||
const disableFavicon = await this.stateService.getDisableFavicon();
|
const disableFavicon = await this.stateService.getDisableFavicon();
|
||||||
await this.stateService.setDisableFavicon(!!disableFavicon);
|
await this.stateService.setDisableFavicon(!!disableFavicon);
|
||||||
this.messagingService.send('unlocked');
|
this.messagingService.send("unlocked");
|
||||||
if (this.onSuccessfulSubmit != null) {
|
if (this.onSuccessfulSubmit != null) {
|
||||||
await this.onSuccessfulSubmit();
|
await this.onSuccessfulSubmit();
|
||||||
} else if (this.router != null) {
|
} else if (this.router != null) {
|
||||||
@@ -195,10 +253,14 @@ export class LockComponent implements OnInit {
|
|||||||
|
|
||||||
private async load() {
|
private async load() {
|
||||||
this.pinSet = await this.vaultTimeoutService.isPinLockSet();
|
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.supportsBiometric = await this.platformUtilsService.supportsBiometric();
|
||||||
this.biometricLock = await this.vaultTimeoutService.isBiometricLockSet() &&
|
this.biometricLock =
|
||||||
(await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric) || !this.platformUtilsService.supportsSecureStorage());
|
(await this.vaultTimeoutService.isBiometricLockSet()) &&
|
||||||
|
((await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric)) ||
|
||||||
|
!this.platformUtilsService.supportsSecureStorage());
|
||||||
this.biometricText = await this.stateService.getBiometricText();
|
this.biometricText = await this.stateService.getBiometricText();
|
||||||
this.email = await this.stateService.getEmail();
|
this.email = await this.stateService.getEmail();
|
||||||
const usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
const usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
||||||
@@ -210,7 +272,8 @@ export class LockComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
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);
|
this.webVaultHostname = Utils.getHostname(vaultUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,30 @@
|
|||||||
import {
|
import { Directive, Input, NgZone, OnInit } from "@angular/core";
|
||||||
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 { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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()
|
@Directive()
|
||||||
export class LoginComponent extends CaptchaProtectedComponent implements OnInit {
|
export class LoginComponent extends CaptchaProtectedComponent implements OnInit {
|
||||||
@Input() email: string = '';
|
@Input() email: string = "";
|
||||||
@Input() rememberEmail = true;
|
@Input() rememberEmail = true;
|
||||||
|
|
||||||
masterPassword: string = '';
|
masterPassword: string = "";
|
||||||
showPassword: boolean = false;
|
showPassword: boolean = false;
|
||||||
formPromise: Promise<AuthResult>;
|
formPromise: Promise<AuthResult>;
|
||||||
onSuccessfulLogin: () => Promise<any>;
|
onSuccessfulLogin: () => Promise<any>;
|
||||||
@@ -37,27 +32,33 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
|||||||
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
|
onSuccessfulLoginTwoFactorNavigate: () => Promise<any>;
|
||||||
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
|
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
|
||||||
|
|
||||||
protected twoFactorRoute = '2fa';
|
protected twoFactorRoute = "2fa";
|
||||||
protected successRoute = 'vault';
|
protected successRoute = "vault";
|
||||||
protected forcePasswordResetRoute = 'update-temp-password';
|
protected forcePasswordResetRoute = "update-temp-password";
|
||||||
|
|
||||||
constructor(protected authService: AuthService, protected router: Router,
|
constructor(
|
||||||
platformUtilsService: PlatformUtilsService, i18nService: I18nService,
|
protected authService: AuthService,
|
||||||
protected stateService: StateService, environmentService: EnvironmentService,
|
protected router: Router,
|
||||||
|
platformUtilsService: PlatformUtilsService,
|
||||||
|
i18nService: I18nService,
|
||||||
|
protected stateService: StateService,
|
||||||
|
environmentService: EnvironmentService,
|
||||||
protected passwordGenerationService: PasswordGenerationService,
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
protected cryptoFunctionService: CryptoFunctionService, protected logService: LogService,
|
protected cryptoFunctionService: CryptoFunctionService,
|
||||||
protected ngZone: NgZone) {
|
protected logService: LogService,
|
||||||
|
protected ngZone: NgZone
|
||||||
|
) {
|
||||||
super(environmentService, i18nService, platformUtilsService);
|
super(environmentService, i18nService, platformUtilsService);
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
if (this.email == null || this.email === '') {
|
if (this.email == null || this.email === "") {
|
||||||
this.email = await this.stateService.getRememberedEmail();
|
this.email = await this.stateService.getRememberedEmail();
|
||||||
if (this.email == null) {
|
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) {
|
if (Utils.isBrowser && !Utils.isNode) {
|
||||||
this.focusInput();
|
this.focusInput();
|
||||||
}
|
}
|
||||||
@@ -66,19 +67,28 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
|||||||
async submit() {
|
async submit() {
|
||||||
await this.setupCaptcha();
|
await this.setupCaptcha();
|
||||||
|
|
||||||
if (this.email == null || this.email === '') {
|
if (this.email == null || this.email === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('emailRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("emailRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.email.indexOf('@') === -1) {
|
if (this.email.indexOf("@") === -1) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidEmail'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidEmail")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.masterPassword == null || this.masterPassword === '') {
|
if (this.masterPassword == null || this.masterPassword === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,16 +134,18 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
|||||||
togglePassword() {
|
togglePassword() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
if (this.ngZone.isStable) {
|
if (this.ngZone.isStable) {
|
||||||
document.getElementById('masterPassword').focus();
|
document.getElementById("masterPassword").focus();
|
||||||
} else {
|
} 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) {
|
async launchSsoBrowser(clientId: string, ssoRedirectUri: string) {
|
||||||
// Generate necessary sso params
|
// Generate necessary sso params
|
||||||
const passwordOptions: any = {
|
const passwordOptions: any = {
|
||||||
type: 'password',
|
type: "password",
|
||||||
length: 64,
|
length: 64,
|
||||||
uppercase: true,
|
uppercase: true,
|
||||||
lowercase: true,
|
lowercase: true,
|
||||||
@@ -142,7 +154,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
|||||||
};
|
};
|
||||||
const state = await this.passwordGenerationService.generatePassword(passwordOptions);
|
const state = await this.passwordGenerationService.generatePassword(passwordOptions);
|
||||||
const ssoCodeVerifier = 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);
|
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
|
||||||
|
|
||||||
// Save sso params
|
// Save sso params
|
||||||
@@ -153,12 +165,22 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
|
|||||||
const webUrl = this.environmentService.getWebVaultUrl();
|
const webUrl = this.environmentService.getWebVaultUrl();
|
||||||
|
|
||||||
// Launch browser
|
// Launch browser
|
||||||
this.platformUtilsService.launchUri(webUrl + '/#/sso?clientId=' + clientId +
|
this.platformUtilsService.launchUri(
|
||||||
'&redirectUri=' + encodeURIComponent(ssoRedirectUri) +
|
webUrl +
|
||||||
'&state=' + state + '&codeChallenge=' + codeChallenge);
|
"/#/sso?clientId=" +
|
||||||
|
clientId +
|
||||||
|
"&redirectUri=" +
|
||||||
|
encodeURIComponent(ssoRedirectUri) +
|
||||||
|
"&state=" +
|
||||||
|
state +
|
||||||
|
"&codeChallenge=" +
|
||||||
|
codeChallenge
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected focusInput() {
|
protected focusInput() {
|
||||||
document.getElementById(this.email == null || this.email === '' ? 'email' : 'masterPassword').focus();
|
document
|
||||||
|
.getElementById(this.email == null || this.email === "" ? "email" : "masterPassword")
|
||||||
|
.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,35 +7,37 @@ import {
|
|||||||
OnDestroy,
|
OnDestroy,
|
||||||
Type,
|
Type,
|
||||||
ViewChild,
|
ViewChild,
|
||||||
ViewContainerRef
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from "@angular/core";
|
||||||
|
|
||||||
import {
|
import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from "@angular/cdk/a11y";
|
||||||
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({
|
@Component({
|
||||||
selector: 'app-modal',
|
selector: "app-modal",
|
||||||
template: '<ng-template #modalContent></ng-template>',
|
template: "<ng-template #modalContent></ng-template>",
|
||||||
})
|
})
|
||||||
export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
||||||
componentRef: ComponentRef<any>;
|
componentRef: ComponentRef<any>;
|
||||||
|
|
||||||
@ViewChild('modalContent', { read: ViewContainerRef, static: true }) modalContentRef: ViewContainerRef;
|
@ViewChild("modalContent", { read: ViewContainerRef, static: true })
|
||||||
|
modalContentRef: ViewContainerRef;
|
||||||
|
|
||||||
childComponentType: Type<any>;
|
childComponentType: Type<any>;
|
||||||
setComponentParameters: (component: any) => void;
|
setComponentParameters: (component: any) => void;
|
||||||
|
|
||||||
private focusTrap: ConfigurableFocusTrap;
|
private focusTrap: ConfigurableFocusTrap;
|
||||||
|
|
||||||
constructor(private modalService: ModalService, private cd: ChangeDetectorRef,
|
constructor(
|
||||||
private el: ElementRef<HTMLElement>, private focusTrapFactory: ConfigurableFocusTrapFactory,
|
private modalService: ModalService,
|
||||||
public modalRef: ModalRef) { }
|
private cd: ChangeDetectorRef,
|
||||||
|
private el: ElementRef<HTMLElement>,
|
||||||
|
private focusTrapFactory: ConfigurableFocusTrapFactory,
|
||||||
|
public modalRef: ModalRef
|
||||||
|
) {}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
this.loadChildComponent(this.childComponentType);
|
this.loadChildComponent(this.childComponentType);
|
||||||
@@ -45,8 +47,10 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
|||||||
this.cd.detectChanges();
|
this.cd.detectChanges();
|
||||||
|
|
||||||
this.modalRef.created(this.el.nativeElement);
|
this.modalRef.created(this.el.nativeElement);
|
||||||
this.focusTrap = this.focusTrapFactory.create(this.el.nativeElement.querySelector('.modal-dialog'));
|
this.focusTrap = this.focusTrapFactory.create(
|
||||||
if (this.el.nativeElement.querySelector('[appAutoFocus]') == null) {
|
this.el.nativeElement.querySelector(".modal-dialog")
|
||||||
|
);
|
||||||
|
if (this.el.nativeElement.querySelector("[appAutoFocus]") == null) {
|
||||||
this.focusTrap.focusFirstTabbableElementWhenReady();
|
this.focusTrap.focusFirstTabbableElementWhenReady();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,7 +74,7 @@ export class DynamicModalComponent implements AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFocus() {
|
getFocus() {
|
||||||
const autoFocusEl = this.el.nativeElement.querySelector('[appAutoFocus]') as HTMLElement;
|
const autoFocusEl = this.el.nativeElement.querySelector("[appAutoFocus]") as HTMLElement;
|
||||||
autoFocusEl?.focus();
|
autoFocusEl?.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { InjectFlags, InjectionToken, Injector, Type } from "@angular/core";
|
||||||
InjectFlags,
|
|
||||||
InjectionToken,
|
|
||||||
Injector,
|
|
||||||
Type
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
export class ModalInjector implements Injector {
|
export class ModalInjector implements Injector {
|
||||||
constructor(private _parentInjector: Injector, private _additionalTokens: WeakMap<any, any>) {}
|
constructor(private _parentInjector: Injector, private _additionalTokens: WeakMap<any, any>) {}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from "rxjs";
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
export class ModalRef {
|
export class ModalRef {
|
||||||
|
|
||||||
onCreated: Observable<HTMLElement>; // Modal added to the DOM.
|
onCreated: Observable<HTMLElement>; // Modal added to the DOM.
|
||||||
onClose: Observable<any>; // Initiated close.
|
onClose: Observable<any>; // Initiated close.
|
||||||
onClosed: Observable<any>; // Modal was closed (Remove element from DOM)
|
onClosed: Observable<any>; // Modal was closed (Remove element from DOM)
|
||||||
|
|||||||
@@ -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 { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Directive()
|
||||||
export class PasswordGeneratorHistoryComponent implements OnInit {
|
export class PasswordGeneratorHistoryComponent implements OnInit {
|
||||||
history: GeneratedPasswordHistory[] = [];
|
history: GeneratedPasswordHistory[] = [];
|
||||||
|
|
||||||
constructor(protected passwordGenerationService: PasswordGenerationService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService,
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
private win: Window) { }
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
private win: Window
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.history = await this.passwordGenerationService.getHistory();
|
this.history = await this.passwordGenerationService.getHistory();
|
||||||
@@ -26,7 +29,10 @@ export class PasswordGeneratorHistoryComponent implements OnInit {
|
|||||||
copy(password: string) {
|
copy(password: string) {
|
||||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||||
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
||||||
this.platformUtilsService.showToast('info', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('valueCopied', this.i18nService.t('password')));
|
"info",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t("password"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Directive()
|
||||||
export class PasswordGeneratorComponent implements OnInit {
|
export class PasswordGeneratorComponent implements OnInit {
|
||||||
@@ -19,17 +13,20 @@ export class PasswordGeneratorComponent implements OnInit {
|
|||||||
|
|
||||||
passTypeOptions: any[];
|
passTypeOptions: any[];
|
||||||
options: any = {};
|
options: any = {};
|
||||||
password: string = '-';
|
password: string = "-";
|
||||||
showOptions = false;
|
showOptions = false;
|
||||||
avoidAmbiguous = false;
|
avoidAmbiguous = false;
|
||||||
enforcedPolicyOptions: PasswordGeneratorPolicyOptions;
|
enforcedPolicyOptions: PasswordGeneratorPolicyOptions;
|
||||||
|
|
||||||
constructor(protected passwordGenerationService: PasswordGenerationService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService,
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
private win: Window) {
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
private win: Window
|
||||||
|
) {
|
||||||
this.passTypeOptions = [
|
this.passTypeOptions = [
|
||||||
{ name: i18nService.t('password'), value: 'password' },
|
{ name: i18nService.t("password"), value: "password" },
|
||||||
{ name: i18nService.t('passphrase'), value: 'passphrase' },
|
{ name: i18nService.t("passphrase"), value: "passphrase" },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +35,7 @@ export class PasswordGeneratorComponent implements OnInit {
|
|||||||
this.options = optionsResponse[0];
|
this.options = optionsResponse[0];
|
||||||
this.enforcedPolicyOptions = optionsResponse[1];
|
this.enforcedPolicyOptions = optionsResponse[1];
|
||||||
this.avoidAmbiguous = !this.options.ambiguous;
|
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);
|
this.password = await this.passwordGenerationService.generatePassword(this.options);
|
||||||
await this.passwordGenerationService.addHistory(this.password);
|
await this.passwordGenerationService.addHistory(this.password);
|
||||||
}
|
}
|
||||||
@@ -70,8 +67,11 @@ export class PasswordGeneratorComponent implements OnInit {
|
|||||||
copy() {
|
copy() {
|
||||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||||
this.platformUtilsService.copyToClipboard(this.password, copyOptions);
|
this.platformUtilsService.copyToClipboard(this.password, copyOptions);
|
||||||
this.platformUtilsService.showToast('info', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('valueCopied', this.i18nService.t('password')));
|
"info",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t("password"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
select() {
|
select() {
|
||||||
@@ -86,10 +86,15 @@ export class PasswordGeneratorComponent implements OnInit {
|
|||||||
// Application level normalize options depedent on class variables
|
// Application level normalize options depedent on class variables
|
||||||
this.options.ambiguous = !this.avoidAmbiguous;
|
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;
|
this.options.lowercase = true;
|
||||||
if (this.win != null) {
|
if (this.win != null) {
|
||||||
const lowercase = this.win.document.querySelector('#lowercase') as HTMLInputElement;
|
const lowercase = this.win.document.querySelector("#lowercase") as HTMLInputElement;
|
||||||
if (lowercase) {
|
if (lowercase) {
|
||||||
lowercase.checked = true;
|
lowercase.checked = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Directive()
|
||||||
export class PasswordHistoryComponent implements OnInit {
|
export class PasswordHistoryComponent implements OnInit {
|
||||||
cipherId: string;
|
cipherId: string;
|
||||||
history: PasswordHistoryView[] = [];
|
history: PasswordHistoryView[] = [];
|
||||||
|
|
||||||
constructor(protected cipherService: CipherService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected i18nService: I18nService, private win: Window) { }
|
protected cipherService: CipherService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
private win: Window
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.init();
|
await this.init();
|
||||||
@@ -21,8 +25,11 @@ export class PasswordHistoryComponent implements OnInit {
|
|||||||
copy(password: string) {
|
copy(password: string) {
|
||||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||||
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
||||||
this.platformUtilsService.showToast('info', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('valueCopied', this.i18nService.t('password')));
|
"info",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t("password"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async init() {
|
protected async init() {
|
||||||
|
|||||||
@@ -1,27 +1,33 @@
|
|||||||
import { Directive } from '@angular/core';
|
import { Directive } from "@angular/core";
|
||||||
|
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { ModalRef } from './modal/modal.ref';
|
import { ModalRef } from "./modal/modal.ref";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class PasswordRepromptComponent {
|
export class PasswordRepromptComponent {
|
||||||
|
|
||||||
showPassword = false;
|
showPassword = false;
|
||||||
masterPassword = '';
|
masterPassword = "";
|
||||||
|
|
||||||
constructor(private modalRef: ModalRef, private cryptoService: CryptoService, private platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
private i18nService: I18nService) {}
|
private modalRef: ModalRef,
|
||||||
|
private cryptoService: CryptoService,
|
||||||
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private i18nService: I18nService
|
||||||
|
) {}
|
||||||
|
|
||||||
togglePassword() {
|
togglePassword() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (!await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null)) {
|
if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidMasterPassword'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidMasterPassword")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class PremiumComponent implements OnInit {
|
export class PremiumComponent implements OnInit {
|
||||||
@@ -12,9 +12,13 @@ export class PremiumComponent implements OnInit {
|
|||||||
price: number = 10;
|
price: number = 10;
|
||||||
refreshPromise: Promise<any>;
|
refreshPromise: Promise<any>;
|
||||||
|
|
||||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected apiService: ApiService, private logService: LogService,
|
protected i18nService: I18nService,
|
||||||
protected stateService: StateService) { }
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected apiService: ApiService,
|
||||||
|
private logService: LogService,
|
||||||
|
protected stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.isPremium = await this.stateService.getCanAccessPremium();
|
this.isPremium = await this.stateService.getCanAccessPremium();
|
||||||
@@ -24,7 +28,7 @@ export class PremiumComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.refreshPromise = this.apiService.refreshIdentityToken();
|
this.refreshPromise = this.apiService.refreshIdentityToken();
|
||||||
await this.refreshPromise;
|
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();
|
this.isPremium = await this.stateService.getCanAccessPremium();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -32,18 +36,26 @@ export class PremiumComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async purchase() {
|
async purchase() {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumPurchaseAlert'),
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('premiumPurchase'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
|
this.i18nService.t("premiumPurchaseAlert"),
|
||||||
|
this.i18nService.t("premiumPurchase"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("cancel")
|
||||||
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=purchase');
|
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=purchase");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async manage() {
|
async manage() {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('premiumManageAlert'),
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('premiumManage'), this.i18nService.t('yes'), this.i18nService.t('cancel'));
|
this.i18nService.t("premiumManageAlert"),
|
||||||
|
this.i18nService.t("premiumManage"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("cancel")
|
||||||
|
);
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.platformUtilsService.launchUri('https://vault.bitwarden.com/#/?premium=manage');
|
this.platformUtilsService.launchUri("https://vault.bitwarden.com/#/?premium=manage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
import { Directive, OnInit } from '@angular/core';
|
import { Directive, OnInit } from "@angular/core";
|
||||||
import { Router } from '@angular/router';
|
import { Router } from "@angular/router";
|
||||||
|
|
||||||
import { KeysRequest } from 'jslib-common/models/request/keysRequest';
|
import { KeysRequest } from "jslib-common/models/request/keysRequest";
|
||||||
import { ReferenceEventRequest } from 'jslib-common/models/request/referenceEventRequest';
|
import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest";
|
||||||
import { RegisterRequest } from 'jslib-common/models/request/registerRequest';
|
import { RegisterRequest } from "jslib-common/models/request/registerRequest";
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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()
|
@Directive()
|
||||||
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
|
export class RegisterComponent extends CaptchaProtectedComponent implements OnInit {
|
||||||
name: string = '';
|
name: string = "";
|
||||||
email: string = '';
|
email: string = "";
|
||||||
masterPassword: string = '';
|
masterPassword: string = "";
|
||||||
confirmMasterPassword: string = '';
|
confirmMasterPassword: string = "";
|
||||||
hint: string = '';
|
hint: string = "";
|
||||||
showPassword: boolean = false;
|
showPassword: boolean = false;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
masterPasswordScore: number;
|
masterPasswordScore: number;
|
||||||
@@ -33,15 +33,21 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
showTerms = true;
|
showTerms = true;
|
||||||
acceptPolicies: boolean = false;
|
acceptPolicies: boolean = false;
|
||||||
|
|
||||||
protected successRoute = 'login';
|
protected successRoute = "login";
|
||||||
private masterPasswordStrengthTimeout: any;
|
private masterPasswordStrengthTimeout: any;
|
||||||
|
|
||||||
constructor(protected authService: AuthService, protected router: Router,
|
constructor(
|
||||||
i18nService: I18nService, protected cryptoService: CryptoService,
|
protected authService: AuthService,
|
||||||
protected apiService: ApiService, protected stateService: StateService,
|
protected router: Router,
|
||||||
|
i18nService: I18nService,
|
||||||
|
protected cryptoService: CryptoService,
|
||||||
|
protected apiService: ApiService,
|
||||||
|
protected stateService: StateService,
|
||||||
platformUtilsService: PlatformUtilsService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
protected passwordGenerationService: PasswordGenerationService, environmentService: EnvironmentService,
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
protected logService: LogService) {
|
environmentService: EnvironmentService,
|
||||||
|
protected logService: LogService
|
||||||
|
) {
|
||||||
super(environmentService, i18nService, platformUtilsService);
|
super(environmentService, i18nService, platformUtilsService);
|
||||||
this.showTerms = !platformUtilsService.isSelfHost();
|
this.showTerms = !platformUtilsService.isSelfHost();
|
||||||
}
|
}
|
||||||
@@ -57,89 +63,131 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
get masterPasswordScoreColor() {
|
get masterPasswordScoreColor() {
|
||||||
switch (this.masterPasswordScore) {
|
switch (this.masterPasswordScore) {
|
||||||
case 4:
|
case 4:
|
||||||
return 'success';
|
return "success";
|
||||||
case 3:
|
case 3:
|
||||||
return 'primary';
|
return "primary";
|
||||||
case 2:
|
case 2:
|
||||||
return 'warning';
|
return "warning";
|
||||||
default:
|
default:
|
||||||
return 'danger';
|
return "danger";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get masterPasswordScoreText() {
|
get masterPasswordScoreText() {
|
||||||
switch (this.masterPasswordScore) {
|
switch (this.masterPasswordScore) {
|
||||||
case 4:
|
case 4:
|
||||||
return this.i18nService.t('strong');
|
return this.i18nService.t("strong");
|
||||||
case 3:
|
case 3:
|
||||||
return this.i18nService.t('good');
|
return this.i18nService.t("good");
|
||||||
case 2:
|
case 2:
|
||||||
return this.i18nService.t('weak');
|
return this.i18nService.t("weak");
|
||||||
default:
|
default:
|
||||||
return this.masterPasswordScore != null ? this.i18nService.t('weak') : null;
|
return this.masterPasswordScore != null ? this.i18nService.t("weak") : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (!this.acceptPolicies && this.showTerms) {
|
if (!this.acceptPolicies && this.showTerms) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('acceptPoliciesError'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("acceptPoliciesError")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.email == null || this.email === '') {
|
if (this.email == null || this.email === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('emailRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("emailRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.email.indexOf('@') === -1) {
|
if (this.email.indexOf("@") === -1) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('invalidEmail'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("invalidEmail")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.masterPassword == null || this.masterPassword === '') {
|
if (this.masterPassword == null || this.masterPassword === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.masterPassword.length < 8) {
|
if (this.masterPassword.length < 8) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassLength'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassLength")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.masterPassword !== this.confirmMasterPassword) {
|
if (this.masterPassword !== this.confirmMasterPassword) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('masterPassDoesntMatch'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("masterPassDoesntMatch")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
|
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||||
this.getPasswordStrengthUserInput());
|
this.masterPassword,
|
||||||
|
this.getPasswordStrengthUserInput()
|
||||||
|
);
|
||||||
if (strengthResult != null && strengthResult.score < 3) {
|
if (strengthResult != null && strengthResult.score < 3) {
|
||||||
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
|
const result = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
|
this.i18nService.t("weakMasterPasswordDesc"),
|
||||||
'warning');
|
this.i18nService.t("weakMasterPassword"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hint === this.masterPassword) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.name = this.name === '' ? null : this.name;
|
this.name = this.name === "" ? null : this.name;
|
||||||
this.email = this.email.trim().toLowerCase();
|
this.email = this.email.trim().toLowerCase();
|
||||||
const kdf = KdfType.PBKDF2_SHA256;
|
const kdf = KdfType.PBKDF2_SHA256;
|
||||||
const useLowerKdf = this.platformUtilsService.isIE();
|
const useLowerKdf = this.platformUtilsService.isIE();
|
||||||
const kdfIterations = useLowerKdf ? 10000 : 100000;
|
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 encKey = await this.cryptoService.makeEncKey(key);
|
||||||
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
|
const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key);
|
||||||
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
||||||
const request = new RegisterRequest(this.email, this.name, hashedPassword,
|
const request = new RegisterRequest(
|
||||||
this.hint, encKey[1].encryptedString, kdf, kdfIterations, this.referenceData, this.captchaToken);
|
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);
|
request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
|
||||||
const orgInvite = await this.stateService.getOrganizationInvitation();
|
const orgInvite = await this.stateService.getOrganizationInvitation();
|
||||||
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
|
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
|
||||||
@@ -158,7 +206,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
throw e;
|
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 } });
|
this.router.navigate([this.successRoute], { queryParams: { email: this.email } });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -167,7 +215,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
|
|
||||||
togglePassword(confirmField: boolean) {
|
togglePassword(confirmField: boolean) {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
|
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePasswordStrength() {
|
updatePasswordStrength() {
|
||||||
@@ -175,20 +223,28 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
|
|||||||
clearTimeout(this.masterPasswordStrengthTimeout);
|
clearTimeout(this.masterPasswordStrengthTimeout);
|
||||||
}
|
}
|
||||||
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
this.masterPasswordStrengthTimeout = setTimeout(() => {
|
||||||
const strengthResult = this.passwordGenerationService.passwordStrength(this.masterPassword,
|
const strengthResult = this.passwordGenerationService.passwordStrength(
|
||||||
this.getPasswordStrengthUserInput());
|
this.masterPassword,
|
||||||
|
this.getPasswordStrengthUserInput()
|
||||||
|
);
|
||||||
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getPasswordStrengthUserInput() {
|
private getPasswordStrengthUserInput() {
|
||||||
let userInput: string[] = [];
|
let userInput: string[] = [];
|
||||||
const atPosition = this.email.indexOf('@');
|
const atPosition = this.email.indexOf("@");
|
||||||
if (atPosition > -1) {
|
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 !== '') {
|
if (this.name != null && this.name !== "") {
|
||||||
userInput = userInput.concat(this.name.trim().toLowerCase().split(' '));
|
userInput = userInput.concat(this.name.trim().toLowerCase().split(" "));
|
||||||
}
|
}
|
||||||
return userInput;
|
return userInput;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
import {
|
import { Directive, OnInit } from "@angular/core";
|
||||||
Directive,
|
import { Router } from "@angular/router";
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { SyncService } from 'jslib-common/abstractions/sync.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()
|
@Directive()
|
||||||
export class RemovePasswordComponent implements OnInit {
|
export class RemovePasswordComponent implements OnInit {
|
||||||
|
|
||||||
actionPromise: Promise<any>;
|
actionPromise: Promise<any>;
|
||||||
continuing: boolean = false;
|
continuing: boolean = false;
|
||||||
leaving: boolean = false;
|
leaving: boolean = false;
|
||||||
@@ -24,10 +20,15 @@ export class RemovePasswordComponent implements OnInit {
|
|||||||
organization: Organization;
|
organization: Organization;
|
||||||
email: string;
|
email: string;
|
||||||
|
|
||||||
constructor(private router: Router, private stateService: StateService,
|
constructor(
|
||||||
private apiService: ApiService, private syncService: SyncService,
|
private router: Router,
|
||||||
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
|
private stateService: StateService,
|
||||||
private keyConnectorService: KeyConnectorService) { }
|
private apiService: ApiService,
|
||||||
|
private syncService: SyncService,
|
||||||
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private keyConnectorService: KeyConnectorService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.organization = await this.keyConnectorService.getManagingOrganization();
|
this.organization = await this.keyConnectorService.getManagingOrganization();
|
||||||
@@ -42,18 +43,26 @@ export class RemovePasswordComponent implements OnInit {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await this.actionPromise;
|
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();
|
await this.keyConnectorService.removeConvertAccountRequired();
|
||||||
this.router.navigate(['']);
|
this.router.navigate([""]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e.message);
|
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async leave() {
|
async leave() {
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('leaveOrganizationConfirmation'), this.organization.name,
|
this.i18nService.t("leaveOrganizationConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.organization.name,
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -64,11 +73,11 @@ export class RemovePasswordComponent implements OnInit {
|
|||||||
return this.syncService.fullSync(true);
|
return this.syncService.fullSync(true);
|
||||||
});
|
});
|
||||||
await this.actionPromise;
|
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();
|
await this.keyConnectorService.removeConvertAccountRequired();
|
||||||
this.router.navigate(['']);
|
this.router.navigate([""]);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), e);
|
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,24 @@
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from "@angular/common";
|
||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
import { SendType } from 'jslib-common/enums/sendType';
|
import { SendType } from "jslib-common/enums/sendType";
|
||||||
|
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
import { SendService } from "jslib-common/abstractions/send.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
|
|
||||||
import { SendFileView } from 'jslib-common/models/view/sendFileView';
|
import { SendFileView } from "jslib-common/models/view/sendFileView";
|
||||||
import { SendTextView } from 'jslib-common/models/view/sendTextView';
|
import { SendTextView } from "jslib-common/models/view/sendTextView";
|
||||||
import { SendView } from 'jslib-common/models/view/sendView';
|
import { SendView } from "jslib-common/models/view/sendView";
|
||||||
|
|
||||||
import { EncArrayBuffer } from 'jslib-common/models/domain/encArrayBuffer';
|
import { EncArrayBuffer } from "jslib-common/models/domain/encArrayBuffer";
|
||||||
import { Send } from 'jslib-common/models/domain/send';
|
import { Send } from "jslib-common/models/domain/send";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class AddEditComponent implements OnInit {
|
export class AddEditComponent implements OnInit {
|
||||||
@@ -55,21 +49,27 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
private sendLinkBaseUrl: string;
|
private sendLinkBaseUrl: string;
|
||||||
|
|
||||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected environmentService: EnvironmentService, protected datePipe: DatePipe,
|
protected i18nService: I18nService,
|
||||||
protected sendService: SendService, protected messagingService: MessagingService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected policyService: PolicyService, private logService: LogService,
|
protected environmentService: EnvironmentService,
|
||||||
protected stateService: StateService) {
|
protected datePipe: DatePipe,
|
||||||
|
protected sendService: SendService,
|
||||||
|
protected messagingService: MessagingService,
|
||||||
|
protected policyService: PolicyService,
|
||||||
|
private logService: LogService,
|
||||||
|
protected stateService: StateService
|
||||||
|
) {
|
||||||
this.typeOptions = [
|
this.typeOptions = [
|
||||||
{ name: i18nService.t('sendTypeFile'), value: SendType.File },
|
{ name: i18nService.t("sendTypeFile"), value: SendType.File },
|
||||||
{ name: i18nService.t('sendTypeText'), value: SendType.Text },
|
{ name: i18nService.t("sendTypeText"), value: SendType.Text },
|
||||||
];
|
];
|
||||||
this.sendLinkBaseUrl = this.environmentService.getSendUrl();
|
this.sendLinkBaseUrl = this.environmentService.getSendUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
get link(): string {
|
get link(): string {
|
||||||
if (this.send.id != null && this.send.accessId != null) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -91,22 +91,20 @@ export class AddEditComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get title(): string {
|
get title(): string {
|
||||||
return this.i18nService.t(
|
return this.i18nService.t(this.editMode ? "editSend" : "createSend");
|
||||||
this.editMode ?
|
|
||||||
'editSend' :
|
|
||||||
'createSend'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setDates(event: {deletionDate: string, expirationDate: string}) {
|
setDates(event: { deletionDate: string; expirationDate: string }) {
|
||||||
this.deletionDate = event.deletionDate;
|
this.deletionDate = event.deletionDate;
|
||||||
this.expirationDate = event.expirationDate;
|
this.expirationDate = event.expirationDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
|
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
|
||||||
this.disableHideEmail = await this.policyService.policyAppliesToUser(PolicyType.SendOptions,
|
this.disableHideEmail = await this.policyService.policyAppliesToUser(
|
||||||
p => p.data.disableHideEmail);
|
PolicyType.SendOptions,
|
||||||
|
(p) => p.data.disableHideEmail
|
||||||
|
);
|
||||||
|
|
||||||
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||||
this.emailVerified = await this.stateService.getEmailVerified();
|
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> {
|
async submit(): Promise<boolean> {
|
||||||
if (this.disableSend) {
|
if (this.disableSend) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('sendDisabledWarning'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("sendDisabledWarning")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.send.name == null || this.send.name === '') {
|
if (this.send.name == null || this.send.name === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('nameRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("nameRequired")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let file: File = null;
|
let file: File = null;
|
||||||
if (this.send.type === SendType.File && !this.editMode) {
|
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;
|
const files = fileEl.files;
|
||||||
if (files == null || files.length === 0) {
|
if (files == null || files.length === 0) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('selectFile'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("selectFile")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
file = files[0];
|
file = files[0];
|
||||||
if (files[0].size > 524288000) { // 500 MB
|
if (files[0].size > 524288000) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
// 500 MB
|
||||||
this.i18nService.t('maxFileSize'));
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("maxFileSize")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.password != null && this.password.trim() === '') {
|
if (this.password != null && this.password.trim() === "") {
|
||||||
this.password = null;
|
this.password = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formPromise = this.encryptSend(file)
|
this.formPromise = this.encryptSend(file).then(async (encSend) => {
|
||||||
.then(async encSend => {
|
|
||||||
const uploadPromise = this.sendService.saveWithServer(encSend);
|
const uploadPromise = this.sendService.saveWithServer(encSend);
|
||||||
await uploadPromise;
|
await uploadPromise;
|
||||||
if (this.send.id == null) {
|
if (this.send.id == null) {
|
||||||
@@ -180,12 +190,20 @@ export class AddEditComponent implements OnInit {
|
|||||||
if (this.copyLink && this.link != null) {
|
if (this.copyLink && this.link != null) {
|
||||||
const copySuccess = await this.copyLinkToClipboard(this.link);
|
const copySuccess = await this.copyLinkToClipboard(this.link);
|
||||||
if (copySuccess ?? true) {
|
if (copySuccess ?? true) {
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t(this.editMode ? 'editedSend' : 'createdSend'));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t(this.editMode ? "editedSend" : "createdSend")
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
await this.platformUtilsService.showDialog(
|
await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t(this.editMode ? 'editedSend' : 'createdSend'), null,
|
this.i18nService.t(this.editMode ? "editedSend" : "createdSend"),
|
||||||
this.i18nService.t('ok'), null, 'success', null);
|
null,
|
||||||
|
this.i18nService.t("ok"),
|
||||||
|
null,
|
||||||
|
"success",
|
||||||
|
null
|
||||||
|
);
|
||||||
await this.copyLinkToClipboard(this.link);
|
await this.copyLinkToClipboard(this.link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,9 +226,12 @@ export class AddEditComponent implements OnInit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('deleteSendConfirmation'),
|
this.i18nService.t("deleteSendConfirmation"),
|
||||||
this.i18nService.t('deleteSend'),
|
this.i18nService.t("deleteSend"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -218,7 +239,7 @@ export class AddEditComponent implements OnInit {
|
|||||||
try {
|
try {
|
||||||
this.deletePromise = this.sendService.deleteWithServer(this.send.id);
|
this.deletePromise = this.sendService.deleteWithServer(this.send.id);
|
||||||
await this.deletePromise;
|
await this.deletePromise;
|
||||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend'));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend"));
|
||||||
await this.load();
|
await this.load();
|
||||||
this.onDeletedSend.emit(this.send);
|
this.onDeletedSend.emit(this.send);
|
||||||
return true;
|
return true;
|
||||||
@@ -233,10 +254,10 @@ export class AddEditComponent implements OnInit {
|
|||||||
if (this.send.type === SendType.File && !this.alertShown) {
|
if (this.send.type === SendType.File && !this.alertShown) {
|
||||||
if (!this.canAccessPremium) {
|
if (!this.canAccessPremium) {
|
||||||
this.alertShown = true;
|
this.alertShown = true;
|
||||||
this.messagingService.send('premiumRequired');
|
this.messagingService.send("premiumRequired");
|
||||||
} else if (!this.emailVerified) {
|
} else if (!this.emailVerified) {
|
||||||
this.alertShown = true;
|
this.alertShown = true;
|
||||||
this.messagingService.send('emailVerificationRequired');
|
this.messagingService.send("emailVerificationRequired");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -259,7 +280,8 @@ export class AddEditComponent implements OnInit {
|
|||||||
sendData[0].deletionDate = null;
|
sendData[0].deletionDate = null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
sendData[0].expirationDate = this.expirationDate == null ? null : new Date(this.expirationDate);
|
sendData[0].expirationDate =
|
||||||
|
this.expirationDate == null ? null : new Date(this.expirationDate);
|
||||||
} catch {
|
} catch {
|
||||||
sendData[0].expirationDate = null;
|
sendData[0].expirationDate = null;
|
||||||
}
|
}
|
||||||
@@ -269,6 +291,6 @@ export class AddEditComponent implements OnInit {
|
|||||||
|
|
||||||
protected togglePasswordVisible() {
|
protected togglePasswordVisible() {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById('password').focus();
|
document.getElementById("password").focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,28 @@
|
|||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from "@angular/common";
|
||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
import { FormControl, FormGroup } from "@angular/forms";
|
||||||
EventEmitter,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
Output
|
|
||||||
} from '@angular/core';
|
|
||||||
import { FormControl, FormGroup } from '@angular/forms';
|
|
||||||
|
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
// Different BrowserPath = different controls.
|
// Different BrowserPath = different controls.
|
||||||
enum BrowserPath {
|
enum BrowserPath {
|
||||||
// Native datetime-locale.
|
// Native datetime-locale.
|
||||||
// We are happy.
|
// We are happy.
|
||||||
Default = 'default',
|
Default = "default",
|
||||||
|
|
||||||
// Native date and time inputs, but no datetime-locale.
|
// Native date and time inputs, but no datetime-locale.
|
||||||
// We use individual date and time inputs and create a datetime programatically on submit.
|
// 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.
|
// No native date, time, or datetime-locale inputs.
|
||||||
// We use a polyfill for dates and a dropdown for times.
|
// We use a polyfill for dates and a dropdown for times.
|
||||||
Safari = 'safari',
|
Safari = "safari",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DateField {
|
enum DateField {
|
||||||
DeletionDate = 'deletion',
|
DeletionDate = "deletion",
|
||||||
ExpriationDate = 'expiration',
|
ExpriationDate = "expiration",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value = hours
|
// Value = hours
|
||||||
@@ -57,7 +51,7 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
@Input() readonly editMode: boolean;
|
@Input() readonly editMode: boolean;
|
||||||
@Input() readonly disabled: boolean;
|
@Input() readonly disabled: boolean;
|
||||||
|
|
||||||
@Output() datesChanged = new EventEmitter<{deletionDate: string, expirationDate: string}>();
|
@Output() datesChanged = new EventEmitter<{ deletionDate: string; expirationDate: string }>();
|
||||||
|
|
||||||
get browserPath(): BrowserPath {
|
get browserPath(): BrowserPath {
|
||||||
if (this.platformUtilsService.isFirefox()) {
|
if (this.platformUtilsService.isFirefox()) {
|
||||||
@@ -80,49 +74,49 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
|
|
||||||
deletionDatePresets: any[] = [
|
deletionDatePresets: any[] = [
|
||||||
{ name: this.i18nService.t('oneHour'), value: DatePreset.OneHour },
|
{ name: this.i18nService.t("oneHour"), value: DatePreset.OneHour },
|
||||||
{ name: this.i18nService.t('oneDay'), value: DatePreset.OneDay },
|
{ name: this.i18nService.t("oneDay"), value: DatePreset.OneDay },
|
||||||
{ name: this.i18nService.t('days', '2'), value: DatePreset.TwoDays },
|
{ name: this.i18nService.t("days", "2"), value: DatePreset.TwoDays },
|
||||||
{ name: this.i18nService.t('days', '3'), value: DatePreset.ThreeDays },
|
{ name: this.i18nService.t("days", "3"), value: DatePreset.ThreeDays },
|
||||||
{ name: this.i18nService.t('days', '7'), value: DatePreset.SevenDays },
|
{ name: this.i18nService.t("days", "7"), value: DatePreset.SevenDays },
|
||||||
{ name: this.i18nService.t('days', '30'), value: DatePreset.ThirtyDays },
|
{ name: this.i18nService.t("days", "30"), value: DatePreset.ThirtyDays },
|
||||||
{ name: this.i18nService.t('custom'), value: DatePreset.Custom },
|
{ name: this.i18nService.t("custom"), value: DatePreset.Custom },
|
||||||
];
|
];
|
||||||
|
|
||||||
expirationDatePresets: any[] = [
|
expirationDatePresets: any[] = [
|
||||||
{ name: this.i18nService.t('never'), value: DatePreset.Never },
|
{ name: this.i18nService.t("never"), value: DatePreset.Never },
|
||||||
].concat([...this.deletionDatePresets]);
|
].concat([...this.deletionDatePresets]);
|
||||||
|
|
||||||
get selectedDeletionDatePreset(): FormControl {
|
get selectedDeletionDatePreset(): FormControl {
|
||||||
return this.datesForm.get('selectedDeletionDatePreset') as FormControl;
|
return this.datesForm.get("selectedDeletionDatePreset") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedExpirationDatePreset(): FormControl {
|
get selectedExpirationDatePreset(): FormControl {
|
||||||
return this.datesForm.get('selectedExpirationDatePreset') as FormControl;
|
return this.datesForm.get("selectedExpirationDatePreset") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultDeletionDateTime(): FormControl {
|
get defaultDeletionDateTime(): FormControl {
|
||||||
return this.datesForm.get('defaultDeletionDateTime') as FormControl;
|
return this.datesForm.get("defaultDeletionDateTime") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get defaultExpirationDateTime(): FormControl {
|
get defaultExpirationDateTime(): FormControl {
|
||||||
return this.datesForm.get('defaultExpirationDateTime') as FormControl;
|
return this.datesForm.get("defaultExpirationDateTime") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get fallbackDeletionDate(): FormControl {
|
get fallbackDeletionDate(): FormControl {
|
||||||
return this.datesForm.get('fallbackDeletionDate') as FormControl;
|
return this.datesForm.get("fallbackDeletionDate") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get fallbackDeletionTime(): FormControl {
|
get fallbackDeletionTime(): FormControl {
|
||||||
return this.datesForm.get('fallbackDeletionTime') as FormControl;
|
return this.datesForm.get("fallbackDeletionTime") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get fallbackExpirationDate(): FormControl {
|
get fallbackExpirationDate(): FormControl {
|
||||||
return this.datesForm.get('fallbackExpirationDate') as FormControl;
|
return this.datesForm.get("fallbackExpirationDate") as FormControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
get fallbackExpirationTime(): 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
|
// 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) {
|
switch (this.browserPath) {
|
||||||
case BrowserPath.Safari:
|
case BrowserPath.Safari:
|
||||||
case BrowserPath.Firefox:
|
case BrowserPath.Firefox:
|
||||||
return this.fallbackDeletionDate.value + 'T' + this.fallbackDeletionTime.value;
|
return this.fallbackDeletionDate.value + "T" + this.fallbackDeletionTime.value;
|
||||||
default:
|
default:
|
||||||
return this.defaultDeletionDateTime.value;
|
return this.defaultDeletionDateTime.value;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const miliseconds = now.setTime(now.getTime() +
|
const miliseconds = now.setTime(
|
||||||
(this.selectedDeletionDatePreset.value as number * 60 * 60 * 1000)) ;
|
now.getTime() + (this.selectedDeletionDatePreset.value as number) * 60 * 60 * 1000
|
||||||
|
);
|
||||||
return new Date(miliseconds).toString();
|
return new Date(miliseconds).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,11 +150,13 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
switch (this.browserPath) {
|
switch (this.browserPath) {
|
||||||
case BrowserPath.Safari:
|
case BrowserPath.Safari:
|
||||||
case BrowserPath.Firefox:
|
case BrowserPath.Firefox:
|
||||||
if ((!this.fallbackExpirationDate.value || !this.fallbackExpirationTime.value) &&
|
if (
|
||||||
this.editMode) {
|
(!this.fallbackExpirationDate.value || !this.fallbackExpirationTime.value) &&
|
||||||
|
this.editMode
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return this.fallbackExpirationDate.value + 'T' + this.fallbackExpirationTime.value;
|
return this.fallbackExpirationDate.value + "T" + this.fallbackExpirationTime.value;
|
||||||
default:
|
default:
|
||||||
if (!this.defaultExpirationDateTime.value) {
|
if (!this.defaultExpirationDateTime.value) {
|
||||||
return null;
|
return null;
|
||||||
@@ -168,8 +165,9 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const miliseconds = now.setTime(now.getTime() +
|
const miliseconds = now.setTime(
|
||||||
(this.selectedExpirationDatePreset.value as number * 60 * 60 * 1000));
|
now.getTime() + (this.selectedExpirationDatePreset.value as number) * 60 * 60 * 1000
|
||||||
|
);
|
||||||
return new Date(miliseconds).toString();
|
return new Date(miliseconds).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,9 +187,11 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
return nextWeek;
|
return nextWeek;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected datePipe: DatePipe) {
|
protected i18nService: I18nService,
|
||||||
}
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected datePipe: DatePipe
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.setInitialFormValues();
|
this.setInitialFormValues();
|
||||||
@@ -235,16 +235,23 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
this.fallbackDeletionDate.setValue(this.initialDeletionDate.toISOString().slice(0, 10));
|
this.fallbackDeletionDate.setValue(this.initialDeletionDate.toISOString().slice(0, 10));
|
||||||
this.fallbackDeletionTime.setValue(this.initialDeletionDate.toTimeString().slice(0, 5));
|
this.fallbackDeletionTime.setValue(this.initialDeletionDate.toTimeString().slice(0, 5));
|
||||||
if (this.initialExpirationDate != null) {
|
if (this.initialExpirationDate != null) {
|
||||||
this.fallbackExpirationDate.setValue(this.initialExpirationDate.toISOString().slice(0, 10));
|
this.fallbackExpirationDate.setValue(
|
||||||
this.fallbackExpirationTime.setValue(this.initialExpirationDate.toTimeString().slice(0, 5));
|
this.initialExpirationDate.toISOString().slice(0, 10)
|
||||||
|
);
|
||||||
|
this.fallbackExpirationTime.setValue(
|
||||||
|
this.initialExpirationDate.toTimeString().slice(0, 5)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BrowserPath.Default:
|
case BrowserPath.Default:
|
||||||
if (this.initialExpirationDate) {
|
if (this.initialExpirationDate) {
|
||||||
this.defaultExpirationDateTime.setValue(
|
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;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -254,7 +261,9 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
switch (this.browserPath) {
|
switch (this.browserPath) {
|
||||||
case BrowserPath.Safari:
|
case BrowserPath.Safari:
|
||||||
this.fallbackDeletionDate.setValue(this.nextWeek.toISOString().slice(0, 10));
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -282,10 +291,10 @@ export class EffluxDatesComponent implements OnInit {
|
|||||||
|
|
||||||
// add prepending 0s to single digit hours/minutes
|
// add prepending 0s to single digit hours/minutes
|
||||||
if (h < 10) {
|
if (h < 10) {
|
||||||
hour = '0' + hour;
|
hour = "0" + hour;
|
||||||
}
|
}
|
||||||
if (m < 10) {
|
if (m < 10) {
|
||||||
minutes = '0' + minutes;
|
minutes = "0" + minutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// build time strings and push to relevant sort groups
|
// 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
|
// example: if the Send was created with a different client
|
||||||
if (field === DateField.ExpriationDate && this.initialExpirationDate != null && this.editMode) {
|
if (field === DateField.ExpriationDate && this.initialExpirationDate != null && this.editMode) {
|
||||||
const previousValue: TimeOption = {
|
const previousValue: TimeOption = {
|
||||||
twelveHour: this.datePipe.transform(this.initialExpirationDate, 'hh:mm a'),
|
twelveHour: this.datePipe.transform(this.initialExpirationDate, "hh:mm a"),
|
||||||
twentyFourHour: this.datePipe.transform(this.initialExpirationDate, 'HH:mm'),
|
twentyFourHour: this.datePipe.transform(this.initialExpirationDate, "HH:mm"),
|
||||||
};
|
};
|
||||||
return [previousValue, { twelveHour: null, twentyFourHour: null }, ...validTimes];
|
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 = {
|
const previousValue: TimeOption = {
|
||||||
twelveHour: this.datePipe.transform(this.initialDeletionDate, 'hh:mm a'),
|
twelveHour: this.datePipe.transform(this.initialDeletionDate, "hh:mm a"),
|
||||||
twentyFourHour: this.datePipe.transform(this.initialDeletionDate, 'HH:mm'),
|
twentyFourHour: this.datePipe.transform(this.initialDeletionDate, "HH:mm"),
|
||||||
};
|
};
|
||||||
return [previousValue, ...validTimes];
|
return [previousValue, ...validTimes];
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,25 +1,20 @@
|
|||||||
import {
|
import { Directive, NgZone, OnInit } from "@angular/core";
|
||||||
Directive,
|
|
||||||
NgZone,
|
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
import { SendType } from 'jslib-common/enums/sendType';
|
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 { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { SearchService } from 'jslib-common/abstractions/search.service';
|
import { SearchService } from "jslib-common/abstractions/search.service";
|
||||||
import { SendService } from 'jslib-common/abstractions/send.service';
|
import { SendService } from "jslib-common/abstractions/send.service";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class SendComponent implements OnInit {
|
export class SendComponent implements OnInit {
|
||||||
|
|
||||||
disableSend = false;
|
disableSend = false;
|
||||||
sendType = SendType;
|
sendType = SendType;
|
||||||
loaded = false;
|
loaded = false;
|
||||||
@@ -44,10 +39,16 @@ export class SendComponent implements OnInit {
|
|||||||
|
|
||||||
private searchTimeout: any;
|
private searchTimeout: any;
|
||||||
|
|
||||||
constructor(protected sendService: SendService, protected i18nService: I18nService,
|
constructor(
|
||||||
protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
|
protected sendService: SendService,
|
||||||
protected ngZone: NgZone, protected searchService: SearchService,
|
protected i18nService: I18nService,
|
||||||
protected policyService: PolicyService, private logService: LogService) { }
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected environmentService: EnvironmentService,
|
||||||
|
protected ngZone: NgZone,
|
||||||
|
protected searchService: SearchService,
|
||||||
|
protected policyService: PolicyService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
|
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);
|
||||||
@@ -94,14 +95,14 @@ export class SendComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
if (timeout == null) {
|
if (timeout == null) {
|
||||||
this.hasSearched = this.searchService.isSearchable(this.searchText);
|
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.applyTextSearch();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.searchPending = true;
|
this.searchPending = true;
|
||||||
this.searchTimeout = setTimeout(async () => {
|
this.searchTimeout = setTimeout(async () => {
|
||||||
this.hasSearched = this.searchService.isSearchable(this.searchText);
|
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.applyTextSearch();
|
||||||
this.searchPending = false;
|
this.searchPending = false;
|
||||||
}, timeout);
|
}, timeout);
|
||||||
@@ -111,9 +112,13 @@ export class SendComponent implements OnInit {
|
|||||||
if (this.actionPromise != null || s.password == null) {
|
if (this.actionPromise != null || s.password == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const confirmed = await this.platformUtilsService.showDialog(this.i18nService.t('removePasswordConfirmation'),
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('removePassword'),
|
this.i18nService.t("removePasswordConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("removePassword"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -125,7 +130,7 @@ export class SendComponent implements OnInit {
|
|||||||
this.onSuccessfulRemovePassword();
|
this.onSuccessfulRemovePassword();
|
||||||
} else {
|
} else {
|
||||||
// Default actions
|
// Default actions
|
||||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('removedPassword'));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("removedPassword"));
|
||||||
await this.load();
|
await this.load();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -139,9 +144,12 @@ export class SendComponent implements OnInit {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('deleteSendConfirmation'),
|
this.i18nService.t("deleteSendConfirmation"),
|
||||||
this.i18nService.t('deleteSend'),
|
this.i18nService.t("deleteSend"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -154,7 +162,7 @@ export class SendComponent implements OnInit {
|
|||||||
this.onSuccessfulDelete();
|
this.onSuccessfulDelete();
|
||||||
} else {
|
} else {
|
||||||
// Default actions
|
// Default actions
|
||||||
this.platformUtilsService.showToast('success', null, this.i18nService.t('deletedSend'));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedSend"));
|
||||||
await this.refresh();
|
await this.refresh();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -166,10 +174,13 @@ export class SendComponent implements OnInit {
|
|||||||
|
|
||||||
copy(s: SendView) {
|
copy(s: SendView) {
|
||||||
const sendLinkBaseUrl = this.environmentService.getSendUrl();
|
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.copyToClipboard(link);
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('valueCopied', this.i18nService.t('sendLink')));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t("sendLink"))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
searchTextChanged() {
|
searchTextChanged() {
|
||||||
@@ -185,7 +196,7 @@ export class SendComponent implements OnInit {
|
|||||||
selectType(type: SendType) {
|
selectType(type: SendType) {
|
||||||
this.clearSelections();
|
this.clearSelections();
|
||||||
this.selectedType = type;
|
this.selectedType = type;
|
||||||
this.applyFilter(s => s.type === type);
|
this.applyFilter((s) => s.type === type);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearSelections() {
|
clearSelections() {
|
||||||
|
|||||||
@@ -1,61 +1,73 @@
|
|||||||
import { Directive } from '@angular/core';
|
import { Directive } from "@angular/core";
|
||||||
import {
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
ActivatedRoute,
|
|
||||||
Router
|
|
||||||
} from '@angular/router';
|
|
||||||
|
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { SyncService } from 'jslib-common/abstractions/sync.service';
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
||||||
|
|
||||||
import { EncString } from 'jslib-common/models/domain/encString';
|
import { EncString } from "jslib-common/models/domain/encString";
|
||||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "jslib-common/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { KeysRequest } from 'jslib-common/models/request/keysRequest';
|
import { KeysRequest } from "jslib-common/models/request/keysRequest";
|
||||||
import { OrganizationUserResetPasswordEnrollmentRequest } from 'jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest';
|
import { OrganizationUserResetPasswordEnrollmentRequest } from "jslib-common/models/request/organizationUserResetPasswordEnrollmentRequest";
|
||||||
import { SetPasswordRequest } from 'jslib-common/models/request/setPasswordRequest';
|
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 { HashPurpose } from "jslib-common/enums/hashPurpose";
|
||||||
import { KdfType } from 'jslib-common/enums/kdfType';
|
import { KdfType } from "jslib-common/enums/kdfType";
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class SetPasswordComponent extends BaseChangePasswordComponent {
|
export class SetPasswordComponent extends BaseChangePasswordComponent {
|
||||||
syncLoading: boolean = true;
|
syncLoading: boolean = true;
|
||||||
showPassword: boolean = false;
|
showPassword: boolean = false;
|
||||||
hint: string = '';
|
hint: string = "";
|
||||||
identifier: string = null;
|
identifier: string = null;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
resetPasswordAutoEnroll = false;
|
resetPasswordAutoEnroll = false;
|
||||||
|
|
||||||
onSuccessfulChangePassword: () => Promise<any>;
|
onSuccessfulChangePassword: () => Promise<any>;
|
||||||
successRoute = 'vault';
|
successRoute = "vault";
|
||||||
|
|
||||||
constructor(i18nService: I18nService, cryptoService: CryptoService,
|
constructor(
|
||||||
messagingService: MessagingService, passwordGenerationService: PasswordGenerationService,
|
i18nService: I18nService,
|
||||||
platformUtilsService: PlatformUtilsService, policyService: PolicyService,
|
cryptoService: CryptoService,
|
||||||
protected router: Router, private apiService: ApiService,
|
messagingService: MessagingService,
|
||||||
private syncService: SyncService, private route: ActivatedRoute, stateService: StateService) {
|
passwordGenerationService: PasswordGenerationService,
|
||||||
super(i18nService, cryptoService, messagingService, passwordGenerationService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
platformUtilsService, policyService, stateService);
|
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() {
|
async ngOnInit() {
|
||||||
await this.syncService.fullSync(true);
|
await this.syncService.fullSync(true);
|
||||||
this.syncLoading = false;
|
this.syncLoading = false;
|
||||||
|
|
||||||
this.route.queryParams.pipe(first()).subscribe(async qParams => {
|
this.route.queryParams.pipe(first()).subscribe(async (qParams) => {
|
||||||
if (qParams.identifier != null) {
|
if (qParams.identifier != null) {
|
||||||
this.identifier = qParams.identifier;
|
this.identifier = qParams.identifier;
|
||||||
}
|
}
|
||||||
@@ -68,7 +80,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
this.orgId = response.id;
|
this.orgId = response.id;
|
||||||
this.resetPasswordAutoEnroll = response.resetPasswordEnabled;
|
this.resetPasswordAutoEnroll = response.resetPasswordEnabled;
|
||||||
} catch {
|
} 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
|
async performSubmitActions(
|
||||||
encKey: [SymmetricCryptoKey, EncString]) {
|
masterPasswordHash: string,
|
||||||
|
key: SymmetricCryptoKey,
|
||||||
|
encKey: [SymmetricCryptoKey, EncString]
|
||||||
|
) {
|
||||||
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
const keys = await this.cryptoService.makeKeyPair(encKey[0]);
|
||||||
const request = new SetPasswordRequest(
|
const request = new SetPasswordRequest(
|
||||||
masterPasswordHash,
|
masterPasswordHash,
|
||||||
@@ -96,24 +111,34 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
if (this.resetPasswordAutoEnroll) {
|
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);
|
await this.onSetPasswordSuccess(key, encKey, keys);
|
||||||
return this.apiService.getOrganizationKeys(this.orgId);
|
return this.apiService.getOrganizationKeys(this.orgId);
|
||||||
}).then(async response => {
|
})
|
||||||
|
.then(async (response) => {
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
throw new Error(this.i18nService.t('resetPasswordOrgKeysError'));
|
throw new Error(this.i18nService.t("resetPasswordOrgKeysError"));
|
||||||
}
|
}
|
||||||
const userId = await this.stateService.getUserId();
|
const userId = await this.stateService.getUserId();
|
||||||
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
const publicKey = Utils.fromB64ToArray(response.publicKey);
|
||||||
|
|
||||||
// RSA Encrypt user's encKey.key with organization public key
|
// RSA Encrypt user's encKey.key with organization public key
|
||||||
const userEncKey = await this.cryptoService.getEncKey();
|
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();
|
const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest();
|
||||||
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
|
resetRequest.resetPasswordKey = encryptedKey.encryptedString;
|
||||||
|
|
||||||
return this.apiService.putOrganizationUserResetPasswordEnrollment(this.orgId, userId, resetRequest);
|
return this.apiService.putOrganizationUserResetPasswordEnrollment(
|
||||||
|
this.orgId,
|
||||||
|
userId,
|
||||||
|
resetRequest
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.formPromise = this.apiService.setPassword(request).then(async () => {
|
this.formPromise = this.apiService.setPassword(request).then(async () => {
|
||||||
@@ -129,24 +154,31 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
this.router.navigate([this.successRoute]);
|
this.router.navigate([this.successRoute]);
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
togglePassword(confirmField: boolean) {
|
togglePassword(confirmField: boolean) {
|
||||||
this.showPassword = !this.showPassword;
|
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.setKdfType(this.kdf);
|
||||||
await this.stateService.setKdfIterations(this.kdfIterations);
|
await this.stateService.setKdfIterations(this.kdfIterations);
|
||||||
await this.cryptoService.setKey(key);
|
await this.cryptoService.setKey(key);
|
||||||
await this.cryptoService.setEncKey(encKey[1].encryptedString);
|
await this.cryptoService.setEncKey(encKey[1].encryptedString);
|
||||||
await this.cryptoService.setEncPrivateKey(keys[1].encryptedString);
|
await this.cryptoService.setEncPrivateKey(keys[1].encryptedString);
|
||||||
|
|
||||||
const localKeyHash = await this.cryptoService.hashPassword(this.masterPassword, key,
|
const localKeyHash = await this.cryptoService.hashPassword(
|
||||||
HashPurpose.LocalAuthorization);
|
this.masterPassword,
|
||||||
|
key,
|
||||||
|
HashPurpose.LocalAuthorization
|
||||||
|
);
|
||||||
await this.cryptoService.setKeyHash(localKeyHash);
|
await this.cryptoService.setKeyHash(localKeyHash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
import {
|
import { Directive, OnInit } from "@angular/core";
|
||||||
Directive,
|
|
||||||
OnInit
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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()
|
@Directive()
|
||||||
export class SetPinComponent implements OnInit {
|
export class SetPinComponent implements OnInit {
|
||||||
pin = '';
|
pin = "";
|
||||||
showPin = false;
|
showPin = false;
|
||||||
masterPassOnRestart = true;
|
masterPassOnRestart = true;
|
||||||
showMasterPassOnRestart = true;
|
showMasterPassOnRestart = true;
|
||||||
|
|
||||||
constructor(private modalRef: ModalRef, private cryptoService: CryptoService,
|
constructor(
|
||||||
private keyConnectorService: KeyConnectorService, private stateService: StateService) { }
|
private modalRef: ModalRef,
|
||||||
|
private cryptoService: CryptoService,
|
||||||
|
private keyConnectorService: KeyConnectorService,
|
||||||
|
private stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.showMasterPassOnRestart = this.masterPassOnRestart = !await this.keyConnectorService.getUsesKeyConnector();
|
this.showMasterPassOnRestart = this.masterPassOnRestart =
|
||||||
|
!(await this.keyConnectorService.getUsesKeyConnector());
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleVisibility() {
|
toggleVisibility() {
|
||||||
|
|||||||
@@ -1,27 +1,22 @@
|
|||||||
import {
|
import { Directive, Input, OnInit } from "@angular/core";
|
||||||
Directive,
|
|
||||||
Input,
|
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
import {
|
import {
|
||||||
AbstractControl,
|
AbstractControl,
|
||||||
ControlValueAccessor,
|
ControlValueAccessor,
|
||||||
FormBuilder,
|
FormBuilder,
|
||||||
ValidationErrors,
|
ValidationErrors,
|
||||||
Validator
|
Validator,
|
||||||
} from '@angular/forms';
|
} from "@angular/forms";
|
||||||
|
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
|
|
||||||
import { PolicyType } from 'jslib-common/enums/policyType';
|
import { PolicyType } from "jslib-common/enums/policyType";
|
||||||
import { Policy } from 'jslib-common/models/domain/policy';
|
import { Policy } from "jslib-common/models/domain/policy";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class VaultTimeoutInputComponent implements ControlValueAccessor, Validator, OnInit {
|
export class VaultTimeoutInputComponent implements ControlValueAccessor, Validator, OnInit {
|
||||||
|
|
||||||
get showCustom() {
|
get showCustom() {
|
||||||
return this.form.get('vaultTimeout').value === VaultTimeoutInputComponent.CUSTOM_VALUE;
|
return this.form.get("vaultTimeout").value === VaultTimeoutInputComponent.CUSTOM_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CUSTOM_VALUE = -100;
|
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;
|
vaultTimeoutPolicy: Policy;
|
||||||
vaultTimeoutPolicyHours: number;
|
vaultTimeoutPolicyHours: number;
|
||||||
vaultTimeoutPolicyMinutes: number;
|
vaultTimeoutPolicyMinutes: number;
|
||||||
@@ -42,8 +37,11 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
|
|||||||
private onChange: (vaultTimeout: number) => void;
|
private onChange: (vaultTimeout: number) => void;
|
||||||
private validatorChange: () => 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() {
|
async ngOnInit() {
|
||||||
if (await this.policyService.policyAppliesToUser(PolicyType.MaximumVaultTimeout)) {
|
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.vaultTimeoutPolicyHours = Math.floor(this.vaultTimeoutPolicy.data.minutes / 60);
|
||||||
this.vaultTimeoutPolicyMinutes = 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 <= this.vaultTimeoutPolicy.data.minutes &&
|
||||||
(t.value > 0 || t.value === VaultTimeoutInputComponent.CUSTOM_VALUE) &&
|
(t.value > 0 || t.value === VaultTimeoutInputComponent.CUSTOM_VALUE) &&
|
||||||
t.value != null
|
t.value != null
|
||||||
@@ -61,12 +60,12 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
|
|||||||
this.validatorChange();
|
this.validatorChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.form.valueChanges.subscribe(async value => {
|
this.form.valueChanges.subscribe(async (value) => {
|
||||||
this.onChange(this.getVaultTimeout(value));
|
this.onChange(this.getVaultTimeout(value));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Assign the previous value to the custom fields
|
// 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) {
|
if (value !== VaultTimeoutInputComponent.CUSTOM_VALUE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,7 +81,10 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges() {
|
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) {
|
getVaultTimeout(value: any) {
|
||||||
@@ -98,7 +100,7 @@ export class VaultTimeoutInputComponent implements ControlValueAccessor, Validat
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.vaultTimeouts.every(p => p.value !== value)) {
|
if (this.vaultTimeouts.every((p) => p.value !== value)) {
|
||||||
this.form.setValue({
|
this.form.setValue({
|
||||||
vaultTimeout: VaultTimeoutInputComponent.CUSTOM_VALUE,
|
vaultTimeout: VaultTimeoutInputComponent.CUSTOM_VALUE,
|
||||||
custom: {
|
custom: {
|
||||||
|
|||||||
@@ -1,25 +1,19 @@
|
|||||||
import {
|
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
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 { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CollectionService } from 'jslib-common/abstractions/collection.service';
|
import { CollectionService } from "jslib-common/abstractions/collection.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { OrganizationService } from 'jslib-common/abstractions/organization.service';
|
import { OrganizationService } from "jslib-common/abstractions/organization.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { Organization } from 'jslib-common/models/domain/organization';
|
import { Organization } from "jslib-common/models/domain/organization";
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { CollectionView } from 'jslib-common/models/view/collectionView';
|
import { CollectionView } from "jslib-common/models/view/collectionView";
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class ShareComponent implements OnInit {
|
export class ShareComponent implements OnInit {
|
||||||
@@ -34,9 +28,14 @@ export class ShareComponent implements OnInit {
|
|||||||
|
|
||||||
protected writeableCollections: CollectionView[] = [];
|
protected writeableCollections: CollectionView[] = [];
|
||||||
|
|
||||||
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
protected i18nService: I18nService, protected cipherService: CipherService,
|
protected collectionService: CollectionService,
|
||||||
private logService: LogService, protected organizationService: OrganizationService) { }
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected cipherService: CipherService,
|
||||||
|
private logService: LogService,
|
||||||
|
protected organizationService: OrganizationService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
await this.load();
|
await this.load();
|
||||||
@@ -44,10 +43,11 @@ export class ShareComponent implements OnInit {
|
|||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
const allCollections = await this.collectionService.getAllDecrypted();
|
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();
|
const orgs = await this.organizationService.getAll();
|
||||||
this.organizations = orgs.sort(Utils.getSortFunction(this.i18nService, 'name'))
|
this.organizations = orgs
|
||||||
.filter(o => o.enabled && o.status === OrganizationUserStatusType.Confirmed);
|
.sort(Utils.getSortFunction(this.i18nService, "name"))
|
||||||
|
.filter((o) => o.enabled && o.status === OrganizationUserStatusType.Confirmed);
|
||||||
|
|
||||||
const cipherDomain = await this.cipherService.get(this.cipherId);
|
const cipherDomain = await this.cipherService.get(this.cipherId);
|
||||||
this.cipher = await cipherDomain.decrypt();
|
this.cipher = await cipherDomain.decrypt();
|
||||||
@@ -58,34 +58,45 @@ export class ShareComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterCollections() {
|
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) {
|
if (this.organizationId == null || this.writeableCollections.length === 0) {
|
||||||
this.collections = [];
|
this.collections = [];
|
||||||
} else {
|
} 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> {
|
async submit(): Promise<boolean> {
|
||||||
const selectedCollectionIds = this.collections
|
const selectedCollectionIds = this.collections
|
||||||
.filter(c => !!(c as any).checked)
|
.filter((c) => !!(c as any).checked)
|
||||||
.map(c => c.id);
|
.map((c) => c.id);
|
||||||
if (selectedCollectionIds.length === 0) {
|
if (selectedCollectionIds.length === 0) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('selectOneCollection'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("selectOneCollection")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cipherDomain = await this.cipherService.get(this.cipherId);
|
const cipherDomain = await this.cipherService.get(this.cipherId);
|
||||||
const cipherView = await cipherDomain.decrypt();
|
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 {
|
try {
|
||||||
this.formPromise = this.cipherService.shareWithServer(cipherView, this.organizationId,
|
this.formPromise = this.cipherService
|
||||||
selectedCollectionIds).then(async () => {
|
.shareWithServer(cipherView, this.organizationId, selectedCollectionIds)
|
||||||
|
.then(async () => {
|
||||||
this.onSharedCipher.emit();
|
this.onSharedCipher.emit();
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('movedItemToOrg', cipherView.name, orgName));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("movedItemToOrg", cipherView.name, orgName)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
await this.formPromise;
|
await this.formPromise;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
import { Directive } from '@angular/core';
|
import { Directive } from "@angular/core";
|
||||||
import {
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
ActivatedRoute,
|
|
||||||
Router,
|
|
||||||
} from '@angular/router';
|
|
||||||
|
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { CryptoFunctionService } from 'jslib-common/abstractions/cryptoFunction.service';
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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()
|
@Directive()
|
||||||
export class SsoComponent {
|
export class SsoComponent {
|
||||||
@@ -33,34 +30,54 @@ export class SsoComponent {
|
|||||||
onSuccessfulLoginChangePasswordNavigate: () => Promise<any>;
|
onSuccessfulLoginChangePasswordNavigate: () => Promise<any>;
|
||||||
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
|
onSuccessfulLoginForceResetNavigate: () => Promise<any>;
|
||||||
|
|
||||||
protected twoFactorRoute = '2fa';
|
protected twoFactorRoute = "2fa";
|
||||||
protected successRoute = 'lock';
|
protected successRoute = "lock";
|
||||||
protected changePasswordRoute = 'set-password';
|
protected changePasswordRoute = "set-password";
|
||||||
protected forcePasswordResetRoute = 'update-temp-password';
|
protected forcePasswordResetRoute = "update-temp-password";
|
||||||
protected clientId: string;
|
protected clientId: string;
|
||||||
protected redirectUri: string;
|
protected redirectUri: string;
|
||||||
protected state: string;
|
protected state: string;
|
||||||
protected codeChallenge: string;
|
protected codeChallenge: string;
|
||||||
|
|
||||||
constructor(protected authService: AuthService, protected router: Router,
|
constructor(
|
||||||
protected i18nService: I18nService, protected route: ActivatedRoute,
|
protected authService: AuthService,
|
||||||
protected stateService: StateService, protected platformUtilsService: PlatformUtilsService,
|
protected router: Router,
|
||||||
protected apiService: ApiService, protected cryptoFunctionService: CryptoFunctionService,
|
protected i18nService: I18nService,
|
||||||
protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationService,
|
protected route: ActivatedRoute,
|
||||||
protected logService: LogService) { }
|
protected stateService: StateService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected apiService: ApiService,
|
||||||
|
protected cryptoFunctionService: CryptoFunctionService,
|
||||||
|
protected environmentService: EnvironmentService,
|
||||||
|
protected passwordGenerationService: PasswordGenerationService,
|
||||||
|
protected logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
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) {
|
if (qParams.code != null && qParams.state != null) {
|
||||||
const codeVerifier = await this.stateService.getSsoCodeVerifier();
|
const codeVerifier = await this.stateService.getSsoCodeVerifier();
|
||||||
const state = await this.stateService.getSsoState();
|
const state = await this.stateService.getSsoState();
|
||||||
await this.stateService.setSsoCodeVerifier(null);
|
await this.stateService.setSsoCodeVerifier(null);
|
||||||
await this.stateService.setSsoState(null);
|
await this.stateService.setSsoState(null);
|
||||||
if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
|
if (
|
||||||
await this.logIn(qParams.code, codeVerifier, this.getOrgIdentifierFromState(qParams.state));
|
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 &&
|
} else if (
|
||||||
qParams.codeChallenge != null) {
|
qParams.clientId != null &&
|
||||||
|
qParams.redirectUri != null &&
|
||||||
|
qParams.state != null &&
|
||||||
|
qParams.codeChallenge != null
|
||||||
|
) {
|
||||||
this.redirectUri = qParams.redirectUri;
|
this.redirectUri = qParams.redirectUri;
|
||||||
this.state = qParams.state;
|
this.state = qParams.state;
|
||||||
this.codeChallenge = qParams.codeChallenge;
|
this.codeChallenge = qParams.codeChallenge;
|
||||||
@@ -78,20 +95,26 @@ export class SsoComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async preValidate(): Promise<boolean> {
|
async preValidate(): Promise<boolean> {
|
||||||
if (this.identifier == null || this.identifier === '') {
|
if (this.identifier == null || this.identifier === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('ssoValidationFailed'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('ssoIdentifierRequired'));
|
"error",
|
||||||
|
this.i18nService.t("ssoValidationFailed"),
|
||||||
|
this.i18nService.t("ssoIdentifierRequired")
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return await this.apiService.preValidateSso(this.identifier);
|
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 codeChallenge = this.codeChallenge;
|
||||||
let state = this.state;
|
let state = this.state;
|
||||||
|
|
||||||
const passwordOptions: any = {
|
const passwordOptions: any = {
|
||||||
type: 'password',
|
type: "password",
|
||||||
length: 64,
|
length: 64,
|
||||||
uppercase: true,
|
uppercase: true,
|
||||||
lowercase: true,
|
lowercase: true,
|
||||||
@@ -101,7 +124,7 @@ export class SsoComponent {
|
|||||||
|
|
||||||
if (codeChallenge == null) {
|
if (codeChallenge == null) {
|
||||||
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
|
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);
|
codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
|
||||||
await this.stateService.setSsoCodeVerifier(codeVerifier);
|
await this.stateService.setSsoCodeVerifier(codeVerifier);
|
||||||
}
|
}
|
||||||
@@ -119,12 +142,23 @@ export class SsoComponent {
|
|||||||
// Save state (regardless of new or existing)
|
// Save state (regardless of new or existing)
|
||||||
await this.stateService.setSsoState(state);
|
await this.stateService.setSsoState(state);
|
||||||
|
|
||||||
let authorizeUrl = this.environmentService.getIdentityUrl() + '/connect/authorize?' +
|
let authorizeUrl =
|
||||||
'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' +
|
this.environmentService.getIdentityUrl() +
|
||||||
'response_type=code&scope=api offline_access&' +
|
"/connect/authorize?" +
|
||||||
'state=' + state + '&code_challenge=' + codeChallenge + '&' +
|
"client_id=" +
|
||||||
'code_challenge_method=S256&response_mode=query&' +
|
this.clientId +
|
||||||
'domain_hint=' + encodeURIComponent(this.identifier);
|
"&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) {
|
if (includeUserIdentifier) {
|
||||||
const userIdentifier = await this.apiService.getSsoUserIdentifier();
|
const userIdentifier = await this.apiService.getSsoUserIdentifier();
|
||||||
@@ -137,7 +171,12 @@ export class SsoComponent {
|
|||||||
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
|
private async logIn(code: string, codeVerifier: string, orgIdFromState: string) {
|
||||||
this.loggingIn = true;
|
this.loggingIn = true;
|
||||||
try {
|
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;
|
const response = await this.formPromise;
|
||||||
if (response.twoFactor) {
|
if (response.twoFactor) {
|
||||||
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
|
if (this.onSuccessfulLoginTwoFactorNavigate != null) {
|
||||||
@@ -146,7 +185,7 @@ export class SsoComponent {
|
|||||||
this.router.navigate([this.twoFactorRoute], {
|
this.router.navigate([this.twoFactorRoute], {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
identifier: orgIdFromState,
|
identifier: orgIdFromState,
|
||||||
sso: 'true',
|
sso: "true",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -180,8 +219,12 @@ export class SsoComponent {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
if (e.message === 'Unable to reach key connector') {
|
if (e.message === "Unable to reach key connector") {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('ssoKeyConnectorUnavailable'));
|
this.platformUtilsService.showToast(
|
||||||
|
"error",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("ssoKeyConnectorUnavailable")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.loggingIn = false;
|
this.loggingIn = false;
|
||||||
@@ -192,7 +235,7 @@ export class SsoComponent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateSplit = state.split('_identifier=');
|
const stateSplit = state.split("_identifier=");
|
||||||
return stateSplit.length > 1 ? stateSplit[1] : null;
|
return stateSplit.length > 1 ? stateSplit[1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,8 +247,8 @@ export class SsoComponent {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateSplit = state.split('_identifier=');
|
const stateSplit = state.split("_identifier=");
|
||||||
const checkStateSplit = checkState.split('_identifier=');
|
const checkStateSplit = checkState.split("_identifier=");
|
||||||
return stateSplit[0] === checkStateSplit[0];
|
return stateSplit[0] === checkStateSplit[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
import {
|
||||||
animate,
|
DefaultNoComponentGlobalConfig,
|
||||||
state,
|
GlobalConfig,
|
||||||
style,
|
Toast as BaseToast,
|
||||||
transition,
|
ToastPackage,
|
||||||
trigger
|
ToastrService,
|
||||||
} from '@angular/animations';
|
TOAST_CONFIG,
|
||||||
import { CommonModule } from '@angular/common';
|
} from "ngx-toastr";
|
||||||
import { Component, ModuleWithProviders, NgModule } from '@angular/core';
|
|
||||||
import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, ToastPackage, ToastrService, TOAST_CONFIG } from 'ngx-toastr';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: '[toast-component2]',
|
selector: "[toast-component2]",
|
||||||
template: `
|
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">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
@@ -22,11 +29,20 @@ import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, Toast
|
|||||||
<div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
|
<div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
|
||||||
{{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
|
{{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="message && options.enableHtml" role="alertdialog" aria-live="polite"
|
<div
|
||||||
[class]="options.messageClass" [innerHTML]="message">
|
*ngIf="message && options.enableHtml"
|
||||||
</div>
|
role="alertdialog"
|
||||||
<div *ngIf="message && !options.enableHtml" role="alertdialog" aria-live="polite"
|
aria-live="polite"
|
||||||
[class]="options.messageClass" [attr.aria-label]="message">
|
[class]="options.messageClass"
|
||||||
|
[innerHTML]="message"
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
*ngIf="message && !options.enableHtml"
|
||||||
|
role="alertdialog"
|
||||||
|
aria-live="polite"
|
||||||
|
[class]="options.messageClass"
|
||||||
|
[attr.aria-label]="message"
|
||||||
|
>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,18 +51,12 @@ import { DefaultNoComponentGlobalConfig, GlobalConfig, Toast as BaseToast, Toast
|
|||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
animations: [
|
animations: [
|
||||||
trigger('flyInOut', [
|
trigger("flyInOut", [
|
||||||
state('inactive', style({ opacity: 0 })),
|
state("inactive", style({ opacity: 0 })),
|
||||||
state('active', style({ opacity: 1 })),
|
state("active", style({ opacity: 1 })),
|
||||||
state('removed', style({ opacity: 0 })),
|
state("removed", style({ opacity: 0 })),
|
||||||
transition(
|
transition("inactive => active", animate("{{ easeTime }}ms {{ easing }}")),
|
||||||
'inactive => active',
|
transition("active => removed", animate("{{ easeTime }}ms {{ easing }}")),
|
||||||
animate('{{ easeTime }}ms {{ easing }}')
|
|
||||||
),
|
|
||||||
transition(
|
|
||||||
'active => removed',
|
|
||||||
animate('{{ easeTime }}ms {{ easing }}')
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
preserveWhitespaces: false,
|
preserveWhitespaces: false,
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import {
|
import { Directive, EventEmitter, OnInit, Output } from "@angular/core";
|
||||||
Directive,
|
import { Router } from "@angular/router";
|
||||||
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 { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class TwoFactorOptionsComponent implements OnInit {
|
export class TwoFactorOptionsComponent implements OnInit {
|
||||||
@@ -19,9 +14,13 @@ export class TwoFactorOptionsComponent implements OnInit {
|
|||||||
|
|
||||||
providers: any[] = [];
|
providers: any[] = [];
|
||||||
|
|
||||||
constructor(protected authService: AuthService, protected router: Router,
|
constructor(
|
||||||
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
|
protected authService: AuthService,
|
||||||
protected win: Window) { }
|
protected router: Router,
|
||||||
|
protected i18nService: I18nService,
|
||||||
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
|
protected win: Window
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.providers = this.authService.getSupportedTwoFactorProviders(this.win);
|
this.providers = this.authService.getSupportedTwoFactorProviders(this.win);
|
||||||
@@ -32,7 +31,7 @@ export class TwoFactorOptionsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
recover() {
|
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();
|
this.onRecoverSelected.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,31 @@
|
|||||||
import { Directive, OnDestroy, OnInit } from '@angular/core';
|
import { Directive, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
|
||||||
import {
|
import { ActivatedRoute, Router } from "@angular/router";
|
||||||
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 { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuthService } from 'jslib-common/abstractions/auth.service';
|
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||||
import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.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 * as DuoWebSDK from "duo_web_sdk";
|
||||||
import { WebAuthnIFrame } from 'jslib-common/misc/webauthn_iframe';
|
import { WebAuthnIFrame } from "jslib-common/misc/webauthn_iframe";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class TwoFactorComponent implements OnInit, OnDestroy {
|
export class TwoFactorComponent implements OnInit, OnDestroy {
|
||||||
token: string = '';
|
token: string = "";
|
||||||
remember: boolean = false;
|
remember: boolean = false;
|
||||||
webAuthnReady: boolean = false;
|
webAuthnReady: boolean = false;
|
||||||
webAuthnNewTab: boolean = false;
|
webAuthnNewTab: boolean = false;
|
||||||
@@ -37,7 +34,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
selectedProviderType: TwoFactorProviderType = TwoFactorProviderType.Authenticator;
|
selectedProviderType: TwoFactorProviderType = TwoFactorProviderType.Authenticator;
|
||||||
webAuthnSupported: boolean = false;
|
webAuthnSupported: boolean = false;
|
||||||
webAuthn: WebAuthnIFrame = null;
|
webAuthn: WebAuthnIFrame = null;
|
||||||
title: string = '';
|
title: string = "";
|
||||||
twoFactorEmail: string = null;
|
twoFactorEmail: string = null;
|
||||||
formPromise: Promise<any>;
|
formPromise: Promise<any>;
|
||||||
emailPromise: Promise<any>;
|
emailPromise: Promise<any>;
|
||||||
@@ -49,14 +46,21 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
return `publickey-credentials-get ${this.environmentService.getWebVaultUrl()}`;
|
return `publickey-credentials-get ${this.environmentService.getWebVaultUrl()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loginRoute = 'login';
|
protected loginRoute = "login";
|
||||||
protected successRoute = 'vault';
|
protected successRoute = "vault";
|
||||||
|
|
||||||
constructor(protected authService: AuthService, protected router: Router,
|
constructor(
|
||||||
protected i18nService: I18nService, protected apiService: ApiService,
|
protected authService: AuthService,
|
||||||
protected platformUtilsService: PlatformUtilsService, protected win: Window,
|
protected router: Router,
|
||||||
protected environmentService: EnvironmentService, protected stateService: StateService,
|
protected i18nService: I18nService,
|
||||||
protected route: ActivatedRoute, protected logService: LogService) {
|
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);
|
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,33 +70,42 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.route.queryParams.pipe(first()).subscribe(qParams => {
|
this.route.queryParams.pipe(first()).subscribe((qParams) => {
|
||||||
if (qParams.identifier != null) {
|
if (qParams.identifier != null) {
|
||||||
this.identifier = qParams.identifier;
|
this.identifier = qParams.identifier;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.needsLock) {
|
if (this.needsLock) {
|
||||||
this.successRoute = 'lock';
|
this.successRoute = "lock";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.win != null && this.webAuthnSupported) {
|
if (this.win != null && this.webAuthnSupported) {
|
||||||
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
const webVaultUrl = this.environmentService.getWebVaultUrl();
|
||||||
this.webAuthn = new WebAuthnIFrame(this.win, webVaultUrl, this.webAuthnNewTab, this.platformUtilsService,
|
this.webAuthn = new WebAuthnIFrame(
|
||||||
this.i18nService, (token: string) => {
|
this.win,
|
||||||
|
webVaultUrl,
|
||||||
|
this.webAuthnNewTab,
|
||||||
|
this.platformUtilsService,
|
||||||
|
this.i18nService,
|
||||||
|
(token: string) => {
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.submit();
|
this.submit();
|
||||||
}, (error: string) => {
|
},
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'), error);
|
(error: string) => {
|
||||||
}, (info: string) => {
|
this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), error);
|
||||||
if (info === 'ready') {
|
},
|
||||||
|
(info: string) => {
|
||||||
|
if (info === "ready") {
|
||||||
this.webAuthnReady = true;
|
this.webAuthnReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(this.webAuthnSupported);
|
this.selectedProviderType = this.authService.getDefaultTwoFactorProvider(
|
||||||
|
this.webAuthnSupported
|
||||||
|
);
|
||||||
await this.init();
|
await this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +116,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
if (this.selectedProviderType == null) {
|
if (this.selectedProviderType == null) {
|
||||||
this.title = this.i18nService.t('loginUnavailable');
|
this.title = this.i18nService.t("loginUnavailable");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,9 +160,12 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
if (this.token == null || this.token === '') {
|
if (this.token == null || this.token === "") {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('verificationCodeRequired'));
|
"error",
|
||||||
|
this.i18nService.t("errorOccurred"),
|
||||||
|
this.i18nService.t("verificationCodeRequired")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,9 +175,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (this.selectedProviderType === TwoFactorProviderType.Email ||
|
} else if (
|
||||||
this.selectedProviderType === TwoFactorProviderType.Authenticator) {
|
this.selectedProviderType === TwoFactorProviderType.Email ||
|
||||||
this.token = this.token.replace(' ', '').trim();
|
this.selectedProviderType === TwoFactorProviderType.Authenticator
|
||||||
|
) {
|
||||||
|
this.token = this.token.replace(" ", "").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -174,7 +192,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async doSubmit() {
|
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 response: AuthResult = await this.formPromise;
|
||||||
const disableFavicon = await this.stateService.getDisableFavicon();
|
const disableFavicon = await this.stateService.getDisableFavicon();
|
||||||
await this.stateService.setDisableFavicon(!!disableFavicon);
|
await this.stateService.setDisableFavicon(!!disableFavicon);
|
||||||
@@ -182,10 +204,10 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
this.onSuccessfulLogin();
|
this.onSuccessfulLogin();
|
||||||
}
|
}
|
||||||
if (response.resetMasterPassword) {
|
if (response.resetMasterPassword) {
|
||||||
this.successRoute = 'set-password';
|
this.successRoute = "set-password";
|
||||||
}
|
}
|
||||||
if (response.forcePasswordReset) {
|
if (response.forcePasswordReset) {
|
||||||
this.successRoute = 'update-temp-password';
|
this.successRoute = "update-temp-password";
|
||||||
}
|
}
|
||||||
if (this.onSuccessfulLoginNavigate != null) {
|
if (this.onSuccessfulLoginNavigate != null) {
|
||||||
this.onSuccessfulLoginNavigate();
|
this.onSuccessfulLoginNavigate();
|
||||||
@@ -214,8 +236,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
this.emailPromise = this.apiService.postTwoFactorEmail(request);
|
this.emailPromise = this.apiService.postTwoFactorEmail(request);
|
||||||
await this.emailPromise;
|
await this.emailPromise;
|
||||||
if (doToast) {
|
if (doToast) {
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('verificationCodeEmailSent', this.twoFactorEmail));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("verificationCodeEmailSent", this.twoFactorEmail)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -242,7 +267,11 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get authing(): boolean {
|
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 {
|
get needsLock(): boolean {
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
import { Directive } from '@angular/core';
|
import { Directive } from "@angular/core";
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PolicyService } from 'jslib-common/abstractions/policy.service';
|
import { PolicyService } from "jslib-common/abstractions/policy.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { SyncService } from 'jslib-common/abstractions/sync.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 { EncString } from "jslib-common/models/domain/encString";
|
||||||
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
|
import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPasswordPolicyOptions";
|
||||||
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
|
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()
|
@Directive()
|
||||||
export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
||||||
@@ -28,13 +28,27 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
onSuccessfulChangePassword: () => Promise<any>;
|
onSuccessfulChangePassword: () => Promise<any>;
|
||||||
|
|
||||||
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
|
constructor(
|
||||||
passwordGenerationService: PasswordGenerationService, policyService: PolicyService,
|
i18nService: I18nService,
|
||||||
cryptoService: CryptoService, messagingService: MessagingService,
|
platformUtilsService: PlatformUtilsService,
|
||||||
private apiService: ApiService, stateService: StateService,
|
passwordGenerationService: PasswordGenerationService,
|
||||||
private syncService: SyncService, private logService: LogService) {
|
policyService: PolicyService,
|
||||||
super(i18nService, cryptoService, messagingService, passwordGenerationService,
|
cryptoService: CryptoService,
|
||||||
platformUtilsService, policyService, stateService);
|
messagingService: MessagingService,
|
||||||
|
private apiService: ApiService,
|
||||||
|
stateService: StateService,
|
||||||
|
private syncService: SyncService,
|
||||||
|
private logService: LogService
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
i18nService,
|
||||||
|
cryptoService,
|
||||||
|
messagingService,
|
||||||
|
passwordGenerationService,
|
||||||
|
platformUtilsService,
|
||||||
|
policyService,
|
||||||
|
stateService
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
@@ -44,7 +58,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
togglePassword(confirmField: boolean) {
|
togglePassword(confirmField: boolean) {
|
||||||
this.showPassword = !this.showPassword;
|
this.showPassword = !this.showPassword;
|
||||||
document.getElementById(confirmField ? 'masterPasswordRetype' : 'masterPassword').focus();
|
document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
async setupSubmitActions(): Promise<boolean> {
|
async setupSubmitActions(): Promise<boolean> {
|
||||||
@@ -57,18 +71,22 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
// Validation
|
// Validation
|
||||||
if (!await this.strongPassword()) {
|
if (!(await this.strongPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await this.setupSubmitActions()) {
|
if (!(await this.setupSubmitActions())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create new key and hash new password
|
// Create new key and hash new password
|
||||||
const newKey = await this.cryptoService.makeKey(this.masterPassword, this.email.trim().toLowerCase(),
|
const newKey = await this.cryptoService.makeKey(
|
||||||
this.kdf, this.kdfIterations);
|
this.masterPassword,
|
||||||
|
this.email.trim().toLowerCase(),
|
||||||
|
this.kdf,
|
||||||
|
this.kdfIterations
|
||||||
|
);
|
||||||
const newPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, newKey);
|
const newPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, newKey);
|
||||||
|
|
||||||
// Grab user's current enc key
|
// Grab user's current enc key
|
||||||
@@ -83,8 +101,11 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async performSubmitActions(masterPasswordHash: string, key: SymmetricCryptoKey,
|
async performSubmitActions(
|
||||||
encKey: [SymmetricCryptoKey, EncString]) {
|
masterPasswordHash: string,
|
||||||
|
key: SymmetricCryptoKey,
|
||||||
|
encKey: [SymmetricCryptoKey, EncString]
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
// Create request
|
// Create request
|
||||||
const request = new UpdateTempPasswordRequest();
|
const request = new UpdateTempPasswordRequest();
|
||||||
@@ -95,12 +116,16 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
|
|||||||
// Update user's password
|
// Update user's password
|
||||||
this.formPromise = this.apiService.putUpdateTempPassword(request);
|
this.formPromise = this.apiService.putUpdateTempPassword(request);
|
||||||
await this.formPromise;
|
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) {
|
if (this.onSuccessfulChangePassword != null) {
|
||||||
this.onSuccessfulChangePassword();
|
this.onSuccessfulChangePassword();
|
||||||
} else {
|
} else {
|
||||||
this.messagingService.send('logout');
|
this.messagingService.send("logout");
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
|
|||||||
@@ -1,25 +1,46 @@
|
|||||||
<ng-container *ngIf="!usesKeyConnector">
|
<ng-container *ngIf="!usesKeyConnector">
|
||||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
<label for="masterPassword">{{ "masterPass" | i18n }}</label>
|
||||||
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control"
|
<input
|
||||||
[formControl]="secret" required appAutofocus appInputVerbatim>
|
id="masterPassword"
|
||||||
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
|
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>
|
||||||
<ng-container *ngIf="usesKeyConnector">
|
<ng-container *ngIf="usesKeyConnector">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="d-block">{{'sendVerificationCode' | i18n}}</label>
|
<label class="d-block">{{ "sendVerificationCode" | i18n }}</label>
|
||||||
<button type="button" class="btn btn-outline-secondary" (click)="requestOTP()" [disabled]="disableRequestOTP">
|
<button
|
||||||
{{'sendCode' | i18n}}
|
type="button"
|
||||||
|
class="btn btn-outline-secondary"
|
||||||
|
(click)="requestOTP()"
|
||||||
|
[disabled]="disableRequestOTP"
|
||||||
|
>
|
||||||
|
{{ "sendCode" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
|
<span class="ml-2 text-success" role="alert" @sent *ngIf="sentCode">
|
||||||
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
|
<i class="fa fa-check-circle-o" aria-hidden="true"></i>
|
||||||
{{'codeSent' | i18n}}
|
{{ "codeSent" | i18n }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="verificationCode">{{'verificationCode' | i18n}}</label>
|
<label for="verificationCode">{{ "verificationCode" | i18n }}</label>
|
||||||
<input id="verificationCode" type="input" name="verificationCode" class="form-control"
|
<input
|
||||||
[formControl]="secret" required appAutofocus appInputVerbatim>
|
id="verificationCode"
|
||||||
<small class="form-text text-muted">{{'confirmIdentity' | i18n}}</small>
|
type="input"
|
||||||
|
name="verificationCode"
|
||||||
|
class="form-control"
|
||||||
|
[formControl]="secret"
|
||||||
|
required
|
||||||
|
appAutofocus
|
||||||
|
appInputVerbatim
|
||||||
|
/>
|
||||||
|
<small class="form-text text-muted">{{ "confirmIdentity" | i18n }}</small>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -1,29 +1,17 @@
|
|||||||
import {
|
import { animate, style, transition, trigger } from "@angular/animations";
|
||||||
animate,
|
import { Component, OnInit } from "@angular/core";
|
||||||
style,
|
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||||
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 { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { UserVerificationService } from 'jslib-common/abstractions/userVerification.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({
|
@Component({
|
||||||
selector: 'app-verify-master-password',
|
selector: "app-verify-master-password",
|
||||||
templateUrl: 'verify-master-password.component.html',
|
templateUrl: "verify-master-password.component.html",
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@@ -32,11 +20,8 @@ import { Verification } from 'jslib-common/types/verification';
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
animations: [
|
animations: [
|
||||||
trigger('sent', [
|
trigger("sent", [
|
||||||
transition(':enter', [
|
transition(":enter", [style({ opacity: 0 }), animate("100ms", style({ opacity: 1 }))]),
|
||||||
style({ opacity: 0 }),
|
|
||||||
animate('100ms', style({ opacity: 1 })),
|
|
||||||
]),
|
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -45,18 +30,20 @@ export class VerifyMasterPasswordComponent implements ControlValueAccessor, OnIn
|
|||||||
disableRequestOTP: boolean = false;
|
disableRequestOTP: boolean = false;
|
||||||
sentCode: boolean = false;
|
sentCode: boolean = false;
|
||||||
|
|
||||||
secret = new FormControl('');
|
secret = new FormControl("");
|
||||||
|
|
||||||
private onChange: (value: Verification) => void;
|
private onChange: (value: Verification) => void;
|
||||||
|
|
||||||
constructor(private keyConnectorService: KeyConnectorService,
|
constructor(
|
||||||
private userVerificationService: UserVerificationService) { }
|
private keyConnectorService: KeyConnectorService,
|
||||||
|
private userVerificationService: UserVerificationService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
this.usesKeyConnector = await this.keyConnectorService.getUsesKeyConnector();
|
||||||
this.processChanges(this.secret.value);
|
this.processChanges(this.secret.value);
|
||||||
|
|
||||||
this.secret.valueChanges.subscribe(secret => this.processChanges(secret));
|
this.secret.valueChanges.subscribe((secret) => this.processChanges(secret));
|
||||||
}
|
}
|
||||||
|
|
||||||
async requestOTP() {
|
async requestOTP() {
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import {
|
import { Directive, Input } from "@angular/core";
|
||||||
Directive,
|
|
||||||
Input,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { EventType } from 'jslib-common/enums/eventType';
|
import { EventType } from "jslib-common/enums/eventType";
|
||||||
import { FieldType } from 'jslib-common/enums/fieldType';
|
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 { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { FieldView } from 'jslib-common/models/view/fieldView';
|
import { FieldView } from "jslib-common/models/view/fieldView";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class ViewCustomFieldsComponent {
|
export class ViewCustomFieldsComponent {
|
||||||
@@ -22,11 +19,11 @@ export class ViewCustomFieldsComponent {
|
|||||||
constructor(private eventService: EventService) {}
|
constructor(private eventService: EventService) {}
|
||||||
|
|
||||||
async toggleFieldValue(field: FieldView) {
|
async toggleFieldValue(field: FieldView) {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const f = (field as any);
|
const f = field as any;
|
||||||
f.showValue = !f.showValue;
|
f.showValue = !f.showValue;
|
||||||
if (f.showValue) {
|
if (f.showValue) {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
|
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
|
||||||
|
|||||||
@@ -7,34 +7,34 @@ import {
|
|||||||
OnDestroy,
|
OnDestroy,
|
||||||
OnInit,
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
} from '@angular/core';
|
} from "@angular/core";
|
||||||
|
|
||||||
import { CipherRepromptType } from 'jslib-common/enums/cipherRepromptType';
|
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
|
||||||
import { CipherType } from 'jslib-common/enums/cipherType';
|
import { CipherType } from "jslib-common/enums/cipherType";
|
||||||
import { EventType } from 'jslib-common/enums/eventType';
|
import { EventType } from "jslib-common/enums/eventType";
|
||||||
import { FieldType } from 'jslib-common/enums/fieldType';
|
import { FieldType } from "jslib-common/enums/fieldType";
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/abstractions/api.service';
|
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||||
import { AuditService } from 'jslib-common/abstractions/audit.service';
|
import { AuditService } from "jslib-common/abstractions/audit.service";
|
||||||
import { BroadcasterService } from 'jslib-common/abstractions/broadcaster.service';
|
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
||||||
import { CipherService } from 'jslib-common/abstractions/cipher.service';
|
import { CipherService } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CryptoService } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { EventService } from 'jslib-common/abstractions/event.service';
|
import { EventService } from "jslib-common/abstractions/event.service";
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
|
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { TokenService } from 'jslib-common/abstractions/token.service';
|
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||||
import { TotpService } from 'jslib-common/abstractions/totp.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 { AttachmentView } from "jslib-common/models/view/attachmentView";
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
import { LoginUriView } from 'jslib-common/models/view/loginUriView';
|
import { LoginUriView } from "jslib-common/models/view/loginUriView";
|
||||||
|
|
||||||
const BroadcasterSubscriptionId = 'ViewComponent';
|
const BroadcasterSubscriptionId = "ViewComponent";
|
||||||
|
|
||||||
@Directive()
|
@Directive()
|
||||||
export class ViewComponent implements OnDestroy, OnInit {
|
export class ViewComponent implements OnDestroy, OnInit {
|
||||||
@@ -62,20 +62,30 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
private previousCipherId: string;
|
private previousCipherId: string;
|
||||||
private passwordReprompted: boolean = false;
|
private passwordReprompted: boolean = false;
|
||||||
|
|
||||||
constructor(protected cipherService: CipherService, protected totpService: TotpService,
|
constructor(
|
||||||
protected tokenService: TokenService, protected i18nService: I18nService,
|
protected cipherService: CipherService,
|
||||||
protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
|
protected totpService: TotpService,
|
||||||
protected auditService: AuditService, protected win: Window,
|
protected tokenService: TokenService,
|
||||||
protected broadcasterService: BroadcasterService, protected ngZone: NgZone,
|
protected i18nService: I18nService,
|
||||||
protected changeDetectorRef: ChangeDetectorRef, protected eventService: EventService,
|
protected cryptoService: CryptoService,
|
||||||
protected apiService: ApiService, protected passwordRepromptService: PasswordRepromptService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
private logService: LogService, protected stateService: StateService) { }
|
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() {
|
ngOnInit() {
|
||||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||||
this.ngZone.run(async () => {
|
this.ngZone.run(async () => {
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
case 'syncCompleted':
|
case "syncCompleted":
|
||||||
if (message.successfully) {
|
if (message.successfully) {
|
||||||
await this.load();
|
await this.load();
|
||||||
this.changeDetectorRef.detectChanges();
|
this.changeDetectorRef.detectChanges();
|
||||||
@@ -98,8 +108,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
this.cipher = await cipher.decrypt();
|
this.cipher = await cipher.decrypt();
|
||||||
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
this.canAccessPremium = await this.stateService.getCanAccessPremium();
|
||||||
|
|
||||||
if (this.cipher.type === CipherType.Login && this.cipher.login.totp &&
|
if (
|
||||||
(cipher.organizationUseTotp || this.canAccessPremium)) {
|
this.cipher.type === CipherType.Login &&
|
||||||
|
this.cipher.login.totp &&
|
||||||
|
(cipher.organizationUseTotp || this.canAccessPremium)
|
||||||
|
) {
|
||||||
await this.totpUpdateCode();
|
await this.totpUpdateCode();
|
||||||
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
|
const interval = this.totpService.getTimeInterval(this.cipher.login.totp);
|
||||||
await this.totpTick(interval);
|
await this.totpTick(interval);
|
||||||
@@ -143,21 +156,30 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async delete(): Promise<boolean> {
|
async delete(): Promise<boolean> {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeleteItemConfirmation' : 'deleteItemConfirmation'),
|
this.i18nService.t(
|
||||||
this.i18nService.t('deleteItem'), this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation"
|
||||||
|
),
|
||||||
|
this.i18nService.t("deleteItem"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.deleteCipher();
|
await this.deleteCipher();
|
||||||
this.platformUtilsService.showToast('success', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t(this.cipher.isDeleted ? 'permanentlyDeletedItem' : 'deletedItem'));
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem")
|
||||||
|
);
|
||||||
this.onDeletedCipher.emit(this.cipher);
|
this.onDeletedCipher.emit(this.cipher);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -172,15 +194,19 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await this.platformUtilsService.showDialog(
|
const confirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t('restoreItemConfirmation'), this.i18nService.t('restoreItem'),
|
this.i18nService.t("restoreItemConfirmation"),
|
||||||
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
|
this.i18nService.t("restoreItem"),
|
||||||
|
this.i18nService.t("yes"),
|
||||||
|
this.i18nService.t("no"),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.restoreCipher();
|
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);
|
this.onRestoredCipher.emit(this.cipher);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logService.error(e);
|
this.logService.error(e);
|
||||||
@@ -190,7 +216,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async togglePassword() {
|
async togglePassword() {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +227,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async toggleCardNumber() {
|
async toggleCardNumber() {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +238,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async toggleCardCode() {
|
async toggleCardCode() {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +249,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async checkPassword() {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,10 +261,13 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
const matches = await this.checkPasswordPromise;
|
const matches = await this.checkPasswordPromise;
|
||||||
|
|
||||||
if (matches > 0) {
|
if (matches > 0) {
|
||||||
this.platformUtilsService.showToast('warning', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('passwordExposed', matches.toString()));
|
"warning",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("passwordExposed", matches.toString())
|
||||||
|
);
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.passwordRepromptService.protectedFields().includes(aType) && !await this.promptPassword()) {
|
if (
|
||||||
|
this.passwordRepromptService.protectedFields().includes(aType) &&
|
||||||
|
!(await this.promptPassword())
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||||
this.platformUtilsService.copyToClipboard(value, copyOptions);
|
this.platformUtilsService.copyToClipboard(value, copyOptions);
|
||||||
this.platformUtilsService.showToast('info', null,
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('valueCopied', this.i18nService.t(typeI18nKey)));
|
"info",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey))
|
||||||
|
);
|
||||||
|
|
||||||
if (typeI18nKey === 'password') {
|
if (typeI18nKey === "password") {
|
||||||
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipherId);
|
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipherId);
|
||||||
} else if (typeI18nKey === 'securityCode') {
|
} else if (typeI18nKey === "securityCode") {
|
||||||
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
|
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);
|
this.eventService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setTextDataOnDrag(event: DragEvent, data: string) {
|
setTextDataOnDrag(event: DragEvent, data: string) {
|
||||||
event.dataTransfer.setData('text', data);
|
event.dataTransfer.setData("text", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadAttachment(attachment: AttachmentView) {
|
async downloadAttachment(attachment: AttachmentView) {
|
||||||
if (!await this.promptPassword()) {
|
if (!(await this.promptPassword())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const a = (attachment as any);
|
const a = attachment as any;
|
||||||
if (a.downloading) {
|
if (a.downloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cipher.organizationId == null && !this.canAccessPremium) {
|
if (this.cipher.organizationId == null && !this.canAccessPremium) {
|
||||||
this.platformUtilsService.showToast('error', this.i18nService.t('premiumRequired'),
|
this.platformUtilsService.showToast(
|
||||||
this.i18nService.t('premiumRequiredDesc'));
|
"error",
|
||||||
|
this.i18nService.t("premiumRequired"),
|
||||||
|
this.i18nService.t("premiumRequiredDesc")
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
try {
|
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;
|
url = attachmentDownloadResponse.url;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
|
if (e instanceof ErrorResponse && (e as ErrorResponse).statusCode === 404) {
|
||||||
@@ -307,28 +352,31 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.downloading = true;
|
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) {
|
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;
|
a.downloading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const buf = await response.arrayBuffer();
|
const buf = await response.arrayBuffer();
|
||||||
const key = attachment.key != null ? attachment.key :
|
const key =
|
||||||
await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
attachment.key != null
|
||||||
|
? attachment.key
|
||||||
|
: await this.cryptoService.getOrgKey(this.cipher.organizationId);
|
||||||
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
const decBuf = await this.cryptoService.decryptFromBytes(buf, key);
|
||||||
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
|
this.platformUtilsService.saveFile(this.win, decBuf, null, attachment.fileName);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.platformUtilsService.showToast('error', null, this.i18nService.t('errorOccurred'));
|
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||||
}
|
}
|
||||||
|
|
||||||
a.downloading = false;
|
a.downloading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected deleteCipher() {
|
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);
|
: this.cipherService.softDeleteWithServer(this.cipher.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +389,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.passwordReprompted = await this.passwordRepromptService.showPasswordPrompt();
|
return (this.passwordReprompted = await this.passwordRepromptService.showPasswordPrompt());
|
||||||
}
|
}
|
||||||
|
|
||||||
private cleanUp() {
|
private cleanUp() {
|
||||||
@@ -357,7 +405,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async totpUpdateCode() {
|
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) {
|
if (this.totpInterval) {
|
||||||
clearInterval(this.totpInterval);
|
clearInterval(this.totpInterval);
|
||||||
}
|
}
|
||||||
@@ -368,7 +420,8 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
if (this.totpCode != null) {
|
if (this.totpCode != null) {
|
||||||
if (this.totpCode.length > 4) {
|
if (this.totpCode.length > 4) {
|
||||||
const half = Math.floor(this.totpCode.length / 2);
|
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 {
|
} else {
|
||||||
this.totpCodeFormatted = this.totpCode;
|
this.totpCodeFormatted = this.totpCode;
|
||||||
}
|
}
|
||||||
@@ -385,7 +438,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
|||||||
const mod = epoch % intervalSeconds;
|
const mod = epoch % intervalSeconds;
|
||||||
|
|
||||||
this.totpSec = intervalSeconds - mod;
|
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;
|
this.totpLow = this.totpSec <= 7;
|
||||||
if (mod === 0) {
|
if (mod === 0) {
|
||||||
await this.totpUpdateCode();
|
await this.totpUpdateCode();
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import {
|
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
Input,
|
|
||||||
Renderer2,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appA11yTitle]',
|
selector: "[appA11yTitle]",
|
||||||
})
|
})
|
||||||
export class A11yTitleDirective {
|
export class A11yTitleDirective {
|
||||||
@Input() set appA11yTitle(title: string) {
|
@Input() set appA11yTitle(title: string) {
|
||||||
@@ -18,11 +13,11 @@ export class A11yTitleDirective {
|
|||||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this.el.nativeElement.hasAttribute('title')) {
|
if (!this.el.nativeElement.hasAttribute("title")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'title', this.title);
|
this.renderer.setAttribute(this.el.nativeElement, "title", this.title);
|
||||||
}
|
}
|
||||||
if (!this.el.nativeElement.hasAttribute('aria-label')) {
|
if (!this.el.nativeElement.hasAttribute("aria-label")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'aria-label', this.title);
|
this.renderer.setAttribute(this.el.nativeElement, "aria-label", this.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,21 @@
|
|||||||
import {
|
import { Directive, ElementRef, Input, OnChanges } from "@angular/core";
|
||||||
Directive,
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
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({
|
@Directive({
|
||||||
selector: '[appApiAction]',
|
selector: "[appApiAction]",
|
||||||
})
|
})
|
||||||
export class ApiActionDirective implements OnChanges {
|
export class ApiActionDirective implements OnChanges {
|
||||||
@Input() appApiAction: Promise<any>;
|
@Input() appApiAction: Promise<any>;
|
||||||
|
|
||||||
constructor(private el: ElementRef, private validationService: ValidationService,
|
constructor(
|
||||||
private logService: LogService) { }
|
private el: ElementRef,
|
||||||
|
private validationService: ValidationService,
|
||||||
|
private logService: LogService
|
||||||
|
) {}
|
||||||
|
|
||||||
ngOnChanges(changes: any) {
|
ngOnChanges(changes: any) {
|
||||||
if (this.appApiAction == null || this.appApiAction.then == null) {
|
if (this.appApiAction == null || this.appApiAction.then == null) {
|
||||||
@@ -26,17 +24,23 @@ export class ApiActionDirective implements OnChanges {
|
|||||||
|
|
||||||
this.el.nativeElement.loading = true;
|
this.el.nativeElement.loading = true;
|
||||||
|
|
||||||
this.appApiAction.then((response: any) => {
|
this.appApiAction.then(
|
||||||
|
(response: any) => {
|
||||||
this.el.nativeElement.loading = false;
|
this.el.nativeElement.loading = false;
|
||||||
}, (e: any) => {
|
},
|
||||||
|
(e: any) => {
|
||||||
this.el.nativeElement.loading = false;
|
this.el.nativeElement.loading = false;
|
||||||
|
|
||||||
if ((e instanceof ErrorResponse || e.constructor.name === 'ErrorResponse') && (e as ErrorResponse).captchaRequired) {
|
if (
|
||||||
this.logService.error('Captcha required error response: ' + e.getSingleMessage());
|
(e instanceof ErrorResponse || e.constructor.name === "ErrorResponse") &&
|
||||||
|
(e as ErrorResponse).captchaRequired
|
||||||
|
) {
|
||||||
|
this.logService.error("Captcha required error response: " + e.getSingleMessage());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.logService?.error(`Received API exception: ${e}`);
|
this.logService?.error(`Received API exception: ${e}`);
|
||||||
this.validationService.showError(e);
|
this.validationService.showError(e);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,15 @@
|
|||||||
import {
|
import { Directive, ElementRef, Input, NgZone } from "@angular/core";
|
||||||
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({
|
@Directive({
|
||||||
selector: '[appAutofocus]',
|
selector: "[appAutofocus]",
|
||||||
})
|
})
|
||||||
export class AutofocusDirective {
|
export class AutofocusDirective {
|
||||||
@Input() set appAutofocus(condition: boolean | string) {
|
@Input() set appAutofocus(condition: boolean | string) {
|
||||||
this.autofocus = condition === '' || condition === true;
|
this.autofocus = condition === "" || condition === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private autofocus: boolean;
|
private autofocus: boolean;
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import {
|
import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
HostListener,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appBlurClick]',
|
selector: "[appBlurClick]",
|
||||||
})
|
})
|
||||||
export class BlurClickDirective {
|
export class BlurClickDirective {
|
||||||
constructor(private el: ElementRef) {
|
constructor(private el: ElementRef) {}
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('click') onClick() {
|
@HostListener("click") onClick() {
|
||||||
this.el.nativeElement.blur();
|
this.el.nativeElement.blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import {
|
import { Directive, ElementRef, HostListener, OnInit } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
HostListener,
|
|
||||||
OnInit,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appBoxRow]',
|
selector: "[appBoxRow]",
|
||||||
})
|
})
|
||||||
export class BoxRowDirective implements OnInit {
|
export class BoxRowDirective implements OnInit {
|
||||||
el: HTMLElement = null;
|
el: HTMLElement = null;
|
||||||
@@ -17,30 +12,43 @@ export class BoxRowDirective implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.formEls = Array.from(this.el.querySelectorAll('input:not([type="hidden"]), select, textarea'));
|
this.formEls = Array.from(
|
||||||
this.formEls.forEach(formEl => {
|
this.el.querySelectorAll('input:not([type="hidden"]), select, textarea')
|
||||||
formEl.addEventListener('focus', (event: Event) => {
|
);
|
||||||
this.el.classList.add('active');
|
this.formEls.forEach((formEl) => {
|
||||||
}, false);
|
formEl.addEventListener(
|
||||||
|
"focus",
|
||||||
|
(event: Event) => {
|
||||||
|
this.el.classList.add("active");
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
formEl.addEventListener('blur', (event: Event) => {
|
formEl.addEventListener(
|
||||||
this.el.classList.remove('active');
|
"blur",
|
||||||
}, false);
|
(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;
|
const target = event.target as HTMLElement;
|
||||||
if (target !== this.el && !target.classList.contains('progress') &&
|
if (
|
||||||
!target.classList.contains('progress-bar')) {
|
target !== this.el &&
|
||||||
|
!target.classList.contains("progress") &&
|
||||||
|
!target.classList.contains("progress-bar")
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.formEls.length > 0) {
|
if (this.formEls.length > 0) {
|
||||||
const formEl = (this.formEls[0] as HTMLElement);
|
const formEl = this.formEls[0] as HTMLElement;
|
||||||
if (formEl.tagName.toLowerCase() === 'input') {
|
if (formEl.tagName.toLowerCase() === "input") {
|
||||||
const inputEl = (formEl as HTMLInputElement);
|
const inputEl = formEl as HTMLInputElement;
|
||||||
if (inputEl.type != null && inputEl.type.toLowerCase() === 'checkbox') {
|
if (inputEl.type != null && inputEl.type.toLowerCase() === "checkbox") {
|
||||||
inputEl.click();
|
inputEl.click();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ import {
|
|||||||
CdkFixedSizeVirtualScroll,
|
CdkFixedSizeVirtualScroll,
|
||||||
FixedSizeVirtualScrollStrategy,
|
FixedSizeVirtualScrollStrategy,
|
||||||
VIRTUAL_SCROLL_STRATEGY,
|
VIRTUAL_SCROLL_STRATEGY,
|
||||||
} from '@angular/cdk/scrolling';
|
} from "@angular/cdk/scrolling";
|
||||||
import {
|
import { Directive, forwardRef } from "@angular/core";
|
||||||
Directive,
|
|
||||||
forwardRef,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
// Custom virtual scroll strategy for cdk-virtual-scroll
|
// Custom virtual scroll strategy for cdk-virtual-scroll
|
||||||
// Uses a sample list item to set the itemSize for FixedSizeVirtualScrollStrategy
|
// Uses a sample list item to set the itemSize for FixedSizeVirtualScrollStrategy
|
||||||
@@ -15,7 +12,12 @@ export class CipherListVirtualScrollStrategy extends FixedSizeVirtualScrollStrat
|
|||||||
private checkItemSizeCallback: any;
|
private checkItemSizeCallback: any;
|
||||||
private timeout: 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);
|
super(itemSize, minBufferPx, maxBufferPx);
|
||||||
this.checkItemSizeCallback = checkItemSizeCallback;
|
this.checkItemSizeCallback = checkItemSizeCallback;
|
||||||
}
|
}
|
||||||
@@ -34,29 +36,41 @@ export function _cipherListVirtualScrollStrategyFactory(cipherListDir: CipherLis
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'cdk-virtual-scroll-viewport[itemSize]',
|
selector: "cdk-virtual-scroll-viewport[itemSize]",
|
||||||
providers: [{
|
providers: [
|
||||||
|
{
|
||||||
provide: VIRTUAL_SCROLL_STRATEGY,
|
provide: VIRTUAL_SCROLL_STRATEGY,
|
||||||
useFactory: _cipherListVirtualScrollStrategyFactory,
|
useFactory: _cipherListVirtualScrollStrategyFactory,
|
||||||
deps: [forwardRef(() => CipherListVirtualScroll)],
|
deps: [forwardRef(() => CipherListVirtualScroll)],
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll {
|
export class CipherListVirtualScroll extends CdkFixedSizeVirtualScroll {
|
||||||
_scrollStrategy: CipherListVirtualScrollStrategy;
|
_scrollStrategy: CipherListVirtualScrollStrategy;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._scrollStrategy = new CipherListVirtualScrollStrategy(this.itemSize, this.minBufferPx, this.maxBufferPx,
|
this._scrollStrategy = new CipherListVirtualScrollStrategy(
|
||||||
this.checkAndUpdateItemSize);
|
this.itemSize,
|
||||||
|
this.minBufferPx,
|
||||||
|
this.maxBufferPx,
|
||||||
|
this.checkAndUpdateItemSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
const newItemSize = sampleItem?.offsetHeight;
|
||||||
|
|
||||||
if (newItemSize != null && newItemSize !== this.itemSize) {
|
if (newItemSize != null && newItemSize !== this.itemSize) {
|
||||||
this.itemSize = newItemSize;
|
this.itemSize = newItemSize;
|
||||||
this._scrollStrategy.updateItemAndBufferSize(this.itemSize, this.minBufferPx, this.maxBufferPx);
|
this._scrollStrategy.updateItemAndBufferSize(
|
||||||
}
|
this.itemSize,
|
||||||
|
this.minBufferPx,
|
||||||
|
this.maxBufferPx
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,14 @@
|
|||||||
import {
|
import { Directive, ElementRef, HostListener, Input } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
HostListener,
|
|
||||||
Input,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appFallbackSrc]',
|
selector: "[appFallbackSrc]",
|
||||||
})
|
})
|
||||||
export class FallbackSrcDirective {
|
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;
|
this.el.nativeElement.src = this.appFallbackSrc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import {
|
import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
Input,
|
|
||||||
Renderer2,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appInputVerbatim]',
|
selector: "[appInputVerbatim]",
|
||||||
})
|
})
|
||||||
export class InputVerbatimDirective {
|
export class InputVerbatimDirective {
|
||||||
@Input() set appInputVerbatim(condition: boolean | string) {
|
@Input() set appInputVerbatim(condition: boolean | string) {
|
||||||
this.disableComplete = condition === '' || condition === true;
|
this.disableComplete = condition === "" || condition === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private disableComplete: boolean;
|
private disableComplete: boolean;
|
||||||
@@ -18,20 +13,20 @@ export class InputVerbatimDirective {
|
|||||||
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
constructor(private el: ElementRef, private renderer: Renderer2) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.disableComplete && !this.el.nativeElement.hasAttribute('autocomplete')) {
|
if (this.disableComplete && !this.el.nativeElement.hasAttribute("autocomplete")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'autocomplete', 'off');
|
this.renderer.setAttribute(this.el.nativeElement, "autocomplete", "off");
|
||||||
}
|
}
|
||||||
if (!this.el.nativeElement.hasAttribute('autocapitalize')) {
|
if (!this.el.nativeElement.hasAttribute("autocapitalize")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'autocapitalize', 'none');
|
this.renderer.setAttribute(this.el.nativeElement, "autocapitalize", "none");
|
||||||
}
|
}
|
||||||
if (!this.el.nativeElement.hasAttribute('autocorrect')) {
|
if (!this.el.nativeElement.hasAttribute("autocorrect")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'autocorrect', 'none');
|
this.renderer.setAttribute(this.el.nativeElement, "autocorrect", "none");
|
||||||
}
|
}
|
||||||
if (!this.el.nativeElement.hasAttribute('spellcheck')) {
|
if (!this.el.nativeElement.hasAttribute("spellcheck")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'spellcheck', 'false');
|
this.renderer.setAttribute(this.el.nativeElement, "spellcheck", "false");
|
||||||
}
|
}
|
||||||
if (!this.el.nativeElement.hasAttribute('inputmode')) {
|
if (!this.el.nativeElement.hasAttribute("inputmode")) {
|
||||||
this.renderer.setAttribute(this.el.nativeElement, 'inputmode', 'verbatim');
|
this.renderer.setAttribute(this.el.nativeElement, "inputmode", "verbatim");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
import {
|
import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||||
Directive,
|
|
||||||
ElementRef,
|
|
||||||
HostListener,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appSelectCopy]',
|
selector: "[appSelectCopy]",
|
||||||
})
|
})
|
||||||
export class SelectCopyDirective {
|
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) {
|
if (window == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let copyText = '';
|
let copyText = "";
|
||||||
const selection = window.getSelection();
|
const selection = window.getSelection();
|
||||||
for (let i = 0; i < selection.rangeCount; i++) {
|
for (let i = 0; i < selection.rangeCount; i++) {
|
||||||
const range = selection.getRangeAt(i);
|
const range = selection.getRangeAt(i);
|
||||||
@@ -30,7 +26,7 @@ export class SelectCopyDirective {
|
|||||||
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
|
const newLinePos = text.search(/(?:\r\n|\r|\n)/);
|
||||||
if (newLinePos > -1) {
|
if (newLinePos > -1) {
|
||||||
const otherPart = text.substr(newLinePos).trim();
|
const otherPart = text.substr(newLinePos).trim();
|
||||||
if (otherPart === '') {
|
if (otherPart === "") {
|
||||||
stringEndPos = newLinePos;
|
stringEndPos = newLinePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import {
|
import { Directive, HostListener } from "@angular/core";
|
||||||
Directive,
|
|
||||||
HostListener,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appStopClick]',
|
selector: "[appStopClick]",
|
||||||
})
|
})
|
||||||
export class StopClickDirective {
|
export class StopClickDirective {
|
||||||
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
|
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import {
|
import { Directive, HostListener } from "@angular/core";
|
||||||
Directive,
|
|
||||||
HostListener,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: '[appStopProp]',
|
selector: "[appStopProp]",
|
||||||
})
|
})
|
||||||
export class StopPropDirective {
|
export class StopPropDirective {
|
||||||
@HostListener('click', ['$event']) onClick($event: MouseEvent) {
|
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,9 @@
|
|||||||
import {
|
import { Directive, ElementRef, forwardRef, HostListener, Input, Renderer2 } from "@angular/core";
|
||||||
Directive,
|
import { ControlValueAccessor, NgControl, NG_VALUE_ACCESSOR } from "@angular/forms";
|
||||||
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/
|
// ref: https://juristr.com/blog/2018/02/ng-true-value-directive/
|
||||||
@Directive({
|
@Directive({
|
||||||
selector: 'input[type=checkbox][appTrueFalseValue]',
|
selector: "input[type=checkbox][appTrueFalseValue]",
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: NG_VALUE_ACCESSOR,
|
provide: NG_VALUE_ACCESSOR,
|
||||||
@@ -29,16 +18,16 @@ export class TrueFalseValueDirective implements ControlValueAccessor {
|
|||||||
|
|
||||||
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
|
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
|
||||||
|
|
||||||
@HostListener('change', ['$event'])
|
@HostListener("change", ["$event"])
|
||||||
onHostChange(ev: any) {
|
onHostChange(ev: any) {
|
||||||
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
|
this.propagateChange(ev.target.checked ? this.trueValue : this.falseValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeValue(obj: any): void {
|
writeValue(obj: any): void {
|
||||||
if (obj === this.trueValue) {
|
if (obj === this.trueValue) {
|
||||||
this.renderer.setProperty(this.elementRef.nativeElement, 'checked', true);
|
this.renderer.setProperty(this.elementRef.nativeElement, "checked", true);
|
||||||
} else {
|
} 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;
|
this.propagateChange = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerOnTouched(fn: any): void { /* nothing */ }
|
registerOnTouched(fn: any): void {
|
||||||
|
/* nothing */
|
||||||
setDisabledState?(isDisabled: boolean): void { /* nothing */ }
|
}
|
||||||
|
|
||||||
private propagateChange = (_: any) => { /* nothing */ };
|
setDisabledState?(isDisabled: boolean): void {
|
||||||
|
/* nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
private propagateChange = (_: any) => {
|
||||||
|
/* nothing */
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +1,49 @@
|
|||||||
import {
|
import { Pipe, PipeTransform } from "@angular/core";
|
||||||
Pipe,
|
import { Utils } from "jslib-common/misc/utils";
|
||||||
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)
|
An updated pipe that sanitizes HTML, highlights numbers and special characters (in different colors each)
|
||||||
and handles Unicode / Emoji characters correctly.
|
and handles Unicode / Emoji characters correctly.
|
||||||
*/
|
*/
|
||||||
@Pipe({ name: 'colorPassword' })
|
@Pipe({ name: "colorPassword" })
|
||||||
export class ColorPasswordPipe implements PipeTransform {
|
export class ColorPasswordPipe implements PipeTransform {
|
||||||
transform(password: string) {
|
transform(password: string) {
|
||||||
// Convert to an array to handle cases that stings have special characters, ie: emoji.
|
// Convert to an array to handle cases that stings have special characters, ie: emoji.
|
||||||
const passwordArray = Array.from(password);
|
const passwordArray = Array.from(password);
|
||||||
let colorizedPassword = '';
|
let colorizedPassword = "";
|
||||||
for (let i = 0; i < passwordArray.length; i++) {
|
for (let i = 0; i < passwordArray.length; i++) {
|
||||||
let character = passwordArray[i];
|
let character = passwordArray[i];
|
||||||
let isSpecial = false;
|
let isSpecial = false;
|
||||||
// Sanitize HTML first.
|
// Sanitize HTML first.
|
||||||
switch (character) {
|
switch (character) {
|
||||||
case '&':
|
case "&":
|
||||||
character = '&';
|
character = "&";
|
||||||
isSpecial = true;
|
isSpecial = true;
|
||||||
break;
|
break;
|
||||||
case '<':
|
case "<":
|
||||||
character = '<';
|
character = "<";
|
||||||
isSpecial = true;
|
isSpecial = true;
|
||||||
break;
|
break;
|
||||||
case '>':
|
case ">":
|
||||||
character = '>';
|
character = ">";
|
||||||
isSpecial = true;
|
isSpecial = true;
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case " ":
|
||||||
character = ' ';
|
character = " ";
|
||||||
isSpecial = true;
|
isSpecial = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let type = 'letter';
|
let type = "letter";
|
||||||
if (character.match(Utils.regexpEmojiPresentation)) {
|
if (character.match(Utils.regexpEmojiPresentation)) {
|
||||||
type = 'emoji';
|
type = "emoji";
|
||||||
} else if (isSpecial || character.match(/[^\w ]/)) {
|
} else if (isSpecial || character.match(/[^\w ]/)) {
|
||||||
type = 'special';
|
type = "special";
|
||||||
} else if (character.match(/\d/)) {
|
} 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;
|
return colorizedPassword;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import {
|
import { Pipe, PipeTransform } from "@angular/core";
|
||||||
Pipe,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'i18n',
|
name: "i18n",
|
||||||
})
|
})
|
||||||
export class I18nPipe implements PipeTransform {
|
export class I18nPipe implements PipeTransform {
|
||||||
constructor(private i18nService: I18nService) {}
|
constructor(private i18nService: I18nService) {}
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
import {
|
import { Pipe, PipeTransform } from "@angular/core";
|
||||||
Pipe,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { CipherView } from 'jslib-common/models/view/cipherView';
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'searchCiphers',
|
name: "searchCiphers",
|
||||||
})
|
})
|
||||||
export class SearchCiphersPipe implements PipeTransform {
|
export class SearchCiphersPipe implements PipeTransform {
|
||||||
transform(ciphers: CipherView[], searchText: string, deleted: boolean = false): CipherView[] {
|
transform(ciphers: CipherView[], searchText: string, deleted: boolean = false): CipherView[] {
|
||||||
@@ -15,13 +12,13 @@ export class SearchCiphersPipe implements PipeTransform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchText == null || searchText.length < 2) {
|
if (searchText == null || searchText.length < 2) {
|
||||||
return ciphers.filter(c => {
|
return ciphers.filter((c) => {
|
||||||
return deleted !== c.isDeleted;
|
return deleted !== c.isDeleted;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
searchText = searchText.trim().toLowerCase();
|
searchText = searchText.trim().toLowerCase();
|
||||||
return ciphers.filter(c => {
|
return ciphers.filter((c) => {
|
||||||
if (deleted !== c.isDeleted) {
|
if (deleted !== c.isDeleted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
import {
|
import { Pipe, PipeTransform } from "@angular/core";
|
||||||
Pipe,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'search',
|
name: "search",
|
||||||
})
|
})
|
||||||
export class SearchPipe implements PipeTransform {
|
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) {
|
if (items == null || items.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -17,14 +20,26 @@ export class SearchPipe implements PipeTransform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
searchText = searchText.trim().toLowerCase();
|
searchText = searchText.trim().toLowerCase();
|
||||||
return items.filter(i => {
|
return items.filter((i) => {
|
||||||
if (prop1 != null && i[prop1] != null && i[prop1].toString().toLowerCase().indexOf(searchText) > -1) {
|
if (
|
||||||
|
prop1 != null &&
|
||||||
|
i[prop1] != null &&
|
||||||
|
i[prop1].toString().toLowerCase().indexOf(searchText) > -1
|
||||||
|
) {
|
||||||
return true;
|
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;
|
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 true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import {
|
import { Pipe, PipeTransform } from "@angular/core";
|
||||||
Pipe,
|
|
||||||
PipeTransform,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
name?: string;
|
name?: string;
|
||||||
@@ -9,7 +6,7 @@ interface User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'userName',
|
name: "userName",
|
||||||
})
|
})
|
||||||
export class UserNamePipe implements PipeTransform {
|
export class UserNamePipe implements PipeTransform {
|
||||||
transform(user?: User): string {
|
transform(user?: User): string {
|
||||||
@@ -17,6 +14,6 @@ export class UserNamePipe implements PipeTransform {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return user.name == null || user.name.trim() === '' ? user.email : user.name;
|
return user.name == null || user.name.trim() === "" ? user.email : user.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +1,89 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Open Sans';
|
font-family: "Open Sans";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: auto;
|
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;
|
unicode-range: U+0-10FFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +1,42 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from "@angular/core";
|
||||||
import {
|
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router";
|
||||||
ActivatedRouteSnapshot,
|
|
||||||
CanActivate,
|
|
||||||
Router,
|
|
||||||
RouterStateSnapshot,
|
|
||||||
} from '@angular/router';
|
|
||||||
|
|
||||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { MessagingService } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthGuardService implements CanActivate {
|
export class AuthGuardService implements CanActivate {
|
||||||
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
|
constructor(
|
||||||
private messagingService: MessagingService, private keyConnectorService: KeyConnectorService,
|
private vaultTimeoutService: VaultTimeoutService,
|
||||||
private stateService: StateService) { }
|
private router: Router,
|
||||||
|
private messagingService: MessagingService,
|
||||||
|
private keyConnectorService: KeyConnectorService,
|
||||||
|
private stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
|
||||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
const isAuthed = await this.stateService.getIsAuthenticated();
|
||||||
if (!isAuthed) {
|
if (!isAuthed) {
|
||||||
this.messagingService.send('authBlocked');
|
this.messagingService.send("authBlocked");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const locked = await this.vaultTimeoutService.isLocked();
|
const locked = await this.vaultTimeoutService.isLocked();
|
||||||
if (locked) {
|
if (locked) {
|
||||||
if (routerState != null) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!routerState.url.includes('remove-password') && await this.keyConnectorService.getConvertAccountRequired()) {
|
if (
|
||||||
this.router.navigate(['/remove-password']);
|
!routerState.url.includes("remove-password") &&
|
||||||
|
(await this.keyConnectorService.getConvertAccountRequired())
|
||||||
|
) {
|
||||||
|
this.router.navigate(["/remove-password"]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
@Injectable()
|
||||||
export class BroadcasterService extends BaseBroadcasterService {
|
export class BroadcasterService extends BaseBroadcasterService {}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,91 +1,85 @@
|
|||||||
import {
|
import { Injector, LOCALE_ID, NgModule } from "@angular/core";
|
||||||
Injector,
|
|
||||||
LOCALE_ID,
|
|
||||||
NgModule,
|
|
||||||
} from '@angular/core';
|
|
||||||
|
|
||||||
import { ApiService } from 'jslib-common/services/api.service';
|
import { ApiService } from "jslib-common/services/api.service";
|
||||||
import { AppIdService } from 'jslib-common/services/appId.service';
|
import { AppIdService } from "jslib-common/services/appId.service";
|
||||||
import { AuditService } from 'jslib-common/services/audit.service';
|
import { AuditService } from "jslib-common/services/audit.service";
|
||||||
import { AuthService } from 'jslib-common/services/auth.service';
|
import { AuthService } from "jslib-common/services/auth.service";
|
||||||
import { CipherService } from 'jslib-common/services/cipher.service';
|
import { CipherService } from "jslib-common/services/cipher.service";
|
||||||
import { CollectionService } from 'jslib-common/services/collection.service';
|
import { CollectionService } from "jslib-common/services/collection.service";
|
||||||
import { ConsoleLogService } from 'jslib-common/services/consoleLog.service';
|
import { ConsoleLogService } from "jslib-common/services/consoleLog.service";
|
||||||
import { CryptoService } from 'jslib-common/services/crypto.service';
|
import { CryptoService } from "jslib-common/services/crypto.service";
|
||||||
import { EnvironmentService } from 'jslib-common/services/environment.service';
|
import { EnvironmentService } from "jslib-common/services/environment.service";
|
||||||
import { EventService } from 'jslib-common/services/event.service';
|
import { EventService } from "jslib-common/services/event.service";
|
||||||
import { ExportService } from 'jslib-common/services/export.service';
|
import { ExportService } from "jslib-common/services/export.service";
|
||||||
import { FileUploadService } from 'jslib-common/services/fileUpload.service';
|
import { FileUploadService } from "jslib-common/services/fileUpload.service";
|
||||||
import { FolderService } from 'jslib-common/services/folder.service';
|
import { FolderService } from "jslib-common/services/folder.service";
|
||||||
import { KeyConnectorService } from 'jslib-common/services/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/services/keyConnector.service";
|
||||||
import { NotificationsService } from 'jslib-common/services/notifications.service';
|
import { NotificationsService } from "jslib-common/services/notifications.service";
|
||||||
import { OrganizationService } from 'jslib-common/services/organization.service';
|
import { OrganizationService } from "jslib-common/services/organization.service";
|
||||||
import { PasswordGenerationService } from 'jslib-common/services/passwordGeneration.service';
|
import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service";
|
||||||
import { PolicyService } from 'jslib-common/services/policy.service';
|
import { PolicyService } from "jslib-common/services/policy.service";
|
||||||
import { ProviderService } from 'jslib-common/services/provider.service';
|
import { ProviderService } from "jslib-common/services/provider.service";
|
||||||
import { SearchService } from 'jslib-common/services/search.service';
|
import { SearchService } from "jslib-common/services/search.service";
|
||||||
import { SendService } from 'jslib-common/services/send.service';
|
import { SendService } from "jslib-common/services/send.service";
|
||||||
import { SettingsService } from 'jslib-common/services/settings.service';
|
import { SettingsService } from "jslib-common/services/settings.service";
|
||||||
import { StateService } from 'jslib-common/services/state.service';
|
import { StateService } from "jslib-common/services/state.service";
|
||||||
import { StateMigrationService } from 'jslib-common/services/stateMigration.service';
|
import { StateMigrationService } from "jslib-common/services/stateMigration.service";
|
||||||
import { SyncService } from 'jslib-common/services/sync.service';
|
import { SyncService } from "jslib-common/services/sync.service";
|
||||||
import { TokenService } from 'jslib-common/services/token.service';
|
import { TokenService } from "jslib-common/services/token.service";
|
||||||
import { TotpService } from 'jslib-common/services/totp.service';
|
import { TotpService } from "jslib-common/services/totp.service";
|
||||||
import { UserVerificationService } from 'jslib-common/services/userVerification.service';
|
import { UserVerificationService } from "jslib-common/services/userVerification.service";
|
||||||
import { VaultTimeoutService } from 'jslib-common/services/vaultTimeout.service';
|
import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service";
|
||||||
import { WebCryptoFunctionService } from 'jslib-common/services/webCryptoFunction.service';
|
import { WebCryptoFunctionService } from "jslib-common/services/webCryptoFunction.service";
|
||||||
|
|
||||||
import { ApiService as ApiServiceAbstraction } from 'jslib-common/abstractions/api.service';
|
import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service";
|
||||||
import { AppIdService as AppIdServiceAbstraction } from 'jslib-common/abstractions/appId.service';
|
import { AppIdService as AppIdServiceAbstraction } from "jslib-common/abstractions/appId.service";
|
||||||
import { AuditService as AuditServiceAbstraction } from 'jslib-common/abstractions/audit.service';
|
import { AuditService as AuditServiceAbstraction } from "jslib-common/abstractions/audit.service";
|
||||||
import { AuthService as AuthServiceAbstraction } from 'jslib-common/abstractions/auth.service';
|
import { AuthService as AuthServiceAbstraction } from "jslib-common/abstractions/auth.service";
|
||||||
import { BroadcasterService as BroadcasterServiceAbstraction } from 'jslib-common/abstractions/broadcaster.service';
|
import { BroadcasterService as BroadcasterServiceAbstraction } from "jslib-common/abstractions/broadcaster.service";
|
||||||
import { CipherService as CipherServiceAbstraction } from 'jslib-common/abstractions/cipher.service';
|
import { CipherService as CipherServiceAbstraction } from "jslib-common/abstractions/cipher.service";
|
||||||
import { CollectionService as CollectionServiceAbstraction } from 'jslib-common/abstractions/collection.service';
|
import { CollectionService as CollectionServiceAbstraction } from "jslib-common/abstractions/collection.service";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from 'jslib-common/abstractions/crypto.service';
|
import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from 'jslib-common/abstractions/cryptoFunction.service';
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService as EnvironmentServiceAbstraction } from 'jslib-common/abstractions/environment.service';
|
import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service";
|
||||||
import { EventService as EventServiceAbstraction } from 'jslib-common/abstractions/event.service';
|
import { EventService as EventServiceAbstraction } from "jslib-common/abstractions/event.service";
|
||||||
import { ExportService as ExportServiceAbstraction } from 'jslib-common/abstractions/export.service';
|
import { ExportService as ExportServiceAbstraction } from "jslib-common/abstractions/export.service";
|
||||||
import { FileUploadService as FileUploadServiceAbstraction } from 'jslib-common/abstractions/fileUpload.service';
|
import { FileUploadService as FileUploadServiceAbstraction } from "jslib-common/abstractions/fileUpload.service";
|
||||||
import { FolderService as FolderServiceAbstraction } from 'jslib-common/abstractions/folder.service';
|
import { FolderService as FolderServiceAbstraction } from "jslib-common/abstractions/folder.service";
|
||||||
import { I18nService as I18nServiceAbstraction } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
|
||||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { LogService } from 'jslib-common/abstractions/log.service';
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService as MessagingServiceAbstraction } from 'jslib-common/abstractions/messaging.service';
|
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
|
||||||
import { NotificationsService as NotificationsServiceAbstraction } from 'jslib-common/abstractions/notifications.service';
|
import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service";
|
||||||
import { OrganizationService as OrganizationServiceAbstraction } from 'jslib-common/abstractions/organization.service';
|
import { OrganizationService as OrganizationServiceAbstraction } from "jslib-common/abstractions/organization.service";
|
||||||
import {
|
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "jslib-common/abstractions/passwordGeneration.service";
|
||||||
PasswordGenerationService as PasswordGenerationServiceAbstraction,
|
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
|
||||||
} from 'jslib-common/abstractions/passwordGeneration.service';
|
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
|
import { PolicyService as PolicyServiceAbstraction } from "jslib-common/abstractions/policy.service";
|
||||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from 'jslib-common/abstractions/platformUtils.service';
|
import { ProviderService as ProviderServiceAbstraction } from "jslib-common/abstractions/provider.service";
|
||||||
import { PolicyService as PolicyServiceAbstraction } from 'jslib-common/abstractions/policy.service';
|
import { SearchService as SearchServiceAbstraction } from "jslib-common/abstractions/search.service";
|
||||||
import { ProviderService as ProviderServiceAbstraction } from 'jslib-common/abstractions/provider.service';
|
import { SendService as SendServiceAbstraction } from "jslib-common/abstractions/send.service";
|
||||||
import { SearchService as SearchServiceAbstraction } from 'jslib-common/abstractions/search.service';
|
import { SettingsService as SettingsServiceAbstraction } from "jslib-common/abstractions/settings.service";
|
||||||
import { SendService as SendServiceAbstraction } from 'jslib-common/abstractions/send.service';
|
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
||||||
import { SettingsService as SettingsServiceAbstraction } from 'jslib-common/abstractions/settings.service';
|
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
|
||||||
import { StateService as StateServiceAbstraction } from 'jslib-common/abstractions/state.service';
|
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||||
import { StateMigrationService as StateMigrationServiceAbstraction } from 'jslib-common/abstractions/stateMigration.service';
|
import { SyncService as SyncServiceAbstraction } from "jslib-common/abstractions/sync.service";
|
||||||
import { StorageService as StorageServiceAbstraction } from 'jslib-common/abstractions/storage.service';
|
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
|
||||||
import { SyncService as SyncServiceAbstraction } from 'jslib-common/abstractions/sync.service';
|
import { TotpService as TotpServiceAbstraction } from "jslib-common/abstractions/totp.service";
|
||||||
import { TokenService as TokenServiceAbstraction } from 'jslib-common/abstractions/token.service';
|
import { UserVerificationService as UserVerificationServiceAbstraction } from "jslib-common/abstractions/userVerification.service";
|
||||||
import { TotpService as TotpServiceAbstraction } from 'jslib-common/abstractions/totp.service';
|
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.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 { AuthGuardService } from "./auth-guard.service";
|
||||||
import { BroadcasterService } from './broadcaster.service';
|
import { BroadcasterService } from "./broadcaster.service";
|
||||||
import { LockGuardService } from './lock-guard.service';
|
import { LockGuardService } from "./lock-guard.service";
|
||||||
import { ModalService } from './modal.service';
|
import { ModalService } from "./modal.service";
|
||||||
import { PasswordRepromptService } from './passwordReprompt.service';
|
import { PasswordRepromptService } from "./passwordReprompt.service";
|
||||||
import { UnauthGuardService } from './unauth-guard.service';
|
import { UnauthGuardService } from "./unauth-guard.service";
|
||||||
import { ValidationService } from './validation.service';
|
import { ValidationService } from "./validation.service";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [],
|
declarations: [],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: 'WINDOW', useValue: window },
|
{ provide: "WINDOW", useValue: window },
|
||||||
{
|
{
|
||||||
provide: LOCALE_ID,
|
provide: LOCALE_ID,
|
||||||
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
useFactory: (i18nService: I18nServiceAbstraction) => i18nService.translationLocale,
|
||||||
@@ -135,8 +129,9 @@ import { ValidationService } from './validation.service';
|
|||||||
i18nService: I18nServiceAbstraction,
|
i18nService: I18nServiceAbstraction,
|
||||||
injector: Injector,
|
injector: Injector,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateServiceAbstraction,
|
stateService: StateServiceAbstraction
|
||||||
) => new CipherService(
|
) =>
|
||||||
|
new CipherService(
|
||||||
cryptoService,
|
cryptoService,
|
||||||
settingsService,
|
settingsService,
|
||||||
apiService,
|
apiService,
|
||||||
@@ -144,7 +139,7 @@ import { ValidationService } from './validation.service';
|
|||||||
i18nService,
|
i18nService,
|
||||||
() => injector.get(SearchServiceAbstraction),
|
() => injector.get(SearchServiceAbstraction),
|
||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
CryptoServiceAbstraction,
|
CryptoServiceAbstraction,
|
||||||
@@ -172,11 +167,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: CollectionServiceAbstraction,
|
provide: CollectionServiceAbstraction,
|
||||||
useClass: CollectionService,
|
useClass: CollectionService,
|
||||||
deps: [
|
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, StateServiceAbstraction],
|
||||||
CryptoServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: EnvironmentServiceAbstraction,
|
provide: EnvironmentServiceAbstraction,
|
||||||
@@ -186,11 +177,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: TotpServiceAbstraction,
|
provide: TotpServiceAbstraction,
|
||||||
useClass: TotpService,
|
useClass: TotpService,
|
||||||
deps: [
|
deps: [CryptoFunctionServiceAbstraction, LogService, StateServiceAbstraction],
|
||||||
CryptoFunctionServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StateServiceAbstraction] },
|
{ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StateServiceAbstraction] },
|
||||||
{
|
{
|
||||||
@@ -206,18 +193,22 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: PasswordGenerationServiceAbstraction,
|
provide: PasswordGenerationServiceAbstraction,
|
||||||
useClass: PasswordGenerationService,
|
useClass: PasswordGenerationService,
|
||||||
deps: [
|
deps: [CryptoServiceAbstraction, PolicyServiceAbstraction, StateServiceAbstraction],
|
||||||
CryptoServiceAbstraction,
|
|
||||||
PolicyServiceAbstraction,
|
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: ApiServiceAbstraction,
|
provide: ApiServiceAbstraction,
|
||||||
useFactory: (tokenService: TokenServiceAbstraction, platformUtilsService: PlatformUtilsServiceAbstraction,
|
useFactory: (
|
||||||
environmentService: EnvironmentServiceAbstraction, messagingService: MessagingServiceAbstraction) =>
|
tokenService: TokenServiceAbstraction,
|
||||||
new ApiService(tokenService, platformUtilsService, environmentService,
|
platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||||
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
|
environmentService: EnvironmentServiceAbstraction,
|
||||||
|
messagingService: MessagingServiceAbstraction
|
||||||
|
) =>
|
||||||
|
new ApiService(
|
||||||
|
tokenService,
|
||||||
|
platformUtilsService,
|
||||||
|
environmentService,
|
||||||
|
async (expired: boolean) => messagingService.send("logout", { expired: expired })
|
||||||
|
),
|
||||||
deps: [
|
deps: [
|
||||||
TokenServiceAbstraction,
|
TokenServiceAbstraction,
|
||||||
PlatformUtilsServiceAbstraction,
|
PlatformUtilsServiceAbstraction,
|
||||||
@@ -228,10 +219,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: FileUploadServiceAbstraction,
|
provide: FileUploadServiceAbstraction,
|
||||||
useClass: FileUploadService,
|
useClass: FileUploadService,
|
||||||
deps: [
|
deps: [LogService, ApiServiceAbstraction],
|
||||||
LogService,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: SyncServiceAbstraction,
|
provide: SyncServiceAbstraction,
|
||||||
@@ -249,8 +237,9 @@ import { ValidationService } from './validation.service';
|
|||||||
keyConnectorService: KeyConnectorServiceAbstraction,
|
keyConnectorService: KeyConnectorServiceAbstraction,
|
||||||
stateService: StateServiceAbstraction,
|
stateService: StateServiceAbstraction,
|
||||||
organizationService: OrganizationServiceAbstraction,
|
organizationService: OrganizationServiceAbstraction,
|
||||||
providerService: ProviderServiceAbstraction,
|
providerService: ProviderServiceAbstraction
|
||||||
) => new SyncService(
|
) =>
|
||||||
|
new SyncService(
|
||||||
apiService,
|
apiService,
|
||||||
settingsService,
|
settingsService,
|
||||||
folderService,
|
folderService,
|
||||||
@@ -265,7 +254,8 @@ import { ValidationService } from './validation.service';
|
|||||||
stateService,
|
stateService,
|
||||||
organizationService,
|
organizationService,
|
||||||
providerService,
|
providerService,
|
||||||
async (expired: boolean) => messagingService.send('logout', { expired: expired })),
|
async (expired: boolean) => messagingService.send("logout", { expired: expired })
|
||||||
|
),
|
||||||
deps: [
|
deps: [
|
||||||
ApiServiceAbstraction,
|
ApiServiceAbstraction,
|
||||||
SettingsServiceAbstraction,
|
SettingsServiceAbstraction,
|
||||||
@@ -302,8 +292,9 @@ import { ValidationService } from './validation.service';
|
|||||||
tokenService: TokenServiceAbstraction,
|
tokenService: TokenServiceAbstraction,
|
||||||
policyService: PolicyServiceAbstraction,
|
policyService: PolicyServiceAbstraction,
|
||||||
keyConnectorService: KeyConnectorServiceAbstraction,
|
keyConnectorService: KeyConnectorServiceAbstraction,
|
||||||
stateService: StateServiceAbstraction,
|
stateService: StateServiceAbstraction
|
||||||
) => new VaultTimeoutService(
|
) =>
|
||||||
|
new VaultTimeoutService(
|
||||||
cipherService,
|
cipherService,
|
||||||
folderService,
|
folderService,
|
||||||
collectionService,
|
collectionService,
|
||||||
@@ -316,7 +307,7 @@ import { ValidationService } from './validation.service';
|
|||||||
keyConnectorService,
|
keyConnectorService,
|
||||||
stateService,
|
stateService,
|
||||||
null,
|
null,
|
||||||
async () => messagingService.send('logout', { expired: false }),
|
async () => messagingService.send("logout", { expired: false })
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
CipherServiceAbstraction,
|
CipherServiceAbstraction,
|
||||||
@@ -337,7 +328,7 @@ import { ValidationService } from './validation.service';
|
|||||||
useClass: StateService,
|
useClass: StateService,
|
||||||
deps: [
|
deps: [
|
||||||
StorageServiceAbstraction,
|
StorageServiceAbstraction,
|
||||||
'SECURE_STORAGE',
|
"SECURE_STORAGE",
|
||||||
LogService,
|
LogService,
|
||||||
StateMigrationServiceAbstraction,
|
StateMigrationServiceAbstraction,
|
||||||
],
|
],
|
||||||
@@ -345,10 +336,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: StateMigrationServiceAbstraction,
|
provide: StateMigrationServiceAbstraction,
|
||||||
useClass: StateMigrationService,
|
useClass: StateMigrationService,
|
||||||
deps: [
|
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
||||||
StorageServiceAbstraction,
|
|
||||||
'SECURE_STORAGE',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: ExportServiceAbstraction,
|
provide: ExportServiceAbstraction,
|
||||||
@@ -363,11 +351,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: SearchServiceAbstraction,
|
provide: SearchServiceAbstraction,
|
||||||
useClass: SearchService,
|
useClass: SearchService,
|
||||||
deps: [
|
deps: [CipherServiceAbstraction, LogService, I18nServiceAbstraction],
|
||||||
CipherServiceAbstraction,
|
|
||||||
LogService,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: NotificationsServiceAbstraction,
|
provide: NotificationsServiceAbstraction,
|
||||||
@@ -379,16 +363,17 @@ import { ValidationService } from './validation.service';
|
|||||||
environmentService: EnvironmentServiceAbstraction,
|
environmentService: EnvironmentServiceAbstraction,
|
||||||
messagingService: MessagingServiceAbstraction,
|
messagingService: MessagingServiceAbstraction,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
stateService: StateServiceAbstraction,
|
stateService: StateServiceAbstraction
|
||||||
) => new NotificationsService(
|
) =>
|
||||||
|
new NotificationsService(
|
||||||
syncService,
|
syncService,
|
||||||
appIdService,
|
appIdService,
|
||||||
apiService,
|
apiService,
|
||||||
vaultTimeoutService,
|
vaultTimeoutService,
|
||||||
environmentService,
|
environmentService,
|
||||||
async () => messagingService.send('logout', { expired: true }),
|
async () => messagingService.send("logout", { expired: true }),
|
||||||
logService,
|
logService,
|
||||||
stateService,
|
stateService
|
||||||
),
|
),
|
||||||
deps: [
|
deps: [
|
||||||
SyncServiceAbstraction,
|
SyncServiceAbstraction,
|
||||||
@@ -404,7 +389,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: CryptoFunctionServiceAbstraction,
|
provide: CryptoFunctionServiceAbstraction,
|
||||||
useClass: WebCryptoFunctionService,
|
useClass: WebCryptoFunctionService,
|
||||||
deps: ['WINDOW', PlatformUtilsServiceAbstraction],
|
deps: ["WINDOW", PlatformUtilsServiceAbstraction],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: EventServiceAbstraction,
|
provide: EventServiceAbstraction,
|
||||||
@@ -420,11 +405,7 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: PolicyServiceAbstraction,
|
provide: PolicyServiceAbstraction,
|
||||||
useClass: PolicyService,
|
useClass: PolicyService,
|
||||||
deps: [
|
deps: [StateServiceAbstraction, OrganizationServiceAbstraction, ApiServiceAbstraction],
|
||||||
StateServiceAbstraction,
|
|
||||||
OrganizationServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: SendServiceAbstraction,
|
provide: SendServiceAbstraction,
|
||||||
@@ -453,28 +434,19 @@ import { ValidationService } from './validation.service';
|
|||||||
{
|
{
|
||||||
provide: UserVerificationServiceAbstraction,
|
provide: UserVerificationServiceAbstraction,
|
||||||
useClass: UserVerificationService,
|
useClass: UserVerificationService,
|
||||||
deps: [
|
deps: [CryptoServiceAbstraction, I18nServiceAbstraction, ApiServiceAbstraction],
|
||||||
CryptoServiceAbstraction,
|
|
||||||
I18nServiceAbstraction,
|
|
||||||
ApiServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
{ provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
|
||||||
{
|
{
|
||||||
provide: OrganizationServiceAbstraction,
|
provide: OrganizationServiceAbstraction,
|
||||||
useClass: OrganizationService,
|
useClass: OrganizationService,
|
||||||
deps: [
|
deps: [StateServiceAbstraction],
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: ProviderServiceAbstraction,
|
provide: ProviderServiceAbstraction,
|
||||||
useClass: ProviderService,
|
useClass: ProviderService,
|
||||||
deps: [
|
deps: [StateServiceAbstraction],
|
||||||
StateServiceAbstraction,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class JslibServicesModule {
|
export class JslibServicesModule {}
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from "@angular/core";
|
||||||
import {
|
import { CanActivate, Router } from "@angular/router";
|
||||||
CanActivate,
|
|
||||||
Router,
|
|
||||||
} from '@angular/router';
|
|
||||||
|
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LockGuardService implements CanActivate {
|
export class LockGuardService implements CanActivate {
|
||||||
protected homepage = 'vault';
|
protected homepage = "vault";
|
||||||
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
|
constructor(
|
||||||
private stateService: StateService) { }
|
private vaultTimeoutService: VaultTimeoutService,
|
||||||
|
private router: Router,
|
||||||
|
private stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate() {
|
async canActivate() {
|
||||||
if (!await this.stateService.getIsAuthenticated()) {
|
if (!(await this.stateService.getIsAuthenticated())) {
|
||||||
this.router.navigate(['login']);
|
this.router.navigate(["login"]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await this.vaultTimeoutService.isLocked()) {
|
if (!(await this.vaultTimeoutService.isLocked())) {
|
||||||
this.router.navigate([this.homepage]);
|
this.router.navigate([this.homepage]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
Injector,
|
Injector,
|
||||||
Type,
|
Type,
|
||||||
ViewContainerRef
|
ViewContainerRef,
|
||||||
} from '@angular/core';
|
} from "@angular/core";
|
||||||
import { first } from 'rxjs/operators';
|
import { first } from "rxjs/operators";
|
||||||
|
|
||||||
import { DynamicModalComponent } from '../components/modal/dynamic-modal.component';
|
import { DynamicModalComponent } from "../components/modal/dynamic-modal.component";
|
||||||
import { ModalInjector } from '../components/modal/modal-injector';
|
import { ModalInjector } from "../components/modal/modal-injector";
|
||||||
import { ModalRef } from '../components/modal/modal.ref';
|
import { ModalRef } from "../components/modal/modal.ref";
|
||||||
|
|
||||||
export class ModalConfig<D = any> {
|
export class ModalConfig<D = any> {
|
||||||
data?: D;
|
data?: D;
|
||||||
@@ -28,10 +28,13 @@ export class ModalService {
|
|||||||
// therefore modules needs to manually initialize their resolvers.
|
// therefore modules needs to manually initialize their resolvers.
|
||||||
private factoryResolvers: Map<Type<any>, ComponentFactoryResolver> = new Map();
|
private factoryResolvers: Map<Type<any>, ComponentFactoryResolver> = new Map();
|
||||||
|
|
||||||
constructor(private componentFactoryResolver: ComponentFactoryResolver, private applicationRef: ApplicationRef,
|
constructor(
|
||||||
private injector: Injector) {
|
private componentFactoryResolver: ComponentFactoryResolver,
|
||||||
document.addEventListener('keyup', event => {
|
private applicationRef: ApplicationRef,
|
||||||
if (event.key === 'Escape' && this.modalCount > 0) {
|
private injector: Injector
|
||||||
|
) {
|
||||||
|
document.addEventListener("keyup", (event) => {
|
||||||
|
if (event.key === "Escape" && this.modalCount > 0) {
|
||||||
this.topModal.instance.close();
|
this.topModal.instance.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -45,9 +48,11 @@ export class ModalService {
|
|||||||
return this.modalList[this.modalCount - 1];
|
return this.modalList[this.modalCount - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
async openViewRef<T>(componentType: Type<T>, viewContainerRef: ViewContainerRef,
|
async openViewRef<T>(
|
||||||
setComponentParameters: (component: T) => void = null): Promise<[ModalRef, T]> {
|
componentType: Type<T>,
|
||||||
|
viewContainerRef: ViewContainerRef,
|
||||||
|
setComponentParameters: (component: T) => void = null
|
||||||
|
): Promise<[ModalRef, T]> {
|
||||||
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
|
const [modalRef, modalComponentRef] = this.openInternal(componentType, null, false);
|
||||||
modalComponentRef.instance.setComponentParameters = setComponentParameters;
|
modalComponentRef.instance.setComponentParameters = setComponentParameters;
|
||||||
|
|
||||||
@@ -68,7 +73,10 @@ export class ModalService {
|
|||||||
return modalRef;
|
return modalRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerComponentFactoryResolver<T>(componentType: Type<T>, componentFactoryResolver: ComponentFactoryResolver): void {
|
registerComponentFactoryResolver<T>(
|
||||||
|
componentType: Type<T>,
|
||||||
|
componentFactoryResolver: ComponentFactoryResolver
|
||||||
|
): void {
|
||||||
this.factoryResolvers.set(componentType, componentFactoryResolver);
|
this.factoryResolvers.set(componentType, componentFactoryResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,9 +88,11 @@ export class ModalService {
|
|||||||
return this.componentFactoryResolver.resolveComponentFactory(componentType);
|
return this.componentFactoryResolver.resolveComponentFactory(componentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected openInternal(componentType: Type<any>, config?: ModalConfig, attachToDom?: boolean):
|
protected openInternal(
|
||||||
[ModalRef, ComponentRef<DynamicModalComponent>] {
|
componentType: Type<any>,
|
||||||
|
config?: ModalConfig,
|
||||||
|
attachToDom?: boolean
|
||||||
|
): [ModalRef, ComponentRef<DynamicModalComponent>] {
|
||||||
const [modalRef, componentRef] = this.createModalComponent(config);
|
const [modalRef, componentRef] = this.createModalComponent(config);
|
||||||
componentRef.instance.childComponentType = componentType;
|
componentRef.instance.childComponentType = componentType;
|
||||||
|
|
||||||
@@ -115,25 +125,27 @@ export class ModalService {
|
|||||||
let backdrop: HTMLElement = null;
|
let backdrop: HTMLElement = null;
|
||||||
|
|
||||||
// Add backdrop, setup [data-dismiss] handler.
|
// Add backdrop, setup [data-dismiss] handler.
|
||||||
modalRef.onCreated.pipe(first()).subscribe(el => {
|
modalRef.onCreated.pipe(first()).subscribe((el) => {
|
||||||
document.body.classList.add('modal-open');
|
document.body.classList.add("modal-open");
|
||||||
|
|
||||||
const modalEl: HTMLElement = el.querySelector('.modal');
|
const modalEl: HTMLElement = el.querySelector(".modal");
|
||||||
const dialogEl = modalEl.querySelector('.modal-dialog') as HTMLElement;
|
const dialogEl = modalEl.querySelector(".modal-dialog") as HTMLElement;
|
||||||
|
|
||||||
backdrop = document.createElement('div');
|
backdrop = document.createElement("div");
|
||||||
backdrop.className = 'modal-backdrop fade';
|
backdrop.className = "modal-backdrop fade";
|
||||||
backdrop.style.zIndex = `${this.modalCount}040`;
|
backdrop.style.zIndex = `${this.modalCount}040`;
|
||||||
modalEl.prepend(backdrop);
|
modalEl.prepend(backdrop);
|
||||||
|
|
||||||
dialogEl.addEventListener('click', (e: Event) => {
|
dialogEl.addEventListener("click", (e: Event) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
});
|
});
|
||||||
dialogEl.style.zIndex = `${this.modalCount}050`;
|
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) {
|
for (const closeElement of modals) {
|
||||||
closeElement.addEventListener('click', event => {
|
closeElement.addEventListener("click", (event) => {
|
||||||
modalRef.close();
|
modalRef.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -144,19 +156,22 @@ export class ModalService {
|
|||||||
modalRef.closed();
|
modalRef.closed();
|
||||||
|
|
||||||
if (this.modalCount === 0) {
|
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 modalRef = new ModalRef();
|
||||||
|
|
||||||
const map = new WeakMap();
|
const map = new WeakMap();
|
||||||
map.set(ModalConfig, config);
|
map.set(ModalConfig, config);
|
||||||
map.set(ModalRef, modalRef);
|
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));
|
const componentRef = componentFactory.create(new ModalInjector(this.injector, map));
|
||||||
|
|
||||||
return [modalRef, componentRef];
|
return [modalRef, componentRef];
|
||||||
|
|||||||
@@ -1,23 +1,26 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
import { KeyConnectorService } from 'jslib-common/abstractions/keyConnector.service';
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from 'jslib-common/abstractions/passwordReprompt.service';
|
import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service";
|
||||||
|
|
||||||
import { PasswordRepromptComponent } from '../components/password-reprompt.component';
|
import { PasswordRepromptComponent } from "../components/password-reprompt.component";
|
||||||
import { ModalService } from './modal.service';
|
import { ModalService } from "./modal.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PasswordRepromptService implements PasswordRepromptServiceAbstraction {
|
export class PasswordRepromptService implements PasswordRepromptServiceAbstraction {
|
||||||
protected component = PasswordRepromptComponent;
|
protected component = PasswordRepromptComponent;
|
||||||
|
|
||||||
constructor(private modalService: ModalService, private keyConnectorService: KeyConnectorService) { }
|
constructor(
|
||||||
|
private modalService: ModalService,
|
||||||
|
private keyConnectorService: KeyConnectorService
|
||||||
|
) {}
|
||||||
|
|
||||||
protectedFields() {
|
protectedFields() {
|
||||||
return ['TOTP', 'Password', 'H_Field', 'Card Number', 'Security Code'];
|
return ["TOTP", "Password", "H_Field", "Card Number", "Security Code"];
|
||||||
}
|
}
|
||||||
|
|
||||||
async showPasswordPrompt() {
|
async showPasswordPrompt() {
|
||||||
if (!await this.enabled()) {
|
if (!(await this.enabled())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +35,6 @@ export class PasswordRepromptService implements PasswordRepromptServiceAbstracti
|
|||||||
}
|
}
|
||||||
|
|
||||||
async enabled() {
|
async enabled() {
|
||||||
return !await this.keyConnectorService.getUsesKeyConnector();
|
return !(await this.keyConnectorService.getUsesKeyConnector());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from "@angular/core";
|
||||||
import {
|
import { CanActivate, Router } from "@angular/router";
|
||||||
CanActivate,
|
|
||||||
Router,
|
|
||||||
} from '@angular/router';
|
|
||||||
|
|
||||||
import { StateService } from 'jslib-common/abstractions/state.service';
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
|
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UnauthGuardService implements CanActivate {
|
export class UnauthGuardService implements CanActivate {
|
||||||
|
protected homepage = "vault";
|
||||||
protected homepage = 'vault';
|
constructor(
|
||||||
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
|
private vaultTimeoutService: VaultTimeoutService,
|
||||||
private stateService: StateService) { }
|
private router: Router,
|
||||||
|
private stateService: StateService
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate() {
|
async canActivate() {
|
||||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
const isAuthed = await this.stateService.getIsAuthenticated();
|
||||||
if (isAuthed) {
|
if (isAuthed) {
|
||||||
const locked = await this.vaultTimeoutService.isLocked();
|
const locked = await this.vaultTimeoutService.isLocked();
|
||||||
if (locked) {
|
if (locked) {
|
||||||
this.router.navigate(['lock']);
|
this.router.navigate(["lock"]);
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate([this.homepage]);
|
this.router.navigate([this.homepage]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from "@angular/core";
|
||||||
|
|
||||||
import { I18nService } from 'jslib-common/abstractions/i18n.service';
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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()
|
@Injectable()
|
||||||
export class ValidationService {
|
export class ValidationService {
|
||||||
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService) { }
|
constructor(
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private platformUtilsService: PlatformUtilsService
|
||||||
|
) {}
|
||||||
|
|
||||||
showError(data: any): string[] {
|
showError(data: any): string[] {
|
||||||
const defaultErrorMessage = this.i18nService.t('unexpectedError');
|
const defaultErrorMessage = this.i18nService.t("unexpectedError");
|
||||||
let errors: string[] = [];
|
let errors: string[] = [];
|
||||||
|
|
||||||
if (data != null && typeof data === 'string') {
|
if (data != null && typeof data === "string") {
|
||||||
errors.push(data);
|
errors.push(data);
|
||||||
} else if (data == null || typeof data !== 'object') {
|
} else if (data == null || typeof data !== "object") {
|
||||||
errors.push(defaultErrorMessage);
|
errors.push(defaultErrorMessage);
|
||||||
} else if (data.validationErrors != null) {
|
} else if (data.validationErrors != null) {
|
||||||
errors = errors.concat((data as ErrorResponse).getAllMessages());
|
errors = errors.concat((data as ErrorResponse).getAllMessages());
|
||||||
@@ -24,9 +27,9 @@ export class ValidationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length === 1) {
|
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) {
|
} 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,
|
timeout: 5000 * errors.length,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,17 +14,9 @@
|
|||||||
"declarationDir": "dist/types",
|
"declarationDir": "dist/types",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"paths": {
|
"paths": {
|
||||||
"jslib-common/*": [
|
"jslib-common/*": ["../common/src/*"]
|
||||||
"../common/src/*"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src", "spec"],
|
||||||
"src",
|
"exclude": ["node_modules", "dist"]
|
||||||
"spec"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
"dist"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
const path = require('path');
|
const path = require("path");
|
||||||
const webpack = require('webpack');
|
const webpack = require("webpack");
|
||||||
|
|
||||||
module.exports = (config) => {
|
module.exports = (config) => {
|
||||||
config.set({
|
config.set({
|
||||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||||
basePath: '',
|
basePath: "",
|
||||||
|
|
||||||
// frameworks to use
|
// frameworks to use
|
||||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||||
frameworks: ['jasmine', 'webpack', 'detectBrowsers'],
|
frameworks: ["jasmine", "webpack", "detectBrowsers"],
|
||||||
|
|
||||||
// list of files / patterns to load in the browser
|
// list of files / patterns to load in the browser
|
||||||
files: [
|
files: [{ pattern: "spec/**/*.spec.ts", watched: false }],
|
||||||
{ pattern: 'spec/**/*.spec.ts', watched: false },
|
|
||||||
],
|
|
||||||
|
|
||||||
// list of files to exclude
|
// list of files to exclude
|
||||||
exclude: [],
|
exclude: [],
|
||||||
@@ -21,13 +19,13 @@ module.exports = (config) => {
|
|||||||
// preprocess matching files before serving them to the browser
|
// preprocess matching files before serving them to the browser
|
||||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
'spec/**/*.ts': ['webpack', 'sourcemap'],
|
"spec/**/*.ts": ["webpack", "sourcemap"],
|
||||||
},
|
},
|
||||||
|
|
||||||
// test results reporter to use
|
// test results reporter to use
|
||||||
// possible values: 'dots', 'progress'
|
// possible values: 'dots', 'progress'
|
||||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
reporters: ['progress', 'kjhtml'],
|
reporters: ["progress", "kjhtml"],
|
||||||
|
|
||||||
// web server port
|
// web server port
|
||||||
port: 9876,
|
port: 9876,
|
||||||
@@ -44,31 +42,31 @@ module.exports = (config) => {
|
|||||||
concurrency: Infinity,
|
concurrency: Infinity,
|
||||||
|
|
||||||
client: {
|
client: {
|
||||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||||
},
|
},
|
||||||
|
|
||||||
webpack: {
|
webpack: {
|
||||||
mode: 'development',
|
mode: "development",
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.ts', '.tsx'],
|
extensions: [".js", ".ts", ".tsx"],
|
||||||
fallback: {
|
fallback: {
|
||||||
"util": require.resolve("util/"),
|
util: require.resolve("util/"),
|
||||||
"url": require.resolve("url/"),
|
url: require.resolve("url/"),
|
||||||
},
|
},
|
||||||
alias: {
|
alias: {
|
||||||
src: path.resolve(__dirname, 'src/'),
|
src: path.resolve(__dirname, "src/"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.ProvidePlugin({
|
new webpack.ProvidePlugin({
|
||||||
process: 'process/browser',
|
process: "process/browser",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
loader: 'ts-loader',
|
loader: "ts-loader",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -89,18 +87,19 @@ module.exports = (config) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeBrowser('IE');
|
removeBrowser("IE");
|
||||||
removeBrowser('Opera');
|
removeBrowser("Opera");
|
||||||
removeBrowser('SafariTechPreview');
|
removeBrowser("SafariTechPreview");
|
||||||
|
|
||||||
var githubAction = process.env.GITHUB_WORKFLOW != null && process.env.GITHUB_WORKFLOW !== '';
|
var githubAction =
|
||||||
|
process.env.GITHUB_WORKFLOW != null && process.env.GITHUB_WORKFLOW !== "";
|
||||||
if (githubAction) {
|
if (githubAction) {
|
||||||
removeBrowser('Firefox');
|
removeBrowser("Firefox");
|
||||||
removeBrowser('Safari');
|
removeBrowser("Safari");
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
const TSConsoleReporter = require('jasmine-ts-console-reporter');
|
const TSConsoleReporter = require("jasmine-ts-console-reporter");
|
||||||
jasmine.getEnv().clearReporters(); // Clear default console reporter
|
jasmine.getEnv().clearReporters(); // Clear default console reporter
|
||||||
jasmine.getEnv().addReporter(new TSConsoleReporter());
|
jasmine.getEnv().addReporter(new TSConsoleReporter());
|
||||||
|
|
||||||
// Polyfills
|
// Polyfills
|
||||||
// tslint:disable-next-line
|
// tslint:disable-next-line
|
||||||
const jsdom: any = require('jsdom');
|
const jsdom: any = require("jsdom");
|
||||||
(global as any).DOMParser = new jsdom.JSDOM().window.DOMParser;
|
(global as any).DOMParser = new jsdom.JSDOM().window.DOMParser;
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import { FirefoxCsvImporter as Importer } from 'src/importers/firefoxCsvImporter';
|
import { FirefoxCsvImporter as Importer } from "src/importers/firefoxCsvImporter";
|
||||||
|
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
import { LoginUriView } from 'src/models/view/loginUriView';
|
import { LoginUriView } from "src/models/view/loginUriView";
|
||||||
import { LoginView } from 'src/models/view/loginView';
|
import { LoginView } from "src/models/view/loginView";
|
||||||
|
|
||||||
import { data as firefoxAccountsData } from './testData/firefoxCsv/firefoxAccountsData.csv';
|
import { data as firefoxAccountsData } from "./testData/firefoxCsv/firefoxAccountsData.csv";
|
||||||
import { data as simplePasswordData } from './testData/firefoxCsv/simplePasswordData.csv';
|
import { data as simplePasswordData } from "./testData/firefoxCsv/simplePasswordData.csv";
|
||||||
|
|
||||||
const CipherData = [
|
const CipherData = [
|
||||||
{
|
{
|
||||||
title: 'should parse password',
|
title: "should parse password",
|
||||||
csv: simplePasswordData,
|
csv: simplePasswordData,
|
||||||
expected: Object.assign(new CipherView(), {
|
expected: Object.assign(new CipherView(), {
|
||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'example.com',
|
name: "example.com",
|
||||||
login: Object.assign(new LoginView(), {
|
login: Object.assign(new LoginView(), {
|
||||||
username: 'foo',
|
username: "foo",
|
||||||
password: 'bar',
|
password: "bar",
|
||||||
uris: [
|
uris: [
|
||||||
Object.assign(new LoginUriView(), {
|
Object.assign(new LoginUriView(), {
|
||||||
uri: 'https://example.com',
|
uri: "https://example.com",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -36,13 +36,13 @@ const CipherData = [
|
|||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'example.com',
|
name: "example.com",
|
||||||
login: Object.assign(new LoginView(), {
|
login: Object.assign(new LoginView(), {
|
||||||
username: 'foo',
|
username: "foo",
|
||||||
password: 'bar',
|
password: "bar",
|
||||||
uris: [
|
uris: [
|
||||||
Object.assign(new LoginUriView(), {
|
Object.assign(new LoginUriView(), {
|
||||||
uri: 'https://example.com',
|
uri: "https://example.com",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
@@ -52,8 +52,8 @@ const CipherData = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('Firefox CSV Importer', () => {
|
describe("Firefox CSV Importer", () => {
|
||||||
CipherData.forEach(data => {
|
CipherData.forEach((data) => {
|
||||||
it(data.title, async () => {
|
it(data.title, async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(data.csv);
|
const result = await importer.parse(data.csv);
|
||||||
|
|||||||
@@ -1,80 +1,77 @@
|
|||||||
import { FSecureFskImporter as Importer } from 'src/importers/fsecureFskImporter';
|
import { FSecureFskImporter as Importer } from "src/importers/fsecureFskImporter";
|
||||||
|
|
||||||
const TestDataWithStyleSetToWebsite: string =
|
const TestDataWithStyleSetToWebsite: string = JSON.stringify({
|
||||||
JSON.stringify({
|
|
||||||
data: {
|
data: {
|
||||||
'8d58b5cf252dd06fbd98f5289e918ab1': {
|
"8d58b5cf252dd06fbd98f5289e918ab1": {
|
||||||
color: '#00baff',
|
color: "#00baff",
|
||||||
reatedDate: 1609302913,
|
reatedDate: 1609302913,
|
||||||
creditCvv: '',
|
creditCvv: "",
|
||||||
creditExpiry: '',
|
creditExpiry: "",
|
||||||
creditNumber: '',
|
creditNumber: "",
|
||||||
favorite: 0,
|
favorite: 0,
|
||||||
modifiedDate: 1609302913,
|
modifiedDate: 1609302913,
|
||||||
notes: 'note',
|
notes: "note",
|
||||||
password: 'word',
|
password: "word",
|
||||||
passwordList: [],
|
passwordList: [],
|
||||||
passwordModifiedDate: 1609302913,
|
passwordModifiedDate: 1609302913,
|
||||||
rev: 1,
|
rev: 1,
|
||||||
service: 'My first pass',
|
service: "My first pass",
|
||||||
style: 'website',
|
style: "website",
|
||||||
type: 1,
|
type: 1,
|
||||||
url: 'https://bitwarden.com',
|
url: "https://bitwarden.com",
|
||||||
username: 'pass',
|
username: "pass",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const TestDataWithStyleSetToGlobe: string =
|
const TestDataWithStyleSetToGlobe: string = JSON.stringify({
|
||||||
JSON.stringify({
|
|
||||||
data: {
|
data: {
|
||||||
'8d58b5cf252dd06fbd98f5289e918ab1': {
|
"8d58b5cf252dd06fbd98f5289e918ab1": {
|
||||||
color: '#00baff',
|
color: "#00baff",
|
||||||
reatedDate: 1609302913,
|
reatedDate: 1609302913,
|
||||||
creditCvv: '',
|
creditCvv: "",
|
||||||
creditExpiry: '',
|
creditExpiry: "",
|
||||||
creditNumber: '',
|
creditNumber: "",
|
||||||
favorite: 0,
|
favorite: 0,
|
||||||
modifiedDate: 1609302913,
|
modifiedDate: 1609302913,
|
||||||
notes: 'note',
|
notes: "note",
|
||||||
password: 'word',
|
password: "word",
|
||||||
passwordList: [],
|
passwordList: [],
|
||||||
passwordModifiedDate: 1609302913,
|
passwordModifiedDate: 1609302913,
|
||||||
rev: 1,
|
rev: 1,
|
||||||
service: 'My first pass',
|
service: "My first pass",
|
||||||
style: 'globe',
|
style: "globe",
|
||||||
type: 1,
|
type: 1,
|
||||||
url: 'https://bitwarden.com',
|
url: "https://bitwarden.com",
|
||||||
username: 'pass',
|
username: "pass",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("FSecure FSK Importer", () => {
|
||||||
describe('FSecure FSK Importer', () => {
|
it("should parse data with style set to website", async () => {
|
||||||
it('should parse data with style set to website', async () => {
|
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(TestDataWithStyleSetToWebsite);
|
const result = await importer.parse(TestDataWithStyleSetToWebsite);
|
||||||
expect(result != null).toBe(true);
|
expect(result != null).toBe(true);
|
||||||
|
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
expect(cipher.login.username).toEqual('pass');
|
expect(cipher.login.username).toEqual("pass");
|
||||||
expect(cipher.login.password).toEqual('word');
|
expect(cipher.login.password).toEqual("word");
|
||||||
expect(cipher.login.uris.length).toEqual(1);
|
expect(cipher.login.uris.length).toEqual(1);
|
||||||
const uriView = cipher.login.uris.shift();
|
const uriView = cipher.login.uris.shift();
|
||||||
expect(uriView.uri).toEqual('https://bitwarden.com');
|
expect(uriView.uri).toEqual("https://bitwarden.com");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse data with style set to globe', async () => {
|
it("should parse data with style set to globe", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(TestDataWithStyleSetToGlobe);
|
const result = await importer.parse(TestDataWithStyleSetToGlobe);
|
||||||
expect(result != null).toBe(true);
|
expect(result != null).toBe(true);
|
||||||
|
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
expect(cipher.login.username).toEqual('pass');
|
expect(cipher.login.username).toEqual("pass");
|
||||||
expect(cipher.login.password).toEqual('word');
|
expect(cipher.login.password).toEqual("word");
|
||||||
expect(cipher.login.uris.length).toEqual(1);
|
expect(cipher.login.uris.length).toEqual(1);
|
||||||
const uriView = cipher.login.uris.shift();
|
const uriView = cipher.login.uris.shift();
|
||||||
expect(uriView.uri).toEqual('https://bitwarden.com');
|
expect(uriView.uri).toEqual("https://bitwarden.com");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { KeePass2XmlImporter as Importer } from 'src/importers/keepass2XmlImporter';
|
import { KeePass2XmlImporter as Importer } from "src/importers/keepass2XmlImporter";
|
||||||
|
|
||||||
const TestData: string = `<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
const TestData: string = `<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||||
<KeePassFile>
|
<KeePassFile>
|
||||||
@@ -180,8 +180,8 @@ line2</Value>
|
|||||||
</Root>
|
</Root>
|
||||||
</KeePassFile>`;
|
</KeePassFile>`;
|
||||||
|
|
||||||
describe('KeePass2 Xml Importer', () => {
|
describe("KeePass2 Xml Importer", () => {
|
||||||
it('should parse XML data', async () => {
|
it("should parse XML data", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(TestData);
|
const result = await importer.parse(TestData);
|
||||||
expect(result != null).toBe(true);
|
expect(result != null).toBe(true);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { LastPassCsvImporter as Importer } from 'src/importers/lastpassCsvImporter';
|
import { LastPassCsvImporter as Importer } from "src/importers/lastpassCsvImporter";
|
||||||
|
|
||||||
import { ImportResult } from 'src/models/domain/importResult';
|
import { ImportResult } from "src/models/domain/importResult";
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
import { FieldView } from 'src/models/view/fieldView';
|
import { FieldView } from "src/models/view/fieldView";
|
||||||
|
|
||||||
import { CipherType } from 'src/enums/cipherType';
|
import { CipherType } from "src/enums/cipherType";
|
||||||
import { FieldType } from 'src/enums/fieldType';
|
import { FieldType } from "src/enums/fieldType";
|
||||||
|
|
||||||
function baseExcept(result: ImportResult) {
|
function baseExcept(result: ImportResult) {
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -16,17 +16,17 @@ function baseExcept(result: ImportResult) {
|
|||||||
function expectLogin(cipher: CipherView) {
|
function expectLogin(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Login);
|
expect(cipher.type).toBe(CipherType.Login);
|
||||||
|
|
||||||
expect(cipher.name).toBe('example.com');
|
expect(cipher.name).toBe("example.com");
|
||||||
expect(cipher.notes).toBe('super secure notes');
|
expect(cipher.notes).toBe("super secure notes");
|
||||||
expect(cipher.login.uri).toBe('http://example.com');
|
expect(cipher.login.uri).toBe("http://example.com");
|
||||||
expect(cipher.login.username).toBe('someUser');
|
expect(cipher.login.username).toBe("someUser");
|
||||||
expect(cipher.login.password).toBe('myPassword');
|
expect(cipher.login.password).toBe("myPassword");
|
||||||
expect(cipher.login.totp).toBe('Y64VEVMBTSXCYIWRSHRNDZW62MPGVU2G');
|
expect(cipher.login.totp).toBe("Y64VEVMBTSXCYIWRSHRNDZW62MPGVU2G");
|
||||||
}
|
}
|
||||||
|
|
||||||
const CipherData = [
|
const CipherData = [
|
||||||
{
|
{
|
||||||
title: 'should parse expiration date',
|
title: "should parse expiration date",
|
||||||
csv: `url,username,password,extra,name,grouping,fav
|
csv: `url,username,password,extra,name,grouping,fav
|
||||||
http://sn,,,"NoteType:Credit Card
|
http://sn,,,"NoteType:Credit Card
|
||||||
Name on Card:John Doe
|
Name on Card:John Doe
|
||||||
@@ -41,27 +41,27 @@ Notes:some text
|
|||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'Credit-card',
|
name: "Credit-card",
|
||||||
notes: 'some text\n',
|
notes: "some text\n",
|
||||||
type: 3,
|
type: 3,
|
||||||
card: {
|
card: {
|
||||||
cardholderName: 'John Doe',
|
cardholderName: "John Doe",
|
||||||
number: '1234567812345678',
|
number: "1234567812345678",
|
||||||
code: '123',
|
code: "123",
|
||||||
expYear: '2020',
|
expYear: "2020",
|
||||||
expMonth: '6',
|
expMonth: "6",
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Start Date',
|
name: "Start Date",
|
||||||
value: 'October,2017',
|
value: "October,2017",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'should parse blank card note',
|
title: "should parse blank card note",
|
||||||
csv: `url,username,password,extra,name,grouping,fav
|
csv: `url,username,password,extra,name,grouping,fav
|
||||||
http://sn,,,"NoteType:Credit Card
|
http://sn,,,"NoteType:Credit Card
|
||||||
Name on Card:
|
Name on Card:
|
||||||
@@ -75,7 +75,7 @@ Notes:",empty,,0`,
|
|||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'empty',
|
name: "empty",
|
||||||
notes: null,
|
notes: null,
|
||||||
type: 3,
|
type: 3,
|
||||||
card: {
|
card: {
|
||||||
@@ -83,15 +83,15 @@ Notes:",empty,,0`,
|
|||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Start Date',
|
name: "Start Date",
|
||||||
value: ',',
|
value: ",",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'should parse card expiration date w/ no exp year',
|
title: "should parse card expiration date w/ no exp year",
|
||||||
csv: `url,username,password,extra,name,grouping,fav
|
csv: `url,username,password,extra,name,grouping,fav
|
||||||
http://sn,,,"NoteType:Credit Card
|
http://sn,,,"NoteType:Credit Card
|
||||||
Name on Card:John Doe
|
Name on Card:John Doe
|
||||||
@@ -105,31 +105,31 @@ Notes:",noyear,,0`,
|
|||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'noyear',
|
name: "noyear",
|
||||||
notes: null,
|
notes: null,
|
||||||
type: 3,
|
type: 3,
|
||||||
card: {
|
card: {
|
||||||
cardholderName: 'John Doe',
|
cardholderName: "John Doe",
|
||||||
number: '1234567887654321',
|
number: "1234567887654321",
|
||||||
code: '321',
|
code: "321",
|
||||||
expMonth: '1',
|
expMonth: "1",
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Type',
|
name: "Type",
|
||||||
value: 'Visa',
|
value: "Visa",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Start Date',
|
name: "Start Date",
|
||||||
value: ',',
|
value: ",",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'should parse card expiration date w/ no month',
|
title: "should parse card expiration date w/ no month",
|
||||||
csv: `url,username,password,extra,name,grouping,fav
|
csv: `url,username,password,extra,name,grouping,fav
|
||||||
http://sn,,,"NoteType:Credit Card
|
http://sn,,,"NoteType:Credit Card
|
||||||
Name on Card:John Doe
|
Name on Card:John Doe
|
||||||
@@ -143,25 +143,25 @@ Notes:",nomonth,,0`,
|
|||||||
id: null,
|
id: null,
|
||||||
organizationId: null,
|
organizationId: null,
|
||||||
folderId: null,
|
folderId: null,
|
||||||
name: 'nomonth',
|
name: "nomonth",
|
||||||
notes: null,
|
notes: null,
|
||||||
type: 3,
|
type: 3,
|
||||||
card: {
|
card: {
|
||||||
cardholderName: 'John Doe',
|
cardholderName: "John Doe",
|
||||||
number: '8765432112345678',
|
number: "8765432112345678",
|
||||||
code: '987',
|
code: "987",
|
||||||
expYear: '2020',
|
expYear: "2020",
|
||||||
expMonth: undefined,
|
expMonth: undefined,
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Type',
|
name: "Type",
|
||||||
value: 'Mastercard',
|
value: "Mastercard",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
name: 'Start Date',
|
name: "Start Date",
|
||||||
value: ',',
|
value: ",",
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -169,8 +169,8 @@ Notes:",nomonth,,0`,
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
describe('Lastpass CSV Importer', () => {
|
describe("Lastpass CSV Importer", () => {
|
||||||
CipherData.forEach(data => {
|
CipherData.forEach((data) => {
|
||||||
it(data.title, async () => {
|
it(data.title, async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(data.csv);
|
const result = await importer.parse(data.csv);
|
||||||
@@ -188,7 +188,7 @@ describe('Lastpass CSV Importer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse login with totp', async () => {
|
it("should parse login with totp", async () => {
|
||||||
const input = `url,username,password,totp,extra,name,grouping,fav
|
const input = `url,username,password,totp,extra,name,grouping,fav
|
||||||
http://example.com,someUser,myPassword,Y64VEVMBTSXCYIWRSHRNDZW62MPGVU2G,super secure notes,example.com,,0`;
|
http://example.com,someUser,myPassword,Y64VEVMBTSXCYIWRSHRNDZW62MPGVU2G,super secure notes,example.com,,0`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,121 +1,120 @@
|
|||||||
import { NordPassCsvImporter as Importer } from 'src/importers/nordpassCsvImporter';
|
import { NordPassCsvImporter as Importer } from "src/importers/nordpassCsvImporter";
|
||||||
|
|
||||||
import { CipherType } from 'src/enums/cipherType';
|
import { CipherType } from "src/enums/cipherType";
|
||||||
import { SecureNoteType } from 'src/enums/secureNoteType';
|
import { SecureNoteType } from "src/enums/secureNoteType";
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
import { IdentityView } from 'src/models/view/identityView';
|
import { IdentityView } from "src/models/view/identityView";
|
||||||
|
|
||||||
import { data as creditCardData } from './testData/nordpassCsv/nordpass.card.csv';
|
import { data as creditCardData } from "./testData/nordpassCsv/nordpass.card.csv";
|
||||||
import { data as identityData } from './testData/nordpassCsv/nordpass.identity.csv';
|
import { data as identityData } from "./testData/nordpassCsv/nordpass.identity.csv";
|
||||||
import { data as loginData } from './testData/nordpassCsv/nordpass.login.csv';
|
import { data as loginData } from "./testData/nordpassCsv/nordpass.login.csv";
|
||||||
import { data as secureNoteData } from './testData/nordpassCsv/nordpass.secureNote.csv';
|
import { data as secureNoteData } from "./testData/nordpassCsv/nordpass.secureNote.csv";
|
||||||
|
|
||||||
const namesTestData = [
|
const namesTestData = [
|
||||||
{
|
{
|
||||||
title: 'Given #fullName should set firstName',
|
title: "Given #fullName should set firstName",
|
||||||
fullName: 'MyFirstName',
|
fullName: "MyFirstName",
|
||||||
expected: Object.assign(new IdentityView(), {
|
expected: Object.assign(new IdentityView(), {
|
||||||
firstName: 'MyFirstName',
|
firstName: "MyFirstName",
|
||||||
middleName: null,
|
middleName: null,
|
||||||
lastName: null,
|
lastName: null,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Given #fullName should set first- and lastName',
|
title: "Given #fullName should set first- and lastName",
|
||||||
fullName: 'MyFirstName MyLastName',
|
fullName: "MyFirstName MyLastName",
|
||||||
expected: Object.assign(new IdentityView(), {
|
expected: Object.assign(new IdentityView(), {
|
||||||
firstName: 'MyFirstName',
|
firstName: "MyFirstName",
|
||||||
middleName: null,
|
middleName: null,
|
||||||
lastName: 'MyLastName',
|
lastName: "MyLastName",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Given #fullName should set first-, middle and lastName',
|
title: "Given #fullName should set first-, middle and lastName",
|
||||||
fullName: 'MyFirstName MyMiddleName MyLastName',
|
fullName: "MyFirstName MyMiddleName MyLastName",
|
||||||
expected: Object.assign(new IdentityView(), {
|
expected: Object.assign(new IdentityView(), {
|
||||||
firstName: 'MyFirstName',
|
firstName: "MyFirstName",
|
||||||
middleName: 'MyMiddleName',
|
middleName: "MyMiddleName",
|
||||||
lastName: 'MyLastName',
|
lastName: "MyLastName",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Given #fullName should set first-, middle and lastName with Jr',
|
title: "Given #fullName should set first-, middle and lastName with Jr",
|
||||||
fullName: 'MyFirstName MyMiddleName MyLastName Jr',
|
fullName: "MyFirstName MyMiddleName MyLastName Jr",
|
||||||
expected: Object.assign(new IdentityView(), {
|
expected: Object.assign(new IdentityView(), {
|
||||||
firstName: 'MyFirstName',
|
firstName: "MyFirstName",
|
||||||
middleName: 'MyMiddleName',
|
middleName: "MyMiddleName",
|
||||||
lastName: 'MyLastName Jr',
|
lastName: "MyLastName Jr",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Given #fullName should set first-, middle and lastName with Jr and III',
|
title: "Given #fullName should set first-, middle and lastName with Jr and III",
|
||||||
fullName: 'MyFirstName MyMiddleName MyLastName Jr III',
|
fullName: "MyFirstName MyMiddleName MyLastName Jr III",
|
||||||
expected: Object.assign(new IdentityView(), {
|
expected: Object.assign(new IdentityView(), {
|
||||||
firstName: 'MyFirstName',
|
firstName: "MyFirstName",
|
||||||
middleName: 'MyMiddleName',
|
middleName: "MyMiddleName",
|
||||||
lastName: 'MyLastName Jr III',
|
lastName: "MyLastName Jr III",
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
function expectLogin(cipher: CipherView) {
|
function expectLogin(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Login);
|
expect(cipher.type).toBe(CipherType.Login);
|
||||||
|
|
||||||
expect(cipher.name).toBe('SomeVaultItemName');
|
expect(cipher.name).toBe("SomeVaultItemName");
|
||||||
expect(cipher.notes).toBe('Some note for the VaultItem');
|
expect(cipher.notes).toBe("Some note for the VaultItem");
|
||||||
expect(cipher.login.uri).toBe('https://example.com');
|
expect(cipher.login.uri).toBe("https://example.com");
|
||||||
expect(cipher.login.username).toBe('hello@bitwarden.com');
|
expect(cipher.login.username).toBe("hello@bitwarden.com");
|
||||||
expect(cipher.login.password).toBe('someStrongPassword');
|
expect(cipher.login.password).toBe("someStrongPassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectCreditCard(cipher: CipherView) {
|
function expectCreditCard(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Card);
|
expect(cipher.type).toBe(CipherType.Card);
|
||||||
|
|
||||||
expect(cipher.name).toBe('SomeVisa');
|
expect(cipher.name).toBe("SomeVisa");
|
||||||
expect(cipher.card.brand).toBe('Visa');
|
expect(cipher.card.brand).toBe("Visa");
|
||||||
expect(cipher.card.cardholderName).toBe('SomeHolder');
|
expect(cipher.card.cardholderName).toBe("SomeHolder");
|
||||||
expect(cipher.card.number).toBe('4024007103939509');
|
expect(cipher.card.number).toBe("4024007103939509");
|
||||||
expect(cipher.card.code).toBe('123');
|
expect(cipher.card.code).toBe("123");
|
||||||
expect(cipher.card.expMonth).toBe('1');
|
expect(cipher.card.expMonth).toBe("1");
|
||||||
expect(cipher.card.expYear).toBe('22');
|
expect(cipher.card.expYear).toBe("22");
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectIdentity(cipher: CipherView) {
|
function expectIdentity(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Identity);
|
expect(cipher.type).toBe(CipherType.Identity);
|
||||||
|
|
||||||
expect(cipher.name).toBe('SomeTitle');
|
expect(cipher.name).toBe("SomeTitle");
|
||||||
expect(cipher.identity.fullName).toBe('MyFirstName MyMiddleName MyLastName');
|
expect(cipher.identity.fullName).toBe("MyFirstName MyMiddleName MyLastName");
|
||||||
expect(cipher.identity.firstName).toBe('MyFirstName');
|
expect(cipher.identity.firstName).toBe("MyFirstName");
|
||||||
expect(cipher.identity.middleName).toBe('MyMiddleName');
|
expect(cipher.identity.middleName).toBe("MyMiddleName");
|
||||||
expect(cipher.identity.lastName).toBe('MyLastName');
|
expect(cipher.identity.lastName).toBe("MyLastName");
|
||||||
expect(cipher.identity.email).toBe('hello@bitwarden.com');
|
expect(cipher.identity.email).toBe("hello@bitwarden.com");
|
||||||
expect(cipher.identity.phone).toBe('123456789');
|
expect(cipher.identity.phone).toBe("123456789");
|
||||||
|
|
||||||
expect(cipher.identity.address1).toBe('Test street 123');
|
expect(cipher.identity.address1).toBe("Test street 123");
|
||||||
expect(cipher.identity.address2).toBe('additional addressinfo');
|
expect(cipher.identity.address2).toBe("additional addressinfo");
|
||||||
expect(cipher.identity.postalCode).toBe('123456');
|
expect(cipher.identity.postalCode).toBe("123456");
|
||||||
expect(cipher.identity.city).toBe('Cologne');
|
expect(cipher.identity.city).toBe("Cologne");
|
||||||
expect(cipher.identity.state).toBe('North-Rhine-Westphalia');
|
expect(cipher.identity.state).toBe("North-Rhine-Westphalia");
|
||||||
expect(cipher.identity.country).toBe('GERMANY');
|
expect(cipher.identity.country).toBe("GERMANY");
|
||||||
expect(cipher.notes).toBe('SomeNoteToMyIdentity');
|
expect(cipher.notes).toBe("SomeNoteToMyIdentity");
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectSecureNote(cipher: CipherView) {
|
function expectSecureNote(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.SecureNote);
|
expect(cipher.type).toBe(CipherType.SecureNote);
|
||||||
|
|
||||||
expect(cipher.name).toBe('MySuperSecureNoteTitle');
|
expect(cipher.name).toBe("MySuperSecureNoteTitle");
|
||||||
expect(cipher.secureNote.type).toBe(SecureNoteType.Generic);
|
expect(cipher.secureNote.type).toBe(SecureNoteType.Generic);
|
||||||
expect(cipher.notes).toBe('MySuperSecureNote');
|
expect(cipher.notes).toBe("MySuperSecureNote");
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('NordPass CSV Importer', () => {
|
describe("NordPass CSV Importer", () => {
|
||||||
let importer: Importer;
|
let importer: Importer;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
importer = new Importer();
|
importer = new Importer();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse login records', async () => {
|
it("should parse login records", async () => {
|
||||||
const result = await importer.parse(loginData);
|
const result = await importer.parse(loginData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -125,7 +124,7 @@ describe('NordPass CSV Importer', () => {
|
|||||||
expectLogin(cipher);
|
expectLogin(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse credit card records', async () => {
|
it("should parse credit card records", async () => {
|
||||||
const result = await importer.parse(creditCardData);
|
const result = await importer.parse(creditCardData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -135,8 +134,10 @@ describe('NordPass CSV Importer', () => {
|
|||||||
expectCreditCard(cipher);
|
expectCreditCard(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse identity records', async () => {
|
it("should parse identity records", async () => {
|
||||||
const result = await importer.parse(identityData.replace('#fullName', 'MyFirstName MyMiddleName MyLastName'));
|
const result = await importer.parse(
|
||||||
|
identityData.replace("#fullName", "MyFirstName MyMiddleName MyLastName")
|
||||||
|
);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
@@ -145,9 +146,9 @@ describe('NordPass CSV Importer', () => {
|
|||||||
expectIdentity(cipher);
|
expectIdentity(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
namesTestData.forEach(data => {
|
namesTestData.forEach((data) => {
|
||||||
it(data.title.replace('#fullName', data.fullName), async () => {
|
it(data.title.replace("#fullName", data.fullName), async () => {
|
||||||
const result = await importer.parse(identityData.replace('#fullName', data.fullName));
|
const result = await importer.parse(identityData.replace("#fullName", data.fullName));
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
@@ -159,7 +160,7 @@ describe('NordPass CSV Importer', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse secureNote records', async () => {
|
it("should parse secureNote records", async () => {
|
||||||
const result = await importer.parse(secureNoteData);
|
const result = await importer.parse(secureNoteData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -169,13 +170,13 @@ describe('NordPass CSV Importer', () => {
|
|||||||
expectSecureNote(cipher);
|
expectSecureNote(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse an item and create a folder', async () => {
|
it("should parse an item and create a folder", async () => {
|
||||||
const result = await importer.parse(secureNoteData);
|
const result = await importer.parse(secureNoteData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
expect(result.success).toBe(true);
|
expect(result.success).toBe(true);
|
||||||
expect(result.folders.length).toBe(1);
|
expect(result.folders.length).toBe(1);
|
||||||
const folder = result.folders[0];
|
const folder = result.folders[0];
|
||||||
expect(folder.name).toBe('notesFolder');
|
expect(folder.name).toBe("notesFolder");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,142 +1,143 @@
|
|||||||
import { FieldType } from 'src/enums/fieldType';
|
import { FieldType } from "src/enums/fieldType";
|
||||||
import { OnePassword1PifImporter as Importer } from 'src/importers/onepasswordImporters/onepassword1PifImporter';
|
import { OnePassword1PifImporter as Importer } from "src/importers/onepasswordImporters/onepassword1PifImporter";
|
||||||
|
|
||||||
const TestData: string = '***aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee***\n' +
|
const TestData: string =
|
||||||
|
"***aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee***\n" +
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
uuid: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||||
updatedAt: 1486071244,
|
updatedAt: 1486071244,
|
||||||
securityLevel: 'SL5',
|
securityLevel: "SL5",
|
||||||
contentsHash: 'aaaaaaaa',
|
contentsHash: "aaaaaaaa",
|
||||||
title: 'Imported Entry',
|
title: "Imported Entry",
|
||||||
location: 'https://www.google.com',
|
location: "https://www.google.com",
|
||||||
secureContents: {
|
secureContents: {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
value: 'user@test.net',
|
value: "user@test.net",
|
||||||
id: 'email-input',
|
id: "email-input",
|
||||||
name: 'email',
|
name: "email",
|
||||||
type: 'T',
|
type: "T",
|
||||||
designation: 'username',
|
designation: "username",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'myservicepassword',
|
value: "myservicepassword",
|
||||||
id: 'password-input',
|
id: "password-input",
|
||||||
name: 'password',
|
name: "password",
|
||||||
type: 'P',
|
type: "P",
|
||||||
designation: 'password',
|
designation: "password",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
k: 'concealed',
|
k: "concealed",
|
||||||
n: 'AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC',
|
n: "AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC",
|
||||||
v: 'console-password-123',
|
v: "console-password-123",
|
||||||
t: 'console password',
|
t: "console password",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
title: 'Admin Console',
|
title: "Admin Console",
|
||||||
name: 'admin_console',
|
name: "admin_console",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
passwordHistory: [
|
passwordHistory: [
|
||||||
{
|
{
|
||||||
value: 'old-password',
|
value: "old-password",
|
||||||
time: 1447791421,
|
time: 1447791421,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
URLs: [
|
URLs: [
|
||||||
{
|
{
|
||||||
label: 'website',
|
label: "website",
|
||||||
url: 'https://www.google.com',
|
url: "https://www.google.com",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
txTimestamp: 1508941334,
|
txTimestamp: 1508941334,
|
||||||
createdAt: 1390426636,
|
createdAt: 1390426636,
|
||||||
typeName: 'webforms.WebForm',
|
typeName: "webforms.WebForm",
|
||||||
});
|
});
|
||||||
|
|
||||||
const WindowsOpVaultTestData = JSON.stringify({
|
const WindowsOpVaultTestData = JSON.stringify({
|
||||||
category: '001',
|
category: "001",
|
||||||
created: 1544823719,
|
created: 1544823719,
|
||||||
hmac: 'NtyBmTTPOb88HV3JUKPx1xl/vcMhac9kvCfe/NtszY0=',
|
hmac: "NtyBmTTPOb88HV3JUKPx1xl/vcMhac9kvCfe/NtszY0=",
|
||||||
k: '**REMOVED LONG LINE FOR LINTER** -Kyle',
|
k: "**REMOVED LONG LINE FOR LINTER** -Kyle",
|
||||||
tx: 1553395669,
|
tx: 1553395669,
|
||||||
updated: 1553395669,
|
updated: 1553395669,
|
||||||
uuid: '528AB076FB5F4FBF960884B8E01619AC',
|
uuid: "528AB076FB5F4FBF960884B8E01619AC",
|
||||||
overview: {
|
overview: {
|
||||||
title: 'Google',
|
title: "Google",
|
||||||
URLs: [
|
URLs: [
|
||||||
{
|
{
|
||||||
u: 'google.com',
|
u: "google.com",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
url: 'google.com',
|
url: "google.com",
|
||||||
ps: 26,
|
ps: 26,
|
||||||
ainfo: 'googluser',
|
ainfo: "googluser",
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
passwordHistory: [
|
passwordHistory: [
|
||||||
{
|
{
|
||||||
value: 'oldpass1',
|
value: "oldpass1",
|
||||||
time: 1553394449,
|
time: 1553394449,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'oldpass2',
|
value: "oldpass2",
|
||||||
time: 1553394457,
|
time: 1553394457,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'oldpass3',
|
value: "oldpass3",
|
||||||
time: 1553394458,
|
time: 1553394458,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'oldpass4',
|
value: "oldpass4",
|
||||||
time: 1553394459,
|
time: 1553394459,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'oldpass5',
|
value: "oldpass5",
|
||||||
time: 1553394460,
|
time: 1553394460,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'oldpass6',
|
value: "oldpass6",
|
||||||
time: 1553394461,
|
time: 1553394461,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: 'T',
|
type: "T",
|
||||||
id: 'username',
|
id: "username",
|
||||||
name: 'username',
|
name: "username",
|
||||||
value: 'googluser',
|
value: "googluser",
|
||||||
designation: 'username',
|
designation: "username",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'P',
|
type: "P",
|
||||||
id: 'password',
|
id: "password",
|
||||||
name: 'password',
|
name: "password",
|
||||||
value: '12345678901',
|
value: "12345678901",
|
||||||
designation: 'password',
|
designation: "password",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
notesPlain: 'This is a note\r\n\r\nline1\r\nline2',
|
notesPlain: "This is a note\r\n\r\nline1\r\nline2",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
title: 'test',
|
title: "test",
|
||||||
name: '1214FD88CD30405D9EED14BEB4D61B60',
|
name: "1214FD88CD30405D9EED14BEB4D61B60",
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: '6CC3BD77482D4559A4B8BB2D360F821B',
|
n: "6CC3BD77482D4559A4B8BB2D360F821B",
|
||||||
v: 'fgfg',
|
v: "fgfg",
|
||||||
t: 'fgggf',
|
t: "fgggf",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'concealed',
|
k: "concealed",
|
||||||
n: '5CFE7BCAA1DF4578BBF7EB508959BFF3',
|
n: "5CFE7BCAA1DF4578BBF7EB508959BFF3",
|
||||||
v: 'dfgdfgfdg',
|
v: "dfgdfgfdg",
|
||||||
t: 'pwfield',
|
t: "pwfield",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -145,295 +146,295 @@ const WindowsOpVaultTestData = JSON.stringify({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const IdentityTestData = JSON.stringify({
|
const IdentityTestData = JSON.stringify({
|
||||||
uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
|
uuid: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||||
updatedAt: 1553365894,
|
updatedAt: 1553365894,
|
||||||
securityLevel: 'SL5',
|
securityLevel: "SL5",
|
||||||
contentsHash: 'eeeeeeee',
|
contentsHash: "eeeeeeee",
|
||||||
title: 'Test Identity',
|
title: "Test Identity",
|
||||||
secureContents: {
|
secureContents: {
|
||||||
lastname: 'Fritzenberger',
|
lastname: "Fritzenberger",
|
||||||
zip: '223344',
|
zip: "223344",
|
||||||
birthdate_dd: '11',
|
birthdate_dd: "11",
|
||||||
homephone: '+49 333 222 111',
|
homephone: "+49 333 222 111",
|
||||||
company: 'Web Inc.',
|
company: "Web Inc.",
|
||||||
firstname: 'Frank',
|
firstname: "Frank",
|
||||||
birthdate_mm: '3',
|
birthdate_mm: "3",
|
||||||
country: 'de',
|
country: "de",
|
||||||
sex: 'male',
|
sex: "male",
|
||||||
sections: [
|
sections: [
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'firstname',
|
n: "firstname",
|
||||||
v: 'Frank',
|
v: "Frank",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'first name',
|
t: "first name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'initial',
|
n: "initial",
|
||||||
v: 'MD',
|
v: "MD",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'initial',
|
t: "initial",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'lastname',
|
n: "lastname",
|
||||||
v: 'Fritzenberger',
|
v: "Fritzenberger",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'last name',
|
t: "last name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'menu',
|
k: "menu",
|
||||||
v: 'male',
|
v: "male",
|
||||||
n: 'sex',
|
n: "sex",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'sex',
|
t: "sex",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'date',
|
k: "date",
|
||||||
v: 1552305660,
|
v: 1552305660,
|
||||||
n: 'birthdate',
|
n: "birthdate",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'birth date',
|
t: "birth date",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'occupation',
|
n: "occupation",
|
||||||
v: 'Engineer',
|
v: "Engineer",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'occupation',
|
t: "occupation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'company',
|
n: "company",
|
||||||
v: 'Web Inc.',
|
v: "Web Inc.",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'company',
|
t: "company",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'department',
|
n: "department",
|
||||||
v: 'IT',
|
v: "IT",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'department',
|
t: "department",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Words',
|
autocapitalization: "Words",
|
||||||
},
|
},
|
||||||
n: 'jobtitle',
|
n: "jobtitle",
|
||||||
v: 'Developer',
|
v: "Developer",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'job title',
|
t: "job title",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
title: 'Identification',
|
title: "Identification",
|
||||||
name: 'name',
|
name: "name",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
k: 'address',
|
k: "address",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
autocapitalization: 'Sentences',
|
autocapitalization: "Sentences",
|
||||||
},
|
},
|
||||||
n: 'address',
|
n: "address",
|
||||||
v: {
|
v: {
|
||||||
street: 'Mainstreet 1',
|
street: "Mainstreet 1",
|
||||||
city: 'Berlin',
|
city: "Berlin",
|
||||||
country: 'de',
|
country: "de",
|
||||||
zip: '223344',
|
zip: "223344",
|
||||||
},
|
},
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'address',
|
t: "address",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'phone',
|
k: "phone",
|
||||||
v: '+49 001 222 333 44',
|
v: "+49 001 222 333 44",
|
||||||
n: 'defphone',
|
n: "defphone",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'default phone',
|
t: "default phone",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'phone',
|
k: "phone",
|
||||||
v: '+49 333 222 111',
|
v: "+49 333 222 111",
|
||||||
n: 'homephone',
|
n: "homephone",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'home',
|
t: "home",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'phone',
|
k: "phone",
|
||||||
n: 'cellphone',
|
n: "cellphone",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'mobile',
|
t: "mobile",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'phone',
|
k: "phone",
|
||||||
n: 'busphone',
|
n: "busphone",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'business',
|
t: "business",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
title: 'Address',
|
title: "Address",
|
||||||
name: 'address',
|
name: "address",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'username',
|
n: "username",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'username',
|
t: "username",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'reminderq',
|
n: "reminderq",
|
||||||
t: 'reminder question',
|
t: "reminder question",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'remindera',
|
n: "remindera",
|
||||||
t: 'reminder answer',
|
t: "reminder answer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
keyboard: 'EmailAddress',
|
keyboard: "EmailAddress",
|
||||||
},
|
},
|
||||||
n: 'email',
|
n: "email",
|
||||||
v: 'test@web.de',
|
v: "test@web.de",
|
||||||
a: {
|
a: {
|
||||||
guarded: 'yes',
|
guarded: "yes",
|
||||||
},
|
},
|
||||||
t: 'email',
|
t: "email",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'website',
|
n: "website",
|
||||||
inputTraits: {
|
inputTraits: {
|
||||||
keyboard: 'URL',
|
keyboard: "URL",
|
||||||
},
|
},
|
||||||
t: 'website',
|
t: "website",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'icq',
|
n: "icq",
|
||||||
t: 'ICQ',
|
t: "ICQ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'skype',
|
n: "skype",
|
||||||
t: 'skype',
|
t: "skype",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'aim',
|
n: "aim",
|
||||||
t: 'AOL/AIM',
|
t: "AOL/AIM",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'yahoo',
|
n: "yahoo",
|
||||||
t: 'Yahoo',
|
t: "Yahoo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'msn',
|
n: "msn",
|
||||||
t: 'MSN',
|
t: "MSN",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
k: 'string',
|
k: "string",
|
||||||
n: 'forumsig',
|
n: "forumsig",
|
||||||
t: 'forum signature',
|
t: "forum signature",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
title: 'Internet Details',
|
title: "Internet Details",
|
||||||
name: 'internet',
|
name: "internet",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Related Items',
|
title: "Related Items",
|
||||||
name: 'linked items',
|
name: "linked items",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
initial: 'MD',
|
initial: "MD",
|
||||||
address1: 'Mainstreet 1',
|
address1: "Mainstreet 1",
|
||||||
city: 'Berlin',
|
city: "Berlin",
|
||||||
jobtitle: 'Developer',
|
jobtitle: "Developer",
|
||||||
occupation: 'Engineer',
|
occupation: "Engineer",
|
||||||
department: 'IT',
|
department: "IT",
|
||||||
email: 'test@web.de',
|
email: "test@web.de",
|
||||||
birthdate_yy: '2019',
|
birthdate_yy: "2019",
|
||||||
homephone_local: '+49 333 222 111',
|
homephone_local: "+49 333 222 111",
|
||||||
defphone_local: '+49 001 222 333 44',
|
defphone_local: "+49 001 222 333 44",
|
||||||
defphone: '+49 001 222 333 44',
|
defphone: "+49 001 222 333 44",
|
||||||
},
|
},
|
||||||
txTimestamp: 1553365894,
|
txTimestamp: 1553365894,
|
||||||
createdAt: 1553364679,
|
createdAt: 1553364679,
|
||||||
typeName: 'identities.Identity',
|
typeName: "identities.Identity",
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('1Password 1Pif Importer', () => {
|
describe("1Password 1Pif Importer", () => {
|
||||||
it('should parse data', async () => {
|
it("should parse data", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(TestData);
|
const result = await importer.parse(TestData);
|
||||||
expect(result != null).toBe(true);
|
expect(result != null).toBe(true);
|
||||||
|
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
expect(cipher.login.username).toEqual('user@test.net');
|
expect(cipher.login.username).toEqual("user@test.net");
|
||||||
expect(cipher.login.password).toEqual('myservicepassword');
|
expect(cipher.login.password).toEqual("myservicepassword");
|
||||||
expect(cipher.login.uris.length).toEqual(1);
|
expect(cipher.login.uris.length).toEqual(1);
|
||||||
const uriView = cipher.login.uris.shift();
|
const uriView = cipher.login.uris.shift();
|
||||||
expect(uriView.uri).toEqual('https://www.google.com');
|
expect(uriView.uri).toEqual("https://www.google.com");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create concealed field as "hidden" type', async () => {
|
it('should create concealed field as "hidden" type', async () => {
|
||||||
@@ -449,65 +450,65 @@ describe('1Password 1Pif Importer', () => {
|
|||||||
expect(fields.length).toEqual(1);
|
expect(fields.length).toEqual(1);
|
||||||
|
|
||||||
const field = fields.shift();
|
const field = fields.shift();
|
||||||
expect(field.name).toEqual('console password');
|
expect(field.name).toEqual("console password");
|
||||||
expect(field.value).toEqual('console-password-123');
|
expect(field.value).toEqual("console-password-123");
|
||||||
expect(field.type).toEqual(FieldType.Hidden);
|
expect(field.type).toEqual(FieldType.Hidden);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create identity records', async () => {
|
it("should create identity records", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(IdentityTestData);
|
const result = await importer.parse(IdentityTestData);
|
||||||
expect(result != null).toBe(true);
|
expect(result != null).toBe(true);
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
expect(cipher.name).toEqual('Test Identity');
|
expect(cipher.name).toEqual("Test Identity");
|
||||||
|
|
||||||
const identity = cipher.identity;
|
const identity = cipher.identity;
|
||||||
expect(identity.firstName).toEqual('Frank');
|
expect(identity.firstName).toEqual("Frank");
|
||||||
expect(identity.middleName).toEqual('MD');
|
expect(identity.middleName).toEqual("MD");
|
||||||
expect(identity.lastName).toEqual('Fritzenberger');
|
expect(identity.lastName).toEqual("Fritzenberger");
|
||||||
expect(identity.company).toEqual('Web Inc.');
|
expect(identity.company).toEqual("Web Inc.");
|
||||||
expect(identity.address1).toEqual('Mainstreet 1');
|
expect(identity.address1).toEqual("Mainstreet 1");
|
||||||
expect(identity.country).toEqual('DE');
|
expect(identity.country).toEqual("DE");
|
||||||
expect(identity.city).toEqual('Berlin');
|
expect(identity.city).toEqual("Berlin");
|
||||||
expect(identity.postalCode).toEqual('223344');
|
expect(identity.postalCode).toEqual("223344");
|
||||||
expect(identity.phone).toEqual('+49 001 222 333 44');
|
expect(identity.phone).toEqual("+49 001 222 333 44");
|
||||||
expect(identity.email).toEqual('test@web.de');
|
expect(identity.email).toEqual("test@web.de");
|
||||||
|
|
||||||
// remaining fields as custom fields
|
// remaining fields as custom fields
|
||||||
expect(cipher.fields.length).toEqual(6);
|
expect(cipher.fields.length).toEqual(6);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create password history', async () => {
|
it("should create password history", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(TestData);
|
const result = await importer.parse(TestData);
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
|
|
||||||
expect(cipher.passwordHistory.length).toEqual(1);
|
expect(cipher.passwordHistory.length).toEqual(1);
|
||||||
const ph = cipher.passwordHistory.shift();
|
const ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('old-password');
|
expect(ph.password).toEqual("old-password");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2015-11-17T20:17:01.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2015-11-17T20:17:01.000Z");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create password history from windows opvault 1pif format', async () => {
|
it("should create password history from windows opvault 1pif format", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(WindowsOpVaultTestData);
|
const result = await importer.parse(WindowsOpVaultTestData);
|
||||||
const cipher = result.ciphers.shift();
|
const cipher = result.ciphers.shift();
|
||||||
|
|
||||||
expect(cipher.passwordHistory.length).toEqual(5);
|
expect(cipher.passwordHistory.length).toEqual(5);
|
||||||
let ph = cipher.passwordHistory.shift();
|
let ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('oldpass6');
|
expect(ph.password).toEqual("oldpass6");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:41.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2019-03-24T02:27:41.000Z");
|
||||||
ph = cipher.passwordHistory.shift();
|
ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('oldpass5');
|
expect(ph.password).toEqual("oldpass5");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:40.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2019-03-24T02:27:40.000Z");
|
||||||
ph = cipher.passwordHistory.shift();
|
ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('oldpass4');
|
expect(ph.password).toEqual("oldpass4");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:39.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2019-03-24T02:27:39.000Z");
|
||||||
ph = cipher.passwordHistory.shift();
|
ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('oldpass3');
|
expect(ph.password).toEqual("oldpass3");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:38.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2019-03-24T02:27:38.000Z");
|
||||||
ph = cipher.passwordHistory.shift();
|
ph = cipher.passwordHistory.shift();
|
||||||
expect(ph.password).toEqual('oldpass2');
|
expect(ph.password).toEqual("oldpass2");
|
||||||
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:37.000Z');
|
expect(ph.lastUsedDate.toISOString()).toEqual("2019-03-24T02:27:37.000Z");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,42 +1,46 @@
|
|||||||
import { OnePasswordMacCsvImporter as Importer } from 'src/importers/onepasswordImporters/onepasswordMacCsvImporter';
|
import { OnePasswordMacCsvImporter as Importer } from "src/importers/onepasswordImporters/onepasswordMacCsvImporter";
|
||||||
|
|
||||||
import { CipherType } from 'src/enums/cipherType';
|
import { CipherType } from "src/enums/cipherType";
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
|
|
||||||
import { data as creditCardData } from './testData/onePasswordCsv/creditCard.mac.csv';
|
import { data as creditCardData } from "./testData/onePasswordCsv/creditCard.mac.csv";
|
||||||
import { data as identityData } from './testData/onePasswordCsv/identity.mac.csv';
|
import { data as identityData } from "./testData/onePasswordCsv/identity.mac.csv";
|
||||||
import { data as multiTypeData } from './testData/onePasswordCsv/multipleItems.mac.csv';
|
import { data as multiTypeData } from "./testData/onePasswordCsv/multipleItems.mac.csv";
|
||||||
|
|
||||||
function expectIdentity(cipher: CipherView) {
|
function expectIdentity(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Identity);
|
expect(cipher.type).toBe(CipherType.Identity);
|
||||||
|
|
||||||
expect(cipher.identity).toEqual(jasmine.objectContaining({
|
expect(cipher.identity).toEqual(
|
||||||
firstName: 'first name',
|
jasmine.objectContaining({
|
||||||
middleName: 'mi',
|
firstName: "first name",
|
||||||
lastName: 'last name',
|
middleName: "mi",
|
||||||
username: 'userNam3',
|
lastName: "last name",
|
||||||
company: 'bitwarden',
|
username: "userNam3",
|
||||||
phone: '8005555555',
|
company: "bitwarden",
|
||||||
email: 'email@bitwarden.com',
|
phone: "8005555555",
|
||||||
}));
|
email: "email@bitwarden.com",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
expect(cipher.notes).toContain('address\ncity state zip\nUnited States');
|
expect(cipher.notes).toContain("address\ncity state zip\nUnited States");
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectCreditCard(cipher: CipherView) {
|
function expectCreditCard(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Card);
|
expect(cipher.type).toBe(CipherType.Card);
|
||||||
|
|
||||||
expect(cipher.card).toEqual(jasmine.objectContaining({
|
expect(cipher.card).toEqual(
|
||||||
number: '4111111111111111',
|
jasmine.objectContaining({
|
||||||
code: '111',
|
number: "4111111111111111",
|
||||||
cardholderName: 'test',
|
code: "111",
|
||||||
expMonth: '1',
|
cardholderName: "test",
|
||||||
expYear: '2030',
|
expMonth: "1",
|
||||||
}));
|
expYear: "2030",
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('1Password mac CSV Importer', () => {
|
describe("1Password mac CSV Importer", () => {
|
||||||
it('should parse identity records', async () => {
|
it("should parse identity records", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(identityData);
|
const result = await importer.parse(identityData);
|
||||||
|
|
||||||
@@ -47,7 +51,7 @@ describe('1Password mac CSV Importer', () => {
|
|||||||
expectIdentity(cipher);
|
expectIdentity(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse credit card records', async () => {
|
it("should parse credit card records", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(creditCardData);
|
const result = await importer.parse(creditCardData);
|
||||||
|
|
||||||
@@ -58,7 +62,7 @@ describe('1Password mac CSV Importer', () => {
|
|||||||
expectCreditCard(cipher);
|
expectCreditCard(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse csv\'s with multiple record type', async () => {
|
it("should parse csv's with multiple record type", async () => {
|
||||||
const importer = new Importer();
|
const importer = new Importer();
|
||||||
const result = await importer.parse(multiTypeData);
|
const result = await importer.parse(multiTypeData);
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,61 @@
|
|||||||
import { OnePasswordWinCsvImporter as Importer } from 'src/importers/onepasswordImporters/onepasswordWinCsvImporter';
|
import { OnePasswordWinCsvImporter as Importer } from "src/importers/onepasswordImporters/onepasswordWinCsvImporter";
|
||||||
|
|
||||||
import { CipherType } from 'src/enums/cipherType';
|
import { CipherType } from "src/enums/cipherType";
|
||||||
import { FieldType } from 'src/enums/fieldType';
|
import { FieldType } from "src/enums/fieldType";
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
import { FieldView } from 'src/models/view/fieldView';
|
import { FieldView } from "src/models/view/fieldView";
|
||||||
|
|
||||||
import { data as creditCardData } from './testData/onePasswordCsv/creditCard.windows.csv';
|
import { data as creditCardData } from "./testData/onePasswordCsv/creditCard.windows.csv";
|
||||||
import { data as identityData } from './testData/onePasswordCsv/identity.windows.csv';
|
import { data as identityData } from "./testData/onePasswordCsv/identity.windows.csv";
|
||||||
import { data as multiTypeData } from './testData/onePasswordCsv/multipleItems.windows.csv';
|
import { data as multiTypeData } from "./testData/onePasswordCsv/multipleItems.windows.csv";
|
||||||
|
|
||||||
function expectIdentity(cipher: CipherView) {
|
function expectIdentity(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Identity);
|
expect(cipher.type).toBe(CipherType.Identity);
|
||||||
|
|
||||||
expect(cipher.identity).toEqual(jasmine.objectContaining({
|
expect(cipher.identity).toEqual(
|
||||||
firstName: 'first name',
|
jasmine.objectContaining({
|
||||||
middleName: 'mi',
|
firstName: "first name",
|
||||||
lastName: 'last name',
|
middleName: "mi",
|
||||||
username: 'userNam3',
|
lastName: "last name",
|
||||||
company: 'bitwarden',
|
username: "userNam3",
|
||||||
phone: '8005555555',
|
company: "bitwarden",
|
||||||
email: 'email@bitwarden.com',
|
phone: "8005555555",
|
||||||
}));
|
email: "email@bitwarden.com",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
expect(cipher.fields).toEqual(jasmine.arrayContaining([
|
expect(cipher.fields).toEqual(
|
||||||
|
jasmine.arrayContaining([
|
||||||
Object.assign(new FieldView(), {
|
Object.assign(new FieldView(), {
|
||||||
type: FieldType.Text,
|
type: FieldType.Text,
|
||||||
name: 'address',
|
name: "address",
|
||||||
value: 'address city state zip us',
|
value: "address city state zip us",
|
||||||
}),
|
}),
|
||||||
]));
|
])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectCreditCard(cipher: CipherView) {
|
function expectCreditCard(cipher: CipherView) {
|
||||||
expect(cipher.type).toBe(CipherType.Card);
|
expect(cipher.type).toBe(CipherType.Card);
|
||||||
|
|
||||||
expect(cipher.card).toEqual(jasmine.objectContaining({
|
expect(cipher.card).toEqual(
|
||||||
number: '4111111111111111',
|
jasmine.objectContaining({
|
||||||
code: '111',
|
number: "4111111111111111",
|
||||||
cardholderName: 'test',
|
code: "111",
|
||||||
expMonth: '1',
|
cardholderName: "test",
|
||||||
expYear: '1970',
|
expMonth: "1",
|
||||||
}));
|
expYear: "1970",
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('1Password windows CSV Importer', () => {
|
describe("1Password windows CSV Importer", () => {
|
||||||
let importer: Importer;
|
let importer: Importer;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
importer = new Importer();
|
importer = new Importer();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse identity records', async () => {
|
it("should parse identity records", async () => {
|
||||||
const result = await importer.parse(identityData);
|
const result = await importer.parse(identityData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -59,7 +65,7 @@ describe('1Password windows CSV Importer', () => {
|
|||||||
expectIdentity(cipher);
|
expectIdentity(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse credit card records', async () => {
|
it("should parse credit card records", async () => {
|
||||||
const result = await importer.parse(creditCardData);
|
const result = await importer.parse(creditCardData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
@@ -69,7 +75,7 @@ describe('1Password windows CSV Importer', () => {
|
|||||||
expectCreditCard(cipher);
|
expectCreditCard(cipher);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should parse csv\'s with multiple record types', async () => {
|
it("should parse csv's with multiple record types", async () => {
|
||||||
const result = await importer.parse(multiTypeData);
|
const result = await importer.parse(multiTypeData);
|
||||||
|
|
||||||
expect(result).not.toBeNull();
|
expect(result).not.toBeNull();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { sequentialize } from 'src/misc/sequentialize';
|
import { sequentialize } from "src/misc/sequentialize";
|
||||||
|
|
||||||
describe('sequentialize decorator', () => {
|
describe("sequentialize decorator", () => {
|
||||||
it('should call the function once', async () => {
|
it("should call the function once", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -12,7 +12,7 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(foo.calls).toBe(1);
|
expect(foo.calls).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function once for each instance of the object', async () => {
|
it("should call the function once for each instance of the object", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const foo2 = new Foo();
|
const foo2 = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@@ -26,7 +26,7 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(foo2.calls).toBe(1);
|
expect(foo2.calls).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function once with key function', async () => {
|
it("should call the function once with key function", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -37,7 +37,7 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(foo.calls).toBe(1);
|
expect(foo.calls).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function again when already resolved', async () => {
|
it("should call the function again when already resolved", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
await foo.bar(1);
|
await foo.bar(1);
|
||||||
expect(foo.calls).toBe(1);
|
expect(foo.calls).toBe(1);
|
||||||
@@ -45,7 +45,7 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(foo.calls).toBe(2);
|
expect(foo.calls).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function again when already resolved with a key function', async () => {
|
it("should call the function again when already resolved with a key function", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
await foo.baz(1);
|
await foo.baz(1);
|
||||||
expect(foo.calls).toBe(1);
|
expect(foo.calls).toBe(1);
|
||||||
@@ -53,43 +53,29 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(foo.calls).toBe(2);
|
expect(foo.calls).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function for each argument', async () => {
|
it("should call the function for each argument", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
await Promise.all([
|
await Promise.all([foo.bar(1), foo.bar(1), foo.bar(2), foo.bar(2), foo.bar(3), foo.bar(3)]);
|
||||||
foo.bar(1),
|
|
||||||
foo.bar(1),
|
|
||||||
foo.bar(2),
|
|
||||||
foo.bar(2),
|
|
||||||
foo.bar(3),
|
|
||||||
foo.bar(3),
|
|
||||||
]);
|
|
||||||
expect(foo.calls).toBe(3);
|
expect(foo.calls).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function for each argument with key function', async () => {
|
it("should call the function for each argument with key function", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
await Promise.all([
|
await Promise.all([foo.baz(1), foo.baz(1), foo.baz(2), foo.baz(2), foo.baz(3), foo.baz(3)]);
|
||||||
foo.baz(1),
|
|
||||||
foo.baz(1),
|
|
||||||
foo.baz(2),
|
|
||||||
foo.baz(2),
|
|
||||||
foo.baz(3),
|
|
||||||
foo.baz(3),
|
|
||||||
]);
|
|
||||||
expect(foo.calls).toBe(3);
|
expect(foo.calls).toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return correct result for each call', async () => {
|
it("should return correct result for each call", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const allRes: number[] = [];
|
const allRes: number[] = [];
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
foo.bar(1).then(res => allRes.push(res)),
|
foo.bar(1).then((res) => allRes.push(res)),
|
||||||
foo.bar(1).then(res => allRes.push(res)),
|
foo.bar(1).then((res) => allRes.push(res)),
|
||||||
foo.bar(2).then(res => allRes.push(res)),
|
foo.bar(2).then((res) => allRes.push(res)),
|
||||||
foo.bar(2).then(res => allRes.push(res)),
|
foo.bar(2).then((res) => allRes.push(res)),
|
||||||
foo.bar(3).then(res => allRes.push(res)),
|
foo.bar(3).then((res) => allRes.push(res)),
|
||||||
foo.bar(3).then(res => allRes.push(res)),
|
foo.bar(3).then((res) => allRes.push(res)),
|
||||||
]);
|
]);
|
||||||
expect(foo.calls).toBe(3);
|
expect(foo.calls).toBe(3);
|
||||||
expect(allRes.length).toBe(6);
|
expect(allRes.length).toBe(6);
|
||||||
@@ -97,17 +83,17 @@ describe('sequentialize decorator', () => {
|
|||||||
expect(allRes).toEqual([2, 2, 4, 4, 6, 6]);
|
expect(allRes).toEqual([2, 2, 4, 4, 6, 6]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return correct result for each call with key function', async () => {
|
it("should return correct result for each call with key function", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const allRes: number[] = [];
|
const allRes: number[] = [];
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
foo.baz(1).then(res => allRes.push(res)),
|
foo.baz(1).then((res) => allRes.push(res)),
|
||||||
foo.baz(1).then(res => allRes.push(res)),
|
foo.baz(1).then((res) => allRes.push(res)),
|
||||||
foo.baz(2).then(res => allRes.push(res)),
|
foo.baz(2).then((res) => allRes.push(res)),
|
||||||
foo.baz(2).then(res => allRes.push(res)),
|
foo.baz(2).then((res) => allRes.push(res)),
|
||||||
foo.baz(3).then(res => allRes.push(res)),
|
foo.baz(3).then((res) => allRes.push(res)),
|
||||||
foo.baz(3).then(res => allRes.push(res)),
|
foo.baz(3).then((res) => allRes.push(res)),
|
||||||
]);
|
]);
|
||||||
expect(foo.calls).toBe(3);
|
expect(foo.calls).toBe(3);
|
||||||
expect(allRes.length).toBe(6);
|
expect(allRes.length).toBe(6);
|
||||||
@@ -119,20 +105,20 @@ describe('sequentialize decorator', () => {
|
|||||||
class Foo {
|
class Foo {
|
||||||
calls = 0;
|
calls = 0;
|
||||||
|
|
||||||
@sequentialize(args => 'bar' + args[0])
|
@sequentialize((args) => "bar" + args[0])
|
||||||
bar(a: number): Promise<number> {
|
bar(a: number): Promise<number> {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
return new Promise(res => {
|
return new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
res(a * 2);
|
res(a * 2);
|
||||||
}, Math.random() * 100);
|
}, Math.random() * 100);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@sequentialize(args => 'baz' + args[0])
|
@sequentialize((args) => "baz" + args[0])
|
||||||
baz(a: number): Promise<number> {
|
baz(a: number): Promise<number> {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
return new Promise(res => {
|
return new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
res(a * 3);
|
res(a * 3);
|
||||||
}, Math.random() * 100);
|
}, Math.random() * 100);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { sequentialize } from 'src/misc/sequentialize';
|
import { sequentialize } from "src/misc/sequentialize";
|
||||||
import { throttle } from 'src/misc/throttle';
|
import { throttle } from "src/misc/throttle";
|
||||||
|
|
||||||
describe('throttle decorator', () => {
|
describe("throttle decorator", () => {
|
||||||
it('should call the function once at a time', async () => {
|
it("should call the function once at a time", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -13,7 +13,7 @@ describe('throttle decorator', () => {
|
|||||||
expect(foo.calls).toBe(10);
|
expect(foo.calls).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function once at a time for each object', async () => {
|
it("should call the function once at a time for each object", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const foo2 = new Foo();
|
const foo2 = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@@ -27,7 +27,7 @@ describe('throttle decorator', () => {
|
|||||||
expect(foo2.calls).toBe(10);
|
expect(foo2.calls).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function limit at a time', async () => {
|
it("should call the function limit at a time", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -38,7 +38,7 @@ describe('throttle decorator', () => {
|
|||||||
expect(foo.calls).toBe(10);
|
expect(foo.calls).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the function limit at a time for each object', async () => {
|
it("should call the function limit at a time for each object", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const foo2 = new Foo();
|
const foo2 = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
@@ -52,7 +52,7 @@ describe('throttle decorator', () => {
|
|||||||
expect(foo2.calls).toBe(10);
|
expect(foo2.calls).toBe(10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work together with sequentialize', async () => {
|
it("should work together with sequentialize", async () => {
|
||||||
const foo = new Foo();
|
const foo = new Foo();
|
||||||
const promises = [];
|
const promises = [];
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
@@ -68,11 +68,11 @@ class Foo {
|
|||||||
calls = 0;
|
calls = 0;
|
||||||
inflight = 0;
|
inflight = 0;
|
||||||
|
|
||||||
@throttle(1, () => 'bar')
|
@throttle(1, () => "bar")
|
||||||
bar(a: number) {
|
bar(a: number) {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
this.inflight++;
|
this.inflight++;
|
||||||
return new Promise(res => {
|
return new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(this.inflight).toBe(1);
|
expect(this.inflight).toBe(1);
|
||||||
this.inflight--;
|
this.inflight--;
|
||||||
@@ -81,11 +81,11 @@ class Foo {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@throttle(5, () => 'baz')
|
@throttle(5, () => "baz")
|
||||||
baz(a: number) {
|
baz(a: number) {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
this.inflight++;
|
this.inflight++;
|
||||||
return new Promise(res => {
|
return new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(this.inflight).toBeLessThanOrEqual(5);
|
expect(this.inflight).toBeLessThanOrEqual(5);
|
||||||
this.inflight--;
|
this.inflight--;
|
||||||
@@ -94,12 +94,12 @@ class Foo {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@sequentialize(args => 'qux' + args[0])
|
@sequentialize((args) => "qux" + args[0])
|
||||||
@throttle(1, () => 'qux')
|
@throttle(1, () => "qux")
|
||||||
qux(a: number) {
|
qux(a: number) {
|
||||||
this.calls++;
|
this.calls++;
|
||||||
this.inflight++;
|
this.inflight++;
|
||||||
return new Promise(res => {
|
return new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(this.inflight).toBe(1);
|
expect(this.inflight).toBe(1);
|
||||||
this.inflight--;
|
this.inflight--;
|
||||||
|
|||||||
@@ -1,70 +1,72 @@
|
|||||||
import { Utils } from 'src/misc/utils';
|
import { Utils } from "src/misc/utils";
|
||||||
|
|
||||||
describe('Utils Service', () => {
|
describe("Utils Service", () => {
|
||||||
describe('getDomain', () => {
|
describe("getDomain", () => {
|
||||||
it('should fail for invalid urls', () => {
|
it("should fail for invalid urls", () => {
|
||||||
expect(Utils.getDomain(null)).toBeNull();
|
expect(Utils.getDomain(null)).toBeNull();
|
||||||
expect(Utils.getDomain(undefined)).toBeNull();
|
expect(Utils.getDomain(undefined)).toBeNull();
|
||||||
expect(Utils.getDomain(' ')).toBeNull();
|
expect(Utils.getDomain(" ")).toBeNull();
|
||||||
expect(Utils.getDomain('https://bit!:"_&ward.com')).toBeNull();
|
expect(Utils.getDomain('https://bit!:"_&ward.com')).toBeNull();
|
||||||
expect(Utils.getDomain('bitwarden')).toBeNull();
|
expect(Utils.getDomain("bitwarden")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail for data urls', () => {
|
it("should fail for data urls", () => {
|
||||||
expect(Utils.getDomain('data:image/jpeg;base64,AAA')).toBeNull();
|
expect(Utils.getDomain("data:image/jpeg;base64,AAA")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle urls without protocol', () => {
|
it("should handle urls without protocol", () => {
|
||||||
expect(Utils.getDomain('bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getDomain("bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getDomain('wrong://bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getDomain("wrong://bitwarden.com")).toBe("bitwarden.com");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle valid urls', () => {
|
it("should handle valid urls", () => {
|
||||||
expect(Utils.getDomain('https://bitwarden')).toBe('bitwarden');
|
expect(Utils.getDomain("https://bitwarden")).toBe("bitwarden");
|
||||||
expect(Utils.getDomain('https://bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getDomain("https://bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getDomain('http://bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getDomain("http://bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getDomain('http://vault.bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getDomain("http://vault.bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getDomain('https://user:password@bitwarden.com:8080/password/sites?and&query#hash'))
|
expect(
|
||||||
.toBe('bitwarden.com');
|
Utils.getDomain("https://user:password@bitwarden.com:8080/password/sites?and&query#hash")
|
||||||
expect(Utils.getDomain('https://bitwarden.unknown')).toBe('bitwarden.unknown');
|
).toBe("bitwarden.com");
|
||||||
|
expect(Utils.getDomain("https://bitwarden.unknown")).toBe("bitwarden.unknown");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support localhost and IP', () => {
|
it("should support localhost and IP", () => {
|
||||||
expect(Utils.getDomain('https://localhost')).toBe('localhost');
|
expect(Utils.getDomain("https://localhost")).toBe("localhost");
|
||||||
expect(Utils.getDomain('https://192.168.1.1')).toBe('192.168.1.1');
|
expect(Utils.getDomain("https://192.168.1.1")).toBe("192.168.1.1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reject invalid hostnames', () => {
|
it("should reject invalid hostnames", () => {
|
||||||
expect(Utils.getDomain('https://mywebsite.com$.mywebsite.com')).toBeNull();
|
expect(Utils.getDomain("https://mywebsite.com$.mywebsite.com")).toBeNull();
|
||||||
expect(Utils.getDomain('https://mywebsite.com!.mywebsite.com')).toBeNull();
|
expect(Utils.getDomain("https://mywebsite.com!.mywebsite.com")).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getHostname', () => {
|
describe("getHostname", () => {
|
||||||
it('should fail for invalid urls', () => {
|
it("should fail for invalid urls", () => {
|
||||||
expect(Utils.getHostname(null)).toBeNull();
|
expect(Utils.getHostname(null)).toBeNull();
|
||||||
expect(Utils.getHostname(undefined)).toBeNull();
|
expect(Utils.getHostname(undefined)).toBeNull();
|
||||||
expect(Utils.getHostname(' ')).toBeNull();
|
expect(Utils.getHostname(" ")).toBeNull();
|
||||||
expect(Utils.getHostname('https://bit!:"_&ward.com')).toBeNull();
|
expect(Utils.getHostname('https://bit!:"_&ward.com')).toBeNull();
|
||||||
expect(Utils.getHostname('bitwarden')).toBeNull();
|
expect(Utils.getHostname("bitwarden")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle valid urls', () => {
|
it("should handle valid urls", () => {
|
||||||
expect(Utils.getHostname('bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getHostname("bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getHostname('https://bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getHostname("https://bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getHostname('http://bitwarden.com')).toBe('bitwarden.com');
|
expect(Utils.getHostname("http://bitwarden.com")).toBe("bitwarden.com");
|
||||||
expect(Utils.getHostname('http://vault.bitwarden.com')).toBe('vault.bitwarden.com');
|
expect(Utils.getHostname("http://vault.bitwarden.com")).toBe("vault.bitwarden.com");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support localhost and IP', () => {
|
it("should support localhost and IP", () => {
|
||||||
expect(Utils.getHostname('https://localhost')).toBe('localhost');
|
expect(Utils.getHostname("https://localhost")).toBe("localhost");
|
||||||
expect(Utils.getHostname('https://192.168.1.1')).toBe('192.168.1.1');
|
expect(Utils.getHostname("https://192.168.1.1")).toBe("192.168.1.1");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('newGuid', () => {
|
describe("newGuid", () => {
|
||||||
it('should create a valid guid', () => {
|
it("should create a valid guid", () => {
|
||||||
const validGuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
const validGuid =
|
||||||
|
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||||
expect(Utils.newGuid()).toMatch(validGuid);
|
expect(Utils.newGuid()).toMatch(validGuid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
import { Arg, Substitute, SubstituteOf } from '@fluffy-spoon/substitute';
|
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
|
|
||||||
import { ApiService } from 'src/abstractions/api.service';
|
import { ApiService } from "src/abstractions/api.service";
|
||||||
import { CryptoService } from 'src/abstractions/crypto.service';
|
import { CryptoService } from "src/abstractions/crypto.service";
|
||||||
import { FileUploadService } from 'src/abstractions/fileUpload.service';
|
import { FileUploadService } from "src/abstractions/fileUpload.service";
|
||||||
import { I18nService } from 'src/abstractions/i18n.service';
|
import { I18nService } from "src/abstractions/i18n.service";
|
||||||
import { LogService } from 'src/abstractions/log.service';
|
import { LogService } from "src/abstractions/log.service";
|
||||||
import { SearchService } from 'src/abstractions/search.service';
|
import { SearchService } from "src/abstractions/search.service";
|
||||||
import { SettingsService } from 'src/abstractions/settings.service';
|
import { SettingsService } from "src/abstractions/settings.service";
|
||||||
import { StateService } from 'src/abstractions/state.service';
|
import { StateService } from "src/abstractions/state.service";
|
||||||
|
|
||||||
import { Utils } from 'src/misc/utils';
|
import { Utils } from "src/misc/utils";
|
||||||
import { Cipher } from 'src/models/domain/cipher';
|
import { Cipher } from "src/models/domain/cipher";
|
||||||
import { EncArrayBuffer } from 'src/models/domain/encArrayBuffer';
|
import { EncArrayBuffer } from "src/models/domain/encArrayBuffer";
|
||||||
import { EncString } from 'src/models/domain/encString';
|
import { EncString } from "src/models/domain/encString";
|
||||||
import { SymmetricCryptoKey } from 'src/models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "src/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { CipherService } from 'src/services/cipher.service';
|
import { CipherService } from "src/services/cipher.service";
|
||||||
|
|
||||||
const ENCRYPTED_TEXT = 'This data has been encrypted';
|
const ENCRYPTED_TEXT = "This data has been encrypted";
|
||||||
const ENCRYPTED_BYTES = new EncArrayBuffer(Utils.fromUtf8ToArray(ENCRYPTED_TEXT).buffer);
|
const ENCRYPTED_BYTES = new EncArrayBuffer(Utils.fromUtf8ToArray(ENCRYPTED_TEXT).buffer);
|
||||||
|
|
||||||
describe('Cipher Service', () => {
|
describe("Cipher Service", () => {
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
let cryptoService: SubstituteOf<CryptoService>;
|
||||||
let stateService: SubstituteOf<StateService>;
|
let stateService: SubstituteOf<StateService>;
|
||||||
let settingsService: SubstituteOf<SettingsService>;
|
let settingsService: SubstituteOf<SettingsService>;
|
||||||
@@ -45,17 +45,27 @@ describe('Cipher Service', () => {
|
|||||||
cryptoService.encryptToBytes(Arg.any(), Arg.any()).resolves(ENCRYPTED_BYTES);
|
cryptoService.encryptToBytes(Arg.any(), Arg.any()).resolves(ENCRYPTED_BYTES);
|
||||||
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(new EncString(ENCRYPTED_TEXT));
|
cryptoService.encrypt(Arg.any(), Arg.any()).resolves(new EncString(ENCRYPTED_TEXT));
|
||||||
|
|
||||||
cipherService = new CipherService(cryptoService, settingsService, apiService, fileUploadService,
|
cipherService = new CipherService(
|
||||||
i18nService, () => searchService, logService, stateService);
|
cryptoService,
|
||||||
|
settingsService,
|
||||||
|
apiService,
|
||||||
|
fileUploadService,
|
||||||
|
i18nService,
|
||||||
|
() => searchService,
|
||||||
|
logService,
|
||||||
|
stateService
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('attachments upload encrypted file contents', async () => {
|
it("attachments upload encrypted file contents", async () => {
|
||||||
const fileName = 'filename';
|
const fileName = "filename";
|
||||||
const fileData = new Uint8Array(10).buffer;
|
const fileData = new Uint8Array(10).buffer;
|
||||||
cryptoService.getOrgKey(Arg.any()).resolves(new SymmetricCryptoKey(new Uint8Array(32).buffer));
|
cryptoService.getOrgKey(Arg.any()).resolves(new SymmetricCryptoKey(new Uint8Array(32).buffer));
|
||||||
|
|
||||||
await cipherService.saveAttachmentRawWithServer(new Cipher(), fileName, fileData);
|
await cipherService.saveAttachmentRawWithServer(new Cipher(), fileName, fileData);
|
||||||
|
|
||||||
fileUploadService.received(1).uploadCipherAttachment(Arg.any(), Arg.any(), new EncString(ENCRYPTED_TEXT), ENCRYPTED_BYTES);
|
fileUploadService
|
||||||
|
.received(1)
|
||||||
|
.uploadCipherAttachment(Arg.any(), Arg.any(), new EncString(ENCRYPTED_TEXT), ENCRYPTED_BYTES);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ConsoleLogService } from 'src/services/consoleLog.service';
|
import { ConsoleLogService } from "src/services/consoleLog.service";
|
||||||
|
|
||||||
const originalConsole = console;
|
const originalConsole = console;
|
||||||
let caughtMessage: any;
|
let caughtMessage: any;
|
||||||
@@ -27,7 +27,7 @@ export function restoreConsole() {
|
|||||||
console = originalConsole;
|
console = originalConsole;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('ConsoleLogService', () => {
|
describe("ConsoleLogService", () => {
|
||||||
let logService: ConsoleLogService;
|
let logService: ConsoleLogService;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
caughtMessage = {};
|
caughtMessage = {};
|
||||||
@@ -39,42 +39,49 @@ describe('ConsoleLogService', () => {
|
|||||||
restoreConsole();
|
restoreConsole();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters messages below the set threshold', () => {
|
it("filters messages below the set threshold", () => {
|
||||||
logService = new ConsoleLogService(true, level => true);
|
logService = new ConsoleLogService(true, (level) => true);
|
||||||
logService.debug('debug');
|
logService.debug("debug");
|
||||||
logService.info('info');
|
logService.info("info");
|
||||||
logService.warning('warning');
|
logService.warning("warning");
|
||||||
logService.error('error');
|
logService.error("error");
|
||||||
|
|
||||||
expect(caughtMessage).toEqual({});
|
expect(caughtMessage).toEqual({});
|
||||||
});
|
});
|
||||||
it('only writes debug messages in dev mode', () => {
|
it("only writes debug messages in dev mode", () => {
|
||||||
logService = new ConsoleLogService(false);
|
logService = new ConsoleLogService(false);
|
||||||
|
|
||||||
logService.debug('debug message');
|
logService.debug("debug message");
|
||||||
expect(caughtMessage.log).toBeUndefined();
|
expect(caughtMessage.log).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("writes debug/info messages to console.log", () => {
|
||||||
it('writes debug/info messages to console.log', () => {
|
logService.debug("this is a debug message");
|
||||||
logService.debug('this is a debug message');
|
expect(caughtMessage).toEqual({
|
||||||
expect(caughtMessage).toEqual({ log: jasmine.arrayWithExactContents(['this is a debug message']) });
|
log: jasmine.arrayWithExactContents(["this is a debug message"]),
|
||||||
|
|
||||||
logService.info('this is an info message');
|
|
||||||
expect(caughtMessage).toEqual({ log: jasmine.arrayWithExactContents(['this is an info message']) });
|
|
||||||
});
|
|
||||||
it('writes warning messages to console.warn', () => {
|
|
||||||
logService.warning('this is a warning message');
|
|
||||||
expect(caughtMessage).toEqual({ warn: jasmine.arrayWithExactContents(['this is a warning message']) });
|
|
||||||
});
|
|
||||||
it('writes error messages to console.error', () => {
|
|
||||||
logService.error('this is an error message');
|
|
||||||
expect(caughtMessage).toEqual({ error: jasmine.arrayWithExactContents(['this is an error message']) });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('times with output to info', async () => {
|
logService.info("this is an info message");
|
||||||
|
expect(caughtMessage).toEqual({
|
||||||
|
log: jasmine.arrayWithExactContents(["this is an info message"]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("writes warning messages to console.warn", () => {
|
||||||
|
logService.warning("this is a warning message");
|
||||||
|
expect(caughtMessage).toEqual({
|
||||||
|
warn: jasmine.arrayWithExactContents(["this is a warning message"]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("writes error messages to console.error", () => {
|
||||||
|
logService.error("this is an error message");
|
||||||
|
expect(caughtMessage).toEqual({
|
||||||
|
error: jasmine.arrayWithExactContents(["this is an error message"]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("times with output to info", async () => {
|
||||||
logService.time();
|
logService.time();
|
||||||
await new Promise(r => setTimeout(r, 250));
|
await new Promise((r) => setTimeout(r, 250));
|
||||||
const duration = logService.timeEnd();
|
const duration = logService.timeEnd();
|
||||||
expect(duration[0]).toBe(0);
|
expect(duration[0]).toBe(0);
|
||||||
expect(duration[1]).toBeGreaterThan(0);
|
expect(duration[1]).toBeGreaterThan(0);
|
||||||
@@ -85,8 +92,8 @@ describe('ConsoleLogService', () => {
|
|||||||
expect(caughtMessage.log[0]).toEqual(jasmine.stringMatching(/^default: \d+\.?\d*ms$/));
|
expect(caughtMessage.log[0]).toEqual(jasmine.stringMatching(/^default: \d+\.?\d*ms$/));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('filters time output', async () => {
|
it("filters time output", async () => {
|
||||||
logService = new ConsoleLogService(true, level => true);
|
logService = new ConsoleLogService(true, (level) => true);
|
||||||
logService.time();
|
logService.time();
|
||||||
logService.timeEnd();
|
logService.timeEnd();
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { Substitute, SubstituteOf } from '@fluffy-spoon/substitute';
|
import { Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||||
|
|
||||||
import { ApiService } from 'src/abstractions/api.service';
|
import { ApiService } from "src/abstractions/api.service";
|
||||||
import { CipherService } from 'src/abstractions/cipher.service';
|
import { CipherService } from "src/abstractions/cipher.service";
|
||||||
import { CryptoService } from 'src/abstractions/crypto.service';
|
import { CryptoService } from "src/abstractions/crypto.service";
|
||||||
import { FolderService } from 'src/abstractions/folder.service';
|
import { FolderService } from "src/abstractions/folder.service";
|
||||||
|
|
||||||
import { ExportService } from 'src/services/export.service';
|
import { ExportService } from "src/services/export.service";
|
||||||
|
|
||||||
import { Cipher } from 'src/models/domain/cipher';
|
import { Cipher } from "src/models/domain/cipher";
|
||||||
import { EncString } from 'src/models/domain/encString';
|
import { EncString } from "src/models/domain/encString";
|
||||||
import { Login } from 'src/models/domain/login';
|
import { Login } from "src/models/domain/login";
|
||||||
import { CipherWithIds as CipherExport } from 'src/models/export/cipherWithIds';
|
import { CipherWithIds as CipherExport } from "src/models/export/cipherWithIds";
|
||||||
|
|
||||||
import { CipherType } from 'src/enums/cipherType';
|
import { CipherType } from "src/enums/cipherType";
|
||||||
import { CipherView } from 'src/models/view/cipherView';
|
import { CipherView } from "src/models/view/cipherView";
|
||||||
import { LoginView } from 'src/models/view/loginView';
|
import { LoginView } from "src/models/view/loginView";
|
||||||
|
|
||||||
import { BuildTestObject, GetUniqueString } from '../utils';
|
import { BuildTestObject, GetUniqueString } from "../utils";
|
||||||
|
|
||||||
const UserCipherViews = [
|
const UserCipherViews = [
|
||||||
generateCipherView(false),
|
generateCipherView(false),
|
||||||
@@ -31,31 +31,43 @@ const UserCipherDomains = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
function generateCipherView(deleted: boolean) {
|
function generateCipherView(deleted: boolean) {
|
||||||
return BuildTestObject({
|
return BuildTestObject(
|
||||||
id: GetUniqueString('id'),
|
{
|
||||||
notes: GetUniqueString('notes'),
|
id: GetUniqueString("id"),
|
||||||
|
notes: GetUniqueString("notes"),
|
||||||
type: CipherType.Login,
|
type: CipherType.Login,
|
||||||
login: BuildTestObject<LoginView>({
|
login: BuildTestObject<LoginView>(
|
||||||
username: GetUniqueString('username'),
|
{
|
||||||
password: GetUniqueString('password'),
|
username: GetUniqueString("username"),
|
||||||
}, LoginView),
|
password: GetUniqueString("password"),
|
||||||
|
},
|
||||||
|
LoginView
|
||||||
|
),
|
||||||
collectionIds: null,
|
collectionIds: null,
|
||||||
deletedDate: deleted ? new Date() : null,
|
deletedDate: deleted ? new Date() : null,
|
||||||
}, CipherView);
|
},
|
||||||
|
CipherView
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateCipherDomain(deleted: boolean) {
|
function generateCipherDomain(deleted: boolean) {
|
||||||
return BuildTestObject({
|
return BuildTestObject(
|
||||||
id: GetUniqueString('id'),
|
{
|
||||||
notes: new EncString(GetUniqueString('notes')),
|
id: GetUniqueString("id"),
|
||||||
|
notes: new EncString(GetUniqueString("notes")),
|
||||||
type: CipherType.Login,
|
type: CipherType.Login,
|
||||||
login: BuildTestObject<Login>({
|
login: BuildTestObject<Login>(
|
||||||
username: new EncString(GetUniqueString('username')),
|
{
|
||||||
password: new EncString(GetUniqueString('password')),
|
username: new EncString(GetUniqueString("username")),
|
||||||
}, Login),
|
password: new EncString(GetUniqueString("password")),
|
||||||
|
},
|
||||||
|
Login
|
||||||
|
),
|
||||||
collectionIds: null,
|
collectionIds: null,
|
||||||
deletedDate: deleted ? new Date() : null,
|
deletedDate: deleted ? new Date() : null,
|
||||||
}, Cipher);
|
},
|
||||||
|
Cipher
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string) {
|
function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string) {
|
||||||
@@ -70,7 +82,7 @@ function expectEqualCiphers(ciphers: CipherView[] | Cipher[], jsonResult: string
|
|||||||
expect(actual).toEqual(JSON.stringify(items));
|
expect(actual).toEqual(JSON.stringify(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('ExportService', () => {
|
describe("ExportService", () => {
|
||||||
let exportService: ExportService;
|
let exportService: ExportService;
|
||||||
let apiService: SubstituteOf<ApiService>;
|
let apiService: SubstituteOf<ApiService>;
|
||||||
let cipherService: SubstituteOf<CipherService>;
|
let cipherService: SubstituteOf<CipherService>;
|
||||||
@@ -89,34 +101,34 @@ describe('ExportService', () => {
|
|||||||
exportService = new ExportService(folderService, cipherService, apiService, cryptoService);
|
exportService = new ExportService(folderService, cipherService, apiService, cryptoService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports unecrypted user ciphers', async () => {
|
it("exports unecrypted user ciphers", async () => {
|
||||||
cipherService.getAllDecrypted().resolves(UserCipherViews.slice(0, 1));
|
cipherService.getAllDecrypted().resolves(UserCipherViews.slice(0, 1));
|
||||||
|
|
||||||
const actual = await exportService.getExport('json');
|
const actual = await exportService.getExport("json");
|
||||||
|
|
||||||
expectEqualCiphers(UserCipherViews.slice(0, 1), actual);
|
expectEqualCiphers(UserCipherViews.slice(0, 1), actual);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('exports encrypted json user ciphers', async () => {
|
it("exports encrypted json user ciphers", async () => {
|
||||||
cipherService.getAll().resolves(UserCipherDomains.slice(0, 1));
|
cipherService.getAll().resolves(UserCipherDomains.slice(0, 1));
|
||||||
|
|
||||||
const actual = await exportService.getExport('encrypted_json');
|
const actual = await exportService.getExport("encrypted_json");
|
||||||
|
|
||||||
expectEqualCiphers(UserCipherDomains.slice(0, 1), actual);
|
expectEqualCiphers(UserCipherDomains.slice(0, 1), actual);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not unecrypted export trashed user items', async () => {
|
it("does not unecrypted export trashed user items", async () => {
|
||||||
cipherService.getAllDecrypted().resolves(UserCipherViews);
|
cipherService.getAllDecrypted().resolves(UserCipherViews);
|
||||||
|
|
||||||
const actual = await exportService.getExport('json');
|
const actual = await exportService.getExport("json");
|
||||||
|
|
||||||
expectEqualCiphers(UserCipherViews.slice(0, 2), actual);
|
expectEqualCiphers(UserCipherViews.slice(0, 2), actual);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not encrypted export trashed user items', async () => {
|
it("does not encrypted export trashed user items", async () => {
|
||||||
cipherService.getAll().resolves(UserCipherDomains);
|
cipherService.getAll().resolves(UserCipherDomains);
|
||||||
|
|
||||||
const actual = await exportService.getExport('encrypted_json');
|
const actual = await exportService.getExport("encrypted_json");
|
||||||
|
|
||||||
expectEqualCiphers(UserCipherDomains.slice(0, 2), actual);
|
expectEqualCiphers(UserCipherDomains.slice(0, 2), actual);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
{
|
{
|
||||||
"spec_dir": "dist/spec",
|
"spec_dir": "dist/spec",
|
||||||
"spec_files": [
|
"spec_files": ["!web/**/*[sS]pec.js", "**/*[sS]pec.js"],
|
||||||
"!web/**/*[sS]pec.js",
|
"helpers": ["helpers.js"],
|
||||||
"**/*[sS]pec.js"
|
|
||||||
],
|
|
||||||
"helpers": [
|
|
||||||
"helpers.js"
|
|
||||||
],
|
|
||||||
"stopSpecOnExpectationFailure": false,
|
"stopSpecOnExpectationFailure": false,
|
||||||
"random": true
|
"random": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
function newGuid() {
|
function newGuid() {
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
||||||
// tslint:disable:no-bitwise
|
// tslint:disable:no-bitwise
|
||||||
const r = Math.random() * 16 | 0;
|
const r = (Math.random() * 16) | 0;
|
||||||
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
||||||
return v.toString(16);
|
return v.toString(16);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GetUniqueString(prefix: string = '') {
|
export function GetUniqueString(prefix: string = "") {
|
||||||
return prefix + '_' + newGuid();
|
return prefix + "_" + newGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BuildTestObject<T, K extends keyof T = keyof T>(def: Partial<Pick<T, K>> | T, constructor?: (new () => T)): T {
|
export function BuildTestObject<T, K extends keyof T = keyof T>(
|
||||||
|
def: Partial<Pick<T, K>> | T,
|
||||||
|
constructor?: new () => T
|
||||||
|
): T {
|
||||||
return Object.assign(constructor === null ? {} : new constructor(), def) as T;
|
return Object.assign(constructor === null ? {} : new constructor(), def) as T;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,161 @@
|
|||||||
import Substitute from '@fluffy-spoon/substitute';
|
import Substitute from "@fluffy-spoon/substitute";
|
||||||
|
|
||||||
import { PlatformUtilsService } from 'src/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from "src/abstractions/platformUtils.service";
|
||||||
|
|
||||||
import { WebCryptoFunctionService } from 'src/services/webCryptoFunction.service';
|
import { WebCryptoFunctionService } from "src/services/webCryptoFunction.service";
|
||||||
|
|
||||||
import { Utils } from 'src/misc/utils';
|
import { Utils } from "src/misc/utils";
|
||||||
import { SymmetricCryptoKey } from 'src/models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "src/models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
const RsaPublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP' +
|
const RsaPublicKey =
|
||||||
'4xlU2ab/v0crqIfXfIoWF/XXdHGIdrZeilnRXPPJT1B9dTsasttEZNnua/0Rek/cjNDHtzT52irfoZYS7X6HNIfOi54Q+egP' +
|
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP" +
|
||||||
'RQ1H7iNHVZz3K8Db9GCSKPeC8MbW6gVCzb15esCe1gGzg6wkMuWYDFYPoh/oBqcIqrGah7firqB1nDedzEjw32heP2DAffVN' +
|
"4xlU2ab/v0crqIfXfIoWF/XXdHGIdrZeilnRXPPJT1B9dTsasttEZNnua/0Rek/cjNDHtzT52irfoZYS7X6HNIfOi54Q+egP" +
|
||||||
'084iTDjiWrJNUxBJ2pDD5Z9dT3MzQ2s09ew1yMWK2z37rT3YerC7OgEDmo3WYo3xL3qYJznu3EO2nmrYjiRa40wKSjxsTlUc' +
|
"RQ1H7iNHVZz3K8Db9GCSKPeC8MbW6gVCzb15esCe1gGzg6wkMuWYDFYPoh/oBqcIqrGah7firqB1nDedzEjw32heP2DAffVN" +
|
||||||
'xDF+F0uMW8oR9EMUHgepdepfAtLsSAQIDAQAB';
|
"084iTDjiWrJNUxBJ2pDD5Z9dT3MzQ2s09ew1yMWK2z37rT3YerC7OgEDmo3WYo3xL3qYJznu3EO2nmrYjiRa40wKSjxsTlUc" +
|
||||||
const RsaPrivateKey = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXRVrCX+2hfOQS8Hz' +
|
"xDF+F0uMW8oR9EMUHgepdepfAtLsSAQIDAQAB";
|
||||||
'YUS2oc/jGVTZpv+/Ryuoh9d8ihYX9dd0cYh2tl6KWdFc88lPUH11Oxqy20Rk2e5r/RF6T9yM0Me3NPnaKt+hlhLtfoc0h86L' +
|
const RsaPrivateKey =
|
||||||
'nhD56A9FDUfuI0dVnPcrwNv0YJIo94LwxtbqBULNvXl6wJ7WAbODrCQy5ZgMVg+iH+gGpwiqsZqHt+KuoHWcN53MSPDfaF4/' +
|
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXRVrCX+2hfOQS8Hz" +
|
||||||
'YMB99U3TziJMOOJask1TEEnakMPln11PczNDazT17DXIxYrbPfutPdh6sLs6AQOajdZijfEvepgnOe7cQ7aeatiOJFrjTApK' +
|
"YUS2oc/jGVTZpv+/Ryuoh9d8ihYX9dd0cYh2tl6KWdFc88lPUH11Oxqy20Rk2e5r/RF6T9yM0Me3NPnaKt+hlhLtfoc0h86L" +
|
||||||
'PGxOVRzEMX4XS4xbyhH0QxQeB6l16l8C0uxIBAgMBAAECggEASaWfeVDA3cVzOPFSpvJm20OTE+R6uGOU+7vh36TX/POq92q' +
|
"nhD56A9FDUfuI0dVnPcrwNv0YJIo94LwxtbqBULNvXl6wJ7WAbODrCQy5ZgMVg+iH+gGpwiqsZqHt+KuoHWcN53MSPDfaF4/" +
|
||||||
'Buwbd0h0oMD32FxsXywd2IxtBDUSiFM9699qufTVuM0Q3tZw6lHDTOVG08+tPdr8qSbMtw7PGFxN79fHLBxejjO4IrM9lapj' +
|
"YMB99U3TziJMOOJask1TEEnakMPln11PczNDazT17DXIxYrbPfutPdh6sLs6AQOajdZijfEvepgnOe7cQ7aeatiOJFrjTApK" +
|
||||||
'WpxEF+11x7r+wM+0xRZQ8sNFYG46aPfIaty4BGbL0I2DQ2y8I57iBCAy69eht59NLMm27fRWGJIWCuBIjlpfzET1j2HLXUIh' +
|
"PGxOVRzEMX4XS4xbyhH0QxQeB6l16l8C0uxIBAgMBAAECggEASaWfeVDA3cVzOPFSpvJm20OTE+R6uGOU+7vh36TX/POq92q" +
|
||||||
'5bTBNzqaN039WH49HczGE3mQKVEJZc/efk3HaVd0a1Sjzyn0QY+N1jtZN3jTRbuDWA1AknkX1LX/0tUhuS3/7C3ejHxjw4Dk' +
|
"Buwbd0h0oMD32FxsXywd2IxtBDUSiFM9699qufTVuM0Q3tZw6lHDTOVG08+tPdr8qSbMtw7PGFxN79fHLBxejjO4IrM9lapj" +
|
||||||
'1ZLo5/QKBgQDIWvqFn0+IKRSu6Ua2hDsufIHHUNLelbfLUMmFthxabcUn4zlvIscJO00Tq/ezopSRRvbGiqnxjv/mYxucvOU' +
|
"WpxEF+11x7r+wM+0xRZQ8sNFYG46aPfIaty4BGbL0I2DQ2y8I57iBCAy69eht59NLMm27fRWGJIWCuBIjlpfzET1j2HLXUIh" +
|
||||||
'BeZtlus0Q9RTACBtw9TGoNTmQbEunJ2FOSlqbQxkBBAjgGEppRPt30iGj/VjAhCATq2MYOa/X4dVR51BqQAFIEwKBgQDBSIf' +
|
"5bTBNzqaN039WH49HczGE3mQKVEJZc/efk3HaVd0a1Sjzyn0QY+N1jtZN3jTRbuDWA1AknkX1LX/0tUhuS3/7C3ejHxjw4Dk" +
|
||||||
'TFKC/hDk6FKZlgwvupWYJyU9RkyfstPErZFmzoKhPkQ3YORo2oeAYmVUbS9I2iIYpYpYQJHX8jMuCbCz4ONxTCuSIXYQYUcU' +
|
"1ZLo5/QKBgQDIWvqFn0+IKRSu6Ua2hDsufIHHUNLelbfLUMmFthxabcUn4zlvIscJO00Tq/ezopSRRvbGiqnxjv/mYxucvOU" +
|
||||||
'q4PglCKp31xBAE6TN8SvhfME9/MvuDssnQinAHuF0GDAhF646T3LLS1not6Vszv7brwSoGwKBgQC88v/8cGfi80ssQZeMnVv' +
|
"BeZtlus0Q9RTACBtw9TGoNTmQbEunJ2FOSlqbQxkBBAjgGEppRPt30iGj/VjAhCATq2MYOa/X4dVR51BqQAFIEwKBgQDBSIf" +
|
||||||
'q1UTXIeQcQnoY5lGHJl3K8mbS3TnXE6c9j417Fdz+rj8KWzBzwWXQB5pSPflWcdZO886Xu/mVGmy9RWgLuVFhXwCwsVEPjNX' +
|
"TFKC/hDk6FKZlgwvupWYJyU9RkyfstPErZFmzoKhPkQ3YORo2oeAYmVUbS9I2iIYpYpYQJHX8jMuCbCz4ONxTCuSIXYQYUcU" +
|
||||||
'5ramRb0/vY0yzenUCninBsIxFSbIfrPtLUYCc4hpxr+sr2Mg/y6jpvQKBgBezMRRs3xkcuXepuI2R+BCXL1/b02IJTUf1F+1' +
|
"q4PglCKp31xBAE6TN8SvhfME9/MvuDssnQinAHuF0GDAhF646T3LLS1not6Vszv7brwSoGwKBgQC88v/8cGfi80ssQZeMnVv" +
|
||||||
'eLLGd7YV0H+J3fgNc7gGWK51hOrF9JBZHBGeOUPlaukmPwiPdtQZpu4QNE3l37VlIpKTF30E6mb+BqR+nht3rUjarnMXgAoE' +
|
"q1UTXIeQcQnoY5lGHJl3K8mbS3TnXE6c9j417Fdz+rj8KWzBzwWXQB5pSPflWcdZO886Xu/mVGmy9RWgLuVFhXwCwsVEPjNX" +
|
||||||
'Z18y6/KIjpSMpqC92Nnk/EBM9EYe6Cf4eA9ApAoGAeqEUg46UTlJySkBKURGpIs3v1kkf5I0X8DnOhwb+HPxNaiEdmO7ckm8' +
|
"5ramRb0/vY0yzenUCninBsIxFSbIfrPtLUYCc4hpxr+sr2Mg/y6jpvQKBgBezMRRs3xkcuXepuI2R+BCXL1/b02IJTUf1F+1" +
|
||||||
'+tPVgppLcG0+tMdLjigFQiDUQk2y3WjyxP5ZvXu7U96jaJRI8PFMoE06WeVYcdIzrID2HvqH+w0UQJFrLJ/0Mn4stFAEzXKZ' +
|
"eLLGd7YV0H+J3fgNc7gGWK51hOrF9JBZHBGeOUPlaukmPwiPdtQZpu4QNE3l37VlIpKTF30E6mb+BqR+nht3rUjarnMXgAoE" +
|
||||||
'BokBGnjFnTnKcs7nv/O8=';
|
"Z18y6/KIjpSMpqC92Nnk/EBM9EYe6Cf4eA9ApAoGAeqEUg46UTlJySkBKURGpIs3v1kkf5I0X8DnOhwb+HPxNaiEdmO7ckm8" +
|
||||||
|
"+tPVgppLcG0+tMdLjigFQiDUQk2y3WjyxP5ZvXu7U96jaJRI8PFMoE06WeVYcdIzrID2HvqH+w0UQJFrLJ/0Mn4stFAEzXKZ" +
|
||||||
|
"BokBGnjFnTnKcs7nv/O8=";
|
||||||
|
|
||||||
const Sha1Mac = '4d4c223f95dc577b665ec4ccbcb680b80a397038';
|
const Sha1Mac = "4d4c223f95dc577b665ec4ccbcb680b80a397038";
|
||||||
const Sha256Mac = '6be3caa84922e12aaaaa2f16c40d44433bb081ef323db584eb616333ab4e874f';
|
const Sha256Mac = "6be3caa84922e12aaaaa2f16c40d44433bb081ef323db584eb616333ab4e874f";
|
||||||
const Sha512Mac = '21910e341fa12106ca35758a2285374509326c9fbe0bd64e7b99c898f841dc948c58ce66d3504d8883c' +
|
const Sha512Mac =
|
||||||
'5ea7817a0b7c5d4d9b00364ccd214669131fc17fe4aca';
|
"21910e341fa12106ca35758a2285374509326c9fbe0bd64e7b99c898f841dc948c58ce66d3504d8883c" +
|
||||||
|
"5ea7817a0b7c5d4d9b00364ccd214669131fc17fe4aca";
|
||||||
|
|
||||||
describe('WebCrypto Function Service', () => {
|
describe("WebCrypto Function Service", () => {
|
||||||
describe('pbkdf2', () => {
|
describe("pbkdf2", () => {
|
||||||
const regular256Key = 'pj9prw/OHPleXI6bRdmlaD+saJS4awrMiQsQiDjeu2I=';
|
const regular256Key = "pj9prw/OHPleXI6bRdmlaD+saJS4awrMiQsQiDjeu2I=";
|
||||||
const utf8256Key = 'yqvoFXgMRmHR3QPYr5pyR4uVuoHkltv9aHUP63p8n7I=';
|
const utf8256Key = "yqvoFXgMRmHR3QPYr5pyR4uVuoHkltv9aHUP63p8n7I=";
|
||||||
const unicode256Key = 'ZdeOata6xoRpB4DLp8zHhXz5kLmkWtX5pd+TdRH8w8w=';
|
const unicode256Key = "ZdeOata6xoRpB4DLp8zHhXz5kLmkWtX5pd+TdRH8w8w=";
|
||||||
|
|
||||||
const regular512Key = 'liTi/Ke8LPU1Qv+Vl7NGEVt/XMbsBVJ2kQxtVG/Z1/JFHFKQW3ZkI81qVlwTiCpb+cFXzs+57' +
|
const regular512Key =
|
||||||
'eyhhx5wfKo5Cg==';
|
"liTi/Ke8LPU1Qv+Vl7NGEVt/XMbsBVJ2kQxtVG/Z1/JFHFKQW3ZkI81qVlwTiCpb+cFXzs+57" +
|
||||||
const utf8512Key = 'df0KdvIBeCzD/kyXptwQohaqUa4e7IyFUyhFQjXCANu5T+scq55hCcE4dG4T/MhAk2exw8j7ixRN' +
|
"eyhhx5wfKo5Cg==";
|
||||||
'zXANiVZpnw==';
|
const utf8512Key =
|
||||||
const unicode512Key = 'FE+AnUJaxv8jh+zUDtZz4mjjcYk0/PZDZm+SLJe3XtxtnpdqqpblX6JjuMZt/dYYNMOrb2+mD' +
|
"df0KdvIBeCzD/kyXptwQohaqUa4e7IyFUyhFQjXCANu5T+scq55hCcE4dG4T/MhAk2exw8j7ixRN" +
|
||||||
'L3FiQDTROh1lg==';
|
"zXANiVZpnw==";
|
||||||
|
const unicode512Key =
|
||||||
|
"FE+AnUJaxv8jh+zUDtZz4mjjcYk0/PZDZm+SLJe3XtxtnpdqqpblX6JjuMZt/dYYNMOrb2+mD" +
|
||||||
|
"L3FiQDTROh1lg==";
|
||||||
|
|
||||||
testPbkdf2('sha256', regular256Key, utf8256Key, unicode256Key);
|
testPbkdf2("sha256", regular256Key, utf8256Key, unicode256Key);
|
||||||
testPbkdf2('sha512', regular512Key, utf8512Key, unicode512Key);
|
testPbkdf2("sha512", regular512Key, utf8512Key, unicode512Key);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hkdf', () => {
|
describe("hkdf", () => {
|
||||||
const regular256Key = 'qBUmEYtwTwwGPuw/z6bs/qYXXYNUlocFlyAuuANI8Pw=';
|
const regular256Key = "qBUmEYtwTwwGPuw/z6bs/qYXXYNUlocFlyAuuANI8Pw=";
|
||||||
const utf8256Key = '6DfJwW1R3txgiZKkIFTvVAb7qVlG7lKcmJGJoxR2GBU=';
|
const utf8256Key = "6DfJwW1R3txgiZKkIFTvVAb7qVlG7lKcmJGJoxR2GBU=";
|
||||||
const unicode256Key = 'gejGI82xthA+nKtKmIh82kjw+ttHr+ODsUoGdu5sf0A=';
|
const unicode256Key = "gejGI82xthA+nKtKmIh82kjw+ttHr+ODsUoGdu5sf0A=";
|
||||||
|
|
||||||
const regular512Key = 'xe5cIG6ZfwGmb1FvsOedM0XKOm21myZkjL/eDeKIqqM=';
|
const regular512Key = "xe5cIG6ZfwGmb1FvsOedM0XKOm21myZkjL/eDeKIqqM=";
|
||||||
const utf8512Key = 'XQMVBnxVEhlvjSFDQc77j5GDE9aorvbS0vKnjhRg0LY=';
|
const utf8512Key = "XQMVBnxVEhlvjSFDQc77j5GDE9aorvbS0vKnjhRg0LY=";
|
||||||
const unicode512Key = '148GImrTbrjaGAe/iWEpclINM8Ehhko+9lB14+52lqc=';
|
const unicode512Key = "148GImrTbrjaGAe/iWEpclINM8Ehhko+9lB14+52lqc=";
|
||||||
|
|
||||||
testHkdf('sha256', regular256Key, utf8256Key, unicode256Key);
|
testHkdf("sha256", regular256Key, utf8256Key, unicode256Key);
|
||||||
testHkdf('sha512', regular512Key, utf8512Key, unicode512Key);
|
testHkdf("sha512", regular512Key, utf8512Key, unicode512Key);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hkdfExpand', () => {
|
describe("hkdfExpand", () => {
|
||||||
const prk16Byte = 'criAmKtfzxanbgea5/kelQ==';
|
const prk16Byte = "criAmKtfzxanbgea5/kelQ==";
|
||||||
const prk32Byte = 'F5h4KdYQnIVH4rKH0P9CZb1GrR4n16/sJrS0PsQEn0Y=';
|
const prk32Byte = "F5h4KdYQnIVH4rKH0P9CZb1GrR4n16/sJrS0PsQEn0Y=";
|
||||||
const prk64Byte = 'ssBK0mRG17VHdtsgt8yo4v25CRNpauH+0r2fwY/E9rLyaFBAOMbIeTry+' +
|
const prk64Byte =
|
||||||
'gUJ28p8y+hFh3EI9pcrEWaNvFYonQ==';
|
"ssBK0mRG17VHdtsgt8yo4v25CRNpauH+0r2fwY/E9rLyaFBAOMbIeTry+" +
|
||||||
|
"gUJ28p8y+hFh3EI9pcrEWaNvFYonQ==";
|
||||||
|
|
||||||
testHkdfExpand('sha256', prk32Byte, 32, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD8=');
|
testHkdfExpand("sha256", prk32Byte, 32, "BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD8=");
|
||||||
testHkdfExpand('sha256', prk32Byte, 64, 'BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD9BV+' +
|
testHkdfExpand(
|
||||||
'/queOZenPNkDhmlVyL2WZ3OSU5+7ISNF5NhNfvZA==');
|
"sha256",
|
||||||
testHkdfExpand('sha512', prk64Byte, 32, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlk=');
|
prk32Byte,
|
||||||
testHkdfExpand('sha512', prk64Byte, 64, 'uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlkY5Pv0sB+' +
|
64,
|
||||||
'MqvaopmkC6sD/j89zDwTV9Ib2fpucUydO8w==');
|
"BnIqJlfnHm0e/2iB/15cbHyR19ARPIcWRp4oNS22CD9BV+" +
|
||||||
|
"/queOZenPNkDhmlVyL2WZ3OSU5+7ISNF5NhNfvZA=="
|
||||||
|
);
|
||||||
|
testHkdfExpand("sha512", prk64Byte, 32, "uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlk=");
|
||||||
|
testHkdfExpand(
|
||||||
|
"sha512",
|
||||||
|
prk64Byte,
|
||||||
|
64,
|
||||||
|
"uLWbMWodSBms5uGJ5WTRTesyW+MD7nlpCZvagvIRXlkY5Pv0sB+" +
|
||||||
|
"MqvaopmkC6sD/j89zDwTV9Ib2fpucUydO8w=="
|
||||||
|
);
|
||||||
|
|
||||||
it('should fail with prk too small', async () => {
|
it("should fail with prk too small", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk16Byte), 'info', 32, 'sha256');
|
const f = cryptoFunctionService.hkdfExpand(
|
||||||
await expectAsync(f).toBeRejectedWith(new Error('prk is too small.'));
|
Utils.fromB64ToArray(prk16Byte),
|
||||||
|
"info",
|
||||||
|
32,
|
||||||
|
"sha256"
|
||||||
|
);
|
||||||
|
await expectAsync(f).toBeRejectedWith(new Error("prk is too small."));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fail with outputByteSize is too large', async () => {
|
it("should fail with outputByteSize is too large", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const f = cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(prk32Byte), 'info', 8161, 'sha256');
|
const f = cryptoFunctionService.hkdfExpand(
|
||||||
await expectAsync(f).toBeRejectedWith(new Error('outputByteSize is too large.'));
|
Utils.fromB64ToArray(prk32Byte),
|
||||||
|
"info",
|
||||||
|
8161,
|
||||||
|
"sha256"
|
||||||
|
);
|
||||||
|
await expectAsync(f).toBeRejectedWith(new Error("outputByteSize is too large."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hash', () => {
|
describe("hash", () => {
|
||||||
const regular1Hash = '2a241604fb921fad12bf877282457268e1dccb70';
|
const regular1Hash = "2a241604fb921fad12bf877282457268e1dccb70";
|
||||||
const utf81Hash = '85672798dc5831e96d6c48655d3d39365a9c88b6';
|
const utf81Hash = "85672798dc5831e96d6c48655d3d39365a9c88b6";
|
||||||
const unicode1Hash = '39c975935054a3efc805a9709b60763a823a6ad4';
|
const unicode1Hash = "39c975935054a3efc805a9709b60763a823a6ad4";
|
||||||
|
|
||||||
const regular256Hash = '2b8e96031d352a8655d733d7a930b5ffbea69dc25cf65c7bca7dd946278908b2';
|
const regular256Hash = "2b8e96031d352a8655d733d7a930b5ffbea69dc25cf65c7bca7dd946278908b2";
|
||||||
const utf8256Hash = '25fe8440f5b01ed113b0a0e38e721b126d2f3f77a67518c4a04fcde4e33eeb9d';
|
const utf8256Hash = "25fe8440f5b01ed113b0a0e38e721b126d2f3f77a67518c4a04fcde4e33eeb9d";
|
||||||
const unicode256Hash = 'adc1c0c2afd6e92cefdf703f9b6eb2c38e0d6d1a040c83f8505c561fea58852e';
|
const unicode256Hash = "adc1c0c2afd6e92cefdf703f9b6eb2c38e0d6d1a040c83f8505c561fea58852e";
|
||||||
|
|
||||||
const regular512Hash = 'c15cf11d43bde333647e3f559ec4193bb2edeaa0e8b902772f514cdf3f785a3f49a6e02a4b87b3' +
|
const regular512Hash =
|
||||||
'b47523271ad45b7e0aebb5cdcc1bc54815d256eb5dcb80da9d';
|
"c15cf11d43bde333647e3f559ec4193bb2edeaa0e8b902772f514cdf3f785a3f49a6e02a4b87b3" +
|
||||||
const utf8512Hash = '035c31a877a291af09ed2d3a1a293e69c3e079ea2cecc00211f35e6bce10474ca3ad6e30b59e26118' +
|
"b47523271ad45b7e0aebb5cdcc1bc54815d256eb5dcb80da9d";
|
||||||
'37463f20969c5bc95282965a051a88f8cdf2e166549fcdd';
|
const utf8512Hash =
|
||||||
const unicode512Hash = '2b16a5561af8ad6fe414cc103fc8036492e1fc6d9aabe1b655497054f760fe0e34c5d100ac773d' +
|
"035c31a877a291af09ed2d3a1a293e69c3e079ea2cecc00211f35e6bce10474ca3ad6e30b59e26118" +
|
||||||
'9f3030438284f22dbfa20cb2e9b019f2c98dfe38ce1ef41bae';
|
"37463f20969c5bc95282965a051a88f8cdf2e166549fcdd";
|
||||||
|
const unicode512Hash =
|
||||||
|
"2b16a5561af8ad6fe414cc103fc8036492e1fc6d9aabe1b655497054f760fe0e34c5d100ac773d" +
|
||||||
|
"9f3030438284f22dbfa20cb2e9b019f2c98dfe38ce1ef41bae";
|
||||||
|
|
||||||
const regularMd5 = '5eceffa53a5fd58c44134211e2c5f522';
|
const regularMd5 = "5eceffa53a5fd58c44134211e2c5f522";
|
||||||
const utf8Md5 = '3abc9433c09551b939c80aa0aa3174e1';
|
const utf8Md5 = "3abc9433c09551b939c80aa0aa3174e1";
|
||||||
const unicodeMd5 = '85ae134072c8d81257933f7045ba17ca';
|
const unicodeMd5 = "85ae134072c8d81257933f7045ba17ca";
|
||||||
|
|
||||||
testHash('sha1', regular1Hash, utf81Hash, unicode1Hash);
|
testHash("sha1", regular1Hash, utf81Hash, unicode1Hash);
|
||||||
testHash('sha256', regular256Hash, utf8256Hash, unicode256Hash);
|
testHash("sha256", regular256Hash, utf8256Hash, unicode256Hash);
|
||||||
testHash('sha512', regular512Hash, utf8512Hash, unicode512Hash);
|
testHash("sha512", regular512Hash, utf8512Hash, unicode512Hash);
|
||||||
testHash('md5', regularMd5, utf8Md5, unicodeMd5);
|
testHash("md5", regularMd5, utf8Md5, unicodeMd5);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hmac', () => {
|
describe("hmac", () => {
|
||||||
testHmac('sha1', Sha1Mac);
|
testHmac("sha1", Sha1Mac);
|
||||||
testHmac('sha256', Sha256Mac);
|
testHmac("sha256", Sha256Mac);
|
||||||
testHmac('sha512', Sha512Mac);
|
testHmac("sha512", Sha512Mac);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('compare', () => {
|
describe("compare", () => {
|
||||||
it('should successfully compare two of the same values', async () => {
|
it("should successfully compare two of the same values", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -134,7 +164,7 @@ describe('WebCrypto Function Service', () => {
|
|||||||
expect(equal).toBe(true);
|
expect(equal).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully compare two different values of the same length', async () => {
|
it("should successfully compare two different values of the same length", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -146,7 +176,7 @@ describe('WebCrypto Function Service', () => {
|
|||||||
expect(equal).toBe(false);
|
expect(equal).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully compare two different values of different lengths', async () => {
|
it("should successfully compare two different values of different lengths", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -158,14 +188,14 @@ describe('WebCrypto Function Service', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hmacFast', () => {
|
describe("hmacFast", () => {
|
||||||
testHmacFast('sha1', Sha1Mac);
|
testHmacFast("sha1", Sha1Mac);
|
||||||
testHmacFast('sha256', Sha256Mac);
|
testHmacFast("sha256", Sha256Mac);
|
||||||
testHmacFast('sha512', Sha512Mac);
|
testHmacFast("sha512", Sha512Mac);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('compareFast', () => {
|
describe("compareFast", () => {
|
||||||
it('should successfully compare two of the same values', async () => {
|
it("should successfully compare two of the same values", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -175,7 +205,7 @@ describe('WebCrypto Function Service', () => {
|
|||||||
expect(equal).toBe(true);
|
expect(equal).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully compare two different values of the same length', async () => {
|
it("should successfully compare two different values of the same length", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -189,7 +219,7 @@ describe('WebCrypto Function Service', () => {
|
|||||||
expect(equal).toBe(false);
|
expect(equal).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully compare two different values of different lengths', async () => {
|
it("should successfully compare two different values of different lengths", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const a = new Uint8Array(2);
|
const a = new Uint8Array(2);
|
||||||
a[0] = 1;
|
a[0] = 1;
|
||||||
@@ -203,21 +233,21 @@ describe('WebCrypto Function Service', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('aesEncrypt', () => {
|
describe("aesEncrypt", () => {
|
||||||
it('should successfully encrypt data', async () => {
|
it("should successfully encrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const iv = makeStaticByteArray(16);
|
const iv = makeStaticByteArray(16);
|
||||||
const key = makeStaticByteArray(32);
|
const key = makeStaticByteArray(32);
|
||||||
const data = Utils.fromUtf8ToArray('EncryptMe!');
|
const data = Utils.fromUtf8ToArray("EncryptMe!");
|
||||||
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
||||||
expect(Utils.fromBufferToB64(encValue)).toBe('ByUF8vhyX4ddU9gcooznwA==');
|
expect(Utils.fromBufferToB64(encValue)).toBe("ByUF8vhyX4ddU9gcooznwA==");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully encrypt and then decrypt data fast', async () => {
|
it("should successfully encrypt and then decrypt data fast", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const iv = makeStaticByteArray(16);
|
const iv = makeStaticByteArray(16);
|
||||||
const key = makeStaticByteArray(32);
|
const key = makeStaticByteArray(32);
|
||||||
const value = 'EncryptMe!';
|
const value = "EncryptMe!";
|
||||||
const data = Utils.fromUtf8ToArray(value);
|
const data = Utils.fromUtf8ToArray(value);
|
||||||
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
||||||
const encData = Utils.fromBufferToB64(encValue);
|
const encData = Utils.fromBufferToB64(encValue);
|
||||||
@@ -228,11 +258,11 @@ describe('WebCrypto Function Service', () => {
|
|||||||
expect(decValue).toBe(value);
|
expect(decValue).toBe(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully encrypt and then decrypt data', async () => {
|
it("should successfully encrypt and then decrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const iv = makeStaticByteArray(16);
|
const iv = makeStaticByteArray(16);
|
||||||
const key = makeStaticByteArray(32);
|
const key = makeStaticByteArray(32);
|
||||||
const value = 'EncryptMe!';
|
const value = "EncryptMe!";
|
||||||
const data = Utils.fromUtf8ToArray(value);
|
const data = Utils.fromUtf8ToArray(value);
|
||||||
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
const encValue = await cryptoFunctionService.aesEncrypt(data.buffer, iv.buffer, key.buffer);
|
||||||
const decValue = await cryptoFunctionService.aesDecrypt(encValue, iv.buffer, key.buffer);
|
const decValue = await cryptoFunctionService.aesDecrypt(encValue, iv.buffer, key.buffer);
|
||||||
@@ -240,57 +270,59 @@ describe('WebCrypto Function Service', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('aesDecryptFast', () => {
|
describe("aesDecryptFast", () => {
|
||||||
it('should successfully decrypt data', async () => {
|
it("should successfully decrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const iv = Utils.fromBufferToB64(makeStaticByteArray(16).buffer);
|
const iv = Utils.fromBufferToB64(makeStaticByteArray(16).buffer);
|
||||||
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32).buffer);
|
const symKey = new SymmetricCryptoKey(makeStaticByteArray(32).buffer);
|
||||||
const data = 'ByUF8vhyX4ddU9gcooznwA==';
|
const data = "ByUF8vhyX4ddU9gcooznwA==";
|
||||||
const params = cryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
const params = cryptoFunctionService.aesDecryptFastParameters(data, iv, null, symKey);
|
||||||
const decValue = await cryptoFunctionService.aesDecryptFast(params);
|
const decValue = await cryptoFunctionService.aesDecryptFast(params);
|
||||||
expect(decValue).toBe('EncryptMe!');
|
expect(decValue).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('aesDecrypt', () => {
|
describe("aesDecrypt", () => {
|
||||||
it('should successfully decrypt data', async () => {
|
it("should successfully decrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const iv = makeStaticByteArray(16);
|
const iv = makeStaticByteArray(16);
|
||||||
const key = makeStaticByteArray(32);
|
const key = makeStaticByteArray(32);
|
||||||
const data = Utils.fromB64ToArray('ByUF8vhyX4ddU9gcooznwA==');
|
const data = Utils.fromB64ToArray("ByUF8vhyX4ddU9gcooznwA==");
|
||||||
const decValue = await cryptoFunctionService.aesDecrypt(data.buffer, iv.buffer, key.buffer);
|
const decValue = await cryptoFunctionService.aesDecrypt(data.buffer, iv.buffer, key.buffer);
|
||||||
expect(Utils.fromBufferToUtf8(decValue)).toBe('EncryptMe!');
|
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rsaEncrypt', () => {
|
describe("rsaEncrypt", () => {
|
||||||
it('should successfully encrypt and then decrypt data', async () => {
|
it("should successfully encrypt and then decrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const pubKey = Utils.fromB64ToArray(RsaPublicKey);
|
const pubKey = Utils.fromB64ToArray(RsaPublicKey);
|
||||||
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
||||||
const value = 'EncryptMe!';
|
const value = "EncryptMe!";
|
||||||
const data = Utils.fromUtf8ToArray(value);
|
const data = Utils.fromUtf8ToArray(value);
|
||||||
const encValue = await cryptoFunctionService.rsaEncrypt(data.buffer, pubKey.buffer, 'sha1');
|
const encValue = await cryptoFunctionService.rsaEncrypt(data.buffer, pubKey.buffer, "sha1");
|
||||||
const decValue = await cryptoFunctionService.rsaDecrypt(encValue, privKey.buffer, 'sha1');
|
const decValue = await cryptoFunctionService.rsaDecrypt(encValue, privKey.buffer, "sha1");
|
||||||
expect(Utils.fromBufferToUtf8(decValue)).toBe(value);
|
expect(Utils.fromBufferToUtf8(decValue)).toBe(value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rsaDecrypt', () => {
|
describe("rsaDecrypt", () => {
|
||||||
it('should successfully decrypt data', async () => {
|
it("should successfully decrypt data", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
||||||
const data = Utils.fromB64ToArray('A1/p8BQzN9UrbdYxUY2Va5+kPLyfZXF9JsZrjeEXcaclsnHurdxVAJcnbEqYMP3UXV' +
|
const data = Utils.fromB64ToArray(
|
||||||
'4YAS/mpf+Rxe6/X0WS1boQdA0MAHSgx95hIlAraZYpiMLLiJRKeo2u8YivCdTM9V5vuAEJwf9Tof/qFsFci3sApdbATkorCT' +
|
"A1/p8BQzN9UrbdYxUY2Va5+kPLyfZXF9JsZrjeEXcaclsnHurdxVAJcnbEqYMP3UXV" +
|
||||||
'zFOIEPF2S1zgperEP23M01mr4dWVdYN18B32YF67xdJHMbFhp5dkQwv9CmscoWq7OE5HIfOb+JAh7BEZb+CmKhM3yWJvoR/D' +
|
"4YAS/mpf+Rxe6/X0WS1boQdA0MAHSgx95hIlAraZYpiMLLiJRKeo2u8YivCdTM9V5vuAEJwf9Tof/qFsFci3sApdbATkorCT" +
|
||||||
'/5jcercUtK2o+XrzNrL4UQ7yLZcFz6Bfwb/j6ICYvqd/YJwXNE6dwlL57OfwJyCdw2rRYf0/qI00t9u8Iitw==');
|
"zFOIEPF2S1zgperEP23M01mr4dWVdYN18B32YF67xdJHMbFhp5dkQwv9CmscoWq7OE5HIfOb+JAh7BEZb+CmKhM3yWJvoR/D" +
|
||||||
const decValue = await cryptoFunctionService.rsaDecrypt(data.buffer, privKey.buffer, 'sha1');
|
"/5jcercUtK2o+XrzNrL4UQ7yLZcFz6Bfwb/j6ICYvqd/YJwXNE6dwlL57OfwJyCdw2rRYf0/qI00t9u8Iitw=="
|
||||||
expect(Utils.fromBufferToUtf8(decValue)).toBe('EncryptMe!');
|
);
|
||||||
|
const decValue = await cryptoFunctionService.rsaDecrypt(data.buffer, privKey.buffer, "sha1");
|
||||||
|
expect(Utils.fromBufferToUtf8(decValue)).toBe("EncryptMe!");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rsaExtractPublicKey', () => {
|
describe("rsaExtractPublicKey", () => {
|
||||||
it('should successfully extract key', async () => {
|
it("should successfully extract key", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
const privKey = Utils.fromB64ToArray(RsaPrivateKey);
|
||||||
const publicKey = await cryptoFunctionService.rsaExtractPublicKey(privKey.buffer);
|
const publicKey = await cryptoFunctionService.rsaExtractPublicKey(privKey.buffer);
|
||||||
@@ -298,7 +330,7 @@ describe('WebCrypto Function Service', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('rsaGenerateKeyPair', () => {
|
describe("rsaGenerateKeyPair", () => {
|
||||||
testRsaGenerateKeyPair(1024);
|
testRsaGenerateKeyPair(1024);
|
||||||
testRsaGenerateKeyPair(2048);
|
testRsaGenerateKeyPair(2048);
|
||||||
|
|
||||||
@@ -306,171 +338,222 @@ describe('WebCrypto Function Service', () => {
|
|||||||
// testRsaGenerateKeyPair(4096);
|
// testRsaGenerateKeyPair(4096);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('randomBytes', () => {
|
describe("randomBytes", () => {
|
||||||
it('should make a value of the correct length', async () => {
|
it("should make a value of the correct length", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const randomData = await cryptoFunctionService.randomBytes(16);
|
const randomData = await cryptoFunctionService.randomBytes(16);
|
||||||
expect(randomData.byteLength).toBe(16);
|
expect(randomData.byteLength).toBe(16);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not make the same value twice', async () => {
|
it("should not make the same value twice", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const randomData = await cryptoFunctionService.randomBytes(16);
|
const randomData = await cryptoFunctionService.randomBytes(16);
|
||||||
const randomData2 = await cryptoFunctionService.randomBytes(16);
|
const randomData2 = await cryptoFunctionService.randomBytes(16);
|
||||||
expect(randomData.byteLength === randomData2.byteLength && randomData !== randomData2).toBeTruthy();
|
expect(
|
||||||
|
randomData.byteLength === randomData2.byteLength && randomData !== randomData2
|
||||||
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function testPbkdf2(algorithm: 'sha256' | 'sha512', regularKey: string,
|
function testPbkdf2(
|
||||||
utf8Key: string, unicodeKey: string) {
|
algorithm: "sha256" | "sha512",
|
||||||
const regularEmail = 'user@example.com';
|
regularKey: string,
|
||||||
const utf8Email = 'üser@example.com';
|
utf8Key: string,
|
||||||
|
unicodeKey: string
|
||||||
|
) {
|
||||||
|
const regularEmail = "user@example.com";
|
||||||
|
const utf8Email = "üser@example.com";
|
||||||
|
|
||||||
const regularPassword = 'password';
|
const regularPassword = "password";
|
||||||
const utf8Password = 'pǻssword';
|
const utf8Password = "pǻssword";
|
||||||
const unicodePassword = '😀password🙏';
|
const unicodePassword = "😀password🙏";
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from regular input', async () => {
|
it("should create valid " + algorithm + " key from regular input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.pbkdf2(regularPassword, regularEmail, algorithm, 5000);
|
const key = await cryptoFunctionService.pbkdf2(regularPassword, regularEmail, algorithm, 5000);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from utf8 input', async () => {
|
it("should create valid " + algorithm + " key from utf8 input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.pbkdf2(utf8Password, utf8Email, algorithm, 5000);
|
const key = await cryptoFunctionService.pbkdf2(utf8Password, utf8Email, algorithm, 5000);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from unicode input', async () => {
|
it("should create valid " + algorithm + " key from unicode input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.pbkdf2(unicodePassword, regularEmail, algorithm, 5000);
|
const key = await cryptoFunctionService.pbkdf2(unicodePassword, regularEmail, algorithm, 5000);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from array buffer input', async () => {
|
it("should create valid " + algorithm + " key from array buffer input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.pbkdf2(Utils.fromUtf8ToArray(regularPassword).buffer,
|
const key = await cryptoFunctionService.pbkdf2(
|
||||||
Utils.fromUtf8ToArray(regularEmail).buffer, algorithm, 5000);
|
Utils.fromUtf8ToArray(regularPassword).buffer,
|
||||||
|
Utils.fromUtf8ToArray(regularEmail).buffer,
|
||||||
|
algorithm,
|
||||||
|
5000
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHkdf(algorithm: 'sha256' | 'sha512', regularKey: string, utf8Key: string, unicodeKey: string) {
|
function testHkdf(
|
||||||
const ikm = Utils.fromB64ToArray('criAmKtfzxanbgea5/kelQ==');
|
algorithm: "sha256" | "sha512",
|
||||||
|
regularKey: string,
|
||||||
|
utf8Key: string,
|
||||||
|
unicodeKey: string
|
||||||
|
) {
|
||||||
|
const ikm = Utils.fromB64ToArray("criAmKtfzxanbgea5/kelQ==");
|
||||||
|
|
||||||
const regularSalt = 'salt';
|
const regularSalt = "salt";
|
||||||
const utf8Salt = 'üser_salt';
|
const utf8Salt = "üser_salt";
|
||||||
const unicodeSalt = '😀salt🙏';
|
const unicodeSalt = "😀salt🙏";
|
||||||
|
|
||||||
const regularInfo = 'info';
|
const regularInfo = "info";
|
||||||
const utf8Info = 'üser_info';
|
const utf8Info = "üser_info";
|
||||||
const unicodeInfo = '😀info🙏';
|
const unicodeInfo = "😀info🙏";
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from regular input', async () => {
|
it("should create valid " + algorithm + " key from regular input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.hkdf(ikm, regularSalt, regularInfo, 32, algorithm);
|
const key = await cryptoFunctionService.hkdf(ikm, regularSalt, regularInfo, 32, algorithm);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from utf8 input', async () => {
|
it("should create valid " + algorithm + " key from utf8 input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.hkdf(ikm, utf8Salt, utf8Info, 32, algorithm);
|
const key = await cryptoFunctionService.hkdf(ikm, utf8Salt, utf8Info, 32, algorithm);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
expect(Utils.fromBufferToB64(key)).toBe(utf8Key);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from unicode input', async () => {
|
it("should create valid " + algorithm + " key from unicode input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.hkdf(ikm, unicodeSalt, unicodeInfo, 32, algorithm);
|
const key = await cryptoFunctionService.hkdf(ikm, unicodeSalt, unicodeInfo, 32, algorithm);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
expect(Utils.fromBufferToB64(key)).toBe(unicodeKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' key from array buffer input', async () => {
|
it("should create valid " + algorithm + " key from array buffer input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const key = await cryptoFunctionService.hkdf(ikm, Utils.fromUtf8ToArray(regularSalt).buffer,
|
const key = await cryptoFunctionService.hkdf(
|
||||||
Utils.fromUtf8ToArray(regularInfo).buffer, 32, algorithm);
|
ikm,
|
||||||
|
Utils.fromUtf8ToArray(regularSalt).buffer,
|
||||||
|
Utils.fromUtf8ToArray(regularInfo).buffer,
|
||||||
|
32,
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
expect(Utils.fromBufferToB64(key)).toBe(regularKey);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHkdfExpand(algorithm: 'sha256' | 'sha512', b64prk: string, outputByteSize: number,
|
function testHkdfExpand(
|
||||||
b64ExpectedOkm: string) {
|
algorithm: "sha256" | "sha512",
|
||||||
const info = 'info';
|
b64prk: string,
|
||||||
|
outputByteSize: number,
|
||||||
|
b64ExpectedOkm: string
|
||||||
|
) {
|
||||||
|
const info = "info";
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' ' + outputByteSize + ' byte okm', async () => {
|
it("should create valid " + algorithm + " " + outputByteSize + " byte okm", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const okm = await cryptoFunctionService.hkdfExpand(Utils.fromB64ToArray(b64prk), info, outputByteSize,
|
const okm = await cryptoFunctionService.hkdfExpand(
|
||||||
algorithm);
|
Utils.fromB64ToArray(b64prk),
|
||||||
|
info,
|
||||||
|
outputByteSize,
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToB64(okm)).toBe(b64ExpectedOkm);
|
expect(Utils.fromBufferToB64(okm)).toBe(b64ExpectedOkm);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHash(algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5', regularHash: string,
|
function testHash(
|
||||||
utf8Hash: string, unicodeHash: string) {
|
algorithm: "sha1" | "sha256" | "sha512" | "md5",
|
||||||
const regularValue = 'HashMe!!';
|
regularHash: string,
|
||||||
const utf8Value = 'HǻshMe!!';
|
utf8Hash: string,
|
||||||
const unicodeValue = '😀HashMe!!!🙏';
|
unicodeHash: string
|
||||||
|
) {
|
||||||
|
const regularValue = "HashMe!!";
|
||||||
|
const utf8Value = "HǻshMe!!";
|
||||||
|
const unicodeValue = "😀HashMe!!!🙏";
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' hash from regular input', async () => {
|
it("should create valid " + algorithm + " hash from regular input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const hash = await cryptoFunctionService.hash(regularValue, algorithm);
|
const hash = await cryptoFunctionService.hash(regularValue, algorithm);
|
||||||
expect(Utils.fromBufferToHex(hash)).toBe(regularHash);
|
expect(Utils.fromBufferToHex(hash)).toBe(regularHash);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' hash from utf8 input', async () => {
|
it("should create valid " + algorithm + " hash from utf8 input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const hash = await cryptoFunctionService.hash(utf8Value, algorithm);
|
const hash = await cryptoFunctionService.hash(utf8Value, algorithm);
|
||||||
expect(Utils.fromBufferToHex(hash)).toBe(utf8Hash);
|
expect(Utils.fromBufferToHex(hash)).toBe(utf8Hash);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' hash from unicode input', async () => {
|
it("should create valid " + algorithm + " hash from unicode input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const hash = await cryptoFunctionService.hash(unicodeValue, algorithm);
|
const hash = await cryptoFunctionService.hash(unicodeValue, algorithm);
|
||||||
expect(Utils.fromBufferToHex(hash)).toBe(unicodeHash);
|
expect(Utils.fromBufferToHex(hash)).toBe(unicodeHash);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create valid ' + algorithm + ' hash from array buffer input', async () => {
|
it("should create valid " + algorithm + " hash from array buffer input", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const hash = await cryptoFunctionService.hash(Utils.fromUtf8ToArray(regularValue).buffer, algorithm);
|
const hash = await cryptoFunctionService.hash(
|
||||||
|
Utils.fromUtf8ToArray(regularValue).buffer,
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToHex(hash)).toBe(regularHash);
|
expect(Utils.fromBufferToHex(hash)).toBe(regularHash);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHmac(algorithm: 'sha1' | 'sha256' | 'sha512', mac: string) {
|
function testHmac(algorithm: "sha1" | "sha256" | "sha512", mac: string) {
|
||||||
it('should create valid ' + algorithm + ' hmac', async () => {
|
it("should create valid " + algorithm + " hmac", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const computedMac = await cryptoFunctionService.hmac(Utils.fromUtf8ToArray('SignMe!!').buffer,
|
const computedMac = await cryptoFunctionService.hmac(
|
||||||
Utils.fromUtf8ToArray('secretkey').buffer, algorithm);
|
Utils.fromUtf8ToArray("SignMe!!").buffer,
|
||||||
|
Utils.fromUtf8ToArray("secretkey").buffer,
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToHex(computedMac)).toBe(mac);
|
expect(Utils.fromBufferToHex(computedMac)).toBe(mac);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHmacFast(algorithm: 'sha1' | 'sha256' | 'sha512', mac: string) {
|
function testHmacFast(algorithm: "sha1" | "sha256" | "sha512", mac: string) {
|
||||||
it('should create valid ' + algorithm + ' hmac', async () => {
|
it("should create valid " + algorithm + " hmac", async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const keyByteString = Utils.fromBufferToByteString(Utils.fromUtf8ToArray('secretkey').buffer);
|
const keyByteString = Utils.fromBufferToByteString(Utils.fromUtf8ToArray("secretkey").buffer);
|
||||||
const dataByteString = Utils.fromBufferToByteString(Utils.fromUtf8ToArray('SignMe!!').buffer);
|
const dataByteString = Utils.fromBufferToByteString(Utils.fromUtf8ToArray("SignMe!!").buffer);
|
||||||
const computedMac = await cryptoFunctionService.hmacFast(dataByteString, keyByteString, algorithm);
|
const computedMac = await cryptoFunctionService.hmacFast(
|
||||||
|
dataByteString,
|
||||||
|
keyByteString,
|
||||||
|
algorithm
|
||||||
|
);
|
||||||
expect(Utils.fromBufferToHex(Utils.fromByteStringToArray(computedMac).buffer)).toBe(mac);
|
expect(Utils.fromBufferToHex(Utils.fromByteStringToArray(computedMac).buffer)).toBe(mac);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function testRsaGenerateKeyPair(length: 1024 | 2048 | 4096) {
|
function testRsaGenerateKeyPair(length: 1024 | 2048 | 4096) {
|
||||||
it('should successfully generate a ' + length + ' bit key pair', async () => {
|
it(
|
||||||
|
"should successfully generate a " + length + " bit key pair",
|
||||||
|
async () => {
|
||||||
const cryptoFunctionService = getWebCryptoFunctionService();
|
const cryptoFunctionService = getWebCryptoFunctionService();
|
||||||
const keyPair = await cryptoFunctionService.rsaGenerateKeyPair(length);
|
const keyPair = await cryptoFunctionService.rsaGenerateKeyPair(length);
|
||||||
expect(keyPair[0] == null || keyPair[1] == null).toBe(false);
|
expect(keyPair[0] == null || keyPair[1] == null).toBe(false);
|
||||||
const publicKey = await cryptoFunctionService.rsaExtractPublicKey(keyPair[1]);
|
const publicKey = await cryptoFunctionService.rsaExtractPublicKey(keyPair[1]);
|
||||||
expect(Utils.fromBufferToB64(keyPair[0])).toBe(Utils.fromBufferToB64(publicKey));
|
expect(Utils.fromBufferToB64(keyPair[0])).toBe(Utils.fromBufferToB64(publicKey));
|
||||||
}, 30000);
|
},
|
||||||
|
30000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWebCryptoFunctionService() {
|
function getWebCryptoFunctionService() {
|
||||||
const platformUtilsMock = Substitute.for<PlatformUtilsService>();
|
const platformUtilsMock = Substitute.for<PlatformUtilsService>();
|
||||||
platformUtilsMock.isEdge().mimicks(() => navigator.userAgent.indexOf(' Edg/') !== -1);
|
platformUtilsMock.isEdge().mimicks(() => navigator.userAgent.indexOf(" Edg/") !== -1);
|
||||||
platformUtilsMock.isIE().mimicks(() => navigator.userAgent.indexOf(' Edg/') === -1 &&
|
platformUtilsMock
|
||||||
navigator.userAgent.indexOf(' Trident/') !== -1);
|
.isIE()
|
||||||
|
.mimicks(
|
||||||
|
() =>
|
||||||
|
navigator.userAgent.indexOf(" Edg/") === -1 &&
|
||||||
|
navigator.userAgent.indexOf(" Trident/") !== -1
|
||||||
|
);
|
||||||
|
|
||||||
return new WebCryptoFunctionService(window, platformUtilsMock);
|
return new WebCryptoFunctionService(window, platformUtilsMock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,170 +1,178 @@
|
|||||||
import { PolicyType } from '../enums/policyType';
|
import { PolicyType } from "../enums/policyType";
|
||||||
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
|
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
||||||
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
|
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 { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
||||||
import { CipherBulkDeleteRequest } from '../models/request/cipherBulkDeleteRequest';
|
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
||||||
import { CipherBulkMoveRequest } from '../models/request/cipherBulkMoveRequest';
|
import { CipherBulkMoveRequest } from "../models/request/cipherBulkMoveRequest";
|
||||||
import { CipherBulkRestoreRequest } from '../models/request/cipherBulkRestoreRequest';
|
import { CipherBulkRestoreRequest } from "../models/request/cipherBulkRestoreRequest";
|
||||||
import { CipherBulkShareRequest } from '../models/request/cipherBulkShareRequest';
|
import { CipherBulkShareRequest } from "../models/request/cipherBulkShareRequest";
|
||||||
import { CipherCollectionsRequest } from '../models/request/cipherCollectionsRequest';
|
import { CipherCollectionsRequest } from "../models/request/cipherCollectionsRequest";
|
||||||
import { CipherCreateRequest } from '../models/request/cipherCreateRequest';
|
import { CipherCreateRequest } from "../models/request/cipherCreateRequest";
|
||||||
import { CipherRequest } from '../models/request/cipherRequest';
|
import { CipherRequest } from "../models/request/cipherRequest";
|
||||||
import { CipherShareRequest } from '../models/request/cipherShareRequest';
|
import { CipherShareRequest } from "../models/request/cipherShareRequest";
|
||||||
import { CollectionRequest } from '../models/request/collectionRequest';
|
import { CollectionRequest } from "../models/request/collectionRequest";
|
||||||
import { DeleteRecoverRequest } from '../models/request/deleteRecoverRequest';
|
import { DeleteRecoverRequest } from "../models/request/deleteRecoverRequest";
|
||||||
import { EmailRequest } from '../models/request/emailRequest';
|
import { EmailRequest } from "../models/request/emailRequest";
|
||||||
import { EmailTokenRequest } from '../models/request/emailTokenRequest';
|
import { EmailTokenRequest } from "../models/request/emailTokenRequest";
|
||||||
import { EmergencyAccessAcceptRequest } from '../models/request/emergencyAccessAcceptRequest';
|
import { EmergencyAccessAcceptRequest } from "../models/request/emergencyAccessAcceptRequest";
|
||||||
import { EmergencyAccessConfirmRequest } from '../models/request/emergencyAccessConfirmRequest';
|
import { EmergencyAccessConfirmRequest } from "../models/request/emergencyAccessConfirmRequest";
|
||||||
import { EmergencyAccessInviteRequest } from '../models/request/emergencyAccessInviteRequest';
|
import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessInviteRequest";
|
||||||
import { EmergencyAccessPasswordRequest } from '../models/request/emergencyAccessPasswordRequest';
|
import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest";
|
||||||
import { EmergencyAccessUpdateRequest } from '../models/request/emergencyAccessUpdateRequest';
|
import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest";
|
||||||
import { EventRequest } from '../models/request/eventRequest';
|
import { EventRequest } from "../models/request/eventRequest";
|
||||||
import { FolderRequest } from '../models/request/folderRequest';
|
import { FolderRequest } from "../models/request/folderRequest";
|
||||||
import { GroupRequest } from '../models/request/groupRequest';
|
import { GroupRequest } from "../models/request/groupRequest";
|
||||||
import { IapCheckRequest } from '../models/request/iapCheckRequest';
|
import { IapCheckRequest } from "../models/request/iapCheckRequest";
|
||||||
import { ImportCiphersRequest } from '../models/request/importCiphersRequest';
|
import { ImportCiphersRequest } from "../models/request/importCiphersRequest";
|
||||||
import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest';
|
import { ImportDirectoryRequest } from "../models/request/importDirectoryRequest";
|
||||||
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
|
import { ImportOrganizationCiphersRequest } from "../models/request/importOrganizationCiphersRequest";
|
||||||
import { KdfRequest } from '../models/request/kdfRequest';
|
import { KdfRequest } from "../models/request/kdfRequest";
|
||||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
import { KeyConnectorUserKeyRequest } from "../models/request/keyConnectorUserKeyRequest";
|
||||||
import { KeysRequest } from '../models/request/keysRequest';
|
import { KeysRequest } from "../models/request/keysRequest";
|
||||||
import { OrganizationSponsorshipCreateRequest } from '../models/request/organization/organizationSponsorshipCreateRequest';
|
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organizationSponsorshipCreateRequest";
|
||||||
import { OrganizationSponsorshipRedeemRequest } from '../models/request/organization/organizationSponsorshipRedeemRequest';
|
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organizationSponsorshipRedeemRequest";
|
||||||
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
|
import { OrganizationSsoRequest } from "../models/request/organization/organizationSsoRequest";
|
||||||
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
|
import { OrganizationCreateRequest } from "../models/request/organizationCreateRequest";
|
||||||
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
|
import { OrganizationImportRequest } from "../models/request/organizationImportRequest";
|
||||||
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
|
import { OrganizationKeysRequest } from "../models/request/organizationKeysRequest";
|
||||||
import { OrganizationSubscriptionUpdateRequest } from '../models/request/organizationSubscriptionUpdateRequest';
|
import { OrganizationSubscriptionUpdateRequest } from "../models/request/organizationSubscriptionUpdateRequest";
|
||||||
import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
|
import { OrganizationTaxInfoUpdateRequest } from "../models/request/organizationTaxInfoUpdateRequest";
|
||||||
import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
|
import { OrganizationUpdateRequest } from "../models/request/organizationUpdateRequest";
|
||||||
import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
|
import { OrganizationUpgradeRequest } from "../models/request/organizationUpgradeRequest";
|
||||||
import { OrganizationUserAcceptRequest } from '../models/request/organizationUserAcceptRequest';
|
import { OrganizationUserAcceptRequest } from "../models/request/organizationUserAcceptRequest";
|
||||||
import { OrganizationUserBulkConfirmRequest } from '../models/request/organizationUserBulkConfirmRequest';
|
import { OrganizationUserBulkConfirmRequest } from "../models/request/organizationUserBulkConfirmRequest";
|
||||||
import { OrganizationUserBulkRequest } from '../models/request/organizationUserBulkRequest';
|
import { OrganizationUserBulkRequest } from "../models/request/organizationUserBulkRequest";
|
||||||
import { OrganizationUserConfirmRequest } from '../models/request/organizationUserConfirmRequest';
|
import { OrganizationUserConfirmRequest } from "../models/request/organizationUserConfirmRequest";
|
||||||
import { OrganizationUserInviteRequest } from '../models/request/organizationUserInviteRequest';
|
import { OrganizationUserInviteRequest } from "../models/request/organizationUserInviteRequest";
|
||||||
import { OrganizationUserResetPasswordEnrollmentRequest } from '../models/request/organizationUserResetPasswordEnrollmentRequest';
|
import { OrganizationUserResetPasswordEnrollmentRequest } from "../models/request/organizationUserResetPasswordEnrollmentRequest";
|
||||||
import { OrganizationUserResetPasswordRequest } from '../models/request/organizationUserResetPasswordRequest';
|
import { OrganizationUserResetPasswordRequest } from "../models/request/organizationUserResetPasswordRequest";
|
||||||
import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizationUserUpdateGroupsRequest';
|
import { OrganizationUserUpdateGroupsRequest } from "../models/request/organizationUserUpdateGroupsRequest";
|
||||||
import { OrganizationUserUpdateRequest } from '../models/request/organizationUserUpdateRequest';
|
import { OrganizationUserUpdateRequest } from "../models/request/organizationUserUpdateRequest";
|
||||||
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
|
||||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
import { PasswordRequest } from "../models/request/passwordRequest";
|
||||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
import { PaymentRequest } from "../models/request/paymentRequest";
|
||||||
import { PolicyRequest } from '../models/request/policyRequest';
|
import { PolicyRequest } from "../models/request/policyRequest";
|
||||||
import { PreloginRequest } from '../models/request/preloginRequest';
|
import { PreloginRequest } from "../models/request/preloginRequest";
|
||||||
import { ProviderAddOrganizationRequest } from '../models/request/provider/providerAddOrganizationRequest';
|
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
|
||||||
import { ProviderOrganizationCreateRequest } from '../models/request/provider/providerOrganizationCreateRequest';
|
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
|
||||||
import { ProviderSetupRequest } from '../models/request/provider/providerSetupRequest';
|
import { ProviderSetupRequest } from "../models/request/provider/providerSetupRequest";
|
||||||
import { ProviderUpdateRequest } from '../models/request/provider/providerUpdateRequest';
|
import { ProviderUpdateRequest } from "../models/request/provider/providerUpdateRequest";
|
||||||
import { ProviderUserAcceptRequest } from '../models/request/provider/providerUserAcceptRequest';
|
import { ProviderUserAcceptRequest } from "../models/request/provider/providerUserAcceptRequest";
|
||||||
import { ProviderUserBulkConfirmRequest } from '../models/request/provider/providerUserBulkConfirmRequest';
|
import { ProviderUserBulkConfirmRequest } from "../models/request/provider/providerUserBulkConfirmRequest";
|
||||||
import { ProviderUserBulkRequest } from '../models/request/provider/providerUserBulkRequest';
|
import { ProviderUserBulkRequest } from "../models/request/provider/providerUserBulkRequest";
|
||||||
import { ProviderUserConfirmRequest } from '../models/request/provider/providerUserConfirmRequest';
|
import { ProviderUserConfirmRequest } from "../models/request/provider/providerUserConfirmRequest";
|
||||||
import { ProviderUserInviteRequest } from '../models/request/provider/providerUserInviteRequest';
|
import { ProviderUserInviteRequest } from "../models/request/provider/providerUserInviteRequest";
|
||||||
import { ProviderUserUpdateRequest } from '../models/request/provider/providerUserUpdateRequest';
|
import { ProviderUserUpdateRequest } from "../models/request/provider/providerUserUpdateRequest";
|
||||||
import { RegisterRequest } from '../models/request/registerRequest';
|
import { RegisterRequest } from "../models/request/registerRequest";
|
||||||
import { SeatRequest } from '../models/request/seatRequest';
|
import { SeatRequest } from "../models/request/seatRequest";
|
||||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
|
||||||
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
|
import { SelectionReadOnlyRequest } from "../models/request/selectionReadOnlyRequest";
|
||||||
import { SendAccessRequest } from '../models/request/sendAccessRequest';
|
import { SendAccessRequest } from "../models/request/sendAccessRequest";
|
||||||
import { SendRequest } from '../models/request/sendRequest';
|
import { SendRequest } from "../models/request/sendRequest";
|
||||||
import { SetPasswordRequest } from '../models/request/setPasswordRequest';
|
import { SetPasswordRequest } from "../models/request/setPasswordRequest";
|
||||||
import { StorageRequest } from '../models/request/storageRequest';
|
import { StorageRequest } from "../models/request/storageRequest";
|
||||||
import { TaxInfoUpdateRequest } from '../models/request/taxInfoUpdateRequest';
|
import { TaxInfoUpdateRequest } from "../models/request/taxInfoUpdateRequest";
|
||||||
import { TokenRequest } from '../models/request/tokenRequest';
|
import { TokenRequest } from "../models/request/tokenRequest";
|
||||||
import { TwoFactorEmailRequest } from '../models/request/twoFactorEmailRequest';
|
import { TwoFactorEmailRequest } from "../models/request/twoFactorEmailRequest";
|
||||||
import { TwoFactorProviderRequest } from '../models/request/twoFactorProviderRequest';
|
import { TwoFactorProviderRequest } from "../models/request/twoFactorProviderRequest";
|
||||||
import { TwoFactorRecoveryRequest } from '../models/request/twoFactorRecoveryRequest';
|
import { TwoFactorRecoveryRequest } from "../models/request/twoFactorRecoveryRequest";
|
||||||
import { UpdateDomainsRequest } from '../models/request/updateDomainsRequest';
|
import { UpdateDomainsRequest } from "../models/request/updateDomainsRequest";
|
||||||
import { UpdateKeyRequest } from '../models/request/updateKeyRequest';
|
import { UpdateKeyRequest } from "../models/request/updateKeyRequest";
|
||||||
import { UpdateProfileRequest } from '../models/request/updateProfileRequest';
|
import { UpdateProfileRequest } from "../models/request/updateProfileRequest";
|
||||||
import { UpdateTempPasswordRequest } from '../models/request/updateTempPasswordRequest';
|
import { UpdateTempPasswordRequest } from "../models/request/updateTempPasswordRequest";
|
||||||
import { UpdateTwoFactorAuthenticatorRequest } from '../models/request/updateTwoFactorAuthenticatorRequest';
|
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/updateTwoFactorAuthenticatorRequest";
|
||||||
import { UpdateTwoFactorDuoRequest } from '../models/request/updateTwoFactorDuoRequest';
|
import { UpdateTwoFactorDuoRequest } from "../models/request/updateTwoFactorDuoRequest";
|
||||||
import { UpdateTwoFactorEmailRequest } from '../models/request/updateTwoFactorEmailRequest';
|
import { UpdateTwoFactorEmailRequest } from "../models/request/updateTwoFactorEmailRequest";
|
||||||
import { UpdateTwoFactorWebAuthnDeleteRequest } from '../models/request/updateTwoFactorWebAuthnDeleteRequest';
|
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/updateTwoFactorWebAuthnDeleteRequest";
|
||||||
import { UpdateTwoFactorWebAuthnRequest } from '../models/request/updateTwoFactorWebAuthnRequest';
|
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/updateTwoFactorWebAuthnRequest";
|
||||||
import { UpdateTwoFactorYubioOtpRequest } from '../models/request/updateTwoFactorYubioOtpRequest';
|
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/updateTwoFactorYubioOtpRequest";
|
||||||
import { VerifyBankRequest } from '../models/request/verifyBankRequest';
|
import { VerifyBankRequest } from "../models/request/verifyBankRequest";
|
||||||
import { VerifyDeleteRecoverRequest } from '../models/request/verifyDeleteRecoverRequest';
|
import { VerifyDeleteRecoverRequest } from "../models/request/verifyDeleteRecoverRequest";
|
||||||
import { VerifyEmailRequest } from '../models/request/verifyEmailRequest';
|
import { VerifyEmailRequest } from "../models/request/verifyEmailRequest";
|
||||||
|
|
||||||
import { ApiKeyResponse } from '../models/response/apiKeyResponse';
|
import { ApiKeyResponse } from "../models/response/apiKeyResponse";
|
||||||
import { AttachmentResponse } from '../models/response/attachmentResponse';
|
import { AttachmentResponse } from "../models/response/attachmentResponse";
|
||||||
import { AttachmentUploadDataResponse } from '../models/response/attachmentUploadDataResponse';
|
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
|
||||||
import { BillingResponse } from '../models/response/billingResponse';
|
import { BillingResponse } from "../models/response/billingResponse";
|
||||||
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
|
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
|
||||||
import { CipherResponse } from '../models/response/cipherResponse';
|
import { CipherResponse } from "../models/response/cipherResponse";
|
||||||
import {
|
import {
|
||||||
CollectionGroupDetailsResponse,
|
CollectionGroupDetailsResponse,
|
||||||
CollectionResponse,
|
CollectionResponse,
|
||||||
} from '../models/response/collectionResponse';
|
} from "../models/response/collectionResponse";
|
||||||
import { DomainsResponse } from '../models/response/domainsResponse';
|
import { DomainsResponse } from "../models/response/domainsResponse";
|
||||||
import {
|
import {
|
||||||
EmergencyAccessGranteeDetailsResponse,
|
EmergencyAccessGranteeDetailsResponse,
|
||||||
EmergencyAccessGrantorDetailsResponse,
|
EmergencyAccessGrantorDetailsResponse,
|
||||||
EmergencyAccessTakeoverResponse,
|
EmergencyAccessTakeoverResponse,
|
||||||
EmergencyAccessViewResponse
|
EmergencyAccessViewResponse,
|
||||||
} from '../models/response/emergencyAccessResponse';
|
} from "../models/response/emergencyAccessResponse";
|
||||||
import { EventResponse } from '../models/response/eventResponse';
|
import { EventResponse } from "../models/response/eventResponse";
|
||||||
import { FolderResponse } from '../models/response/folderResponse';
|
import { FolderResponse } from "../models/response/folderResponse";
|
||||||
import {
|
import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse";
|
||||||
GroupDetailsResponse,
|
import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse";
|
||||||
GroupResponse,
|
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
||||||
} from '../models/response/groupResponse';
|
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
||||||
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
|
import { KeyConnectorUserKeyResponse } from "../models/response/keyConnectorUserKeyResponse";
|
||||||
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
|
import { ListResponse } from "../models/response/listResponse";
|
||||||
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
|
import { OrganizationSsoResponse } from "../models/response/organization/organizationSsoResponse";
|
||||||
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
|
import { OrganizationAutoEnrollStatusResponse } from "../models/response/organizationAutoEnrollStatusResponse";
|
||||||
import { ListResponse } from '../models/response/listResponse';
|
import { OrganizationKeysResponse } from "../models/response/organizationKeysResponse";
|
||||||
import { OrganizationSsoResponse } from '../models/response/organization/organizationSsoResponse';
|
import { OrganizationResponse } from "../models/response/organizationResponse";
|
||||||
import { OrganizationAutoEnrollStatusResponse } from '../models/response/organizationAutoEnrollStatusResponse';
|
import { OrganizationSubscriptionResponse } from "../models/response/organizationSubscriptionResponse";
|
||||||
import { OrganizationKeysResponse } from '../models/response/organizationKeysResponse';
|
import { OrganizationUserBulkPublicKeyResponse } from "../models/response/organizationUserBulkPublicKeyResponse";
|
||||||
import { OrganizationResponse } from '../models/response/organizationResponse';
|
import { OrganizationUserBulkResponse } from "../models/response/organizationUserBulkResponse";
|
||||||
import { OrganizationSubscriptionResponse } from '../models/response/organizationSubscriptionResponse';
|
|
||||||
import { OrganizationUserBulkPublicKeyResponse } from '../models/response/organizationUserBulkPublicKeyResponse';
|
|
||||||
import { OrganizationUserBulkResponse } from '../models/response/organizationUserBulkResponse';
|
|
||||||
import {
|
import {
|
||||||
OrganizationUserDetailsResponse,
|
OrganizationUserDetailsResponse,
|
||||||
OrganizationUserResetPasswordDetailsReponse,
|
OrganizationUserResetPasswordDetailsReponse,
|
||||||
OrganizationUserUserDetailsResponse,
|
OrganizationUserUserDetailsResponse,
|
||||||
} from '../models/response/organizationUserResponse';
|
} from "../models/response/organizationUserResponse";
|
||||||
import { PaymentResponse } from '../models/response/paymentResponse';
|
import { PaymentResponse } from "../models/response/paymentResponse";
|
||||||
import { PlanResponse } from '../models/response/planResponse';
|
import { PlanResponse } from "../models/response/planResponse";
|
||||||
import { PolicyResponse } from '../models/response/policyResponse';
|
import { PolicyResponse } from "../models/response/policyResponse";
|
||||||
import { PreloginResponse } from '../models/response/preloginResponse';
|
import { PreloginResponse } from "../models/response/preloginResponse";
|
||||||
import { ProfileResponse } from '../models/response/profileResponse';
|
import { ProfileResponse } from "../models/response/profileResponse";
|
||||||
import { ProviderOrganizationOrganizationDetailsResponse, ProviderOrganizationResponse } from '../models/response/provider/providerOrganizationResponse';
|
import {
|
||||||
import { ProviderResponse } from '../models/response/provider/providerResponse';
|
ProviderOrganizationOrganizationDetailsResponse,
|
||||||
import { ProviderUserBulkPublicKeyResponse } from '../models/response/provider/providerUserBulkPublicKeyResponse';
|
ProviderOrganizationResponse,
|
||||||
import { ProviderUserBulkResponse } from '../models/response/provider/providerUserBulkResponse';
|
} from "../models/response/provider/providerOrganizationResponse";
|
||||||
import { ProviderUserResponse, ProviderUserUserDetailsResponse } from '../models/response/provider/providerUserResponse';
|
import { ProviderResponse } from "../models/response/provider/providerResponse";
|
||||||
import { SelectionReadOnlyResponse } from '../models/response/selectionReadOnlyResponse';
|
import { ProviderUserBulkPublicKeyResponse } from "../models/response/provider/providerUserBulkPublicKeyResponse";
|
||||||
import { SendAccessResponse } from '../models/response/sendAccessResponse';
|
import { ProviderUserBulkResponse } from "../models/response/provider/providerUserBulkResponse";
|
||||||
import { SendFileDownloadDataResponse } from '../models/response/sendFileDownloadDataResponse';
|
import {
|
||||||
import { SendFileUploadDataResponse } from '../models/response/sendFileUploadDataResponse';
|
ProviderUserResponse,
|
||||||
import { SendResponse } from '../models/response/sendResponse';
|
ProviderUserUserDetailsResponse,
|
||||||
import { SubscriptionResponse } from '../models/response/subscriptionResponse';
|
} from "../models/response/provider/providerUserResponse";
|
||||||
import { SyncResponse } from '../models/response/syncResponse';
|
import { SelectionReadOnlyResponse } from "../models/response/selectionReadOnlyResponse";
|
||||||
import { TaxInfoResponse } from '../models/response/taxInfoResponse';
|
import { SendAccessResponse } from "../models/response/sendAccessResponse";
|
||||||
import { TaxRateResponse } from '../models/response/taxRateResponse';
|
import { SendFileDownloadDataResponse } from "../models/response/sendFileDownloadDataResponse";
|
||||||
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
|
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
|
||||||
import { TwoFactorDuoResponse } from '../models/response/twoFactorDuoResponse';
|
import { SendResponse } from "../models/response/sendResponse";
|
||||||
import { TwoFactorEmailResponse } from '../models/response/twoFactorEmailResponse';
|
import { SubscriptionResponse } from "../models/response/subscriptionResponse";
|
||||||
import { TwoFactorProviderResponse } from '../models/response/twoFactorProviderResponse';
|
import { SyncResponse } from "../models/response/syncResponse";
|
||||||
import { TwoFactorRecoverResponse } from '../models/response/twoFactorRescoverResponse';
|
import { TaxInfoResponse } from "../models/response/taxInfoResponse";
|
||||||
import { ChallengeResponse, TwoFactorWebAuthnResponse } from '../models/response/twoFactorWebAuthnResponse';
|
import { TaxRateResponse } from "../models/response/taxRateResponse";
|
||||||
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
|
import { TwoFactorAuthenticatorResponse } from "../models/response/twoFactorAuthenticatorResponse";
|
||||||
import { UserKeyResponse } from '../models/response/userKeyResponse';
|
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 {
|
export abstract class ApiService {
|
||||||
postIdentityToken: (request: TokenRequest) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
postIdentityToken: (
|
||||||
|
request: TokenRequest
|
||||||
|
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
||||||
refreshIdentityToken: () => Promise<any>;
|
refreshIdentityToken: () => Promise<any>;
|
||||||
|
|
||||||
getProfile: () => Promise<ProfileResponse>;
|
getProfile: () => Promise<ProfileResponse>;
|
||||||
@@ -212,7 +220,11 @@ export abstract class ApiService {
|
|||||||
deleteFolder: (id: string) => Promise<any>;
|
deleteFolder: (id: string) => Promise<any>;
|
||||||
|
|
||||||
getSend: (id: string) => Promise<SendResponse>;
|
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>>;
|
getSends: () => Promise<ListResponse<SendResponse>>;
|
||||||
postSend: (request: SendRequest) => Promise<SendResponse>;
|
postSend: (request: SendRequest) => Promise<SendResponse>;
|
||||||
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
|
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
|
||||||
@@ -225,12 +237,20 @@ export abstract class ApiService {
|
|||||||
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
|
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
|
||||||
putSendRemovePassword: (id: string) => Promise<SendResponse>;
|
putSendRemovePassword: (id: string) => Promise<SendResponse>;
|
||||||
deleteSend: (id: string) => Promise<any>;
|
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>;
|
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
|
||||||
|
|
||||||
getCipher: (id: string) => Promise<CipherResponse>;
|
getCipher: (id: string) => Promise<CipherResponse>;
|
||||||
getCipherAdmin: (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>>;
|
getCiphersOrganization: (organizationId: string) => Promise<ListResponse<CipherResponse>>;
|
||||||
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
|
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
|
||||||
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
||||||
@@ -248,14 +268,19 @@ export abstract class ApiService {
|
|||||||
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||||
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
|
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
|
||||||
postImportCiphers: (request: ImportCiphersRequest) => 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>;
|
putDeleteCipher: (id: string) => Promise<any>;
|
||||||
putDeleteCipherAdmin: (id: string) => Promise<any>;
|
putDeleteCipherAdmin: (id: string) => Promise<any>;
|
||||||
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||||
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||||
putRestoreCipher: (id: string) => Promise<CipherResponse>;
|
putRestoreCipher: (id: string) => Promise<CipherResponse>;
|
||||||
putRestoreCipherAdmin: (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.
|
* @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.
|
* This method still exists for backward compatibility with old server versions.
|
||||||
*/
|
*/
|
||||||
postCipherAttachmentAdminLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
|
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>;
|
deleteCipherAttachment: (id: string, attachmentId: string) => Promise<any>;
|
||||||
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
|
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
|
||||||
postShareCipherAttachment: (id: string, attachmentId: string, data: FormData,
|
postShareCipherAttachment: (
|
||||||
organizationId: string) => Promise<any>;
|
id: string,
|
||||||
renewAttachmentUploadUrl: (id: string, attachmentId: string) => Promise<AttachmentUploadDataResponse>;
|
attachmentId: string,
|
||||||
|
data: FormData,
|
||||||
|
organizationId: string
|
||||||
|
) => Promise<any>;
|
||||||
|
renewAttachmentUploadUrl: (
|
||||||
|
id: string,
|
||||||
|
attachmentId: string
|
||||||
|
) => Promise<AttachmentUploadDataResponse>;
|
||||||
postAttachmentFile: (id: string, attachmentId: string, data: FormData) => Promise<any>;
|
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>>;
|
getUserCollections: () => Promise<ListResponse<CollectionResponse>>;
|
||||||
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
|
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
|
||||||
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
|
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
|
||||||
postCollection: (organizationId: string, request: CollectionRequest) => Promise<CollectionResponse>;
|
postCollection: (
|
||||||
putCollectionUsers: (organizationId: string, id: string, request: SelectionReadOnlyRequest[]) => Promise<any>;
|
organizationId: string,
|
||||||
putCollection: (organizationId: string, id: string, request: CollectionRequest) => Promise<CollectionResponse>;
|
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>;
|
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>;
|
getGroupDetails: (organizationId: string, id: string) => Promise<GroupDetailsResponse>;
|
||||||
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
|
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
|
||||||
@@ -296,35 +349,83 @@ export abstract class ApiService {
|
|||||||
|
|
||||||
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
|
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
|
||||||
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
|
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
|
||||||
getPoliciesByToken: (organizationId: string, token: string, email: string, organizationUserId: string) =>
|
getPoliciesByToken: (
|
||||||
Promise<ListResponse<PolicyResponse>>;
|
organizationId: string,
|
||||||
putPolicy: (organizationId: string, type: PolicyType, request: PolicyRequest) => Promise<PolicyResponse>;
|
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[]>;
|
getOrganizationUserGroups: (organizationId: string, id: string) => Promise<string[]>;
|
||||||
getOrganizationUsers: (organizationId: string) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
|
getOrganizationUsers: (
|
||||||
getOrganizationUserResetPasswordDetails: (organizationId: string, id: string)
|
organizationId: string
|
||||||
=> Promise<OrganizationUserResetPasswordDetailsReponse>;
|
) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
|
||||||
postOrganizationUserInvite: (organizationId: string, request: OrganizationUserInviteRequest) => Promise<any>;
|
getOrganizationUserResetPasswordDetails: (
|
||||||
|
organizationId: string,
|
||||||
|
id: string
|
||||||
|
) => Promise<OrganizationUserResetPasswordDetailsReponse>;
|
||||||
|
postOrganizationUserInvite: (
|
||||||
|
organizationId: string,
|
||||||
|
request: OrganizationUserInviteRequest
|
||||||
|
) => Promise<any>;
|
||||||
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
|
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
|
||||||
postManyOrganizationUserReinvite: (organizationId: string, request: OrganizationUserBulkRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
postManyOrganizationUserReinvite: (
|
||||||
postOrganizationUserAccept: (organizationId: string, id: string,
|
organizationId: string,
|
||||||
request: OrganizationUserAcceptRequest) => Promise<any>;
|
request: OrganizationUserBulkRequest
|
||||||
postOrganizationUserConfirm: (organizationId: string, id: string,
|
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
||||||
request: OrganizationUserConfirmRequest) => Promise<any>;
|
postOrganizationUserAccept: (
|
||||||
postOrganizationUsersPublicKey: (organizationId: string, request: OrganizationUserBulkRequest) =>
|
organizationId: string,
|
||||||
Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
|
id: string,
|
||||||
postOrganizationUserBulkConfirm: (organizationId: string, request: OrganizationUserBulkConfirmRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
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>;
|
putOrganizationUser: (
|
||||||
putOrganizationUserGroups: (organizationId: string, id: string,
|
organizationId: string,
|
||||||
request: OrganizationUserUpdateGroupsRequest) => Promise<any>;
|
id: string,
|
||||||
putOrganizationUserResetPasswordEnrollment: (organizationId: string, userId: string,
|
request: OrganizationUserUpdateRequest
|
||||||
request: OrganizationUserResetPasswordEnrollmentRequest) => Promise<any>;
|
) => Promise<any>;
|
||||||
putOrganizationUserResetPassword: (organizationId: string, id: string,
|
putOrganizationUserGroups: (
|
||||||
request: OrganizationUserResetPasswordRequest) => Promise<any>;
|
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>;
|
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>;
|
getSync: () => Promise<SyncResponse>;
|
||||||
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
|
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
|
||||||
@@ -334,28 +435,45 @@ export abstract class ApiService {
|
|||||||
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
|
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
|
||||||
|
|
||||||
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||||
getTwoFactorOrganizationProviders: (organizationId: string) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
getTwoFactorOrganizationProviders: (
|
||||||
getTwoFactorAuthenticator: (request: SecretVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
organizationId: string
|
||||||
|
) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||||
|
getTwoFactorAuthenticator: (
|
||||||
|
request: SecretVerificationRequest
|
||||||
|
) => Promise<TwoFactorAuthenticatorResponse>;
|
||||||
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||||
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||||
getTwoFactorOrganizationDuo: (organizationId: string,
|
getTwoFactorOrganizationDuo: (
|
||||||
request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
organizationId: string,
|
||||||
|
request: SecretVerificationRequest
|
||||||
|
) => Promise<TwoFactorDuoResponse>;
|
||||||
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||||
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||||
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
||||||
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||||
putTwoFactorAuthenticator: (
|
putTwoFactorAuthenticator: (
|
||||||
request: UpdateTwoFactorAuthenticatorRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
request: UpdateTwoFactorAuthenticatorRequest
|
||||||
|
) => Promise<TwoFactorAuthenticatorResponse>;
|
||||||
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
||||||
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
|
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
|
||||||
putTwoFactorOrganizationDuo: (organizationId: string,
|
putTwoFactorOrganizationDuo: (
|
||||||
request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
|
organizationId: string,
|
||||||
putTwoFactorYubiKey: (request: UpdateTwoFactorYubioOtpRequest) => Promise<TwoFactorYubiKeyResponse>;
|
request: UpdateTwoFactorDuoRequest
|
||||||
putTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnRequest) => Promise<TwoFactorWebAuthnResponse>;
|
) => Promise<TwoFactorDuoResponse>;
|
||||||
deleteTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnDeleteRequest) => Promise<TwoFactorWebAuthnResponse>;
|
putTwoFactorYubiKey: (
|
||||||
|
request: UpdateTwoFactorYubioOtpRequest
|
||||||
|
) => Promise<TwoFactorYubiKeyResponse>;
|
||||||
|
putTwoFactorWebAuthn: (
|
||||||
|
request: UpdateTwoFactorWebAuthnRequest
|
||||||
|
) => Promise<TwoFactorWebAuthnResponse>;
|
||||||
|
deleteTwoFactorWebAuthn: (
|
||||||
|
request: UpdateTwoFactorWebAuthnDeleteRequest
|
||||||
|
) => Promise<TwoFactorWebAuthnResponse>;
|
||||||
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
|
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
|
||||||
putTwoFactorOrganizationDisable: (organizationId: string,
|
putTwoFactorOrganizationDisable: (
|
||||||
request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
|
organizationId: string,
|
||||||
|
request: TwoFactorProviderRequest
|
||||||
|
) => Promise<TwoFactorProviderResponse>;
|
||||||
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
|
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
|
||||||
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
|
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
|
||||||
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
|
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
|
||||||
@@ -374,7 +492,10 @@ export abstract class ApiService {
|
|||||||
postEmergencyAccessApprove: (id: string) => Promise<any>;
|
postEmergencyAccessApprove: (id: string) => Promise<any>;
|
||||||
postEmergencyAccessReject: (id: string) => Promise<any>;
|
postEmergencyAccessReject: (id: string) => Promise<any>;
|
||||||
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
|
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
|
||||||
postEmergencyAccessPassword: (id: string, request: EmergencyAccessPasswordRequest) => Promise<any>;
|
postEmergencyAccessPassword: (
|
||||||
|
id: string,
|
||||||
|
request: EmergencyAccessPasswordRequest
|
||||||
|
) => Promise<any>;
|
||||||
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
|
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
|
||||||
|
|
||||||
getOrganization: (id: string) => Promise<OrganizationResponse>;
|
getOrganization: (id: string) => Promise<OrganizationResponse>;
|
||||||
@@ -382,19 +503,39 @@ export abstract class ApiService {
|
|||||||
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
|
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
|
||||||
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
|
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
|
||||||
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
|
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
|
||||||
getOrganizationAutoEnrollStatus: (identifier: string) => Promise<OrganizationAutoEnrollStatusResponse>;
|
getOrganizationAutoEnrollStatus: (
|
||||||
|
identifier: string
|
||||||
|
) => Promise<OrganizationAutoEnrollStatusResponse>;
|
||||||
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
|
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
|
||||||
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
|
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>;
|
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
|
||||||
postLeaveOrganization: (id: string) => Promise<any>;
|
postLeaveOrganization: (id: string) => Promise<any>;
|
||||||
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
||||||
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
||||||
postOrganizationApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
postOrganizationApiKey: (
|
||||||
postOrganizationRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
id: string,
|
||||||
postOrganizationSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
|
request: SecretVerificationRequest
|
||||||
postOrganizationUpgrade: (id: string, request: OrganizationUpgradeRequest) => Promise<PaymentResponse>;
|
) => Promise<ApiKeyResponse>;
|
||||||
postOrganizationUpdateSubscription: (id: string, request: OrganizationSubscriptionUpdateRequest) => Promise<void>;
|
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>;
|
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
|
||||||
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
|
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
|
||||||
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
|
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
|
||||||
@@ -405,7 +546,10 @@ export abstract class ApiService {
|
|||||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
||||||
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
||||||
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
|
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>;
|
postProviderSetup: (id: string, request: ProviderSetupRequest) => Promise<ProviderResponse>;
|
||||||
getProvider: (id: string) => Promise<ProviderResponse>;
|
getProvider: (id: string) => Promise<ProviderResponse>;
|
||||||
@@ -415,28 +559,84 @@ export abstract class ApiService {
|
|||||||
getProviderUser: (providerId: string, id: string) => Promise<ProviderUserResponse>;
|
getProviderUser: (providerId: string, id: string) => Promise<ProviderUserResponse>;
|
||||||
postProviderUserInvite: (providerId: string, request: ProviderUserInviteRequest) => Promise<any>;
|
postProviderUserInvite: (providerId: string, request: ProviderUserInviteRequest) => Promise<any>;
|
||||||
postProviderUserReinvite: (providerId: string, id: string) => Promise<any>;
|
postProviderUserReinvite: (providerId: string, id: string) => Promise<any>;
|
||||||
postManyProviderUserReinvite: (providerId: string, request: ProviderUserBulkRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
postManyProviderUserReinvite: (
|
||||||
postProviderUserAccept: (providerId: string, id: string, request: ProviderUserAcceptRequest) => Promise<any>;
|
providerId: string,
|
||||||
postProviderUserConfirm: (providerId: string, id: string, request: ProviderUserConfirmRequest) => Promise<any>;
|
request: ProviderUserBulkRequest
|
||||||
postProviderUsersPublicKey: (providerId: string, request: ProviderUserBulkRequest) =>
|
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
||||||
Promise<ListResponse<ProviderUserBulkPublicKeyResponse>>;
|
postProviderUserAccept: (
|
||||||
postProviderUserBulkConfirm: (providerId: string, request: ProviderUserBulkConfirmRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
providerId: string,
|
||||||
putProviderUser: (providerId: string, id: string, request: ProviderUserUpdateRequest) => Promise<any>;
|
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>;
|
deleteProviderUser: (organizationId: string, id: string) => Promise<any>;
|
||||||
deleteManyProviderUsers: (providerId: string, request: ProviderUserBulkRequest) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
deleteManyProviderUsers: (
|
||||||
getProviderClients: (providerId: string) => Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>>;
|
providerId: string,
|
||||||
postProviderAddOrganization: (providerId: string, request: ProviderAddOrganizationRequest) => Promise<any>;
|
request: ProviderUserBulkRequest
|
||||||
postProviderCreateOrganization: (providerId: string, request: ProviderOrganizationCreateRequest) => Promise<ProviderOrganizationResponse>;
|
) => 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>;
|
deleteProviderOrganization: (providerId: string, organizationId: string) => Promise<any>;
|
||||||
|
|
||||||
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
||||||
getEventsCipher: (id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
getEventsCipher: (
|
||||||
getEventsOrganization: (id: string, start: string, end: string,
|
id: string,
|
||||||
token: string) => Promise<ListResponse<EventResponse>>;
|
start: string,
|
||||||
getEventsOrganizationUser: (organizationId: string, id: string,
|
end: string,
|
||||||
start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
token: string
|
||||||
getEventsProvider: (id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
) => Promise<ListResponse<EventResponse>>;
|
||||||
getEventsProviderUser: (providerId: string, 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>;
|
postEventsCollect: (request: EventRequest[]) => Promise<any>;
|
||||||
|
|
||||||
deleteSsoUser: (organizationId: string) => Promise<any>;
|
deleteSsoUser: (organizationId: string) => Promise<any>;
|
||||||
@@ -455,14 +655,23 @@ export abstract class ApiService {
|
|||||||
|
|
||||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
preValidateSso: (identifier: string) => Promise<boolean>;
|
||||||
|
|
||||||
postCreateSponsorship: (sponsorshipOrgId: string, request: OrganizationSponsorshipCreateRequest) => Promise<void>;
|
postCreateSponsorship: (
|
||||||
|
sponsorshipOrgId: string,
|
||||||
|
request: OrganizationSponsorshipCreateRequest
|
||||||
|
) => Promise<void>;
|
||||||
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
||||||
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
||||||
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
|
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
|
||||||
postRedeemSponsorship: (sponsorshipToken: string, request: OrganizationSponsorshipRedeemRequest) => Promise<void>;
|
postRedeemSponsorship: (
|
||||||
|
sponsorshipToken: string,
|
||||||
|
request: OrganizationSponsorshipRedeemRequest
|
||||||
|
) => Promise<void>;
|
||||||
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
||||||
|
|
||||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
||||||
postUserKeyToKeyConnector: (keyConnectorUrl: string, request: KeyConnectorUserKeyRequest) => Promise<void>;
|
postUserKeyToKeyConnector: (
|
||||||
|
keyConnectorUrl: string,
|
||||||
|
request: KeyConnectorUserKeyRequest
|
||||||
|
) => Promise<void>;
|
||||||
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
|
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
|
||||||
|
|
||||||
export abstract class AuditService {
|
export abstract class AuditService {
|
||||||
passwordLeaked: (password: string) => Promise<number>;
|
passwordLeaked: (password: string) => Promise<number>;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
import { TwoFactorProviderType } from "../enums/twoFactorProviderType";
|
||||||
|
|
||||||
import { AuthResult } from '../models/domain/authResult';
|
import { AuthResult } from "../models/domain/authResult";
|
||||||
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
export abstract class AuthService {
|
export abstract class AuthService {
|
||||||
email: string;
|
email: string;
|
||||||
@@ -11,20 +11,45 @@ export abstract class AuthService {
|
|||||||
ssoRedirectUrl: string;
|
ssoRedirectUrl: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
clientSecret: string;
|
clientSecret: string;
|
||||||
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string; }>;
|
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string }>;
|
||||||
selectedTwoFactorProviderType: TwoFactorProviderType;
|
selectedTwoFactorProviderType: TwoFactorProviderType;
|
||||||
|
|
||||||
logIn: (email: string, masterPassword: string, captchaToken?: string) => Promise<AuthResult>;
|
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>;
|
logInApiKey: (clientId: string, clientSecret: string) => Promise<AuthResult>;
|
||||||
logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
|
logInTwoFactor: (
|
||||||
remember?: boolean) => Promise<AuthResult>;
|
twoFactorProvider: TwoFactorProviderType,
|
||||||
logInComplete: (email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
|
twoFactorToken: string,
|
||||||
twoFactorToken: string, remember?: boolean, captchaToken?: string) => Promise<AuthResult>;
|
remember?: boolean
|
||||||
logInSsoComplete: (code: string, codeVerifier: string, redirectUrl: string,
|
) => Promise<AuthResult>;
|
||||||
twoFactorProvider: TwoFactorProviderType, twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
|
logInComplete: (
|
||||||
logInApiKeyComplete: (clientId: string, clientSecret: string, twoFactorProvider: TwoFactorProviderType,
|
email: string,
|
||||||
twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
|
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;
|
logOut: (callback: Function) => void;
|
||||||
getSupportedTwoFactorProviders: (win: Window) => any[];
|
getSupportedTwoFactorProviders: (win: Window) => any[];
|
||||||
getDefaultTwoFactorProvider: (webAuthnSupported: boolean) => TwoFactorProviderType;
|
getDefaultTwoFactorProvider: (webAuthnSupported: boolean) => TwoFactorProviderType;
|
||||||
|
|||||||
@@ -1,26 +1,33 @@
|
|||||||
import { CipherType } from '../enums/cipherType';
|
import { CipherType } from "../enums/cipherType";
|
||||||
import { UriMatchType } from '../enums/uriMatchType';
|
import { UriMatchType } from "../enums/uriMatchType";
|
||||||
|
|
||||||
import { CipherData } from '../models/data/cipherData';
|
import { CipherData } from "../models/data/cipherData";
|
||||||
|
|
||||||
import { Cipher } from '../models/domain/cipher';
|
import { Cipher } from "../models/domain/cipher";
|
||||||
import { Field } from '../models/domain/field';
|
import { Field } from "../models/domain/field";
|
||||||
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
||||||
|
|
||||||
import { CipherView } from '../models/view/cipherView';
|
import { CipherView } from "../models/view/cipherView";
|
||||||
import { FieldView } from '../models/view/fieldView';
|
import { FieldView } from "../models/view/fieldView";
|
||||||
|
|
||||||
export abstract class CipherService {
|
export abstract class CipherService {
|
||||||
clearCache: (userId?: string) => Promise<void>;
|
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[]>;
|
encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise<Field[]>;
|
||||||
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;
|
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;
|
||||||
get: (id: string) => Promise<Cipher>;
|
get: (id: string) => Promise<Cipher>;
|
||||||
getAll: () => Promise<Cipher[]>;
|
getAll: () => Promise<Cipher[]>;
|
||||||
getAllDecrypted: () => Promise<CipherView[]>;
|
getAllDecrypted: () => Promise<CipherView[]>;
|
||||||
getAllDecryptedForGrouping: (groupingId: string, folder?: boolean) => Promise<CipherView[]>;
|
getAllDecryptedForGrouping: (groupingId: string, folder?: boolean) => Promise<CipherView[]>;
|
||||||
getAllDecryptedForUrl: (url: string, includeOtherTypes?: CipherType[],
|
getAllDecryptedForUrl: (
|
||||||
defaultMatch?: UriMatchType) => Promise<CipherView[]>;
|
url: string,
|
||||||
|
includeOtherTypes?: CipherType[],
|
||||||
|
defaultMatch?: UriMatchType
|
||||||
|
) => Promise<CipherView[]>;
|
||||||
getAllFromApiForOrganization: (organizationId: string) => Promise<CipherView[]>;
|
getAllFromApiForOrganization: (organizationId: string) => Promise<CipherView[]>;
|
||||||
getLastUsedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
|
getLastUsedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
|
||||||
getLastLaunchedForUrl: (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>;
|
updateLastLaunchedDate: (id: string) => Promise<void>;
|
||||||
saveNeverDomain: (domain: string) => Promise<void>;
|
saveNeverDomain: (domain: string) => Promise<void>;
|
||||||
saveWithServer: (cipher: Cipher) => Promise<any>;
|
saveWithServer: (cipher: Cipher) => Promise<any>;
|
||||||
shareWithServer: (cipher: CipherView, organizationId: string, collectionIds: string[]) => Promise<any>;
|
shareWithServer: (
|
||||||
shareManyWithServer: (ciphers: CipherView[], organizationId: string, collectionIds: string[]) => Promise<any>;
|
cipher: CipherView,
|
||||||
saveAttachmentWithServer: (cipher: Cipher, unencryptedFile: any, admin?: boolean) => Promise<Cipher>;
|
organizationId: string,
|
||||||
saveAttachmentRawWithServer: (cipher: Cipher, filename: string, data: ArrayBuffer,
|
collectionIds: string[]
|
||||||
admin?: boolean) => Promise<Cipher>;
|
) => 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>;
|
saveCollectionsWithServer: (cipher: Cipher) => Promise<any>;
|
||||||
upsert: (cipher: CipherData | CipherData[]) => 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>;
|
clear: (userId: string) => Promise<any>;
|
||||||
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
|
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
delete: (id: string | string[]) => Promise<any>;
|
||||||
@@ -51,7 +74,9 @@ export abstract class CipherService {
|
|||||||
softDelete: (id: string | string[]) => Promise<any>;
|
softDelete: (id: string | string[]) => Promise<any>;
|
||||||
softDeleteWithServer: (id: string) => Promise<any>;
|
softDeleteWithServer: (id: string) => Promise<any>;
|
||||||
softDeleteManyWithServer: (ids: 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>;
|
restoreWithServer: (id: string) => Promise<any>;
|
||||||
restoreManyWithServer: (ids: string[]) => Promise<any>;
|
restoreManyWithServer: (ids: string[]) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { CollectionData } from '../models/data/collectionData';
|
import { CollectionData } from "../models/data/collectionData";
|
||||||
|
|
||||||
import { Collection } from '../models/domain/collection';
|
import { Collection } from "../models/domain/collection";
|
||||||
import { TreeNode } from '../models/domain/treeNode';
|
import { TreeNode } from "../models/domain/treeNode";
|
||||||
|
|
||||||
import { CollectionView } from '../models/view/collectionView';
|
import { CollectionView } from "../models/view/collectionView";
|
||||||
|
|
||||||
export abstract class CollectionService {
|
export abstract class CollectionService {
|
||||||
clearCache: (userId?: string) => Promise<void>;
|
clearCache: (userId?: string) => Promise<void>;
|
||||||
@@ -15,7 +15,7 @@ export abstract class CollectionService {
|
|||||||
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
|
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
|
||||||
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
|
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
|
||||||
upsert: (collection: CollectionData | CollectionData[]) => Promise<any>;
|
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>;
|
clear: (userId: string) => Promise<any>;
|
||||||
delete: (id: string | string[]) => Promise<any>;
|
delete: (id: string | string[]) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user