mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
Compare commits
228 Commits
version_bu
...
googleapi-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1d7920d73 | ||
|
|
a4ec6df118 | ||
|
|
01e60bf090 | ||
|
|
7c27202dab | ||
|
|
77ea7a395d | ||
|
|
a259de8b26 | ||
|
|
06dbc14136 | ||
|
|
e74546e8c3 | ||
|
|
5ac0cc408e | ||
|
|
9044f94f43 | ||
|
|
1b2c854569 | ||
|
|
e5b3e58a02 | ||
|
|
32b29d2d34 | ||
|
|
a68744524c | ||
|
|
cee7700895 | ||
|
|
b2c60aab1e | ||
|
|
ab76a7eac4 | ||
|
|
d662c05b3e | ||
|
|
ec2c40a565 | ||
|
|
8dc2be7fab | ||
|
|
2879d9c38c | ||
|
|
71ca0772a9 | ||
|
|
6ff39dd207 | ||
|
|
489effb852 | ||
|
|
acb5bc4d25 | ||
|
|
cac411fb29 | ||
|
|
94881d0db0 | ||
|
|
a7c3c40570 | ||
|
|
88af7d6b12 | ||
|
|
3716e5ca57 | ||
|
|
3cc4f90688 | ||
|
|
afa6ced621 | ||
|
|
68efd0a86e | ||
|
|
7fb8732e1e | ||
|
|
48acb783fe | ||
|
|
3df63b8ddf | ||
|
|
ed40b17a80 | ||
|
|
460de6a075 | ||
|
|
4784d45d23 | ||
|
|
60d9a35239 | ||
|
|
5ffd761326 | ||
|
|
55fe14b744 | ||
|
|
c0cbf7651a | ||
|
|
926202f80a | ||
|
|
3013e5f06f | ||
|
|
6789a14527 | ||
|
|
66c38dc18f | ||
|
|
763497e160 | ||
|
|
c28a93bdbe | ||
|
|
3715df42d7 | ||
|
|
a643175a99 | ||
|
|
0c1d20aaa6 | ||
|
|
c51e37e77d | ||
|
|
eec7420826 | ||
|
|
284206b735 | ||
|
|
51042857c9 | ||
|
|
a462ae7457 | ||
|
|
5dfd60d25c | ||
|
|
19937fcbe9 | ||
|
|
46405ad75c | ||
|
|
04ee7533e4 | ||
|
|
02aa653a48 | ||
|
|
921466677e | ||
|
|
e8f0d17944 | ||
|
|
2cc2292ed6 | ||
|
|
c96e0bb147 | ||
|
|
6964a7db49 | ||
|
|
32e3327974 | ||
|
|
3a46e1781e | ||
|
|
dc64f7191e | ||
|
|
570bcf1581 | ||
|
|
fc06bf401a | ||
|
|
61d7c996c1 | ||
|
|
71a19fecaa | ||
|
|
ae37cea276 | ||
|
|
09f1f6981c | ||
|
|
ceff0559f2 | ||
|
|
4d55bf0527 | ||
|
|
7347c1992f | ||
|
|
46d2797d8c | ||
|
|
ed58d7c758 | ||
|
|
cd6bbd792a | ||
|
|
3b3ea8ac47 | ||
|
|
5f9adf9ab7 | ||
|
|
1deb22a446 | ||
|
|
115a60316d | ||
|
|
e11225b2ce | ||
|
|
4909d306ba | ||
|
|
caa8c4d070 | ||
|
|
ed1d941282 | ||
|
|
f6f874360f | ||
|
|
18b110e70d | ||
|
|
83c42cec73 | ||
|
|
2d80fceb8c | ||
|
|
0489f0cbe9 | ||
|
|
c5d4cb9fb6 | ||
|
|
16d6647090 | ||
|
|
a08673917b | ||
|
|
27e1ab9bcf | ||
|
|
3573e201a6 | ||
|
|
23d285a9f6 | ||
|
|
527d2cb75d | ||
|
|
42efd689e3 | ||
|
|
2fe980dea6 | ||
|
|
9446eedec7 | ||
|
|
41ee0d82d5 | ||
|
|
40a85bb875 | ||
|
|
50be1218e2 | ||
|
|
e4abb2c751 | ||
|
|
23c591f903 | ||
|
|
2ea2fd701c | ||
|
|
3b74be446e | ||
|
|
2651a53f27 | ||
|
|
09ed8326c3 | ||
|
|
c5a65a85ad | ||
|
|
3ae90cbb4c | ||
|
|
99dbb3162e | ||
|
|
f146d41b66 | ||
|
|
b35cf8e995 | ||
|
|
f7ee5dcd92 | ||
|
|
61bbff771e | ||
|
|
2047b6644e | ||
|
|
26dd9662cf | ||
|
|
70073fb570 | ||
|
|
8642b9d7aa | ||
|
|
d77b50c540 | ||
|
|
ed935d998a | ||
|
|
682da52040 | ||
|
|
531619af1d | ||
|
|
cf54858cc5 | ||
|
|
6cc022b135 | ||
|
|
a8a4390624 | ||
|
|
f9d817f0b1 | ||
|
|
112bda1137 | ||
|
|
23713d92fa | ||
|
|
6ebc9631aa | ||
|
|
e8579f11d3 | ||
|
|
6b2c7a5f00 | ||
|
|
2a1a5bf064 | ||
|
|
1464d72b27 | ||
|
|
f5cbd8f03d | ||
|
|
fdbbef68c1 | ||
|
|
efb412684d | ||
|
|
79f7a2b495 | ||
|
|
4342734412 | ||
|
|
62f14e5043 | ||
|
|
c2b22518fe | ||
|
|
37c992f16b | ||
|
|
69156677ac | ||
|
|
aaed7b13ea | ||
|
|
096d2a03ab | ||
|
|
bd5bcbebd9 | ||
|
|
bb9ece6078 | ||
|
|
40de47e6e3 | ||
|
|
094ed57e03 | ||
|
|
96a38e2d76 | ||
|
|
9e200c8705 | ||
|
|
ca945318ed | ||
|
|
04abed9251 | ||
|
|
9b08ca6db8 | ||
|
|
0cbe6e9d33 | ||
|
|
dda6dd99ed | ||
|
|
5492466276 | ||
|
|
ef571ec0c3 | ||
|
|
f2bea1b6d7 | ||
|
|
07a1ae6dea | ||
|
|
f23997dd72 | ||
|
|
18547d6eaa | ||
|
|
c3a4f25160 | ||
|
|
e57a52e483 | ||
|
|
ff1380ee67 | ||
|
|
2269b82e7e | ||
|
|
8ab3516377 | ||
|
|
91dfd7e0b7 | ||
|
|
6db28408e6 | ||
|
|
bdacf3d4e4 | ||
|
|
9c566f50a2 | ||
|
|
e3fbc4e731 | ||
|
|
3c5bafe39f | ||
|
|
d65f42684e | ||
|
|
743b4b44cb | ||
|
|
1931a7f065 | ||
|
|
7d01bf0c6c | ||
|
|
c28ce25381 | ||
|
|
74c152f142 | ||
|
|
d4e317d804 | ||
|
|
605facb464 | ||
|
|
5a6ae00a82 | ||
|
|
19344bf696 | ||
|
|
8d8b3ca13e | ||
|
|
4fee3298f8 | ||
|
|
493e819b1c | ||
|
|
df4eb139e4 | ||
|
|
6cdd07429c | ||
|
|
278ec1acf0 | ||
|
|
e3d3c856c5 | ||
|
|
37ac5fc936 | ||
|
|
15978f69b1 | ||
|
|
ee7d97b797 | ||
|
|
930d7cf224 | ||
|
|
cf106b148e | ||
|
|
cfd0722587 | ||
|
|
b462a78c18 | ||
|
|
4bb96f049c | ||
|
|
b991fea958 | ||
|
|
111b8bd646 | ||
|
|
42af888615 | ||
|
|
a28fad020b | ||
|
|
f190433348 | ||
|
|
1e211becc3 | ||
|
|
4652c6489f | ||
|
|
9dc497dd13 | ||
|
|
3d9465917d | ||
|
|
6b1b6bf1c4 | ||
|
|
f52af53dad | ||
|
|
6e6039d298 | ||
|
|
332d07eca6 | ||
|
|
c3ed541efd | ||
|
|
4ae4cba877 | ||
|
|
3ecca16f50 | ||
|
|
1f30ef165f | ||
|
|
dfd8fce231 | ||
|
|
0b7c0ec9c2 | ||
|
|
6d569e9319 | ||
|
|
3ed4e76f95 | ||
|
|
abf7e0400c | ||
|
|
5600f20760 | ||
|
|
bbc65d77e3 |
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
@@ -6,3 +6,9 @@
|
||||
|
||||
# Default file owners.
|
||||
* @bitwarden/team-admin-console-dev
|
||||
|
||||
# Docker-related files
|
||||
**/Dockerfile @bitwarden/team-appsec @bitwarden/dept-bre
|
||||
**/*.dockerignore @bitwarden/team-appsec @bitwarden/dept-bre
|
||||
**/entrypoint.sh @bitwarden/team-appsec @bitwarden/dept-bre
|
||||
**/docker-compose.yml @bitwarden/team-appsec @bitwarden/dept-bre
|
||||
|
||||
12
.github/renovate.json
vendored
12
.github/renovate.json
vendored
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["github>bitwarden/renovate-config"],
|
||||
"enabledManagers": ["github-actions", "npm"],
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "gh minor",
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["minor", "patch"]
|
||||
}
|
||||
]
|
||||
}
|
||||
25
.github/renovate.json5
vendored
Normal file
25
.github/renovate.json5
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
$schema: "https://docs.renovatebot.com/renovate-schema.json",
|
||||
extends: ["github>bitwarden/renovate-config"],
|
||||
enabledManagers: ["github-actions", "npm"],
|
||||
packageRules: [
|
||||
{
|
||||
groupName: "gh minor",
|
||||
matchManagers: ["github-actions"],
|
||||
matchUpdateTypes: ["minor", "patch"],
|
||||
},
|
||||
{
|
||||
groupName: "Google Libraries",
|
||||
matchPackagePatterns: ["google-auth-library", "googleapis"],
|
||||
matchManagers: ["npm"],
|
||||
groupSlug: "google-libraries",
|
||||
},
|
||||
],
|
||||
ignoreDeps: [
|
||||
// yao-pkg is used to create a single executable application bundle for the CLI.
|
||||
// It is a third party build of node which carries a high supply chain risk.
|
||||
// This must be manually vetted by our appsec team before upgrading.
|
||||
// It is excluded from renovate to avoid accidentally upgrading to a non-vetted version.
|
||||
"@yao-pkg/pkg",
|
||||
],
|
||||
}
|
||||
383
.github/workflows/build.yml
vendored
383
.github/workflows/build.yml
vendored
@@ -1,4 +1,3 @@
|
||||
---
|
||||
name: Build
|
||||
|
||||
on:
|
||||
@@ -6,72 +5,67 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "rc"
|
||||
- "hotfix-rc"
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cloc:
|
||||
name: CLOC
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Set up CLOC
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt -y install cloc
|
||||
|
||||
- name: Print lines of code
|
||||
run: cloc --include-lang TypeScript,JavaScript,HTML,Sass,CSS --vcs git
|
||||
|
||||
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
package_version: ${{ steps.retrieve-version.outputs.package_version }}
|
||||
node_version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Package Version
|
||||
id: retrieve-version
|
||||
run: |
|
||||
PKG_VERSION=$(jq -r .version package.json)
|
||||
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Get Node Version
|
||||
id: retrieve-node-version
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
linux-cli:
|
||||
name: Build Linux CLI
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs: setup
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_PKG_FETCH_NODE_VERSION: 18.5.0
|
||||
_PKG_FETCH_VERSION: 3.4
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g node-gyp
|
||||
node-gyp install $(node -v)
|
||||
|
||||
- name: Get pkg-fetch
|
||||
run: |
|
||||
cd $HOME
|
||||
fetchedUrl="https://github.com/vercel/pkg-fetch/releases/download/v$_PKG_FETCH_VERSION/node-v$_PKG_FETCH_NODE_VERSION-linux-x64"
|
||||
|
||||
mkdir -p .pkg-cache/v$_PKG_FETCH_VERSION
|
||||
wget $fetchedUrl -O "./.pkg-cache/v$_PKG_FETCH_VERSION/fetched-v$_PKG_FETCH_NODE_VERSION-linux-x64"
|
||||
node-gyp install "$(node -v)"
|
||||
|
||||
- name: Keytar
|
||||
run: |
|
||||
@@ -82,8 +76,8 @@ jobs:
|
||||
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
||||
|
||||
mkdir -p ./keytar/linux
|
||||
wget $keytarUrl -O ./keytar/linux/$keytarTarGz
|
||||
tar -xvf ./keytar/linux/$keytarTarGz -C ./keytar/linux
|
||||
wget "$keytarUrl" -O "./keytar/linux/$keytarTarGz"
|
||||
tar -xvf "./keytar/linux/$keytarTarGz" -C ./keytar/linux
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
@@ -92,24 +86,19 @@ jobs:
|
||||
run: npm run dist:cli:lin
|
||||
|
||||
- name: Zip
|
||||
run: zip -j dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip dist-cli/linux/bwdc keytar/linux/build/Release/keytar.node
|
||||
|
||||
- name: Create checksums
|
||||
run: |
|
||||
shasum -a 256 dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip | \
|
||||
cut -d " " -f 1 > dist-cli/bwdc-linux-sha256-$_PACKAGE_VERSION.txt
|
||||
run: zip -j "dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip" "dist-cli/linux/bwdc" "keytar/linux/build/Release/keytar.node"
|
||||
|
||||
- name: Version Test
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt install libsecret-1-0 dbus-x11 gnome-keyring
|
||||
eval $(dbus-launch --sh-syntax)
|
||||
eval "$(dbus-launch --sh-syntax)"
|
||||
|
||||
eval $(echo -n "" | /usr/bin/gnome-keyring-daemon --login)
|
||||
eval $(/usr/bin/gnome-keyring-daemon --components=secrets --start)
|
||||
eval "$(echo -n "" | /usr/bin/gnome-keyring-daemon --login)"
|
||||
eval "$(/usr/bin/gnome-keyring-daemon --components=secrets --start)"
|
||||
|
||||
mkdir -p test/linux
|
||||
unzip ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip -d ./test/linux
|
||||
unzip "./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip" -d ./test/linux
|
||||
|
||||
testVersion=$(./test/linux/bwdc -v)
|
||||
|
||||
@@ -122,51 +111,39 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload Linux Zip to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
||||
path: ./dist-cli/bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Linux checksum to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
path: ./dist-cli/bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
macos-cli:
|
||||
name: Build Mac CLI
|
||||
runs-on: macos-13
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_PKG_FETCH_NODE_VERSION: 18.5.0
|
||||
_PKG_FETCH_VERSION: 3.4
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g node-gyp
|
||||
node-gyp install $(node -v)
|
||||
|
||||
- name: Get pkg-fetch
|
||||
run: |
|
||||
cd $HOME
|
||||
fetchedUrl="https://github.com/vercel/pkg-fetch/releases/download/v$_PKG_FETCH_VERSION/node-v$_PKG_FETCH_NODE_VERSION-macos-x64"
|
||||
|
||||
mkdir -p .pkg-cache/v$_PKG_FETCH_VERSION
|
||||
wget $fetchedUrl -O "./.pkg-cache/v$_PKG_FETCH_VERSION/fetched-v$_PKG_FETCH_NODE_VERSION-macos-x64"
|
||||
node-gyp install "$(node -v)"
|
||||
|
||||
- name: Keytar
|
||||
run: |
|
||||
@@ -177,8 +154,8 @@ jobs:
|
||||
keytarUrl="https://github.com/atom/node-keytar/releases/download/v$keytarVersion/$keytarTarGz"
|
||||
|
||||
mkdir -p ./keytar/macos
|
||||
wget $keytarUrl -O ./keytar/macos/$keytarTarGz
|
||||
tar -xvf ./keytar/macos/$keytarTarGz -C ./keytar/macos
|
||||
wget "$keytarUrl" -O "./keytar/macos/$keytarTarGz"
|
||||
tar -xvf "./keytar/macos/$keytarTarGz" -C ./keytar/macos
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
@@ -187,17 +164,12 @@ jobs:
|
||||
run: npm run dist:cli:mac
|
||||
|
||||
- name: Zip
|
||||
run: zip -j dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip dist-cli/macos/bwdc keytar/macos/build/Release/keytar.node
|
||||
|
||||
- name: Create checksums
|
||||
run: |
|
||||
shasum -a 256 dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip | \
|
||||
cut -d " " -f 1 > dist-cli/bwdc-macos-sha256-$_PACKAGE_VERSION.txt
|
||||
run: zip -j "dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip" "dist-cli/macos/bwdc" "keytar/macos/build/Release/keytar.node"
|
||||
|
||||
- name: Version Test
|
||||
run: |
|
||||
mkdir -p test/macos
|
||||
unzip ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip -d ./test/macos
|
||||
unzip "./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip" -d ./test/macos
|
||||
|
||||
testVersion=$(./test/macos/bwdc -v)
|
||||
|
||||
@@ -210,59 +182,44 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Upload Mac Zip to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
||||
path: ./dist-cli/bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Mac checksum to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
path: ./dist-cli/bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
if-no-files-found: error
|
||||
|
||||
windows-cli:
|
||||
name: Build Windows CLI
|
||||
runs-on: windows-2022
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_WIN_PKG_FETCH_VERSION: 18.5.0
|
||||
_WIN_PKG_VERSION: 3.4
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Windows builder
|
||||
run: |
|
||||
choco install checksum --no-progress
|
||||
choco install reshack --no-progress
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g node-gyp
|
||||
node-gyp install $(node -v)
|
||||
|
||||
- name: Get pkg-fetch
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd $HOME
|
||||
$fetchedUrl = "https://github.com/vercel/pkg-fetch/releases/download/v$env:_WIN_PKG_VERSION/node-v$env:_WIN_PKG_FETCH_VERSION-win-x64"
|
||||
|
||||
New-Item -ItemType directory -Path ./.pkg-cache
|
||||
New-Item -ItemType directory -Path ./.pkg-cache/v$env:_WIN_PKG_VERSION
|
||||
Invoke-RestMethod -Uri $fetchedUrl `
|
||||
-OutFile "./.pkg-cache/v$env:_WIN_PKG_VERSION/fetched-v$env:_WIN_PKG_FETCH_VERSION-win-x64"
|
||||
|
||||
- name: Keytar
|
||||
shell: pwsh
|
||||
run: |
|
||||
@@ -279,54 +236,6 @@ jobs:
|
||||
|
||||
7z e "./keytar/windows/$($keytarTar -f "win32")" -o"./keytar/windows"
|
||||
|
||||
- name: Setup Version Info
|
||||
shell: pwsh
|
||||
run: |
|
||||
$major, $minor, $patch = $env:_PACKAGE_VERSION.split('.')
|
||||
|
||||
$versionInfo = @"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION $major,$minor,$patch,0
|
||||
PRODUCTVERSION $major,$minor,$patch,0
|
||||
FILEOS 0x40004
|
||||
FILETYPE 0x1
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904b0"
|
||||
{
|
||||
VALUE "CompanyName", "Bitwarden Inc."
|
||||
VALUE "ProductName", "Bitwarden"
|
||||
VALUE "FileDescription", "Bitwarden Directory Connector CLI"
|
||||
VALUE "FileVersion", "$env:_PACKAGE_VERSION"
|
||||
VALUE "ProductVersion", "$env:_PACKAGE_VERSION"
|
||||
VALUE "OriginalFilename", "bwdc.exe"
|
||||
VALUE "InternalName", "bwdc"
|
||||
VALUE "LegalCopyright", "Copyright Bitwarden Inc."
|
||||
}
|
||||
}
|
||||
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x0409 0x04B0
|
||||
}
|
||||
}
|
||||
"@
|
||||
|
||||
$versionInfo | Out-File ./version-info.rc
|
||||
|
||||
- name: Resource Hacker
|
||||
shell: cmd
|
||||
run: |
|
||||
set PATH=%PATH%;C:\Program Files (x86)\Resource Hacker
|
||||
set WIN_PKG=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\fetched-v%_WIN_PKG_FETCH_VERSION%-win-x64
|
||||
set WIN_PKG_BUILT=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\built-v%_WIN_PKG_FETCH_VERSION%-win-x64
|
||||
|
||||
ResourceHacker -open %WIN_PKG% -save %WIN_PKG% -action delete -mask ICONGROUP,1,
|
||||
ResourceHacker -open version-info.rc -save version-info.res -action compile
|
||||
ResourceHacker -open %WIN_PKG% -save %WIN_PKG% -action addoverwrite -resource version-info.res
|
||||
|
||||
- name: Install
|
||||
run: npm install
|
||||
|
||||
@@ -340,7 +249,7 @@ jobs:
|
||||
- name: Version Test
|
||||
shell: pwsh
|
||||
run: |
|
||||
Expand-Archive -Path "dist-cli\bwdc-windows-${{ env._PACKAGE_VERSION }}.zip" -DestinationPath "test\windows"
|
||||
Expand-Archive -Path "dist-cli\bwdc-windows-$env:_PACKAGE_VERSION.zip" -DestinationPath "test\windows"
|
||||
$testVersion = Invoke-Expression '& .\test\windows\bwdc.exe -v'
|
||||
echo "version: ${env:_PACKAGE_VERSION}"
|
||||
echo "testVersion: $testVersion"
|
||||
@@ -348,44 +257,38 @@ jobs:
|
||||
Throw "Version test failed."
|
||||
}
|
||||
|
||||
- name: Create checksums
|
||||
run: |
|
||||
checksum -f="./dist-cli/bwdc-windows-${env:_PACKAGE_VERSION}.zip" `
|
||||
-t sha256 | Out-File ./dist-cli/bwdc-windows-sha256-${env:_PACKAGE_VERSION}.txt
|
||||
|
||||
- name: Upload Windows Zip to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
||||
path: ./dist-cli/bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Windows checksum to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
with:
|
||||
name: bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
path: ./dist-cli/bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
windows-gui:
|
||||
name: Build Windows GUI
|
||||
runs-on: windows-2022
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
HUSKY: 0
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
@@ -403,39 +306,60 @@ jobs:
|
||||
- name: Install Node dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
with:
|
||||
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "code-signing-vault-url,
|
||||
code-signing-client-id,
|
||||
code-signing-tenant-id,
|
||||
code-signing-client-secret,
|
||||
code-signing-cert-name"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
|
||||
- name: Build & Sign
|
||||
run: npm run dist:win
|
||||
env:
|
||||
ELECTRON_BUILDER_SIGN: 1
|
||||
SIGNING_VAULT_URL: ${{ secrets.SIGNING_VAULT_URL }}
|
||||
SIGNING_CLIENT_ID: ${{ secrets.SIGNING_CLIENT_ID }}
|
||||
SIGNING_TENANT_ID: ${{ secrets.SIGNING_TENANT_ID }}
|
||||
SIGNING_CLIENT_SECRET: ${{ secrets.SIGNING_CLIENT_SECRET }}
|
||||
SIGNING_CERT_NAME: ${{ secrets.SIGNING_CERT_NAME }}
|
||||
SIGNING_VAULT_URL: ${{ steps.retrieve-secrets.outputs.code-signing-vault-url }}
|
||||
SIGNING_CLIENT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-client-id }}
|
||||
SIGNING_TENANT_ID: ${{ steps.retrieve-secrets.outputs.code-signing-tenant-id }}
|
||||
SIGNING_CLIENT_SECRET: ${{ steps.retrieve-secrets.outputs.code-signing-client-secret }}
|
||||
SIGNING_CERT_NAME: ${{ steps.retrieve-secrets.outputs.code-signing-cert-name }}
|
||||
|
||||
- name: Upload Portable Executable to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
||||
path: ./dist/Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Installer Executable to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Installer Executable Blockmap to GitHub
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
||||
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload latest auto-update artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: latest.yml
|
||||
path: ./dist/latest.yml
|
||||
@@ -444,27 +368,32 @@ jobs:
|
||||
|
||||
linux-gui:
|
||||
name: Build Linux GUI
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: read
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
HUSKY: 0
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g node-gyp
|
||||
node-gyp install $(node -v)
|
||||
node-gyp install "$(node -v)"
|
||||
|
||||
- name: Set up environment
|
||||
run: |
|
||||
@@ -482,14 +411,14 @@ jobs:
|
||||
run: npm run dist:lin
|
||||
|
||||
- name: Upload AppImage
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload latest auto-update artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: latest-linux.yml
|
||||
path: ./dist/latest-linux.yml
|
||||
@@ -500,25 +429,31 @@ jobs:
|
||||
name: Build MacOS GUI
|
||||
runs-on: macos-13
|
||||
needs: setup
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
env:
|
||||
NODE_OPTIONS: --max_old_space_size=4096
|
||||
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
|
||||
_NODE_VERSION: ${{ needs.setup.outputs.node_version }}
|
||||
HUSKY: 0
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: '18'
|
||||
node-version: ${{ env._NODE_VERSION }}
|
||||
|
||||
- name: Update NPM
|
||||
run: |
|
||||
npm install -g node-gyp
|
||||
node-gyp install $(node -v)
|
||||
node-gyp install "$(node -v)"
|
||||
|
||||
- name: Print environment
|
||||
run: |
|
||||
@@ -527,31 +462,43 @@ jobs:
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
echo "GitHub event: $GITHUB_EVENT"
|
||||
|
||||
- name: Login to Azure
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
|
||||
- name: Get Azure Key Vault secrets
|
||||
id: get-kv-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||
with:
|
||||
keyvault: gh-directory-connector
|
||||
secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER"
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
|
||||
- name: Set up keychain
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
|
||||
@@ -563,12 +510,12 @@ jobs:
|
||||
security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Load package version
|
||||
run: |
|
||||
$rootPath = $env:GITHUB_WORKSPACE;
|
||||
$packageVersion = (Get-Content -Raw -Path $rootPath\package.json | ConvertFrom-Json).version;
|
||||
$packageVersion = (Get-Content -Raw -Path "$rootPath\package.json" | ConvertFrom-Json).version;
|
||||
|
||||
Write-Output "Setting package version to $packageVersion";
|
||||
Write-Output "PACKAGE_VERSION=$packageVersion" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append;
|
||||
@@ -576,45 +523,47 @@ jobs:
|
||||
|
||||
- name: Install Node dependencies
|
||||
run: npm install
|
||||
|
||||
|
||||
- name: Set up private auth key
|
||||
env:
|
||||
_APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
run: |
|
||||
mkdir ~/private_keys
|
||||
cat << EOF > ~/private_keys/AuthKey_UFD296548T.p8
|
||||
${{ secrets.APP_STORE_CONNECT_AUTH_KEY }}
|
||||
${_APP_STORE_CONNECT_AUTH_KEY}
|
||||
EOF
|
||||
|
||||
- name: Build application
|
||||
run: npm run dist:mac
|
||||
env:
|
||||
APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}
|
||||
APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}
|
||||
APP_STORE_CONNECT_AUTH_KEY: UFD296548T
|
||||
APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_UFD296548T.p8
|
||||
CSC_FOR_PULL_REQUEST: true
|
||||
|
||||
- name: Upload .zip artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload .dmg artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload .dmg Blockmap artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
||||
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload latest auto-update artifact
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: latest-mac.yml
|
||||
path: ./dist/latest-mac.yml
|
||||
@@ -623,9 +572,8 @@ jobs:
|
||||
|
||||
check-failures:
|
||||
name: Check for failures
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- cloc
|
||||
- setup
|
||||
- linux-cli
|
||||
- macos-cli
|
||||
@@ -633,16 +581,24 @@ jobs:
|
||||
- windows-gui
|
||||
- linux-gui
|
||||
- macos-gui
|
||||
permissions:
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Check if any job failed
|
||||
if: github.ref == 'refs/heads/main' && contains(needs.*.result, 'failure')
|
||||
if: |
|
||||
(github.ref == 'refs/heads/main'
|
||||
|| github.ref == 'refs/heads/rc'
|
||||
|| github.ref == 'refs/heads/hotfix-rc')
|
||||
&& contains(needs.*.result, 'failure')
|
||||
run: exit 1
|
||||
|
||||
- name: Login to Azure - CI subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
- name: Log in to Azure
|
||||
if: failure()
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
@@ -652,6 +608,9 @@ jobs:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "devops-alerts-slack-webhook-url"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
|
||||
- name: Notify Slack on failure
|
||||
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0
|
||||
if: failure()
|
||||
|
||||
6
.github/workflows/enforce-labels.yml
vendored
6
.github/workflows/enforce-labels.yml
vendored
@@ -1,13 +1,15 @@
|
||||
---
|
||||
name: Enforce PR labels
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [labeled, unlabeled, opened, edited, synchronize]
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
jobs:
|
||||
enforce-label:
|
||||
name: EnforceLabel
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Enforce Label
|
||||
uses: yogevbd/enforce-label-action@a3c219da6b8fa73f6ba62b68ff09c469b3a1c024 # 2.2.2
|
||||
|
||||
77
.github/workflows/integration-test.yml
vendored
Normal file
77
.github/workflows/integration-test.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
name: Integration Testing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
paths:
|
||||
- ".github/workflows/integration-test.yml" # this file
|
||||
- "src/services/ldap-directory.service*" # we only have integration for LDAP testing at the moment
|
||||
- "./openldap/**/*" # any change to test fixtures
|
||||
- "./docker-compose.yml" # any change to Docker configuration
|
||||
- "./package.json" # dependencies
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/integration-test.yml" # this file
|
||||
- "src/services/ldap-directory.service*" # we only have integration for LDAP testing at the moment
|
||||
- "./openldap/**/*" # any change to test fixtures
|
||||
- "./docker-compose.yml" # any change to Docker configuration
|
||||
- "./package.json" # dependencies
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write # required by dorny/test-reporter to upload its results
|
||||
jobs:
|
||||
testing:
|
||||
name: Run tests
|
||||
if: ${{ startsWith(github.head_ref, 'version_bump_') == false }}
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Node version
|
||||
id: retrieve-node-version
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
node-version: ${{ steps.retrieve-node-version.outputs.node_version }}
|
||||
|
||||
- name: Install Node dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Install mkcert
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install mkcert
|
||||
|
||||
- name: Setup integration tests
|
||||
run: npm run test:integration:setup
|
||||
|
||||
- name: Run integration tests
|
||||
run: npm run test:integration --coverage
|
||||
|
||||
- name: Report test results
|
||||
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3 # v2.1.1
|
||||
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && !cancelled() }}
|
||||
with:
|
||||
name: Test Results
|
||||
path: "junit.xml"
|
||||
reporter: jest-junit
|
||||
fail-on-error: true
|
||||
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@5a605bd92782ce0810fa3b8acc235c921b497052 # v5.2.0
|
||||
|
||||
- name: Upload results to codecov.io
|
||||
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
|
||||
41
.github/workflows/release.yml
vendored
41
.github/workflows/release.yml
vendored
@@ -1,4 +1,3 @@
|
||||
---
|
||||
name: Release
|
||||
|
||||
on:
|
||||
@@ -14,22 +13,29 @@ on:
|
||||
- Redeploy
|
||||
- Dry Run
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
name: Setup
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: read
|
||||
outputs:
|
||||
release-version: ${{ steps.version.outputs.version }}
|
||||
release_version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" != "refs/heads/main" ]]; then
|
||||
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
|
||||
echo "==================================="
|
||||
echo "[!] Can only release from the 'main' branch"
|
||||
echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
|
||||
echo "==================================="
|
||||
exit 1
|
||||
fi
|
||||
@@ -38,17 +44,21 @@ jobs:
|
||||
id: version
|
||||
uses: bitwarden/gh-actions/release-version-check@main
|
||||
with:
|
||||
release-type: ${{ github.event.inputs.release_type }}
|
||||
release-type: ${{ inputs.release_type }}
|
||||
project-type: ts
|
||||
file: package.json
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
needs: setup
|
||||
permissions:
|
||||
actions: read
|
||||
packages: read
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
uses: bitwarden/gh-actions/download-artifacts@main
|
||||
with:
|
||||
workflow: build.yml
|
||||
@@ -56,7 +66,7 @@ jobs:
|
||||
branch: ${{ github.ref_name }}
|
||||
|
||||
- name: Dry Run - Download all artifacts
|
||||
if: ${{ github.event.inputs.release_type == 'Dry Run' }}
|
||||
if: ${{ inputs.release_type == 'Dry Run' }}
|
||||
uses: bitwarden/gh-actions/download-artifacts@main
|
||||
with:
|
||||
workflow: build.yml
|
||||
@@ -64,17 +74,14 @@ jobs:
|
||||
branch: main
|
||||
|
||||
- name: Create release
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
uses: ncipollo/release-action@2c591bcc8ecdcd2db72b97d6147f871fcd833ba5 # v1.14.0
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 # v1.15.0
|
||||
env:
|
||||
PKG_VERSION: ${{ needs.setup.outputs.release-version }}
|
||||
PKG_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||
with:
|
||||
artifacts: "./bwdc-windows-${{ env.PKG_VERSION }}.zip,
|
||||
./bwdc-macos-${{ env.PKG_VERSION }}.zip,
|
||||
./bwdc-linux-${{ env.PKG_VERSION }}.zip,
|
||||
./bwdc-windows-sha256-${{ env.PKG_VERSION }}.txt,
|
||||
./bwdc-macos-sha256-${{ env.PKG_VERSION }}.txt,
|
||||
./bwdc-linux-sha256-${{ env.PKG_VERSION }}.txt,
|
||||
./Bitwarden-Connector-Portable-${{ env.PKG_VERSION }}.exe,
|
||||
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe,
|
||||
./Bitwarden-Connector-Installer-${{ env.PKG_VERSION }}.exe.blockmap,
|
||||
|
||||
78
.github/workflows/scan.yml
vendored
78
.github/workflows/scan.yml
vendored
@@ -5,74 +5,48 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches-ignore:
|
||||
- "main"
|
||||
pull_request_target:
|
||||
types: [opened, synchronize]
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- "main"
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
check-run:
|
||||
name: Check PR run
|
||||
uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
sast:
|
||||
name: SAST scan
|
||||
runs-on: ubuntu-22.04
|
||||
name: Checkmarx
|
||||
uses: bitwarden/gh-actions/.github/workflows/_checkmarx.yml@main
|
||||
needs: check-run
|
||||
secrets:
|
||||
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Scan with Checkmarx
|
||||
uses: checkmarx/ast-github-action@6c56658230f79c227a55120e9b24845d574d5225 # 2.0.31
|
||||
env:
|
||||
INCREMENTAL: "${{ contains(github.event_name, 'pull_request') && '--sast-incremental' || '' }}"
|
||||
with:
|
||||
project_name: ${{ github.repository }}
|
||||
cx_tenant: ${{ secrets.CHECKMARX_TENANT }}
|
||||
base_uri: https://ast.checkmarx.net/
|
||||
cx_client_id: ${{ secrets.CHECKMARX_CLIENT_ID }}
|
||||
cx_client_secret: ${{ secrets.CHECKMARX_SECRET }}
|
||||
additional_params: |
|
||||
--report-format sarif \
|
||||
--filter "state=TO_VERIFY;PROPOSED_NOT_EXPLOITABLE;CONFIRMED;URGENT" \
|
||||
--output-path . ${{ env.INCREMENTAL }}
|
||||
|
||||
- name: Upload Checkmarx results to GitHub
|
||||
uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
|
||||
with:
|
||||
sarif_file: cx_result.sarif
|
||||
id-token: write
|
||||
|
||||
quality:
|
||||
name: Quality scan
|
||||
runs-on: ubuntu-22.04
|
||||
name: Sonar
|
||||
uses: bitwarden/gh-actions/.github/workflows/_sonar.yml@main
|
||||
needs: check-run
|
||||
secrets:
|
||||
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
- name: Scan with SonarCloud
|
||||
uses: sonarsource/sonarcloud-github-action@eb211723266fe8e83102bac7361f0a05c3ac1d1b # v3.0.0
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.organization=${{ github.repository_owner }}
|
||||
-Dsonar.projectKey=${{ github.repository_owner }}_${{ github.event.repository.name }}
|
||||
-Dsonar.tests=.
|
||||
-Dsonar.sources=.
|
||||
-Dsonar.test.inclusions=**/*.spec.ts
|
||||
-Dsonar.exclusions=**/*.spec.ts
|
||||
id-token: write
|
||||
|
||||
52
.github/workflows/test.yml
vendored
52
.github/workflows/test.yml
vendored
@@ -5,50 +5,36 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- "rc"
|
||||
- "hotfix-rc"
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-test-secrets:
|
||||
name: Check for test secrets
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
available: ${{ steps.check-test-secrets.outputs.available }}
|
||||
permissions:
|
||||
contents: read
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write # required by dorny/test-reporter to upload its results
|
||||
|
||||
steps:
|
||||
- name: Check
|
||||
id: check-test-secrets
|
||||
run: |
|
||||
if [ "${{ secrets.CODECOV_TOKEN }}" != '' ]; then
|
||||
echo "available=true" >> $GITHUB_OUTPUT;
|
||||
else
|
||||
echo "available=false" >> $GITHUB_OUTPUT;
|
||||
fi
|
||||
jobs:
|
||||
|
||||
testing:
|
||||
name: Run tests
|
||||
if: ${{ startsWith(github.head_ref, 'version_bump_') == false }}
|
||||
runs-on: ubuntu-22.04
|
||||
needs: check-test-secrets
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Node version
|
||||
id: retrieve-node-version
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
with:
|
||||
cache: 'npm'
|
||||
cache-dependency-path: '**/package-lock.json'
|
||||
@@ -67,8 +53,8 @@ jobs:
|
||||
run: npm run test --coverage
|
||||
|
||||
- name: Report test results
|
||||
uses: dorny/test-reporter@31a54ee7ebcacc03a09ea97a7e5465a47b84aea5 # v1.9.1
|
||||
if: ${{ needs.check-test-secrets.outputs.available == 'true' && !cancelled() }}
|
||||
uses: dorny/test-reporter@dc3a92680fcc15842eef52e8c4606ea7ce6bd3f3 # v2.1.1
|
||||
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && !cancelled() }}
|
||||
with:
|
||||
name: Test Results
|
||||
path: "junit.xml"
|
||||
@@ -76,13 +62,7 @@ jobs:
|
||||
fail-on-error: true
|
||||
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
||||
if: ${{ needs.check-test-secrets.outputs.available == 'true' }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
uses: codecov/codecov-action@5a605bd92782ce0810fa3b8acc235c921b497052 # v5.2.0
|
||||
|
||||
- name: Upload results to codecov.io
|
||||
uses: codecov/test-results-action@1b5b448b98e58ba90d1a1a1d9fcb72ca2263be46 # v1.0.0
|
||||
if: ${{ needs.check-test-secrets.outputs.available == 'true' }}
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
uses: codecov/test-results-action@4e79e65778be1cecd5df25e14af1eafb6df80ea9 # v1.0.2
|
||||
|
||||
159
.github/workflows/version-bump.yml
vendored
159
.github/workflows/version-bump.yml
vendored
@@ -1,4 +1,3 @@
|
||||
---
|
||||
name: Version Bump
|
||||
|
||||
on:
|
||||
@@ -8,17 +7,16 @@ on:
|
||||
description: "New version override (leave blank for automatic calculation, example: '2024.1.0')"
|
||||
required: false
|
||||
type: string
|
||||
enable_slack_notification:
|
||||
description: "Enable Slack notifications for upcoming release?"
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
bump_version:
|
||||
name: Bump Version
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
version: ${{ steps.set-final-version-output.outputs.version }}
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Validate version input
|
||||
if: ${{ inputs.version_number_override != '' }}
|
||||
@@ -26,55 +24,46 @@ jobs:
|
||||
with:
|
||||
version: ${{ inputs.version_number_override }}
|
||||
|
||||
- name: Slack Notification Check
|
||||
run: |
|
||||
if [[ "${{ inputs.enable_slack_notification }}" == true ]]; then
|
||||
echo "Slack notifications enabled."
|
||||
else
|
||||
echo "Slack notifications disabled."
|
||||
fi
|
||||
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
- name: Login to Azure - CI Subscription
|
||||
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
with:
|
||||
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||||
tenant_id: ${{ secrets.AZURE_TENANT_ID }}
|
||||
client_id: ${{ secrets.AZURE_CLIENT_ID }}
|
||||
|
||||
- name: Retrieve secrets
|
||||
id: retrieve-secrets
|
||||
- name: Get Azure Key Vault secrets
|
||||
id: get-kv-secrets
|
||||
uses: bitwarden/gh-actions/get-keyvault-secrets@main
|
||||
with:
|
||||
keyvault: "bitwarden-ci"
|
||||
secrets: "github-gpg-private-key,
|
||||
github-gpg-private-key-passphrase"
|
||||
keyvault: gh-org-bitwarden
|
||||
secrets: "BW-GHAPP-ID,BW-GHAPP-KEY"
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
|
||||
- name: Generate GH App token
|
||||
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
|
||||
id: app-token
|
||||
with:
|
||||
gpg_private_key: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key }}
|
||||
passphrase: ${{ steps.retrieve-secrets.outputs.github-gpg-private-key-passphrase }}
|
||||
git_user_signingkey: true
|
||||
git_commit_gpgsign: true
|
||||
app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
|
||||
private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
|
||||
|
||||
- name: Checkout Branch
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Setup git
|
||||
run: |
|
||||
git config --local user.email "106330231+bitwarden-devops-bot@users.noreply.github.com"
|
||||
git config --local user.name "bitwarden-devops-bot"
|
||||
|
||||
- name: Create Version Branch
|
||||
id: create-branch
|
||||
run: |
|
||||
NAME=version_bump_${{ github.ref_name }}_$(date +"%Y-%m-%d")
|
||||
git switch -c $NAME
|
||||
echo "name=$NAME" >> $GITHUB_OUTPUT
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
- name: Get current version
|
||||
id: current-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Verify input version
|
||||
if: ${{ inputs.version_number_override != '' }}
|
||||
@@ -89,8 +78,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check if version is newer.
|
||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
||||
if [ $? -eq 0 ]; then
|
||||
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||
echo "Version check successful."
|
||||
else
|
||||
echo "Version check failed."
|
||||
@@ -122,84 +110,35 @@ jobs:
|
||||
|
||||
- name: Set final version output
|
||||
id: set-final-version-output
|
||||
env:
|
||||
_BUMP_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-version-override.outcome }}
|
||||
_INPUT_VERSION_NUMBER_OVERRIDE: ${{ inputs.version_number_override }}
|
||||
_BUMP_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-version-automatic.outcome }}
|
||||
_CALCULATE_NEXT_VERSION: ${{ steps.calculate-next-version.outputs.version }}
|
||||
|
||||
run: |
|
||||
if [[ "${{ steps.bump-version-override.outcome }}" == "success" ]]; then
|
||||
echo "version=${{ inputs.version_number_override }}" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ steps.bump-version-automatic.outcome }}" == "success" ]]; then
|
||||
echo "version=${{ steps.calculate-next-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
if [[ "$_BUMP_VERSION_OVERRIDE_OUTCOME" == "success" ]]; then
|
||||
echo "version=$_INPUT_VERSION_NUMBER_OVERRIDE" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$_BUMP_VERSION_AUTOMATIC_OUTCOME" == "success" ]]; then
|
||||
echo "version=$_CALCULATE_NEXT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check if version changed
|
||||
id: version-changed
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "changes_to_commit=TRUE" >> $GITHUB_OUTPUT
|
||||
echo "changes_to_commit=TRUE" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changes_to_commit=FALSE" >> $GITHUB_OUTPUT
|
||||
echo "changes_to_commit=FALSE" >> "$GITHUB_OUTPUT"
|
||||
echo "No changes to commit!";
|
||||
fi
|
||||
|
||||
- name: Commit files
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
run: git commit -m "Bumped version to ${{ steps.set-final-version-output.outputs.version }}" -a
|
||||
env:
|
||||
_VERSION: ${{ steps.set-final-version-output.outputs.version }}
|
||||
run: git commit -m "Bumped version to $_VERSION" -a
|
||||
|
||||
- name: Push changes
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
env:
|
||||
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
||||
run: git push -u origin $PR_BRANCH
|
||||
|
||||
- name: Generate GH App token
|
||||
uses: actions/create-github-app-token@3378cda945da322a8db4b193e19d46352ebe2de5 # v1.10.4
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.GH_APP_ID }}
|
||||
private-key: ${{ secrets.GH_APP_KEY }}
|
||||
owner: ${{ github.repository_owner }}
|
||||
|
||||
- name: Create Version PR
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
id: create-pr
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
PR_BRANCH: ${{ steps.create-branch.outputs.name }}
|
||||
TITLE: "Bump version to ${{ steps.set-final-version-output.outputs.version }}"
|
||||
run: |
|
||||
PR_URL=$(gh pr create --title "$TITLE" \
|
||||
--base "main" \
|
||||
--head "$PR_BRANCH" \
|
||||
--label "version update" \
|
||||
--label "automated pr" \
|
||||
--body "
|
||||
## Type of change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature development
|
||||
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
|
||||
- [ ] Build/deploy pipeline (DevOps)
|
||||
- [X] Other
|
||||
|
||||
## Objective
|
||||
Automated version bump to ${{ steps.set-final-version-output.outputs.version }}")
|
||||
echo "pr_number=${PR_URL##*/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Approve PR
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
||||
run: gh pr review $PR_NUMBER --approve
|
||||
|
||||
- name: Merge PR
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }}
|
||||
run: gh pr merge $PR_NUMBER --squash --auto --delete-branch
|
||||
|
||||
- name: Report upcoming release version to Slack
|
||||
if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' && inputs.enable_slack_notification == true }}
|
||||
uses: bitwarden/gh-actions/report-upcoming-release-version@main
|
||||
with:
|
||||
version: ${{ steps.set-final-version-output.outputs.version }}
|
||||
project: ${{ github.repository }}
|
||||
AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }}
|
||||
run: git push
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
# Bitwarden Directory Connector
|
||||
|
||||
The Bitwarden Directory Connector is a a desktop application used to sync your Bitwarden enterprise organization to an existing directory of users and groups.
|
||||
The Bitwarden Directory Connector is a desktop application used to sync your Bitwarden enterprise organization to an existing directory of users and groups.
|
||||
|
||||
Supported directories:
|
||||
|
||||
- Active Directory
|
||||
- Any other LDAP-based directory
|
||||
- Azure Active Directory
|
||||
- Microsoft Entra ID
|
||||
- G Suite (Google)
|
||||
- Okta
|
||||
|
||||
|
||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
open-ldap:
|
||||
image: bitnamilegacy/openldap:latest
|
||||
hostname: openldap
|
||||
environment:
|
||||
- LDAP_ADMIN_USERNAME=admin
|
||||
- LDAP_ADMIN_PASSWORD=admin
|
||||
- LDAP_ROOT=dc=bitwarden,dc=com
|
||||
- LDAP_ENABLE_TLS=yes
|
||||
- LDAP_TLS_CERT_FILE=/certs/openldap.pem
|
||||
- LDAP_TLS_KEY_FILE=/certs/openldap-key.pem
|
||||
- LDAP_TLS_CA_FILE=/certs/rootCA.pem
|
||||
volumes:
|
||||
- "./openldap/ldifs:/ldifs"
|
||||
- "./openldap/certs:/certs"
|
||||
ports:
|
||||
- "1389:1389"
|
||||
- "1636:1636"
|
||||
@@ -1,35 +0,0 @@
|
||||
<div
|
||||
#callout
|
||||
class="callout callout-{{ calloutStyle }}"
|
||||
[ngClass]="{ clickable: clickable }"
|
||||
[attr.role]="useAlertRole ? 'alert' : null"
|
||||
>
|
||||
<h3 class="callout-heading" *ngIf="title">
|
||||
<i class="bwi {{ icon }}" *ngIf="icon" aria-hidden="true"></i>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<div class="enforced-policy-options" *ngIf="enforcedPolicyOptions">
|
||||
{{ enforcedPolicyMessage }}
|
||||
<ul>
|
||||
<li *ngIf="enforcedPolicyOptions?.minComplexity > 0">
|
||||
{{ "policyInEffectMinComplexity" | i18n: getPasswordScoreAlertDisplay() }}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.minLength > 0">
|
||||
{{ "policyInEffectMinLength" | i18n: enforcedPolicyOptions?.minLength.toString() }}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireUpper">
|
||||
{{ "policyInEffectUppercase" | i18n }}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireLower">
|
||||
{{ "policyInEffectLowercase" | i18n }}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireNumbers">
|
||||
{{ "policyInEffectNumbers" | i18n }}
|
||||
</li>
|
||||
<li *ngIf="enforcedPolicyOptions?.requireSpecial">
|
||||
{{ "policyInEffectSpecial" | i18n: "!@#$%^&*" }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
@@ -1,78 +0,0 @@
|
||||
import { Component, Input, OnInit } from "@angular/core";
|
||||
|
||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { MasterPasswordPolicyOptions } from "@/jslib/common/src/models/domain/masterPasswordPolicyOptions";
|
||||
|
||||
@Component({
|
||||
selector: "app-callout",
|
||||
templateUrl: "callout.component.html",
|
||||
})
|
||||
export class CalloutComponent implements OnInit {
|
||||
@Input() type = "info";
|
||||
@Input() icon: string;
|
||||
@Input() title: string;
|
||||
@Input() clickable: boolean;
|
||||
@Input() enforcedPolicyOptions: MasterPasswordPolicyOptions;
|
||||
@Input() enforcedPolicyMessage: string;
|
||||
@Input() useAlertRole = false;
|
||||
|
||||
calloutStyle: string;
|
||||
|
||||
constructor(private i18nService: I18nService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.calloutStyle = this.type;
|
||||
|
||||
if (this.enforcedPolicyMessage === undefined) {
|
||||
this.enforcedPolicyMessage = this.i18nService.t("masterPasswordPolicyInEffect");
|
||||
}
|
||||
|
||||
if (this.type === "warning" || this.type === "danger") {
|
||||
if (this.type === "danger") {
|
||||
this.calloutStyle = "danger";
|
||||
}
|
||||
if (this.title === undefined) {
|
||||
this.title = this.i18nService.t("warning");
|
||||
}
|
||||
if (this.icon === undefined) {
|
||||
this.icon = "bwi-exclamation-triangle";
|
||||
}
|
||||
} else if (this.type === "error") {
|
||||
this.calloutStyle = "danger";
|
||||
if (this.title === undefined) {
|
||||
this.title = this.i18nService.t("error");
|
||||
}
|
||||
if (this.icon === undefined) {
|
||||
this.icon = "bwi-error";
|
||||
}
|
||||
} else if (this.type === "tip") {
|
||||
this.calloutStyle = "success";
|
||||
if (this.title === undefined) {
|
||||
this.title = this.i18nService.t("tip");
|
||||
}
|
||||
if (this.icon === undefined) {
|
||||
this.icon = "bwi-lightbulb";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getPasswordScoreAlertDisplay() {
|
||||
if (this.enforcedPolicyOptions == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let str: string;
|
||||
switch (this.enforcedPolicyOptions.minComplexity) {
|
||||
case 4:
|
||||
str = this.i18nService.t("strong");
|
||||
break;
|
||||
case 3:
|
||||
str = this.i18nService.t("good");
|
||||
break;
|
||||
default:
|
||||
str = this.i18nService.t("weak");
|
||||
break;
|
||||
}
|
||||
return str + " (" + this.enforcedPolicyOptions.minComplexity + ")";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<div class="icon" aria-hidden="true">
|
||||
<img
|
||||
[src]="image"
|
||||
appFallbackSrc="{{ fallbackImage }}"
|
||||
*ngIf="imageEnabled && image"
|
||||
alt=""
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
/>
|
||||
<i class="bwi bwi-fw bwi-lg {{ icon }}" *ngIf="!imageEnabled || !image"></i>
|
||||
</div>
|
||||
@@ -1,115 +0,0 @@
|
||||
import { Component, Input, OnChanges } from "@angular/core";
|
||||
|
||||
import { EnvironmentService } from "@/jslib/common/src/abstractions/environment.service";
|
||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { CipherType } from "@/jslib/common/src/enums/cipherType";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { CipherView } from "@/jslib/common/src/models/view/cipherView";
|
||||
|
||||
/**
|
||||
* Provides a mapping from supported card brands to
|
||||
* the filenames of icon that should be present in images/cards folder of clients.
|
||||
*/
|
||||
const cardIcons: Record<string, string> = {
|
||||
Visa: "card-visa",
|
||||
Mastercard: "card-mastercard",
|
||||
Amex: "card-amex",
|
||||
Discover: "card-discover",
|
||||
"Diners Club": "card-diners-club",
|
||||
JCB: "card-jcb",
|
||||
Maestro: "card-maestro",
|
||||
UnionPay: "card-union-pay",
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: "app-vault-icon",
|
||||
templateUrl: "icon.component.html",
|
||||
})
|
||||
export class IconComponent implements OnChanges {
|
||||
@Input() cipher: CipherView;
|
||||
icon: string;
|
||||
image: string;
|
||||
fallbackImage: string;
|
||||
imageEnabled: boolean;
|
||||
|
||||
private iconsUrl: string;
|
||||
|
||||
constructor(
|
||||
environmentService: EnvironmentService,
|
||||
private stateService: StateService,
|
||||
) {
|
||||
this.iconsUrl = environmentService.getIconsUrl();
|
||||
}
|
||||
|
||||
async ngOnChanges() {
|
||||
// Components may be re-used when using cdk-virtual-scroll. Which puts the component in a weird state,
|
||||
// to avoid this we reset all state variables.
|
||||
this.image = null;
|
||||
this.fallbackImage = null;
|
||||
this.imageEnabled = !(await this.stateService.getDisableFavicon());
|
||||
this.load();
|
||||
}
|
||||
|
||||
protected load() {
|
||||
switch (this.cipher.type) {
|
||||
case CipherType.Login:
|
||||
this.icon = "bwi-globe";
|
||||
this.setLoginIcon();
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
this.icon = "bwi-sticky-note";
|
||||
break;
|
||||
case CipherType.Card:
|
||||
this.icon = "bwi-credit-card";
|
||||
this.setCardIcon();
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
this.icon = "bwi-id-card";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private setLoginIcon() {
|
||||
if (this.cipher.login.uri) {
|
||||
let hostnameUri = this.cipher.login.uri;
|
||||
let isWebsite = false;
|
||||
|
||||
if (hostnameUri.indexOf("androidapp://") === 0) {
|
||||
this.icon = "bwi-android";
|
||||
this.image = null;
|
||||
} else if (hostnameUri.indexOf("iosapp://") === 0) {
|
||||
this.icon = "bwi-apple";
|
||||
this.image = null;
|
||||
} else if (
|
||||
this.imageEnabled &&
|
||||
hostnameUri.indexOf("://") === -1 &&
|
||||
hostnameUri.indexOf(".") > -1
|
||||
) {
|
||||
hostnameUri = "http://" + hostnameUri;
|
||||
isWebsite = true;
|
||||
} else if (this.imageEnabled) {
|
||||
isWebsite = hostnameUri.indexOf("http") === 0 && hostnameUri.indexOf(".") > -1;
|
||||
}
|
||||
|
||||
if (this.imageEnabled && isWebsite) {
|
||||
try {
|
||||
this.image = this.iconsUrl + "/" + Utils.getHostname(hostnameUri) + "/icon.png";
|
||||
this.fallbackImage = "images/bwi-globe.png";
|
||||
} catch (e) {
|
||||
// Ignore error since the fallback icon will be shown if image is null.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.image = null;
|
||||
}
|
||||
}
|
||||
|
||||
private setCardIcon() {
|
||||
const brand = this.cipher.card.brand;
|
||||
if (this.imageEnabled && brand in cardIcons) {
|
||||
this.icon = "credit-card-icon " + cardIcons[brand];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { Directive } from "@angular/core";
|
||||
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
|
||||
import { ModalRef } from "./modal/modal.ref";
|
||||
|
||||
/**
|
||||
* Used to verify the user's Master Password for the "Master Password Re-prompt" feature only.
|
||||
* See UserVerificationComponent for any other situation where you need to verify the user's identity.
|
||||
*/
|
||||
@Directive()
|
||||
export class PasswordRepromptComponent {
|
||||
showPassword = false;
|
||||
masterPassword = "";
|
||||
|
||||
constructor(
|
||||
private modalRef: ModalRef,
|
||||
private cryptoService: CryptoService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
togglePassword() {
|
||||
this.showPassword = !this.showPassword;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
if (!(await this.cryptoService.compareAndUpdateKeyHash(this.masterPassword, null))) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("invalidMasterPassword"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.modalRef.close(true);
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ import {
|
||||
]),
|
||||
],
|
||||
preserveWhitespaces: false,
|
||||
standalone: false,
|
||||
})
|
||||
export class BitwardenToast extends BaseToast {
|
||||
constructor(
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, Input, Renderer2 } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appA11yTitle]",
|
||||
standalone: false,
|
||||
})
|
||||
export class A11yTitleDirective {
|
||||
@Input() set appA11yTitle(title: string) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ValidationService } from "../services/validation.service";
|
||||
*/
|
||||
@Directive({
|
||||
selector: "[appApiAction]",
|
||||
standalone: false,
|
||||
})
|
||||
export class ApiActionDirective implements OnChanges {
|
||||
@Input() appApiAction: Promise<any>;
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
|
||||
@Directive({
|
||||
selector: "[appAutofocus]",
|
||||
standalone: false,
|
||||
})
|
||||
export class AutofocusDirective {
|
||||
@Input() set appAutofocus(condition: boolean | string) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appBlurClick]",
|
||||
standalone: false,
|
||||
})
|
||||
export class BlurClickDirective {
|
||||
constructor(private el: ElementRef) {}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener, OnInit } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appBoxRow]",
|
||||
standalone: false,
|
||||
})
|
||||
export class BoxRowDirective implements OnInit {
|
||||
el: HTMLElement = null;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, ElementRef, HostListener, Input } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appFallbackSrc]",
|
||||
standalone: false,
|
||||
})
|
||||
export class FallbackSrcDirective {
|
||||
@Input("appFallbackSrc") appFallbackSrc: string;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appStopClick]",
|
||||
standalone: false,
|
||||
})
|
||||
export class StopClickDirective {
|
||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Directive, HostListener } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appStopProp]",
|
||||
standalone: false,
|
||||
})
|
||||
export class StopPropDirective {
|
||||
@HostListener("click", ["$event"]) onClick($event: MouseEvent) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { I18nService } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
|
||||
@Pipe({
|
||||
name: "i18n",
|
||||
standalone: false,
|
||||
})
|
||||
export class I18nPipe implements PipeTransform {
|
||||
constructor(private i18nService: I18nService) {}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
import { CipherView } from "@/jslib/common/src/models/view/cipherView";
|
||||
|
||||
@Pipe({
|
||||
name: "searchCiphers",
|
||||
})
|
||||
export class SearchCiphersPipe implements PipeTransform {
|
||||
transform(ciphers: CipherView[], searchText: string, deleted = false): CipherView[] {
|
||||
if (ciphers == null || ciphers.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (searchText == null || searchText.length < 2) {
|
||||
return ciphers.filter((c) => {
|
||||
return deleted !== c.isDeleted;
|
||||
});
|
||||
}
|
||||
|
||||
searchText = searchText.trim().toLowerCase();
|
||||
return ciphers.filter((c) => {
|
||||
if (deleted !== c.isDeleted) {
|
||||
return false;
|
||||
}
|
||||
if (c.name != null && c.name.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
if (searchText.length >= 8 && c.id.startsWith(searchText)) {
|
||||
return true;
|
||||
}
|
||||
if (c.subTitle != null && c.subTitle.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
if (c.login && c.login.uri != null && c.login.uri.toLowerCase().indexOf(searchText) > -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,44 +2,36 @@ import { LOCALE_ID, NgModule } from "@angular/core";
|
||||
|
||||
import { ApiService as ApiServiceAbstraction } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService as AppIdServiceAbstraction } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { AuthService as AuthServiceAbstraction } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "@/jslib/common/src/abstractions/broadcaster.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@/jslib/common/src/abstractions/cryptoFunction.service";
|
||||
import { EnvironmentService as EnvironmentServiceAbstraction } from "@/jslib/common/src/abstractions/environment.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@/jslib/common/src/abstractions/i18n.service";
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@/jslib/common/src/abstractions/keyConnector.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService as MessagingServiceAbstraction } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { OrganizationService as OrganizationServiceAbstraction } from "@/jslib/common/src/abstractions/organization.service";
|
||||
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@/jslib/common/src/abstractions/passwordGeneration.service";
|
||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { PolicyService as PolicyServiceAbstraction } from "@/jslib/common/src/abstractions/policy.service";
|
||||
import { StateService as StateServiceAbstraction } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "@/jslib/common/src/abstractions/stateMigration.service";
|
||||
import { StorageService as StorageServiceAbstraction } from "@/jslib/common/src/abstractions/storage.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService as TwoFactorServiceAbstraction } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { StateFactory } from "@/jslib/common/src/factories/stateFactory";
|
||||
import { Account } from "@/jslib/common/src/models/domain/account";
|
||||
import { GlobalState } from "@/jslib/common/src/models/domain/globalState";
|
||||
import { ApiService } from "@/jslib/common/src/services/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/services/appId.service";
|
||||
import { AuthService } from "@/jslib/common/src/services/auth.service";
|
||||
import { ConsoleLogService } from "@/jslib/common/src/services/consoleLog.service";
|
||||
import { CryptoService } from "@/jslib/common/src/services/crypto.service";
|
||||
import { EnvironmentService } from "@/jslib/common/src/services/environment.service";
|
||||
import { KeyConnectorService } from "@/jslib/common/src/services/keyConnector.service";
|
||||
import { OrganizationService } from "@/jslib/common/src/services/organization.service";
|
||||
import { PasswordGenerationService } from "@/jslib/common/src/services/passwordGeneration.service";
|
||||
import { PolicyService } from "@/jslib/common/src/services/policy.service";
|
||||
import { StateService } from "@/jslib/common/src/services/state.service";
|
||||
import { StateMigrationService } from "@/jslib/common/src/services/stateMigration.service";
|
||||
import { TokenService } from "@/jslib/common/src/services/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/services/twoFactor.service";
|
||||
|
||||
import { SafeInjectionToken, SECURE_STORAGE, WINDOW } from '../../../../src/app/services/injection-tokens';
|
||||
import { SafeProvider, safeProvider } from '../../../../src/app/services/safe-provider';
|
||||
import {
|
||||
SafeInjectionToken,
|
||||
SECURE_STORAGE,
|
||||
WINDOW,
|
||||
} from "../../../../src/app/services/injection-tokens";
|
||||
import { SafeProvider, safeProvider } from "../../../../src/app/services/safe-provider";
|
||||
|
||||
import { BroadcasterService } from "./broadcaster.service";
|
||||
import { ModalService } from "./modal.service";
|
||||
@@ -61,31 +53,17 @@ import { ValidationService } from "./validation.service";
|
||||
useClass: AppIdService,
|
||||
deps: [StorageServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: AuthServiceAbstraction,
|
||||
useClass: AuthService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
LogService,
|
||||
KeyConnectorServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
TwoFactorServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({ provide: LogService, useFactory: () => new ConsoleLogService(false), deps: [] }),
|
||||
safeProvider({
|
||||
provide: EnvironmentServiceAbstraction,
|
||||
useClass: EnvironmentService,
|
||||
deps: [StateServiceAbstraction],
|
||||
}),
|
||||
safeProvider({ provide: TokenServiceAbstraction, useClass: TokenService, deps: [StateServiceAbstraction] }),
|
||||
safeProvider({
|
||||
provide: TokenServiceAbstraction,
|
||||
useClass: TokenService,
|
||||
deps: [StateServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: CryptoServiceAbstraction,
|
||||
useClass: CryptoService,
|
||||
@@ -96,11 +74,6 @@ import { ValidationService } from "./validation.service";
|
||||
StateServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: PasswordGenerationServiceAbstraction,
|
||||
useClass: PasswordGenerationService,
|
||||
deps: [CryptoServiceAbstraction, PolicyServiceAbstraction, StateServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: ApiServiceAbstraction,
|
||||
useFactory: (
|
||||
@@ -125,7 +98,11 @@ import { ValidationService } from "./validation.service";
|
||||
AppIdServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({ provide: BroadcasterServiceAbstraction, useClass: BroadcasterService, useAngularDecorators: true }),
|
||||
safeProvider({
|
||||
provide: BroadcasterServiceAbstraction,
|
||||
useClass: BroadcasterService,
|
||||
useAngularDecorators: true,
|
||||
}),
|
||||
safeProvider({
|
||||
provide: StateServiceAbstraction,
|
||||
useFactory: (
|
||||
@@ -161,34 +138,6 @@ import { ValidationService } from "./validation.service";
|
||||
),
|
||||
deps: [StorageServiceAbstraction, SECURE_STORAGE],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: PolicyServiceAbstraction,
|
||||
useClass: PolicyService,
|
||||
deps: [StateServiceAbstraction, OrganizationServiceAbstraction, ApiServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: KeyConnectorServiceAbstraction,
|
||||
useClass: KeyConnectorService,
|
||||
deps: [
|
||||
StateServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
LogService,
|
||||
OrganizationServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: OrganizationServiceAbstraction,
|
||||
useClass: OrganizationService,
|
||||
deps: [StateServiceAbstraction],
|
||||
}),
|
||||
safeProvider({
|
||||
provide: TwoFactorServiceAbstraction,
|
||||
useClass: TwoFactorService,
|
||||
deps: [I18nServiceAbstraction, PlatformUtilsServiceAbstraction],
|
||||
}),
|
||||
] satisfies SafeProvider[],
|
||||
})
|
||||
export class JslibServicesModule {}
|
||||
|
||||
@@ -143,7 +143,7 @@ export class ModalService {
|
||||
dialogEl.style.zIndex = `${this.modalCount}050`;
|
||||
|
||||
const modals = Array.from(
|
||||
el.querySelectorAll('.modal-backdrop, .modal *[data-dismiss="modal"]'),
|
||||
el.querySelectorAll('.modal-backdrop, .modal *[data-bs-dismiss="modal"]'),
|
||||
);
|
||||
for (const closeElement of modals) {
|
||||
closeElement.addEventListener("click", () => {
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { AttachmentData } from "@/jslib/common/src/models/data/attachmentData";
|
||||
import { Attachment } from "@/jslib/common/src/models/domain/attachment";
|
||||
import { SymmetricCryptoKey } from "@/jslib/common/src/models/domain/symmetricCryptoKey";
|
||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
||||
|
||||
import { makeStaticByteArray, mockEnc } from "../utils";
|
||||
|
||||
describe("Attachment", () => {
|
||||
let data: AttachmentData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
id: "id",
|
||||
url: "url",
|
||||
fileName: "fileName",
|
||||
key: "key",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new AttachmentData();
|
||||
const attachment = new Attachment(data);
|
||||
|
||||
expect(attachment).toEqual({
|
||||
id: null,
|
||||
url: null,
|
||||
size: undefined,
|
||||
sizeName: null,
|
||||
key: null,
|
||||
fileName: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const attachment = new Attachment(data);
|
||||
|
||||
expect(attachment).toEqual({
|
||||
size: "1100",
|
||||
id: "id",
|
||||
url: "url",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: { encryptedString: "fileName", encryptionType: 0 },
|
||||
key: { encryptedString: "key", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("toAttachmentData", () => {
|
||||
const attachment = new Attachment(data);
|
||||
expect(attachment.toAttachmentData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const attachment = new Attachment();
|
||||
attachment.id = "id";
|
||||
attachment.url = "url";
|
||||
attachment.size = "1100";
|
||||
attachment.sizeName = "1.1 KB";
|
||||
attachment.key = mockEnc("key");
|
||||
attachment.fileName = mockEnc("fileName");
|
||||
|
||||
const cryptoService = Substitute.for<CryptoService>();
|
||||
cryptoService.getOrgKey(null).resolves(null);
|
||||
cryptoService.decryptToBytes(Arg.any(), Arg.any()).resolves(makeStaticByteArray(32));
|
||||
|
||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
||||
|
||||
const view = await attachment.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
id: "id",
|
||||
url: "url",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: "fileName",
|
||||
key: expect.any(SymmetricCryptoKey),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,73 +0,0 @@
|
||||
import { CardData } from "@/jslib/common/src/models/data/cardData";
|
||||
import { Card } from "@/jslib/common/src/models/domain/card";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Card", () => {
|
||||
let data: CardData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
cardholderName: "encHolder",
|
||||
brand: "encBrand",
|
||||
number: "encNumber",
|
||||
expMonth: "encMonth",
|
||||
expYear: "encYear",
|
||||
code: "encCode",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new CardData();
|
||||
const card = new Card(data);
|
||||
|
||||
expect(card).toEqual({
|
||||
cardholderName: null,
|
||||
brand: null,
|
||||
number: null,
|
||||
expMonth: null,
|
||||
expYear: null,
|
||||
code: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const card = new Card(data);
|
||||
|
||||
expect(card).toEqual({
|
||||
cardholderName: { encryptedString: "encHolder", encryptionType: 0 },
|
||||
brand: { encryptedString: "encBrand", encryptionType: 0 },
|
||||
number: { encryptedString: "encNumber", encryptionType: 0 },
|
||||
expMonth: { encryptedString: "encMonth", encryptionType: 0 },
|
||||
expYear: { encryptedString: "encYear", encryptionType: 0 },
|
||||
code: { encryptedString: "encCode", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("toCardData", () => {
|
||||
const card = new Card(data);
|
||||
expect(card.toCardData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const card = new Card();
|
||||
card.cardholderName = mockEnc("cardHolder");
|
||||
card.brand = mockEnc("brand");
|
||||
card.number = mockEnc("number");
|
||||
card.expMonth = mockEnc("expMonth");
|
||||
card.expYear = mockEnc("expYear");
|
||||
card.code = mockEnc("code");
|
||||
|
||||
const view = await card.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
_brand: "brand",
|
||||
_number: "number",
|
||||
_subTitle: null,
|
||||
cardholderName: "cardHolder",
|
||||
code: "code",
|
||||
expMonth: "expMonth",
|
||||
expYear: "expYear",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,599 +0,0 @@
|
||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { CipherRepromptType } from "@/jslib/common/src/enums/cipherRepromptType";
|
||||
import { CipherType } from "@/jslib/common/src/enums/cipherType";
|
||||
import { FieldType } from "@/jslib/common/src/enums/fieldType";
|
||||
import { SecureNoteType } from "@/jslib/common/src/enums/secureNoteType";
|
||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
||||
import { CipherData } from "@/jslib/common/src/models/data/cipherData";
|
||||
import { Card } from "@/jslib/common/src/models/domain/card";
|
||||
import { Cipher } from "@/jslib/common/src/models/domain/cipher";
|
||||
import { Identity } from "@/jslib/common/src/models/domain/identity";
|
||||
import { Login } from "@/jslib/common/src/models/domain/login";
|
||||
import { SecureNote } from "@/jslib/common/src/models/domain/secureNote";
|
||||
import { CardView } from "@/jslib/common/src/models/view/cardView";
|
||||
import { IdentityView } from "@/jslib/common/src/models/view/identityView";
|
||||
import { LoginView } from "@/jslib/common/src/models/view/loginView";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Cipher DTO", () => {
|
||||
it("Convert from empty CipherData", () => {
|
||||
const data = new CipherData();
|
||||
const cipher = new Cipher(data);
|
||||
|
||||
expect(cipher).toEqual({
|
||||
id: null,
|
||||
userId: null,
|
||||
organizationId: null,
|
||||
folderId: null,
|
||||
name: null,
|
||||
notes: null,
|
||||
type: undefined,
|
||||
favorite: undefined,
|
||||
organizationUseTotp: undefined,
|
||||
edit: undefined,
|
||||
viewPassword: true,
|
||||
revisionDate: null,
|
||||
collectionIds: undefined,
|
||||
localData: null,
|
||||
deletedDate: null,
|
||||
reprompt: undefined,
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
});
|
||||
});
|
||||
|
||||
describe("LoginCipher", () => {
|
||||
let cipherData: CipherData;
|
||||
|
||||
beforeEach(() => {
|
||||
cipherData = {
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
userId: "userId",
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
organizationUseTotp: true,
|
||||
favorite: false,
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
type: CipherType.Login,
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
deletedDate: null,
|
||||
reprompt: CipherRepromptType.None,
|
||||
login: {
|
||||
uris: [{ uri: "EncryptedString", match: UriMatchType.Domain }],
|
||||
username: "EncryptedString",
|
||||
password: "EncryptedString",
|
||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
||||
totp: "EncryptedString",
|
||||
autofillOnPageLoad: false,
|
||||
},
|
||||
passwordHistory: [
|
||||
{ password: "EncryptedString", lastUsedDate: "2022-01-31T12:00:00.000Z" },
|
||||
],
|
||||
attachments: [
|
||||
{
|
||||
id: "a1",
|
||||
url: "url",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: "file",
|
||||
key: "EncKey",
|
||||
},
|
||||
{
|
||||
id: "a2",
|
||||
url: "url",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: "file",
|
||||
key: "EncKey",
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
name: "EncryptedString",
|
||||
value: "EncryptedString",
|
||||
type: FieldType.Text,
|
||||
linkedId: null,
|
||||
},
|
||||
{
|
||||
name: "EncryptedString",
|
||||
value: "EncryptedString",
|
||||
type: FieldType.Hidden,
|
||||
linkedId: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
|
||||
expect(cipher).toEqual({
|
||||
id: "id",
|
||||
userId: "userId",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 1,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
collectionIds: undefined,
|
||||
localData: null,
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
login: {
|
||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
autofillOnPageLoad: false,
|
||||
username: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
password: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
totp: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
uris: [{ match: 0, uri: { encryptedString: "EncryptedString", encryptionType: 0 } }],
|
||||
},
|
||||
attachments: [
|
||||
{
|
||||
fileName: { encryptedString: "file", encryptionType: 0 },
|
||||
id: "a1",
|
||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
url: "url",
|
||||
},
|
||||
{
|
||||
fileName: { encryptedString: "file", encryptionType: 0 },
|
||||
id: "a2",
|
||||
key: { encryptedString: "EncKey", encryptionType: 0 },
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
url: "url",
|
||||
},
|
||||
],
|
||||
fields: [
|
||||
{
|
||||
linkedId: null,
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 0,
|
||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
},
|
||||
{
|
||||
linkedId: null,
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 1,
|
||||
value: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
},
|
||||
],
|
||||
passwordHistory: [
|
||||
{
|
||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
password: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("toCipherData", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const cipher = new Cipher();
|
||||
cipher.id = "id";
|
||||
cipher.organizationId = "orgId";
|
||||
cipher.folderId = "folderId";
|
||||
cipher.edit = true;
|
||||
cipher.viewPassword = true;
|
||||
cipher.organizationUseTotp = true;
|
||||
cipher.favorite = false;
|
||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
cipher.type = CipherType.Login;
|
||||
cipher.name = mockEnc("EncryptedString");
|
||||
cipher.notes = mockEnc("EncryptedString");
|
||||
cipher.deletedDate = null;
|
||||
cipher.reprompt = CipherRepromptType.None;
|
||||
|
||||
const loginView = new LoginView();
|
||||
loginView.username = "username";
|
||||
loginView.password = "password";
|
||||
|
||||
const login = Substitute.for<Login>();
|
||||
login.decrypt(Arg.any(), Arg.any()).resolves(loginView);
|
||||
cipher.login = login;
|
||||
|
||||
const cipherView = await cipher.decrypt();
|
||||
|
||||
expect(cipherView).toMatchObject({
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
type: 1,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
login: loginView,
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
collectionIds: undefined,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
localData: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("SecureNoteCipher", () => {
|
||||
let cipherData: CipherData;
|
||||
|
||||
beforeEach(() => {
|
||||
cipherData = {
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
userId: "userId",
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
organizationUseTotp: true,
|
||||
favorite: false,
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
type: CipherType.SecureNote,
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
deletedDate: null,
|
||||
reprompt: CipherRepromptType.None,
|
||||
secureNote: {
|
||||
type: SecureNoteType.Generic,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
|
||||
expect(cipher).toEqual({
|
||||
id: "id",
|
||||
userId: "userId",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 2,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
collectionIds: undefined,
|
||||
localData: null,
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
secureNote: { type: SecureNoteType.Generic },
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("toCipherData", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const cipher = new Cipher();
|
||||
cipher.id = "id";
|
||||
cipher.organizationId = "orgId";
|
||||
cipher.folderId = "folderId";
|
||||
cipher.edit = true;
|
||||
cipher.viewPassword = true;
|
||||
cipher.organizationUseTotp = true;
|
||||
cipher.favorite = false;
|
||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
cipher.type = CipherType.SecureNote;
|
||||
cipher.name = mockEnc("EncryptedString");
|
||||
cipher.notes = mockEnc("EncryptedString");
|
||||
cipher.deletedDate = null;
|
||||
cipher.reprompt = CipherRepromptType.None;
|
||||
cipher.secureNote = new SecureNote();
|
||||
cipher.secureNote.type = SecureNoteType.Generic;
|
||||
|
||||
const cipherView = await cipher.decrypt();
|
||||
|
||||
expect(cipherView).toMatchObject({
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
type: 2,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
secureNote: { type: 0 },
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
collectionIds: undefined,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
localData: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("CardCipher", () => {
|
||||
let cipherData: CipherData;
|
||||
|
||||
beforeEach(() => {
|
||||
cipherData = {
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
userId: "userId",
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
organizationUseTotp: true,
|
||||
favorite: false,
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
type: CipherType.Card,
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
deletedDate: null,
|
||||
reprompt: CipherRepromptType.None,
|
||||
card: {
|
||||
cardholderName: "EncryptedString",
|
||||
brand: "EncryptedString",
|
||||
number: "EncryptedString",
|
||||
expMonth: "EncryptedString",
|
||||
expYear: "EncryptedString",
|
||||
code: "EncryptedString",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
|
||||
expect(cipher).toEqual({
|
||||
id: "id",
|
||||
userId: "userId",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 3,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
collectionIds: undefined,
|
||||
localData: null,
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
card: {
|
||||
cardholderName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
brand: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
number: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
expMonth: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
expYear: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
code: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
},
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("toCipherData", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const cipher = new Cipher();
|
||||
cipher.id = "id";
|
||||
cipher.organizationId = "orgId";
|
||||
cipher.folderId = "folderId";
|
||||
cipher.edit = true;
|
||||
cipher.viewPassword = true;
|
||||
cipher.organizationUseTotp = true;
|
||||
cipher.favorite = false;
|
||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
cipher.type = CipherType.Card;
|
||||
cipher.name = mockEnc("EncryptedString");
|
||||
cipher.notes = mockEnc("EncryptedString");
|
||||
cipher.deletedDate = null;
|
||||
cipher.reprompt = CipherRepromptType.None;
|
||||
|
||||
const cardView = new CardView();
|
||||
cardView.cardholderName = "cardholderName";
|
||||
cardView.number = "4111111111111111";
|
||||
|
||||
const card = Substitute.for<Card>();
|
||||
card.decrypt(Arg.any(), Arg.any()).resolves(cardView);
|
||||
cipher.card = card;
|
||||
|
||||
const cipherView = await cipher.decrypt();
|
||||
|
||||
expect(cipherView).toMatchObject({
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
type: 3,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
card: cardView,
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
collectionIds: undefined,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
localData: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("IdentityCipher", () => {
|
||||
let cipherData: CipherData;
|
||||
|
||||
beforeEach(() => {
|
||||
cipherData = {
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
userId: "userId",
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
organizationUseTotp: true,
|
||||
favorite: false,
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
type: CipherType.Identity,
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
deletedDate: null,
|
||||
reprompt: CipherRepromptType.None,
|
||||
identity: {
|
||||
title: "EncryptedString",
|
||||
firstName: "EncryptedString",
|
||||
middleName: "EncryptedString",
|
||||
lastName: "EncryptedString",
|
||||
address1: "EncryptedString",
|
||||
address2: "EncryptedString",
|
||||
address3: "EncryptedString",
|
||||
city: "EncryptedString",
|
||||
state: "EncryptedString",
|
||||
postalCode: "EncryptedString",
|
||||
country: "EncryptedString",
|
||||
company: "EncryptedString",
|
||||
email: "EncryptedString",
|
||||
phone: "EncryptedString",
|
||||
ssn: "EncryptedString",
|
||||
username: "EncryptedString",
|
||||
passportNumber: "EncryptedString",
|
||||
licenseNumber: "EncryptedString",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
|
||||
expect(cipher).toEqual({
|
||||
id: "id",
|
||||
userId: "userId",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
notes: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
type: 4,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
collectionIds: undefined,
|
||||
localData: null,
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
identity: {
|
||||
title: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
firstName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
middleName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
lastName: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
address1: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
address2: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
address3: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
city: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
state: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
postalCode: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
country: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
company: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
email: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
phone: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
ssn: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
username: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
passportNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
licenseNumber: { encryptedString: "EncryptedString", encryptionType: 0 },
|
||||
},
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("toCipherData", () => {
|
||||
const cipher = new Cipher(cipherData);
|
||||
expect(cipher.toCipherData("userId")).toEqual(cipherData);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const cipher = new Cipher();
|
||||
cipher.id = "id";
|
||||
cipher.organizationId = "orgId";
|
||||
cipher.folderId = "folderId";
|
||||
cipher.edit = true;
|
||||
cipher.viewPassword = true;
|
||||
cipher.organizationUseTotp = true;
|
||||
cipher.favorite = false;
|
||||
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
cipher.type = CipherType.Identity;
|
||||
cipher.name = mockEnc("EncryptedString");
|
||||
cipher.notes = mockEnc("EncryptedString");
|
||||
cipher.deletedDate = null;
|
||||
cipher.reprompt = CipherRepromptType.None;
|
||||
|
||||
const identityView = new IdentityView();
|
||||
identityView.firstName = "firstName";
|
||||
identityView.lastName = "lastName";
|
||||
|
||||
const identity = Substitute.for<Identity>();
|
||||
identity.decrypt(Arg.any(), Arg.any()).resolves(identityView);
|
||||
cipher.identity = identity;
|
||||
|
||||
const cipherView = await cipher.decrypt();
|
||||
|
||||
expect(cipherView).toMatchObject({
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
folderId: "folderId",
|
||||
name: "EncryptedString",
|
||||
notes: "EncryptedString",
|
||||
type: 4,
|
||||
favorite: false,
|
||||
organizationUseTotp: true,
|
||||
edit: true,
|
||||
viewPassword: true,
|
||||
identity: identityView,
|
||||
attachments: null,
|
||||
fields: null,
|
||||
passwordHistory: null,
|
||||
collectionIds: undefined,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletedDate: null,
|
||||
reprompt: 0,
|
||||
localData: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,66 +0,0 @@
|
||||
import { CollectionData } from "@/jslib/common/src/models/data/collectionData";
|
||||
import { Collection } from "@/jslib/common/src/models/domain/collection";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Collection", () => {
|
||||
let data: CollectionData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
name: "encName",
|
||||
externalId: "extId",
|
||||
readOnly: true,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new CollectionData({} as any);
|
||||
const card = new Collection(data);
|
||||
|
||||
expect(card).toEqual({
|
||||
externalId: null,
|
||||
hidePasswords: null,
|
||||
id: null,
|
||||
name: null,
|
||||
organizationId: null,
|
||||
readOnly: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const collection = new Collection(data);
|
||||
|
||||
expect(collection).toEqual({
|
||||
id: "id",
|
||||
organizationId: "orgId",
|
||||
name: { encryptedString: "encName", encryptionType: 0 },
|
||||
externalId: "extId",
|
||||
readOnly: true,
|
||||
hidePasswords: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const collection = new Collection();
|
||||
collection.id = "id";
|
||||
collection.organizationId = "orgId";
|
||||
collection.name = mockEnc("encName");
|
||||
collection.externalId = "extId";
|
||||
collection.readOnly = false;
|
||||
collection.hidePasswords = false;
|
||||
|
||||
const view = await collection.decrypt();
|
||||
|
||||
expect(view).toEqual({
|
||||
externalId: "extId",
|
||||
hidePasswords: false,
|
||||
id: "id",
|
||||
name: "encName",
|
||||
organizationId: "orgId",
|
||||
readOnly: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
import { FieldType } from "@/jslib/common/src/enums/fieldType";
|
||||
import { FieldData } from "@/jslib/common/src/models/data/fieldData";
|
||||
import { Field } from "@/jslib/common/src/models/domain/field";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Field", () => {
|
||||
let data: FieldData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
type: FieldType.Text,
|
||||
name: "encName",
|
||||
value: "encValue",
|
||||
linkedId: null,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new FieldData();
|
||||
const field = new Field(data);
|
||||
|
||||
expect(field).toEqual({
|
||||
type: undefined,
|
||||
name: null,
|
||||
value: null,
|
||||
linkedId: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const field = new Field(data);
|
||||
|
||||
expect(field).toEqual({
|
||||
type: FieldType.Text,
|
||||
name: { encryptedString: "encName", encryptionType: 0 },
|
||||
value: { encryptedString: "encValue", encryptionType: 0 },
|
||||
linkedId: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("toFieldData", () => {
|
||||
const field = new Field(data);
|
||||
expect(field.toFieldData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const field = new Field();
|
||||
field.type = FieldType.Text;
|
||||
field.name = mockEnc("encName");
|
||||
field.value = mockEnc("encValue");
|
||||
|
||||
const view = await field.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
type: 0,
|
||||
name: "encName",
|
||||
value: "encValue",
|
||||
newField: false,
|
||||
showCount: false,
|
||||
showValue: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,42 +0,0 @@
|
||||
import { FolderData } from "@/jslib/common/src/models/data/folderData";
|
||||
import { Folder } from "@/jslib/common/src/models/domain/folder";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Folder", () => {
|
||||
let data: FolderData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
id: "id",
|
||||
userId: "userId",
|
||||
name: "encName",
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const field = new Folder(data);
|
||||
|
||||
expect(field).toEqual({
|
||||
id: "id",
|
||||
name: { encryptedString: "encName", encryptionType: 0 },
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const folder = new Folder();
|
||||
folder.id = "id";
|
||||
folder.name = mockEnc("encName");
|
||||
folder.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
|
||||
const view = await folder.decrypt();
|
||||
|
||||
expect(view).toEqual({
|
||||
id: "id",
|
||||
name: "encName",
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,134 +0,0 @@
|
||||
import { IdentityData } from "@/jslib/common/src/models/data/identityData";
|
||||
import { Identity } from "@/jslib/common/src/models/domain/identity";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Identity", () => {
|
||||
let data: IdentityData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
title: "enctitle",
|
||||
firstName: "encfirstName",
|
||||
middleName: "encmiddleName",
|
||||
lastName: "enclastName",
|
||||
address1: "encaddress1",
|
||||
address2: "encaddress2",
|
||||
address3: "encaddress3",
|
||||
city: "enccity",
|
||||
state: "encstate",
|
||||
postalCode: "encpostalCode",
|
||||
country: "enccountry",
|
||||
company: "enccompany",
|
||||
email: "encemail",
|
||||
phone: "encphone",
|
||||
ssn: "encssn",
|
||||
username: "encusername",
|
||||
passportNumber: "encpassportNumber",
|
||||
licenseNumber: "enclicenseNumber",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new IdentityData();
|
||||
const identity = new Identity(data);
|
||||
|
||||
expect(identity).toEqual({
|
||||
address1: null,
|
||||
address2: null,
|
||||
address3: null,
|
||||
city: null,
|
||||
company: null,
|
||||
country: null,
|
||||
email: null,
|
||||
firstName: null,
|
||||
lastName: null,
|
||||
licenseNumber: null,
|
||||
middleName: null,
|
||||
passportNumber: null,
|
||||
phone: null,
|
||||
postalCode: null,
|
||||
ssn: null,
|
||||
state: null,
|
||||
title: null,
|
||||
username: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const identity = new Identity(data);
|
||||
|
||||
expect(identity).toEqual({
|
||||
title: { encryptedString: "enctitle", encryptionType: 0 },
|
||||
firstName: { encryptedString: "encfirstName", encryptionType: 0 },
|
||||
middleName: { encryptedString: "encmiddleName", encryptionType: 0 },
|
||||
lastName: { encryptedString: "enclastName", encryptionType: 0 },
|
||||
address1: { encryptedString: "encaddress1", encryptionType: 0 },
|
||||
address2: { encryptedString: "encaddress2", encryptionType: 0 },
|
||||
address3: { encryptedString: "encaddress3", encryptionType: 0 },
|
||||
city: { encryptedString: "enccity", encryptionType: 0 },
|
||||
state: { encryptedString: "encstate", encryptionType: 0 },
|
||||
postalCode: { encryptedString: "encpostalCode", encryptionType: 0 },
|
||||
country: { encryptedString: "enccountry", encryptionType: 0 },
|
||||
company: { encryptedString: "enccompany", encryptionType: 0 },
|
||||
email: { encryptedString: "encemail", encryptionType: 0 },
|
||||
phone: { encryptedString: "encphone", encryptionType: 0 },
|
||||
ssn: { encryptedString: "encssn", encryptionType: 0 },
|
||||
username: { encryptedString: "encusername", encryptionType: 0 },
|
||||
passportNumber: { encryptedString: "encpassportNumber", encryptionType: 0 },
|
||||
licenseNumber: { encryptedString: "enclicenseNumber", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("toIdentityData", () => {
|
||||
const identity = new Identity(data);
|
||||
expect(identity.toIdentityData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const identity = new Identity();
|
||||
|
||||
identity.title = mockEnc("mockTitle");
|
||||
identity.firstName = mockEnc("mockFirstName");
|
||||
identity.middleName = mockEnc("mockMiddleName");
|
||||
identity.lastName = mockEnc("mockLastName");
|
||||
identity.address1 = mockEnc("mockAddress1");
|
||||
identity.address2 = mockEnc("mockAddress2");
|
||||
identity.address3 = mockEnc("mockAddress3");
|
||||
identity.city = mockEnc("mockCity");
|
||||
identity.state = mockEnc("mockState");
|
||||
identity.postalCode = mockEnc("mockPostalCode");
|
||||
identity.country = mockEnc("mockCountry");
|
||||
identity.company = mockEnc("mockCompany");
|
||||
identity.email = mockEnc("mockEmail");
|
||||
identity.phone = mockEnc("mockPhone");
|
||||
identity.ssn = mockEnc("mockSsn");
|
||||
identity.username = mockEnc("mockUsername");
|
||||
identity.passportNumber = mockEnc("mockPassportNumber");
|
||||
identity.licenseNumber = mockEnc("mockLicenseNumber");
|
||||
|
||||
const view = await identity.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
_firstName: "mockFirstName",
|
||||
_lastName: "mockLastName",
|
||||
_subTitle: null,
|
||||
address1: "mockAddress1",
|
||||
address2: "mockAddress2",
|
||||
address3: "mockAddress3",
|
||||
city: "mockCity",
|
||||
company: "mockCompany",
|
||||
country: "mockCountry",
|
||||
email: "mockEmail",
|
||||
licenseNumber: "mockLicenseNumber",
|
||||
middleName: "mockMiddleName",
|
||||
passportNumber: "mockPassportNumber",
|
||||
phone: "mockPhone",
|
||||
postalCode: "mockPostalCode",
|
||||
ssn: "mockSsn",
|
||||
state: "mockState",
|
||||
title: "mockTitle",
|
||||
username: "mockUsername",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,101 +0,0 @@
|
||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
||||
import { LoginData } from "@/jslib/common/src/models/data/loginData";
|
||||
import { Login } from "@/jslib/common/src/models/domain/login";
|
||||
import { LoginUri } from "@/jslib/common/src/models/domain/loginUri";
|
||||
import { LoginUriView } from "@/jslib/common/src/models/view/loginUriView";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Login DTO", () => {
|
||||
it("Convert from empty LoginData", () => {
|
||||
const data = new LoginData();
|
||||
const login = new Login(data);
|
||||
|
||||
expect(login).toEqual({
|
||||
passwordRevisionDate: null,
|
||||
autofillOnPageLoad: undefined,
|
||||
username: null,
|
||||
password: null,
|
||||
totp: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert from full LoginData", () => {
|
||||
const data: LoginData = {
|
||||
uris: [{ uri: "uri", match: UriMatchType.Domain }],
|
||||
username: "username",
|
||||
password: "password",
|
||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
||||
totp: "123",
|
||||
autofillOnPageLoad: false,
|
||||
};
|
||||
const login = new Login(data);
|
||||
|
||||
expect(login).toEqual({
|
||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
autofillOnPageLoad: false,
|
||||
username: { encryptedString: "username", encryptionType: 0 },
|
||||
password: { encryptedString: "password", encryptionType: 0 },
|
||||
totp: { encryptedString: "123", encryptionType: 0 },
|
||||
uris: [{ match: 0, uri: { encryptedString: "uri", encryptionType: 0 } }],
|
||||
});
|
||||
});
|
||||
|
||||
it("Initialize without LoginData", () => {
|
||||
const login = new Login();
|
||||
|
||||
expect(login).toEqual({});
|
||||
});
|
||||
|
||||
it("Decrypts correctly", async () => {
|
||||
const loginUri = Substitute.for<LoginUri>();
|
||||
const loginUriView = new LoginUriView();
|
||||
loginUriView.uri = "decrypted uri";
|
||||
loginUri.decrypt(Arg.any()).resolves(loginUriView);
|
||||
|
||||
const login = new Login();
|
||||
login.uris = [loginUri];
|
||||
login.username = mockEnc("encrypted username");
|
||||
login.password = mockEnc("encrypted password");
|
||||
login.passwordRevisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
login.totp = mockEnc("encrypted totp");
|
||||
login.autofillOnPageLoad = true;
|
||||
|
||||
const loginView = await login.decrypt(null);
|
||||
expect(loginView).toEqual({
|
||||
username: "encrypted username",
|
||||
password: "encrypted password",
|
||||
passwordRevisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
totp: "encrypted totp",
|
||||
uris: [
|
||||
{
|
||||
match: null,
|
||||
_uri: "decrypted uri",
|
||||
_domain: null,
|
||||
_hostname: null,
|
||||
_host: null,
|
||||
_canLaunch: null,
|
||||
},
|
||||
],
|
||||
autofillOnPageLoad: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("Converts from LoginData and back", () => {
|
||||
const data: LoginData = {
|
||||
uris: [{ uri: "uri", match: UriMatchType.Domain }],
|
||||
username: "username",
|
||||
password: "password",
|
||||
passwordRevisionDate: "2022-01-31T12:00:00.000Z",
|
||||
totp: "123",
|
||||
autofillOnPageLoad: false,
|
||||
};
|
||||
const login = new Login(data);
|
||||
|
||||
const loginData = login.toLoginData();
|
||||
|
||||
expect(loginData).toEqual(data);
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
import { UriMatchType } from "@/jslib/common/src/enums/uriMatchType";
|
||||
import { LoginUriData } from "@/jslib/common/src/models/data/loginUriData";
|
||||
import { LoginUri } from "@/jslib/common/src/models/domain/loginUri";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("LoginUri", () => {
|
||||
let data: LoginUriData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
uri: "encUri",
|
||||
match: UriMatchType.Domain,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new LoginUriData();
|
||||
const loginUri = new LoginUri(data);
|
||||
|
||||
expect(loginUri).toEqual({
|
||||
match: null,
|
||||
uri: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const loginUri = new LoginUri(data);
|
||||
|
||||
expect(loginUri).toEqual({
|
||||
match: 0,
|
||||
uri: { encryptedString: "encUri", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("toLoginUriData", () => {
|
||||
const loginUri = new LoginUri(data);
|
||||
expect(loginUri.toLoginUriData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const loginUri = new LoginUri();
|
||||
loginUri.match = UriMatchType.Exact;
|
||||
loginUri.uri = mockEnc("uri");
|
||||
|
||||
const view = await loginUri.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
_canLaunch: null,
|
||||
_domain: null,
|
||||
_host: null,
|
||||
_hostname: null,
|
||||
_uri: "uri",
|
||||
match: 3,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import { PasswordHistoryData } from "@/jslib/common/src/models/data/passwordHistoryData";
|
||||
import { Password } from "@/jslib/common/src/models/domain/password";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("Password", () => {
|
||||
let data: PasswordHistoryData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
password: "encPassword",
|
||||
lastUsedDate: "2022-01-31T12:00:00.000Z",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new PasswordHistoryData();
|
||||
const password = new Password(data);
|
||||
|
||||
expect(password).toMatchObject({
|
||||
password: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const password = new Password(data);
|
||||
|
||||
expect(password).toEqual({
|
||||
password: { encryptedString: "encPassword", encryptionType: 0 },
|
||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
});
|
||||
});
|
||||
|
||||
it("toPasswordHistoryData", () => {
|
||||
const password = new Password(data);
|
||||
expect(password.toPasswordHistoryData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const password = new Password();
|
||||
password.password = mockEnc("password");
|
||||
password.lastUsedDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
|
||||
const view = await password.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
password: "password",
|
||||
lastUsedDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import { SecureNoteType } from "@/jslib/common/src/enums/secureNoteType";
|
||||
import { SecureNoteData } from "@/jslib/common/src/models/data/secureNoteData";
|
||||
import { SecureNote } from "@/jslib/common/src/models/domain/secureNote";
|
||||
|
||||
describe("SecureNote", () => {
|
||||
let data: SecureNoteData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
type: SecureNoteType.Generic,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new SecureNoteData();
|
||||
const secureNote = new SecureNote(data);
|
||||
|
||||
expect(secureNote).toEqual({
|
||||
type: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const secureNote = new SecureNote(data);
|
||||
|
||||
expect(secureNote).toEqual({
|
||||
type: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it("toSecureNoteData", () => {
|
||||
const secureNote = new SecureNote(data);
|
||||
expect(secureNote.toSecureNoteData()).toEqual(data);
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const secureNote = new SecureNote();
|
||||
secureNote.type = SecureNoteType.Generic;
|
||||
|
||||
const view = await secureNote.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
type: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,144 +0,0 @@
|
||||
import { Substitute, Arg, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { SendType } from "@/jslib/common/src/enums/sendType";
|
||||
import { SendData } from "@/jslib/common/src/models/data/sendData";
|
||||
import { EncString } from "@/jslib/common/src/models/domain/encString";
|
||||
import { Send } from "@/jslib/common/src/models/domain/send";
|
||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
||||
import { ContainerService } from "@/jslib/common/src/services/container.service";
|
||||
|
||||
import { makeStaticByteArray, mockEnc } from "../utils";
|
||||
|
||||
describe("Send", () => {
|
||||
let data: SendData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
id: "id",
|
||||
accessId: "accessId",
|
||||
userId: "userId",
|
||||
type: SendType.Text,
|
||||
name: "encName",
|
||||
notes: "encNotes",
|
||||
text: {
|
||||
text: "encText",
|
||||
hidden: true,
|
||||
},
|
||||
file: null,
|
||||
key: "encKey",
|
||||
maxAccessCount: null,
|
||||
accessCount: 10,
|
||||
revisionDate: "2022-01-31T12:00:00.000Z",
|
||||
expirationDate: "2022-01-31T12:00:00.000Z",
|
||||
deletionDate: "2022-01-31T12:00:00.000Z",
|
||||
password: "password",
|
||||
disabled: false,
|
||||
hideEmail: true,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new SendData();
|
||||
const send = new Send(data);
|
||||
|
||||
expect(send).toEqual({
|
||||
id: null,
|
||||
accessId: null,
|
||||
userId: null,
|
||||
type: undefined,
|
||||
name: null,
|
||||
notes: null,
|
||||
text: undefined,
|
||||
file: undefined,
|
||||
key: null,
|
||||
maxAccessCount: undefined,
|
||||
accessCount: undefined,
|
||||
revisionDate: null,
|
||||
expirationDate: null,
|
||||
deletionDate: null,
|
||||
password: undefined,
|
||||
disabled: undefined,
|
||||
hideEmail: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const send = new Send(data);
|
||||
|
||||
expect(send).toEqual({
|
||||
id: "id",
|
||||
accessId: "accessId",
|
||||
userId: "userId",
|
||||
type: SendType.Text,
|
||||
name: { encryptedString: "encName", encryptionType: 0 },
|
||||
notes: { encryptedString: "encNotes", encryptionType: 0 },
|
||||
text: {
|
||||
text: { encryptedString: "encText", encryptionType: 0 },
|
||||
hidden: true,
|
||||
},
|
||||
key: { encryptedString: "encKey", encryptionType: 0 },
|
||||
maxAccessCount: null,
|
||||
accessCount: 10,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
password: "password",
|
||||
disabled: false,
|
||||
hideEmail: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const text = Substitute.for<SendText>();
|
||||
text.decrypt(Arg.any()).resolves("textView" as any);
|
||||
|
||||
const send = new Send();
|
||||
send.id = "id";
|
||||
send.accessId = "accessId";
|
||||
send.userId = "userId";
|
||||
send.type = SendType.Text;
|
||||
send.name = mockEnc("name");
|
||||
send.notes = mockEnc("notes");
|
||||
send.text = text;
|
||||
send.key = mockEnc("key");
|
||||
send.accessCount = 10;
|
||||
send.revisionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
send.expirationDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
send.deletionDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
send.password = "password";
|
||||
send.disabled = false;
|
||||
send.hideEmail = true;
|
||||
|
||||
const cryptoService = Substitute.for<CryptoService>();
|
||||
cryptoService.decryptToBytes(send.key, null).resolves(makeStaticByteArray(32));
|
||||
cryptoService.makeSendKey(Arg.any()).resolves("cryptoKey" as any);
|
||||
|
||||
(window as any).bitwardenContainerService = new ContainerService(cryptoService);
|
||||
|
||||
const view = await send.decrypt();
|
||||
|
||||
text.received(1).decrypt("cryptoKey" as any);
|
||||
(send.name as SubstituteOf<EncString>).received(1).decrypt(null, "cryptoKey" as any);
|
||||
|
||||
expect(view).toMatchObject({
|
||||
id: "id",
|
||||
accessId: "accessId",
|
||||
name: "name",
|
||||
notes: "notes",
|
||||
type: 0,
|
||||
key: expect.anything(),
|
||||
cryptoKey: "cryptoKey",
|
||||
file: expect.anything(),
|
||||
text: "textView",
|
||||
maxAccessCount: undefined,
|
||||
accessCount: 10,
|
||||
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
deletionDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
password: "password",
|
||||
disabled: false,
|
||||
hideEmail: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
import { Substitute, Arg } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { SendType } from "@/jslib/common/src/enums/sendType";
|
||||
import { SendAccess } from "@/jslib/common/src/models/domain/sendAccess";
|
||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
||||
import { SendAccessResponse } from "@/jslib/common/src/models/response/sendAccessResponse";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("SendAccess", () => {
|
||||
let request: SendAccessResponse;
|
||||
|
||||
beforeEach(() => {
|
||||
request = {
|
||||
id: "id",
|
||||
type: SendType.Text,
|
||||
name: "encName",
|
||||
file: null,
|
||||
text: {
|
||||
text: "encText",
|
||||
hidden: true,
|
||||
},
|
||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
creatorIdentifier: "creatorIdentifier",
|
||||
} as SendAccessResponse;
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const request = new SendAccessResponse({});
|
||||
const sendAccess = new SendAccess(request);
|
||||
|
||||
expect(sendAccess).toEqual({
|
||||
id: null,
|
||||
type: undefined,
|
||||
name: null,
|
||||
creatorIdentifier: null,
|
||||
expirationDate: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const sendAccess = new SendAccess(request);
|
||||
|
||||
expect(sendAccess).toEqual({
|
||||
id: "id",
|
||||
type: 0,
|
||||
name: { encryptedString: "encName", encryptionType: 0 },
|
||||
text: {
|
||||
hidden: true,
|
||||
text: { encryptedString: "encText", encryptionType: 0 },
|
||||
},
|
||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
creatorIdentifier: "creatorIdentifier",
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const sendAccess = new SendAccess();
|
||||
sendAccess.id = "id";
|
||||
sendAccess.type = SendType.Text;
|
||||
sendAccess.name = mockEnc("name");
|
||||
|
||||
const text = Substitute.for<SendText>();
|
||||
text.decrypt(Arg.any()).resolves({} as any);
|
||||
sendAccess.text = text;
|
||||
|
||||
sendAccess.expirationDate = new Date("2022-01-31T12:00:00.000Z");
|
||||
sendAccess.creatorIdentifier = "creatorIdentifier";
|
||||
|
||||
const view = await sendAccess.decrypt(null);
|
||||
|
||||
text.received(1).decrypt(Arg.any());
|
||||
|
||||
expect(view).toEqual({
|
||||
id: "id",
|
||||
type: 0,
|
||||
name: "name",
|
||||
text: {},
|
||||
file: expect.anything(),
|
||||
expirationDate: new Date("2022-01-31T12:00:00.000Z"),
|
||||
creatorIdentifier: "creatorIdentifier",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
import { SendFileData } from "@/jslib/common/src/models/data/sendFileData";
|
||||
import { SendFile } from "@/jslib/common/src/models/domain/sendFile";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("SendFile", () => {
|
||||
let data: SendFileData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
id: "id",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: "encFileName",
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new SendFileData();
|
||||
const sendFile = new SendFile(data);
|
||||
|
||||
expect(sendFile).toEqual({
|
||||
fileName: null,
|
||||
id: null,
|
||||
size: undefined,
|
||||
sizeName: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const sendFile = new SendFile(data);
|
||||
|
||||
expect(sendFile).toEqual({
|
||||
id: "id",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
fileName: { encryptedString: "encFileName", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const sendFile = new SendFile();
|
||||
sendFile.id = "id";
|
||||
sendFile.size = "1100";
|
||||
sendFile.sizeName = "1.1 KB";
|
||||
sendFile.fileName = mockEnc("fileName");
|
||||
|
||||
const view = await sendFile.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
fileName: "fileName",
|
||||
id: "id",
|
||||
size: "1100",
|
||||
sizeName: "1.1 KB",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,47 +0,0 @@
|
||||
import { SendTextData } from "@/jslib/common/src/models/data/sendTextData";
|
||||
import { SendText } from "@/jslib/common/src/models/domain/sendText";
|
||||
|
||||
import { mockEnc } from "../utils";
|
||||
|
||||
describe("SendText", () => {
|
||||
let data: SendTextData;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
text: "encText",
|
||||
hidden: false,
|
||||
};
|
||||
});
|
||||
|
||||
it("Convert from empty", () => {
|
||||
const data = new SendTextData();
|
||||
const secureNote = new SendText(data);
|
||||
|
||||
expect(secureNote).toEqual({
|
||||
hidden: undefined,
|
||||
text: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("Convert", () => {
|
||||
const secureNote = new SendText(data);
|
||||
|
||||
expect(secureNote).toEqual({
|
||||
hidden: false,
|
||||
text: { encryptedString: "encText", encryptionType: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
it("Decrypt", async () => {
|
||||
const secureNote = new SendText();
|
||||
secureNote.text = mockEnc("text");
|
||||
secureNote.hidden = true;
|
||||
|
||||
const view = await secureNote.decrypt(null);
|
||||
|
||||
expect(view).toEqual({
|
||||
text: "text",
|
||||
hidden: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { EnvironmentService } from "@/jslib/common/src/abstractions/environment.service";
|
||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { ApiLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/apiLogin.strategy";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { ApiLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
|
||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
||||
|
||||
describe("ApiLogInStrategy", () => {
|
||||
let cryptoService: SubstituteOf<CryptoService>;
|
||||
let apiService: SubstituteOf<ApiService>;
|
||||
let tokenService: SubstituteOf<TokenService>;
|
||||
let appIdService: SubstituteOf<AppIdService>;
|
||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||
let messagingService: SubstituteOf<MessagingService>;
|
||||
let logService: SubstituteOf<LogService>;
|
||||
let environmentService: SubstituteOf<EnvironmentService>;
|
||||
let keyConnectorService: SubstituteOf<KeyConnectorService>;
|
||||
let stateService: SubstituteOf<StateService>;
|
||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
||||
|
||||
let apiLogInStrategy: ApiLogInStrategy;
|
||||
let credentials: ApiLogInCredentials;
|
||||
|
||||
const deviceId = Utils.newGuid();
|
||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
||||
const apiClientId = "API_CLIENT_ID";
|
||||
const apiClientSecret = "API_CLIENT_SECRET";
|
||||
|
||||
beforeEach(async () => {
|
||||
cryptoService = Substitute.for<CryptoService>();
|
||||
apiService = Substitute.for<ApiService>();
|
||||
tokenService = Substitute.for<TokenService>();
|
||||
appIdService = Substitute.for<AppIdService>();
|
||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
||||
messagingService = Substitute.for<MessagingService>();
|
||||
logService = Substitute.for<LogService>();
|
||||
environmentService = Substitute.for<EnvironmentService>();
|
||||
stateService = Substitute.for<StateService>();
|
||||
keyConnectorService = Substitute.for<KeyConnectorService>();
|
||||
twoFactorService = Substitute.for<TwoFactorService>();
|
||||
|
||||
appIdService.getAppId().resolves(deviceId);
|
||||
tokenService.getTwoFactorToken().resolves(null);
|
||||
|
||||
apiLogInStrategy = new ApiLogInStrategy(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
environmentService,
|
||||
keyConnectorService,
|
||||
);
|
||||
|
||||
credentials = new ApiLogInCredentials(apiClientId, apiClientSecret);
|
||||
});
|
||||
|
||||
it("sends api key credentials to the server", async () => {
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
await apiLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const apiTokenRequest = actual as any;
|
||||
return (
|
||||
apiTokenRequest.clientId === apiClientId &&
|
||||
apiTokenRequest.clientSecret === apiClientSecret &&
|
||||
apiTokenRequest.device.identifier === deviceId &&
|
||||
apiTokenRequest.twoFactor.provider == null &&
|
||||
apiTokenRequest.twoFactor.token == null &&
|
||||
apiTokenRequest.captchaResponse == null
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("sets the local environment after a successful login", async () => {
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
|
||||
await apiLogInStrategy.logIn(credentials);
|
||||
|
||||
stateService.received(1).setApiKeyClientId(apiClientId);
|
||||
stateService.received(1).setApiKeyClientSecret(apiClientSecret);
|
||||
stateService.received(1).addAccount(Arg.any());
|
||||
});
|
||||
|
||||
it("gets and sets the Key Connector key from environmentUrl", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.apiUseKeyConnector = true;
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
environmentService.getKeyConnectorUrl().returns(keyConnectorUrl);
|
||||
|
||||
await apiLogInStrategy.logIn(credentials);
|
||||
|
||||
keyConnectorService.received(1).getAndSetKey(keyConnectorUrl);
|
||||
});
|
||||
});
|
||||
@@ -1,288 +0,0 @@
|
||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { TwoFactorProviderType } from "@/jslib/common/src/enums/twoFactorProviderType";
|
||||
import { PasswordLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/passwordLogin.strategy";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { Account, AccountProfile, AccountTokens } from "@/jslib/common/src/models/domain/account";
|
||||
import { AuthResult } from "@/jslib/common/src/models/domain/authResult";
|
||||
import { EncString } from "@/jslib/common/src/models/domain/encString";
|
||||
import { PasswordLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { PasswordTokenRequest } from "@/jslib/common/src/models/request/identityToken/passwordTokenRequest";
|
||||
import { TokenRequestTwoFactor } from "@/jslib/common/src/models/request/identityToken/tokenRequestTwoFactor";
|
||||
import { IdentityCaptchaResponse } from "@/jslib/common/src/models/response/identityCaptchaResponse";
|
||||
import { IdentityTokenResponse } from "@/jslib/common/src/models/response/identityTokenResponse";
|
||||
import { IdentityTwoFactorResponse } from "@/jslib/common/src/models/response/identityTwoFactorResponse";
|
||||
|
||||
const email = "hello@world.com";
|
||||
const masterPassword = "password";
|
||||
|
||||
const deviceId = Utils.newGuid();
|
||||
const accessToken = "ACCESS_TOKEN";
|
||||
const refreshToken = "REFRESH_TOKEN";
|
||||
const encKey = "ENC_KEY";
|
||||
const privateKey = "PRIVATE_KEY";
|
||||
const captchaSiteKey = "CAPTCHA_SITE_KEY";
|
||||
const kdf = 0;
|
||||
const kdfIterations = 10000;
|
||||
const userId = Utils.newGuid();
|
||||
const masterPasswordHash = "MASTER_PASSWORD_HASH";
|
||||
|
||||
const decodedToken = {
|
||||
sub: userId,
|
||||
email: email,
|
||||
premium: false,
|
||||
};
|
||||
|
||||
const twoFactorProviderType = TwoFactorProviderType.Authenticator;
|
||||
const twoFactorToken = "TWO_FACTOR_TOKEN";
|
||||
const twoFactorRemember = true;
|
||||
|
||||
export function identityTokenResponseFactory() {
|
||||
return new IdentityTokenResponse({
|
||||
ForcePasswordReset: false,
|
||||
Kdf: kdf,
|
||||
KdfIterations: kdfIterations,
|
||||
Key: encKey,
|
||||
PrivateKey: privateKey,
|
||||
ResetMasterPassword: false,
|
||||
access_token: accessToken,
|
||||
expires_in: 3600,
|
||||
refresh_token: refreshToken,
|
||||
scope: "api offline_access",
|
||||
token_type: "Bearer",
|
||||
});
|
||||
}
|
||||
|
||||
describe("LogInStrategy", () => {
|
||||
let cryptoService: SubstituteOf<CryptoService>;
|
||||
let apiService: SubstituteOf<ApiService>;
|
||||
let tokenService: SubstituteOf<TokenService>;
|
||||
let appIdService: SubstituteOf<AppIdService>;
|
||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||
let messagingService: SubstituteOf<MessagingService>;
|
||||
let logService: SubstituteOf<LogService>;
|
||||
let stateService: SubstituteOf<StateService>;
|
||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
||||
let authService: SubstituteOf<AuthService>;
|
||||
|
||||
let passwordLogInStrategy: PasswordLogInStrategy;
|
||||
let credentials: PasswordLogInCredentials;
|
||||
|
||||
beforeEach(async () => {
|
||||
cryptoService = Substitute.for<CryptoService>();
|
||||
apiService = Substitute.for<ApiService>();
|
||||
tokenService = Substitute.for<TokenService>();
|
||||
appIdService = Substitute.for<AppIdService>();
|
||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
||||
messagingService = Substitute.for<MessagingService>();
|
||||
logService = Substitute.for<LogService>();
|
||||
stateService = Substitute.for<StateService>();
|
||||
twoFactorService = Substitute.for<TwoFactorService>();
|
||||
authService = Substitute.for<AuthService>();
|
||||
|
||||
appIdService.getAppId().resolves(deviceId);
|
||||
|
||||
// The base class is abstract so we test it via PasswordLogInStrategy
|
||||
passwordLogInStrategy = new PasswordLogInStrategy(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
authService,
|
||||
);
|
||||
credentials = new PasswordLogInCredentials(email, masterPassword);
|
||||
});
|
||||
|
||||
describe("base class", () => {
|
||||
it("sets the local environment after a successful login", async () => {
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
tokenService.decodeToken(accessToken).resolves(decodedToken);
|
||||
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
stateService.received(1).addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: userId,
|
||||
email: email,
|
||||
hasPremiumPersonally: false,
|
||||
kdfIterations: kdfIterations,
|
||||
kdfType: kdf,
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
cryptoService.received(1).setEncKey(encKey);
|
||||
cryptoService.received(1).setEncPrivateKey(privateKey);
|
||||
|
||||
stateService.received(1).setBiometricLocked(false);
|
||||
messagingService.received(1).send("loggedIn");
|
||||
});
|
||||
|
||||
it("builds AuthResult", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.forcePasswordReset = true;
|
||||
tokenResponse.resetMasterPassword = true;
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
const result = await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
const expected = new AuthResult();
|
||||
expected.forcePasswordReset = true;
|
||||
expected.resetMasterPassword = true;
|
||||
expected.twoFactorProviders = null;
|
||||
expected.captchaSiteKey = "";
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it("rejects login if CAPTCHA is required", async () => {
|
||||
// Sample CAPTCHA response
|
||||
const tokenResponse = new IdentityCaptchaResponse({
|
||||
error: "invalid_grant",
|
||||
error_description: "Captcha required.",
|
||||
HCaptcha_SiteKey: captchaSiteKey,
|
||||
});
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
const result = await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
stateService.didNotReceive().addAccount(Arg.any());
|
||||
messagingService.didNotReceive().send(Arg.any());
|
||||
|
||||
const expected = new AuthResult();
|
||||
expected.captchaSiteKey = captchaSiteKey;
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it("makes a new public and private key for an old account", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.privateKey = null;
|
||||
cryptoService.makeKeyPair(Arg.any()).resolves(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postAccountKeys(Arg.any());
|
||||
});
|
||||
});
|
||||
|
||||
describe("Two-factor authentication", () => {
|
||||
it("rejects login if 2FA is required", async () => {
|
||||
// Sample response where TOTP 2FA required
|
||||
const tokenResponse = new IdentityTwoFactorResponse({
|
||||
TwoFactorProviders: ["0"],
|
||||
TwoFactorProviders2: { 0: null },
|
||||
error: "invalid_grant",
|
||||
error_description: "Two factor required.",
|
||||
});
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
const result = await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
stateService.didNotReceive().addAccount(Arg.any());
|
||||
messagingService.didNotReceive().send(Arg.any());
|
||||
|
||||
const expected = new AuthResult();
|
||||
expected.twoFactorProviders = new Map<TwoFactorProviderType, { [key: string]: string }>();
|
||||
expected.twoFactorProviders.set(0, null);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it("sends stored 2FA token to server", async () => {
|
||||
tokenService.getTwoFactorToken().resolves(twoFactorToken);
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const passwordTokenRequest = actual as any;
|
||||
return (
|
||||
passwordTokenRequest.twoFactor.provider === TwoFactorProviderType.Remember &&
|
||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
||||
passwordTokenRequest.twoFactor.remember === false
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("sends 2FA token provided by user to server (single step)", async () => {
|
||||
// This occurs if the user enters the 2FA code as an argument in the CLI
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
credentials.twoFactor = new TokenRequestTwoFactor(
|
||||
twoFactorProviderType,
|
||||
twoFactorToken,
|
||||
twoFactorRemember,
|
||||
);
|
||||
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const passwordTokenRequest = actual as any;
|
||||
return (
|
||||
passwordTokenRequest.twoFactor.provider === twoFactorProviderType &&
|
||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
||||
passwordTokenRequest.twoFactor.remember === twoFactorRemember
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("sends 2FA token provided by user to server (two-step)", async () => {
|
||||
// Simulate a partially completed login
|
||||
passwordLogInStrategy.tokenRequest = new PasswordTokenRequest(
|
||||
email,
|
||||
masterPasswordHash,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
|
||||
await passwordLogInStrategy.logInTwoFactor(
|
||||
new TokenRequestTwoFactor(twoFactorProviderType, twoFactorToken, twoFactorRemember),
|
||||
null,
|
||||
);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const passwordTokenRequest = actual as any;
|
||||
return (
|
||||
passwordTokenRequest.twoFactor.provider === twoFactorProviderType &&
|
||||
passwordTokenRequest.twoFactor.token === twoFactorToken &&
|
||||
passwordTokenRequest.twoFactor.remember === twoFactorRemember
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,110 +0,0 @@
|
||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { AuthService } from "@/jslib/common/src/abstractions/auth.service";
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { HashPurpose } from "@/jslib/common/src/enums/hashPurpose";
|
||||
import { PasswordLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/passwordLogin.strategy";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { PasswordLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
import { SymmetricCryptoKey } from "@/jslib/common/src/models/domain/symmetricCryptoKey";
|
||||
|
||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
||||
|
||||
const email = "hello@world.com";
|
||||
const masterPassword = "password";
|
||||
const hashedPassword = "HASHED_PASSWORD";
|
||||
const localHashedPassword = "LOCAL_HASHED_PASSWORD";
|
||||
const preloginKey = new SymmetricCryptoKey(
|
||||
Utils.fromB64ToArray(
|
||||
"N2KWjlLpfi5uHjv+YcfUKIpZ1l+W+6HRensmIqD+BFYBf6N/dvFpJfWwYnVBdgFCK2tJTAIMLhqzIQQEUmGFgg==",
|
||||
),
|
||||
);
|
||||
const deviceId = Utils.newGuid();
|
||||
|
||||
describe("PasswordLogInStrategy", () => {
|
||||
let cryptoService: SubstituteOf<CryptoService>;
|
||||
let apiService: SubstituteOf<ApiService>;
|
||||
let tokenService: SubstituteOf<TokenService>;
|
||||
let appIdService: SubstituteOf<AppIdService>;
|
||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||
let messagingService: SubstituteOf<MessagingService>;
|
||||
let logService: SubstituteOf<LogService>;
|
||||
let stateService: SubstituteOf<StateService>;
|
||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
||||
let authService: SubstituteOf<AuthService>;
|
||||
|
||||
let passwordLogInStrategy: PasswordLogInStrategy;
|
||||
let credentials: PasswordLogInCredentials;
|
||||
|
||||
beforeEach(async () => {
|
||||
cryptoService = Substitute.for<CryptoService>();
|
||||
apiService = Substitute.for<ApiService>();
|
||||
tokenService = Substitute.for<TokenService>();
|
||||
appIdService = Substitute.for<AppIdService>();
|
||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
||||
messagingService = Substitute.for<MessagingService>();
|
||||
logService = Substitute.for<LogService>();
|
||||
stateService = Substitute.for<StateService>();
|
||||
twoFactorService = Substitute.for<TwoFactorService>();
|
||||
authService = Substitute.for<AuthService>();
|
||||
|
||||
appIdService.getAppId().resolves(deviceId);
|
||||
tokenService.getTwoFactorToken().resolves(null);
|
||||
|
||||
authService.makePreloginKey(Arg.any(), Arg.any()).resolves(preloginKey);
|
||||
|
||||
cryptoService.hashPassword(masterPassword, Arg.any()).resolves(hashedPassword);
|
||||
cryptoService
|
||||
.hashPassword(masterPassword, Arg.any(), HashPurpose.LocalAuthorization)
|
||||
.resolves(localHashedPassword);
|
||||
|
||||
passwordLogInStrategy = new PasswordLogInStrategy(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
authService,
|
||||
);
|
||||
credentials = new PasswordLogInCredentials(email, masterPassword);
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
});
|
||||
|
||||
it("sends master password credentials to the server", async () => {
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const passwordTokenRequest = actual as any; // Need to access private fields
|
||||
return (
|
||||
passwordTokenRequest.email === email &&
|
||||
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
||||
passwordTokenRequest.device.identifier === deviceId &&
|
||||
passwordTokenRequest.twoFactor.provider == null &&
|
||||
passwordTokenRequest.twoFactor.token == null &&
|
||||
passwordTokenRequest.captchaResponse == null
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("sets the local environment after a successful login", async () => {
|
||||
await passwordLogInStrategy.logIn(credentials);
|
||||
|
||||
cryptoService.received(1).setKey(preloginKey);
|
||||
cryptoService.received(1).setKeyHash(localHashedPassword);
|
||||
});
|
||||
});
|
||||
@@ -1,127 +0,0 @@
|
||||
import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute";
|
||||
|
||||
import { ApiService } from "@/jslib/common/src/abstractions/api.service";
|
||||
import { AppIdService } from "@/jslib/common/src/abstractions/appId.service";
|
||||
import { CryptoService } from "@/jslib/common/src/abstractions/crypto.service";
|
||||
import { KeyConnectorService } from "@/jslib/common/src/abstractions/keyConnector.service";
|
||||
import { LogService } from "@/jslib/common/src/abstractions/log.service";
|
||||
import { MessagingService } from "@/jslib/common/src/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@/jslib/common/src/abstractions/platformUtils.service";
|
||||
import { StateService } from "@/jslib/common/src/abstractions/state.service";
|
||||
import { TokenService } from "@/jslib/common/src/abstractions/token.service";
|
||||
import { TwoFactorService } from "@/jslib/common/src/abstractions/twoFactor.service";
|
||||
import { SsoLogInStrategy } from "@/jslib/common/src/misc/logInStrategies/ssoLogin.strategy";
|
||||
import { Utils } from "@/jslib/common/src/misc/utils";
|
||||
import { SsoLogInCredentials } from "@/jslib/common/src/models/domain/logInCredentials";
|
||||
|
||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
||||
|
||||
describe("SsoLogInStrategy", () => {
|
||||
let cryptoService: SubstituteOf<CryptoService>;
|
||||
let apiService: SubstituteOf<ApiService>;
|
||||
let tokenService: SubstituteOf<TokenService>;
|
||||
let appIdService: SubstituteOf<AppIdService>;
|
||||
let platformUtilsService: SubstituteOf<PlatformUtilsService>;
|
||||
let messagingService: SubstituteOf<MessagingService>;
|
||||
let logService: SubstituteOf<LogService>;
|
||||
let keyConnectorService: SubstituteOf<KeyConnectorService>;
|
||||
let stateService: SubstituteOf<StateService>;
|
||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
||||
|
||||
let ssoLogInStrategy: SsoLogInStrategy;
|
||||
let credentials: SsoLogInCredentials;
|
||||
|
||||
const deviceId = Utils.newGuid();
|
||||
const encKey = "ENC_KEY";
|
||||
const privateKey = "PRIVATE_KEY";
|
||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
||||
|
||||
const ssoCode = "SSO_CODE";
|
||||
const ssoCodeVerifier = "SSO_CODE_VERIFIER";
|
||||
const ssoRedirectUrl = "SSO_REDIRECT_URL";
|
||||
const ssoOrgId = "SSO_ORG_ID";
|
||||
|
||||
beforeEach(async () => {
|
||||
cryptoService = Substitute.for<CryptoService>();
|
||||
apiService = Substitute.for<ApiService>();
|
||||
tokenService = Substitute.for<TokenService>();
|
||||
appIdService = Substitute.for<AppIdService>();
|
||||
platformUtilsService = Substitute.for<PlatformUtilsService>();
|
||||
messagingService = Substitute.for<MessagingService>();
|
||||
logService = Substitute.for<LogService>();
|
||||
stateService = Substitute.for<StateService>();
|
||||
keyConnectorService = Substitute.for<KeyConnectorService>();
|
||||
twoFactorService = Substitute.for<TwoFactorService>();
|
||||
|
||||
tokenService.getTwoFactorToken().resolves(null);
|
||||
appIdService.getAppId().resolves(deviceId);
|
||||
|
||||
ssoLogInStrategy = new SsoLogInStrategy(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
keyConnectorService,
|
||||
);
|
||||
credentials = new SsoLogInCredentials(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId);
|
||||
});
|
||||
|
||||
it("sends SSO information to server", async () => {
|
||||
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
|
||||
|
||||
await ssoLogInStrategy.logIn(credentials);
|
||||
|
||||
apiService.received(1).postIdentityToken(
|
||||
Arg.is((actual) => {
|
||||
const ssoTokenRequest = actual as any;
|
||||
return (
|
||||
ssoTokenRequest.code === ssoCode &&
|
||||
ssoTokenRequest.codeVerifier === ssoCodeVerifier &&
|
||||
ssoTokenRequest.redirectUri === ssoRedirectUrl &&
|
||||
ssoTokenRequest.device.identifier === deviceId &&
|
||||
ssoTokenRequest.twoFactor.provider == null &&
|
||||
ssoTokenRequest.twoFactor.token == null
|
||||
);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("does not set keys for new SSO user flow", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.key = null;
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
await ssoLogInStrategy.logIn(credentials);
|
||||
|
||||
cryptoService.didNotReceive().setEncPrivateKey(privateKey);
|
||||
cryptoService.didNotReceive().setEncKey(encKey);
|
||||
});
|
||||
|
||||
it("gets and sets KeyConnector key for enrolled user", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.keyConnectorUrl = keyConnectorUrl;
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
await ssoLogInStrategy.logIn(credentials);
|
||||
|
||||
keyConnectorService.received(1).getAndSetKey(keyConnectorUrl);
|
||||
});
|
||||
|
||||
it("converts new SSO user to Key Connector on first login", async () => {
|
||||
const tokenResponse = identityTokenResponseFactory();
|
||||
tokenResponse.keyConnectorUrl = keyConnectorUrl;
|
||||
tokenResponse.key = null;
|
||||
|
||||
apiService.postIdentityToken(Arg.any()).resolves(tokenResponse);
|
||||
|
||||
await ssoLogInStrategy.logIn(credentials);
|
||||
|
||||
keyConnectorService.received(1).convertNewSsoUserToKeyConnector(tokenResponse, ssoOrgId);
|
||||
});
|
||||
});
|
||||
@@ -1,679 +1,14 @@
|
||||
import { PolicyType } from "../enums/policyType";
|
||||
import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest";
|
||||
import { VerifyOTPRequest } from "../models/request/account/verifyOTPRequest";
|
||||
import { AttachmentRequest } from "../models/request/attachmentRequest";
|
||||
import { BitPayInvoiceRequest } from "../models/request/bitPayInvoiceRequest";
|
||||
import { CipherBulkDeleteRequest } from "../models/request/cipherBulkDeleteRequest";
|
||||
import { CipherBulkMoveRequest } from "../models/request/cipherBulkMoveRequest";
|
||||
import { CipherBulkRestoreRequest } from "../models/request/cipherBulkRestoreRequest";
|
||||
import { CipherBulkShareRequest } from "../models/request/cipherBulkShareRequest";
|
||||
import { CipherCollectionsRequest } from "../models/request/cipherCollectionsRequest";
|
||||
import { CipherCreateRequest } from "../models/request/cipherCreateRequest";
|
||||
import { CipherRequest } from "../models/request/cipherRequest";
|
||||
import { CipherShareRequest } from "../models/request/cipherShareRequest";
|
||||
import { CollectionRequest } from "../models/request/collectionRequest";
|
||||
import { DeleteRecoverRequest } from "../models/request/deleteRecoverRequest";
|
||||
import { EmailRequest } from "../models/request/emailRequest";
|
||||
import { EmailTokenRequest } from "../models/request/emailTokenRequest";
|
||||
import { EmergencyAccessAcceptRequest } from "../models/request/emergencyAccessAcceptRequest";
|
||||
import { EmergencyAccessConfirmRequest } from "../models/request/emergencyAccessConfirmRequest";
|
||||
import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessInviteRequest";
|
||||
import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest";
|
||||
import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest";
|
||||
import { EventRequest } from "../models/request/eventRequest";
|
||||
import { FolderRequest } from "../models/request/folderRequest";
|
||||
import { GroupRequest } from "../models/request/groupRequest";
|
||||
import { IapCheckRequest } from "../models/request/iapCheckRequest";
|
||||
import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest";
|
||||
import { PasswordTokenRequest } from "../models/request/identityToken/passwordTokenRequest";
|
||||
import { SsoTokenRequest } from "../models/request/identityToken/ssoTokenRequest";
|
||||
import { ImportCiphersRequest } from "../models/request/importCiphersRequest";
|
||||
import { ImportDirectoryRequest } from "../models/request/importDirectoryRequest";
|
||||
import { ImportOrganizationCiphersRequest } from "../models/request/importOrganizationCiphersRequest";
|
||||
import { KdfRequest } from "../models/request/kdfRequest";
|
||||
import { KeyConnectorUserKeyRequest } from "../models/request/keyConnectorUserKeyRequest";
|
||||
import { KeysRequest } from "../models/request/keysRequest";
|
||||
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organizationSponsorshipCreateRequest";
|
||||
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organizationSponsorshipRedeemRequest";
|
||||
import { OrganizationSsoRequest } from "../models/request/organization/organizationSsoRequest";
|
||||
import { OrganizationCreateRequest } from "../models/request/organizationCreateRequest";
|
||||
import { OrganizationImportRequest } from "../models/request/organizationImportRequest";
|
||||
import { OrganizationKeysRequest } from "../models/request/organizationKeysRequest";
|
||||
import { OrganizationSubscriptionUpdateRequest } from "../models/request/organizationSubscriptionUpdateRequest";
|
||||
import { OrganizationTaxInfoUpdateRequest } from "../models/request/organizationTaxInfoUpdateRequest";
|
||||
import { OrganizationUpdateRequest } from "../models/request/organizationUpdateRequest";
|
||||
import { OrganizationUpgradeRequest } from "../models/request/organizationUpgradeRequest";
|
||||
import { OrganizationUserAcceptRequest } from "../models/request/organizationUserAcceptRequest";
|
||||
import { OrganizationUserBulkConfirmRequest } from "../models/request/organizationUserBulkConfirmRequest";
|
||||
import { OrganizationUserBulkRequest } from "../models/request/organizationUserBulkRequest";
|
||||
import { OrganizationUserConfirmRequest } from "../models/request/organizationUserConfirmRequest";
|
||||
import { OrganizationUserInviteRequest } from "../models/request/organizationUserInviteRequest";
|
||||
import { OrganizationUserResetPasswordEnrollmentRequest } from "../models/request/organizationUserResetPasswordEnrollmentRequest";
|
||||
import { OrganizationUserResetPasswordRequest } from "../models/request/organizationUserResetPasswordRequest";
|
||||
import { OrganizationUserUpdateGroupsRequest } from "../models/request/organizationUserUpdateGroupsRequest";
|
||||
import { OrganizationUserUpdateRequest } from "../models/request/organizationUserUpdateRequest";
|
||||
import { PasswordHintRequest } from "../models/request/passwordHintRequest";
|
||||
import { PasswordRequest } from "../models/request/passwordRequest";
|
||||
import { PaymentRequest } from "../models/request/paymentRequest";
|
||||
import { PolicyRequest } from "../models/request/policyRequest";
|
||||
import { PreloginRequest } from "../models/request/preloginRequest";
|
||||
import { ProviderAddOrganizationRequest } from "../models/request/provider/providerAddOrganizationRequest";
|
||||
import { ProviderOrganizationCreateRequest } from "../models/request/provider/providerOrganizationCreateRequest";
|
||||
import { ProviderSetupRequest } from "../models/request/provider/providerSetupRequest";
|
||||
import { ProviderUpdateRequest } from "../models/request/provider/providerUpdateRequest";
|
||||
import { ProviderUserAcceptRequest } from "../models/request/provider/providerUserAcceptRequest";
|
||||
import { ProviderUserBulkConfirmRequest } from "../models/request/provider/providerUserBulkConfirmRequest";
|
||||
import { ProviderUserBulkRequest } from "../models/request/provider/providerUserBulkRequest";
|
||||
import { ProviderUserConfirmRequest } from "../models/request/provider/providerUserConfirmRequest";
|
||||
import { ProviderUserInviteRequest } from "../models/request/provider/providerUserInviteRequest";
|
||||
import { ProviderUserUpdateRequest } from "../models/request/provider/providerUserUpdateRequest";
|
||||
import { RegisterRequest } from "../models/request/registerRequest";
|
||||
import { SeatRequest } from "../models/request/seatRequest";
|
||||
import { SecretVerificationRequest } from "../models/request/secretVerificationRequest";
|
||||
import { SelectionReadOnlyRequest } from "../models/request/selectionReadOnlyRequest";
|
||||
import { SendAccessRequest } from "../models/request/sendAccessRequest";
|
||||
import { SendRequest } from "../models/request/sendRequest";
|
||||
import { SetPasswordRequest } from "../models/request/setPasswordRequest";
|
||||
import { StorageRequest } from "../models/request/storageRequest";
|
||||
import { TaxInfoUpdateRequest } from "../models/request/taxInfoUpdateRequest";
|
||||
import { TwoFactorEmailRequest } from "../models/request/twoFactorEmailRequest";
|
||||
import { TwoFactorProviderRequest } from "../models/request/twoFactorProviderRequest";
|
||||
import { TwoFactorRecoveryRequest } from "../models/request/twoFactorRecoveryRequest";
|
||||
import { UpdateDomainsRequest } from "../models/request/updateDomainsRequest";
|
||||
import { UpdateKeyRequest } from "../models/request/updateKeyRequest";
|
||||
import { UpdateProfileRequest } from "../models/request/updateProfileRequest";
|
||||
import { UpdateTempPasswordRequest } from "../models/request/updateTempPasswordRequest";
|
||||
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/updateTwoFactorAuthenticatorRequest";
|
||||
import { UpdateTwoFactorDuoRequest } from "../models/request/updateTwoFactorDuoRequest";
|
||||
import { UpdateTwoFactorEmailRequest } from "../models/request/updateTwoFactorEmailRequest";
|
||||
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/updateTwoFactorWebAuthnDeleteRequest";
|
||||
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/updateTwoFactorWebAuthnRequest";
|
||||
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/updateTwoFactorYubioOtpRequest";
|
||||
import { VerifyBankRequest } from "../models/request/verifyBankRequest";
|
||||
import { VerifyDeleteRecoverRequest } from "../models/request/verifyDeleteRecoverRequest";
|
||||
import { VerifyEmailRequest } from "../models/request/verifyEmailRequest";
|
||||
import { ApiKeyResponse } from "../models/response/apiKeyResponse";
|
||||
import { AttachmentResponse } from "../models/response/attachmentResponse";
|
||||
import { AttachmentUploadDataResponse } from "../models/response/attachmentUploadDataResponse";
|
||||
import { BillingResponse } from "../models/response/billingResponse";
|
||||
import { BreachAccountResponse } from "../models/response/breachAccountResponse";
|
||||
import { CipherResponse } from "../models/response/cipherResponse";
|
||||
import {
|
||||
CollectionGroupDetailsResponse,
|
||||
CollectionResponse,
|
||||
} from "../models/response/collectionResponse";
|
||||
import { DomainsResponse } from "../models/response/domainsResponse";
|
||||
import {
|
||||
EmergencyAccessGranteeDetailsResponse,
|
||||
EmergencyAccessGrantorDetailsResponse,
|
||||
EmergencyAccessTakeoverResponse,
|
||||
EmergencyAccessViewResponse,
|
||||
} from "../models/response/emergencyAccessResponse";
|
||||
import { EventResponse } from "../models/response/eventResponse";
|
||||
import { FolderResponse } from "../models/response/folderResponse";
|
||||
import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse";
|
||||
import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse";
|
||||
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
||||
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
||||
import { KeyConnectorUserKeyResponse } from "../models/response/keyConnectorUserKeyResponse";
|
||||
import { ListResponse } from "../models/response/listResponse";
|
||||
import { OrganizationSsoResponse } from "../models/response/organization/organizationSsoResponse";
|
||||
import { OrganizationAutoEnrollStatusResponse } from "../models/response/organizationAutoEnrollStatusResponse";
|
||||
import { OrganizationKeysResponse } from "../models/response/organizationKeysResponse";
|
||||
import { OrganizationResponse } from "../models/response/organizationResponse";
|
||||
import { OrganizationSubscriptionResponse } from "../models/response/organizationSubscriptionResponse";
|
||||
import { OrganizationUserBulkPublicKeyResponse } from "../models/response/organizationUserBulkPublicKeyResponse";
|
||||
import { OrganizationUserBulkResponse } from "../models/response/organizationUserBulkResponse";
|
||||
import {
|
||||
OrganizationUserDetailsResponse,
|
||||
OrganizationUserResetPasswordDetailsReponse,
|
||||
OrganizationUserUserDetailsResponse,
|
||||
} from "../models/response/organizationUserResponse";
|
||||
import { PaymentResponse } from "../models/response/paymentResponse";
|
||||
import { PlanResponse } from "../models/response/planResponse";
|
||||
import { PolicyResponse } from "../models/response/policyResponse";
|
||||
import { PreloginResponse } from "../models/response/preloginResponse";
|
||||
import { ProfileResponse } from "../models/response/profileResponse";
|
||||
import {
|
||||
ProviderOrganizationOrganizationDetailsResponse,
|
||||
ProviderOrganizationResponse,
|
||||
} from "../models/response/provider/providerOrganizationResponse";
|
||||
import { ProviderResponse } from "../models/response/provider/providerResponse";
|
||||
import { ProviderUserBulkPublicKeyResponse } from "../models/response/provider/providerUserBulkPublicKeyResponse";
|
||||
import { ProviderUserBulkResponse } from "../models/response/provider/providerUserBulkResponse";
|
||||
import {
|
||||
ProviderUserResponse,
|
||||
ProviderUserUserDetailsResponse,
|
||||
} from "../models/response/provider/providerUserResponse";
|
||||
import { SelectionReadOnlyResponse } from "../models/response/selectionReadOnlyResponse";
|
||||
import { SendAccessResponse } from "../models/response/sendAccessResponse";
|
||||
import { SendFileDownloadDataResponse } from "../models/response/sendFileDownloadDataResponse";
|
||||
import { SendFileUploadDataResponse } from "../models/response/sendFileUploadDataResponse";
|
||||
import { SendResponse } from "../models/response/sendResponse";
|
||||
import { SubscriptionResponse } from "../models/response/subscriptionResponse";
|
||||
import { SyncResponse } from "../models/response/syncResponse";
|
||||
import { TaxInfoResponse } from "../models/response/taxInfoResponse";
|
||||
import { TaxRateResponse } from "../models/response/taxRateResponse";
|
||||
import { TwoFactorAuthenticatorResponse } from "../models/response/twoFactorAuthenticatorResponse";
|
||||
import { TwoFactorDuoResponse } from "../models/response/twoFactorDuoResponse";
|
||||
import { TwoFactorEmailResponse } from "../models/response/twoFactorEmailResponse";
|
||||
import { TwoFactorProviderResponse } from "../models/response/twoFactorProviderResponse";
|
||||
import { TwoFactorRecoverResponse } from "../models/response/twoFactorRescoverResponse";
|
||||
import {
|
||||
ChallengeResponse,
|
||||
TwoFactorWebAuthnResponse,
|
||||
} from "../models/response/twoFactorWebAuthnResponse";
|
||||
import { TwoFactorYubiKeyResponse } from "../models/response/twoFactorYubiKeyResponse";
|
||||
import { UserKeyResponse } from "../models/response/userKeyResponse";
|
||||
import { SendAccessView } from "../models/view/sendAccessView";
|
||||
|
||||
export abstract class ApiService {
|
||||
postIdentityToken: (
|
||||
request: PasswordTokenRequest | SsoTokenRequest | ApiTokenRequest,
|
||||
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
||||
refreshIdentityToken: () => Promise<any>;
|
||||
|
||||
getProfile: () => Promise<ProfileResponse>;
|
||||
getUserBilling: () => Promise<BillingResponse>;
|
||||
getUserSubscription: () => Promise<SubscriptionResponse>;
|
||||
getTaxInfo: () => Promise<TaxInfoResponse>;
|
||||
putProfile: (request: UpdateProfileRequest) => Promise<ProfileResponse>;
|
||||
putTaxInfo: (request: TaxInfoUpdateRequest) => Promise<any>;
|
||||
postPrelogin: (request: PreloginRequest) => Promise<PreloginResponse>;
|
||||
postEmailToken: (request: EmailTokenRequest) => Promise<any>;
|
||||
postEmail: (request: EmailRequest) => Promise<any>;
|
||||
postPassword: (request: PasswordRequest) => Promise<any>;
|
||||
setPassword: (request: SetPasswordRequest) => Promise<any>;
|
||||
postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: SecretVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: SecretVerificationRequest) => Promise<any>;
|
||||
getAccountRevisionDate: () => Promise<number>;
|
||||
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
|
||||
postRegister: (request: RegisterRequest) => Promise<any>;
|
||||
postPremium: (data: FormData) => Promise<PaymentResponse>;
|
||||
postIapCheck: (request: IapCheckRequest) => Promise<any>;
|
||||
postReinstatePremium: () => Promise<any>;
|
||||
postCancelPremium: () => Promise<any>;
|
||||
postAccountStorage: (request: StorageRequest) => Promise<PaymentResponse>;
|
||||
postAccountPayment: (request: PaymentRequest) => Promise<any>;
|
||||
postAccountLicense: (data: FormData) => Promise<any>;
|
||||
postAccountKey: (request: UpdateKeyRequest) => Promise<any>;
|
||||
postAccountKeys: (request: KeysRequest) => Promise<any>;
|
||||
postAccountVerifyEmail: () => Promise<any>;
|
||||
postAccountVerifyEmailToken: (request: VerifyEmailRequest) => Promise<any>;
|
||||
postAccountVerifyPassword: (request: SecretVerificationRequest) => Promise<any>;
|
||||
postAccountRecoverDelete: (request: DeleteRecoverRequest) => Promise<any>;
|
||||
postAccountRecoverDeleteToken: (request: VerifyDeleteRecoverRequest) => Promise<any>;
|
||||
postAccountKdf: (request: KdfRequest) => Promise<any>;
|
||||
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
||||
postAccountRequestOTP: () => Promise<void>;
|
||||
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
||||
postConvertToKeyConnector: () => Promise<void>;
|
||||
|
||||
getFolder: (id: string) => Promise<FolderResponse>;
|
||||
postFolder: (request: FolderRequest) => Promise<FolderResponse>;
|
||||
putFolder: (id: string, request: FolderRequest) => Promise<FolderResponse>;
|
||||
deleteFolder: (id: string) => Promise<any>;
|
||||
|
||||
getSend: (id: string) => Promise<SendResponse>;
|
||||
postSendAccess: (
|
||||
id: string,
|
||||
request: SendAccessRequest,
|
||||
apiUrl?: string,
|
||||
) => Promise<SendAccessResponse>;
|
||||
getSends: () => Promise<ListResponse<SendResponse>>;
|
||||
postSend: (request: SendRequest) => Promise<SendResponse>;
|
||||
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
|
||||
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
|
||||
/**
|
||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
||||
* This method still exists for backward compatibility with old server versions.
|
||||
*/
|
||||
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
|
||||
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
|
||||
putSendRemovePassword: (id: string) => Promise<SendResponse>;
|
||||
deleteSend: (id: string) => Promise<any>;
|
||||
getSendFileDownloadData: (
|
||||
send: SendAccessView,
|
||||
request: SendAccessRequest,
|
||||
apiUrl?: string,
|
||||
) => Promise<SendFileDownloadDataResponse>;
|
||||
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
|
||||
|
||||
getCipher: (id: string) => Promise<CipherResponse>;
|
||||
getCipherAdmin: (id: string) => Promise<CipherResponse>;
|
||||
getAttachmentData: (
|
||||
cipherId: string,
|
||||
attachmentId: string,
|
||||
emergencyAccessId?: string,
|
||||
) => Promise<AttachmentResponse>;
|
||||
getCiphersOrganization: (organizationId: string) => Promise<ListResponse<CipherResponse>>;
|
||||
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
|
||||
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
||||
postCipherAdmin: (request: CipherCreateRequest) => Promise<CipherResponse>;
|
||||
putCipher: (id: string, request: CipherRequest) => Promise<CipherResponse>;
|
||||
putCipherAdmin: (id: string, request: CipherRequest) => Promise<CipherResponse>;
|
||||
deleteCipher: (id: string) => Promise<any>;
|
||||
deleteCipherAdmin: (id: string) => Promise<any>;
|
||||
deleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
deleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
putMoveCiphers: (request: CipherBulkMoveRequest) => Promise<any>;
|
||||
putShareCipher: (id: string, request: CipherShareRequest) => Promise<CipherResponse>;
|
||||
putShareCiphers: (request: CipherBulkShareRequest) => Promise<any>;
|
||||
putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
|
||||
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
|
||||
postImportOrganizationCiphers: (
|
||||
organizationId: string,
|
||||
request: ImportOrganizationCiphersRequest,
|
||||
) => Promise<any>;
|
||||
putDeleteCipher: (id: string) => Promise<any>;
|
||||
putDeleteCipherAdmin: (id: string) => Promise<any>;
|
||||
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
putRestoreCipher: (id: string) => Promise<CipherResponse>;
|
||||
putRestoreCipherAdmin: (id: string) => Promise<CipherResponse>;
|
||||
putRestoreManyCiphers: (
|
||||
request: CipherBulkRestoreRequest,
|
||||
) => Promise<ListResponse<CipherResponse>>;
|
||||
|
||||
/**
|
||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
||||
* This method still exists for backward compatibility with old server versions.
|
||||
*/
|
||||
postCipherAttachmentLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
|
||||
/**
|
||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
||||
* This method still exists for backward compatibility with old server versions.
|
||||
*/
|
||||
postCipherAttachmentAdminLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
|
||||
postCipherAttachment: (
|
||||
id: string,
|
||||
request: AttachmentRequest,
|
||||
) => Promise<AttachmentUploadDataResponse>;
|
||||
deleteCipherAttachment: (id: string, attachmentId: string) => Promise<any>;
|
||||
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
|
||||
postShareCipherAttachment: (
|
||||
id: string,
|
||||
attachmentId: string,
|
||||
data: FormData,
|
||||
organizationId: string,
|
||||
) => Promise<any>;
|
||||
renewAttachmentUploadUrl: (
|
||||
id: string,
|
||||
attachmentId: string,
|
||||
) => Promise<AttachmentUploadDataResponse>;
|
||||
postAttachmentFile: (id: string, attachmentId: string, data: FormData) => Promise<any>;
|
||||
|
||||
getCollectionDetails: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
) => Promise<CollectionGroupDetailsResponse>;
|
||||
getUserCollections: () => Promise<ListResponse<CollectionResponse>>;
|
||||
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
|
||||
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
|
||||
postCollection: (
|
||||
organizationId: string,
|
||||
request: CollectionRequest,
|
||||
) => Promise<CollectionResponse>;
|
||||
putCollectionUsers: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: SelectionReadOnlyRequest[],
|
||||
) => Promise<any>;
|
||||
putCollection: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: CollectionRequest,
|
||||
) => Promise<CollectionResponse>;
|
||||
deleteCollection: (organizationId: string, id: string) => Promise<any>;
|
||||
deleteCollectionUser: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
organizationUserId: string,
|
||||
) => Promise<any>;
|
||||
|
||||
getGroupDetails: (organizationId: string, id: string) => Promise<GroupDetailsResponse>;
|
||||
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
|
||||
getGroupUsers: (organizationId: string, id: string) => Promise<string[]>;
|
||||
postGroup: (organizationId: string, request: GroupRequest) => Promise<GroupResponse>;
|
||||
putGroup: (organizationId: string, id: string, request: GroupRequest) => Promise<GroupResponse>;
|
||||
putGroupUsers: (organizationId: string, id: string, request: string[]) => Promise<any>;
|
||||
deleteGroup: (organizationId: string, id: string) => Promise<any>;
|
||||
deleteGroupUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
|
||||
|
||||
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
|
||||
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
|
||||
getPoliciesByToken: (
|
||||
organizationId: string,
|
||||
token: string,
|
||||
email: string,
|
||||
organizationUserId: string,
|
||||
) => Promise<ListResponse<PolicyResponse>>;
|
||||
getPoliciesByInvitedUser: (
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
) => Promise<ListResponse<PolicyResponse>>;
|
||||
putPolicy: (
|
||||
organizationId: string,
|
||||
type: PolicyType,
|
||||
request: PolicyRequest,
|
||||
) => Promise<PolicyResponse>;
|
||||
|
||||
getOrganizationUser: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
) => Promise<OrganizationUserDetailsResponse>;
|
||||
getOrganizationUserGroups: (organizationId: string, id: string) => Promise<string[]>;
|
||||
getOrganizationUsers: (
|
||||
organizationId: string,
|
||||
) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
|
||||
getOrganizationUserResetPasswordDetails: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
) => Promise<OrganizationUserResetPasswordDetailsReponse>;
|
||||
postOrganizationUserInvite: (
|
||||
organizationId: string,
|
||||
request: OrganizationUserInviteRequest,
|
||||
) => Promise<any>;
|
||||
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
|
||||
postManyOrganizationUserReinvite: (
|
||||
organizationId: string,
|
||||
request: OrganizationUserBulkRequest,
|
||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
||||
postOrganizationUserAccept: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: OrganizationUserAcceptRequest,
|
||||
) => Promise<any>;
|
||||
postOrganizationUserConfirm: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: OrganizationUserConfirmRequest,
|
||||
) => Promise<any>;
|
||||
postOrganizationUsersPublicKey: (
|
||||
organizationId: string,
|
||||
request: OrganizationUserBulkRequest,
|
||||
) => Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
|
||||
postOrganizationUserBulkConfirm: (
|
||||
organizationId: string,
|
||||
request: OrganizationUserBulkConfirmRequest,
|
||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
||||
|
||||
putOrganizationUser: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: OrganizationUserUpdateRequest,
|
||||
) => Promise<any>;
|
||||
putOrganizationUserGroups: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: OrganizationUserUpdateGroupsRequest,
|
||||
) => Promise<any>;
|
||||
putOrganizationUserResetPasswordEnrollment: (
|
||||
organizationId: string,
|
||||
userId: string,
|
||||
request: OrganizationUserResetPasswordEnrollmentRequest,
|
||||
) => Promise<any>;
|
||||
putOrganizationUserResetPassword: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
request: OrganizationUserResetPasswordRequest,
|
||||
) => Promise<any>;
|
||||
deleteOrganizationUser: (organizationId: string, id: string) => Promise<any>;
|
||||
deleteManyOrganizationUsers: (
|
||||
organizationId: string,
|
||||
request: OrganizationUserBulkRequest,
|
||||
) => Promise<ListResponse<OrganizationUserBulkResponse>>;
|
||||
|
||||
getSync: () => Promise<SyncResponse>;
|
||||
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
|
||||
postPublicImportDirectory: (request: OrganizationImportRequest) => Promise<any>;
|
||||
|
||||
getSettingsDomains: () => Promise<DomainsResponse>;
|
||||
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
|
||||
|
||||
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorOrganizationProviders: (
|
||||
organizationId: string,
|
||||
) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorAuthenticator: (
|
||||
request: SecretVerificationRequest,
|
||||
) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorOrganizationDuo: (
|
||||
organizationId: string,
|
||||
request: SecretVerificationRequest,
|
||||
) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
||||
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||
putTwoFactorAuthenticator: (
|
||||
request: UpdateTwoFactorAuthenticatorRequest,
|
||||
) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
||||
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
|
||||
putTwoFactorOrganizationDuo: (
|
||||
organizationId: string,
|
||||
request: UpdateTwoFactorDuoRequest,
|
||||
) => Promise<TwoFactorDuoResponse>;
|
||||
putTwoFactorYubiKey: (
|
||||
request: UpdateTwoFactorYubioOtpRequest,
|
||||
) => Promise<TwoFactorYubiKeyResponse>;
|
||||
putTwoFactorWebAuthn: (
|
||||
request: UpdateTwoFactorWebAuthnRequest,
|
||||
) => Promise<TwoFactorWebAuthnResponse>;
|
||||
deleteTwoFactorWebAuthn: (
|
||||
request: UpdateTwoFactorWebAuthnDeleteRequest,
|
||||
) => Promise<TwoFactorWebAuthnResponse>;
|
||||
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
|
||||
putTwoFactorOrganizationDisable: (
|
||||
organizationId: string,
|
||||
request: TwoFactorProviderRequest,
|
||||
) => Promise<TwoFactorProviderResponse>;
|
||||
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
|
||||
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
|
||||
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
|
||||
|
||||
getEmergencyAccessTrusted: () => Promise<ListResponse<EmergencyAccessGranteeDetailsResponse>>;
|
||||
getEmergencyAccessGranted: () => Promise<ListResponse<EmergencyAccessGrantorDetailsResponse>>;
|
||||
getEmergencyAccess: (id: string) => Promise<EmergencyAccessGranteeDetailsResponse>;
|
||||
getEmergencyGrantorPolicies: (id: string) => Promise<ListResponse<PolicyResponse>>;
|
||||
putEmergencyAccess: (id: string, request: EmergencyAccessUpdateRequest) => Promise<any>;
|
||||
deleteEmergencyAccess: (id: string) => Promise<any>;
|
||||
postEmergencyAccessInvite: (request: EmergencyAccessInviteRequest) => Promise<any>;
|
||||
postEmergencyAccessReinvite: (id: string) => Promise<any>;
|
||||
postEmergencyAccessAccept: (id: string, request: EmergencyAccessAcceptRequest) => Promise<any>;
|
||||
postEmergencyAccessConfirm: (id: string, request: EmergencyAccessConfirmRequest) => Promise<any>;
|
||||
postEmergencyAccessInitiate: (id: string) => Promise<any>;
|
||||
postEmergencyAccessApprove: (id: string) => Promise<any>;
|
||||
postEmergencyAccessReject: (id: string) => Promise<any>;
|
||||
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
|
||||
postEmergencyAccessPassword: (
|
||||
id: string,
|
||||
request: EmergencyAccessPasswordRequest,
|
||||
) => Promise<any>;
|
||||
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
|
||||
|
||||
getOrganization: (id: string) => Promise<OrganizationResponse>;
|
||||
getOrganizationBilling: (id: string) => Promise<BillingResponse>;
|
||||
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
|
||||
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
|
||||
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
|
||||
getOrganizationAutoEnrollStatus: (
|
||||
identifier: string,
|
||||
) => Promise<OrganizationAutoEnrollStatusResponse>;
|
||||
getOrganizationSso: (id: string) => Promise<OrganizationSsoResponse>;
|
||||
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
|
||||
putOrganization: (
|
||||
id: string,
|
||||
request: OrganizationUpdateRequest,
|
||||
) => Promise<OrganizationResponse>;
|
||||
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
|
||||
postLeaveOrganization: (id: string) => Promise<any>;
|
||||
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
||||
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
||||
postOrganizationApiKey: (
|
||||
id: string,
|
||||
request: SecretVerificationRequest,
|
||||
) => Promise<ApiKeyResponse>;
|
||||
postOrganizationRotateApiKey: (
|
||||
id: string,
|
||||
request: SecretVerificationRequest,
|
||||
) => Promise<ApiKeyResponse>;
|
||||
postOrganizationSso: (
|
||||
id: string,
|
||||
request: OrganizationSsoRequest,
|
||||
) => Promise<OrganizationSsoResponse>;
|
||||
postOrganizationUpgrade: (
|
||||
id: string,
|
||||
request: OrganizationUpgradeRequest,
|
||||
) => Promise<PaymentResponse>;
|
||||
postOrganizationUpdateSubscription: (
|
||||
id: string,
|
||||
request: OrganizationSubscriptionUpdateRequest,
|
||||
) => Promise<void>;
|
||||
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
|
||||
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
|
||||
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
|
||||
postOrganizationVerifyBank: (id: string, request: VerifyBankRequest) => Promise<any>;
|
||||
postOrganizationCancel: (id: string) => Promise<any>;
|
||||
postOrganizationReinstate: (id: string) => Promise<any>;
|
||||
deleteOrganization: (id: string, request: SecretVerificationRequest) => Promise<any>;
|
||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
||||
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
||||
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
|
||||
postOrganizationKeys: (
|
||||
id: string,
|
||||
request: OrganizationKeysRequest,
|
||||
) => Promise<OrganizationKeysResponse>;
|
||||
|
||||
postProviderSetup: (id: string, request: ProviderSetupRequest) => Promise<ProviderResponse>;
|
||||
getProvider: (id: string) => Promise<ProviderResponse>;
|
||||
putProvider: (id: string, request: ProviderUpdateRequest) => Promise<ProviderResponse>;
|
||||
|
||||
getProviderUsers: (providerId: string) => Promise<ListResponse<ProviderUserUserDetailsResponse>>;
|
||||
getProviderUser: (providerId: string, id: string) => Promise<ProviderUserResponse>;
|
||||
postProviderUserInvite: (providerId: string, request: ProviderUserInviteRequest) => Promise<any>;
|
||||
postProviderUserReinvite: (providerId: string, id: string) => Promise<any>;
|
||||
postManyProviderUserReinvite: (
|
||||
providerId: string,
|
||||
request: ProviderUserBulkRequest,
|
||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
||||
postProviderUserAccept: (
|
||||
providerId: string,
|
||||
id: string,
|
||||
request: ProviderUserAcceptRequest,
|
||||
) => Promise<any>;
|
||||
postProviderUserConfirm: (
|
||||
providerId: string,
|
||||
id: string,
|
||||
request: ProviderUserConfirmRequest,
|
||||
) => Promise<any>;
|
||||
postProviderUsersPublicKey: (
|
||||
providerId: string,
|
||||
request: ProviderUserBulkRequest,
|
||||
) => Promise<ListResponse<ProviderUserBulkPublicKeyResponse>>;
|
||||
postProviderUserBulkConfirm: (
|
||||
providerId: string,
|
||||
request: ProviderUserBulkConfirmRequest,
|
||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
||||
putProviderUser: (
|
||||
providerId: string,
|
||||
id: string,
|
||||
request: ProviderUserUpdateRequest,
|
||||
) => Promise<any>;
|
||||
deleteProviderUser: (organizationId: string, id: string) => Promise<any>;
|
||||
deleteManyProviderUsers: (
|
||||
providerId: string,
|
||||
request: ProviderUserBulkRequest,
|
||||
) => Promise<ListResponse<ProviderUserBulkResponse>>;
|
||||
getProviderClients: (
|
||||
providerId: string,
|
||||
) => Promise<ListResponse<ProviderOrganizationOrganizationDetailsResponse>>;
|
||||
postProviderAddOrganization: (
|
||||
providerId: string,
|
||||
request: ProviderAddOrganizationRequest,
|
||||
) => Promise<any>;
|
||||
postProviderCreateOrganization: (
|
||||
providerId: string,
|
||||
request: ProviderOrganizationCreateRequest,
|
||||
) => Promise<ProviderOrganizationResponse>;
|
||||
deleteProviderOrganization: (providerId: string, organizationId: string) => Promise<any>;
|
||||
|
||||
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
|
||||
getEventsCipher: (
|
||||
id: string,
|
||||
start: string,
|
||||
end: string,
|
||||
token: string,
|
||||
) => Promise<ListResponse<EventResponse>>;
|
||||
getEventsOrganization: (
|
||||
id: string,
|
||||
start: string,
|
||||
end: string,
|
||||
token: string,
|
||||
) => Promise<ListResponse<EventResponse>>;
|
||||
getEventsOrganizationUser: (
|
||||
organizationId: string,
|
||||
id: string,
|
||||
start: string,
|
||||
end: string,
|
||||
token: string,
|
||||
) => Promise<ListResponse<EventResponse>>;
|
||||
getEventsProvider: (
|
||||
id: string,
|
||||
start: string,
|
||||
end: string,
|
||||
token: string,
|
||||
) => Promise<ListResponse<EventResponse>>;
|
||||
getEventsProviderUser: (
|
||||
providerId: string,
|
||||
id: string,
|
||||
start: string,
|
||||
end: string,
|
||||
token: string,
|
||||
) => Promise<ListResponse<EventResponse>>;
|
||||
postEventsCollect: (request: EventRequest[]) => Promise<any>;
|
||||
|
||||
deleteSsoUser: (organizationId: string) => Promise<any>;
|
||||
getSsoUserIdentifier: () => Promise<string>;
|
||||
|
||||
getUserPublicKey: (id: string) => Promise<UserKeyResponse>;
|
||||
|
||||
getHibpBreach: (username: string) => Promise<BreachAccountResponse[]>;
|
||||
|
||||
postBitPayInvoice: (request: BitPayInvoiceRequest) => Promise<string>;
|
||||
postSetupPayment: () => Promise<string>;
|
||||
|
||||
getActiveBearerToken: () => Promise<string>;
|
||||
fetch: (request: Request) => Promise<Response>;
|
||||
nativeFetch: (request: Request) => Promise<Response>;
|
||||
|
||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
||||
|
||||
postCreateSponsorship: (
|
||||
sponsorshipOrgId: string,
|
||||
request: OrganizationSponsorshipCreateRequest,
|
||||
) => Promise<void>;
|
||||
deleteRevokeSponsorship: (sponsoringOrganizationId: string) => Promise<void>;
|
||||
deleteRemoveSponsorship: (sponsoringOrgId: string) => Promise<void>;
|
||||
postPreValidateSponsorshipToken: (sponsorshipToken: string) => Promise<boolean>;
|
||||
postRedeemSponsorship: (
|
||||
sponsorshipToken: string,
|
||||
request: OrganizationSponsorshipRedeemRequest,
|
||||
) => Promise<void>;
|
||||
postResendSponsorshipOffer: (sponsoringOrgId: string) => Promise<void>;
|
||||
|
||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
||||
postUserKeyToKeyConnector: (
|
||||
keyConnectorUrl: string,
|
||||
request: KeyConnectorUserKeyRequest,
|
||||
) => Promise<void>;
|
||||
getKeyConnectorAlive: (keyConnectorUrl: string) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { AuthResult } from "../models/domain/authResult";
|
||||
import {
|
||||
ApiLogInCredentials,
|
||||
PasswordLogInCredentials,
|
||||
SsoLogInCredentials,
|
||||
} from "../models/domain/logInCredentials";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
||||
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequestTwoFactor";
|
||||
|
||||
export abstract class AuthService {
|
||||
masterPasswordHash: string;
|
||||
email: string;
|
||||
logIn: (
|
||||
credentials: ApiLogInCredentials | PasswordLogInCredentials | SsoLogInCredentials,
|
||||
) => Promise<AuthResult>;
|
||||
logInTwoFactor: (
|
||||
twoFactor: TokenRequestTwoFactor,
|
||||
captchaResponse: string,
|
||||
) => Promise<AuthResult>;
|
||||
logOut: (callback: () => void) => void;
|
||||
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
|
||||
authingWithApiKey: () => boolean;
|
||||
authingWithSso: () => boolean;
|
||||
authingWithPassword: () => boolean;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Organization } from "../models/domain/organization";
|
||||
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
||||
|
||||
export abstract class KeyConnectorService {
|
||||
getAndSetKey: (url?: string) => Promise<void>;
|
||||
getManagingOrganization: () => Promise<Organization>;
|
||||
getUsesKeyConnector: () => Promise<boolean>;
|
||||
migrateUser: () => Promise<void>;
|
||||
userNeedsMigration: () => Promise<boolean>;
|
||||
convertNewSsoUserToKeyConnector: (
|
||||
tokenResponse: IdentityTokenResponse,
|
||||
orgId: string,
|
||||
) => Promise<void>;
|
||||
setUsesKeyConnector: (enabled: boolean) => Promise<void>;
|
||||
setConvertAccountRequired: (status: boolean) => Promise<void>;
|
||||
getConvertAccountRequired: () => Promise<boolean>;
|
||||
removeConvertAccountRequired: () => Promise<void>;
|
||||
clear: () => Promise<void>;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import { OrganizationData } from "../models/data/organizationData";
|
||||
import { Organization } from "../models/domain/organization";
|
||||
|
||||
export abstract class OrganizationService {
|
||||
get: (id: string) => Promise<Organization>;
|
||||
getByIdentifier: (identifier: string) => Promise<Organization>;
|
||||
getAll: (userId?: string) => Promise<Organization[]>;
|
||||
save: (orgs: { [id: string]: OrganizationData }) => Promise<any>;
|
||||
canManageSponsorships: () => Promise<boolean>;
|
||||
hasOrganizations: (userId?: string) => Promise<boolean>;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as zxcvbn from "zxcvbn";
|
||||
|
||||
import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory";
|
||||
import { PasswordGeneratorPolicyOptions } from "../models/domain/passwordGeneratorPolicyOptions";
|
||||
|
||||
export abstract class PasswordGenerationService {
|
||||
generatePassword: (options: any) => Promise<string>;
|
||||
generatePassphrase: (options: any) => Promise<string>;
|
||||
getOptions: () => Promise<[any, PasswordGeneratorPolicyOptions]>;
|
||||
enforcePasswordGeneratorPoliciesOnOptions: (
|
||||
options: any,
|
||||
) => Promise<[any, PasswordGeneratorPolicyOptions]>;
|
||||
getPasswordGeneratorPolicyOptions: () => Promise<PasswordGeneratorPolicyOptions>;
|
||||
saveOptions: (options: any) => Promise<any>;
|
||||
getHistory: () => Promise<GeneratedPasswordHistory[]>;
|
||||
addHistory: (password: string) => Promise<any>;
|
||||
clear: (userId?: string) => Promise<any>;
|
||||
passwordStrength: (password: string, userInputs?: string[]) => zxcvbn.ZXCVBNResult;
|
||||
normalizeOptions: (options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) => void;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { PolicyType } from "../enums/policyType";
|
||||
import { PolicyData } from "../models/data/policyData";
|
||||
import { MasterPasswordPolicyOptions } from "../models/domain/masterPasswordPolicyOptions";
|
||||
import { Policy } from "../models/domain/policy";
|
||||
import { ResetPasswordPolicyOptions } from "../models/domain/resetPasswordPolicyOptions";
|
||||
import { ListResponse } from "../models/response/listResponse";
|
||||
import { PolicyResponse } from "../models/response/policyResponse";
|
||||
|
||||
export abstract class PolicyService {
|
||||
clearCache: () => void;
|
||||
getAll: (type?: PolicyType, userId?: string) => Promise<Policy[]>;
|
||||
getPolicyForOrganization: (policyType: PolicyType, organizationId: string) => Promise<Policy>;
|
||||
replace: (policies: { [id: string]: PolicyData }) => Promise<any>;
|
||||
clear: (userId?: string) => Promise<any>;
|
||||
getMasterPasswordPoliciesForInvitedUsers: (orgId: string) => Promise<MasterPasswordPolicyOptions>;
|
||||
getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise<MasterPasswordPolicyOptions>;
|
||||
evaluateMasterPassword: (
|
||||
passwordStrength: number,
|
||||
newPassword: string,
|
||||
enforcedPolicyOptions?: MasterPasswordPolicyOptions,
|
||||
) => boolean;
|
||||
getResetPasswordPolicyOptions: (
|
||||
policies: Policy[],
|
||||
orgId: string,
|
||||
) => [ResetPasswordPolicyOptions, boolean];
|
||||
mapPoliciesFromToken: (policiesResponse: ListResponse<PolicyResponse>) => Policy[];
|
||||
policyAppliesToUser: (
|
||||
policyType: PolicyType,
|
||||
policyFilter?: (policy: Policy) => boolean,
|
||||
userId?: string,
|
||||
) => Promise<boolean>;
|
||||
}
|
||||
@@ -3,26 +3,14 @@ import { Observable } from "rxjs";
|
||||
import { KdfType } from "../enums/kdfType";
|
||||
import { ThemeType } from "../enums/themeType";
|
||||
import { UriMatchType } from "../enums/uriMatchType";
|
||||
import { CipherData } from "../models/data/cipherData";
|
||||
import { CollectionData } from "../models/data/collectionData";
|
||||
import { EventData } from "../models/data/eventData";
|
||||
import { FolderData } from "../models/data/folderData";
|
||||
import { OrganizationData } from "../models/data/organizationData";
|
||||
import { PolicyData } from "../models/data/policyData";
|
||||
import { ProviderData } from "../models/data/providerData";
|
||||
import { SendData } from "../models/data/sendData";
|
||||
import { Account } from "../models/domain/account";
|
||||
import { EncString } from "../models/domain/encString";
|
||||
import { EnvironmentUrls } from "../models/domain/environmentUrls";
|
||||
import { GeneratedPasswordHistory } from "../models/domain/generatedPasswordHistory";
|
||||
import { Policy } from "../models/domain/policy";
|
||||
import { StorageOptions } from "../models/domain/storageOptions";
|
||||
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
|
||||
import { WindowState } from "../models/domain/windowState";
|
||||
import { CipherView } from "../models/view/cipherView";
|
||||
import { CollectionView } from "../models/view/collectionView";
|
||||
import { FolderView } from "../models/view/folderView";
|
||||
import { SendView } from "../models/view/sendView";
|
||||
|
||||
export abstract class StateService<T extends Account = Account> {
|
||||
accounts$: Observable<{ [userId: string]: T }>;
|
||||
@@ -45,8 +33,6 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setApiKeyClientSecret: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getAutoConfirmFingerPrints: (options?: StorageOptions) => Promise<boolean>;
|
||||
setAutoConfirmFingerprints: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getAutoFillOnPageLoadDefault: (options?: StorageOptions) => Promise<boolean>;
|
||||
setAutoFillOnPageLoadDefault: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricAwaitingAcceptance: (options?: StorageOptions) => Promise<boolean>;
|
||||
setBiometricAwaitingAcceptance: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getBiometricFingerprintValidated: (options?: StorageOptions) => Promise<boolean>;
|
||||
@@ -75,17 +61,11 @@ export abstract class StateService<T extends Account = Account> {
|
||||
setCryptoMasterKeyBiometric: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getDecodedToken: (options?: StorageOptions) => Promise<any>;
|
||||
setDecodedToken: (value: any, options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCiphers: (options?: StorageOptions) => Promise<CipherView[]>;
|
||||
setDecryptedCiphers: (value: CipherView[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCollections: (options?: StorageOptions) => Promise<CollectionView[]>;
|
||||
setDecryptedCollections: (value: CollectionView[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<SymmetricCryptoKey>;
|
||||
setDecryptedCryptoSymmetricKey: (
|
||||
value: SymmetricCryptoKey,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getDecryptedFolders: (options?: StorageOptions) => Promise<FolderView[]>;
|
||||
setDecryptedFolders: (value: FolderView[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedOrganizationKeys: (
|
||||
options?: StorageOptions,
|
||||
) => Promise<Map<string, SymmetricCryptoKey>>;
|
||||
@@ -93,17 +73,8 @@ export abstract class StateService<T extends Account = Account> {
|
||||
value: Map<string, SymmetricCryptoKey>,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getDecryptedPasswordGenerationHistory: (
|
||||
options?: StorageOptions,
|
||||
) => Promise<GeneratedPasswordHistory[]>;
|
||||
setDecryptedPasswordGenerationHistory: (
|
||||
value: GeneratedPasswordHistory[],
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getDecryptedPinProtected: (options?: StorageOptions) => Promise<EncString>;
|
||||
setDecryptedPinProtected: (value: EncString, options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedPolicies: (options?: StorageOptions) => Promise<Policy[]>;
|
||||
setDecryptedPolicies: (value: Policy[], options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedPrivateKey: (options?: StorageOptions) => Promise<ArrayBuffer>;
|
||||
setDecryptedPrivateKey: (value: ArrayBuffer, options?: StorageOptions) => Promise<void>;
|
||||
getDecryptedProviderKeys: (options?: StorageOptions) => Promise<Map<string, SymmetricCryptoKey>>;
|
||||
@@ -111,111 +82,54 @@ export abstract class StateService<T extends Account = Account> {
|
||||
value: Map<string, SymmetricCryptoKey>,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getDecryptedSends: (options?: StorageOptions) => Promise<SendView[]>;
|
||||
setDecryptedSends: (value: SendView[], options?: StorageOptions) => Promise<void>;
|
||||
getDefaultUriMatch: (options?: StorageOptions) => Promise<UriMatchType>;
|
||||
setDefaultUriMatch: (value: UriMatchType, options?: StorageOptions) => Promise<void>;
|
||||
getDisableAddLoginNotification: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableAddLoginNotification: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableAutoBiometricsPrompt: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableAutoBiometricsPrompt: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableAutoTotpCopy: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableAutoTotpCopy: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableBadgeCounter: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableBadgeCounter: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableChangedPasswordNotification: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableChangedPasswordNotification: (
|
||||
value: boolean,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getDisableContextMenuItem: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableContextMenuItem: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableFavicon: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableFavicon: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDisableGa: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDisableGa: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDontShowCardsCurrentTab: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDontShowCardsCurrentTab: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getDontShowIdentitiesCurrentTab: (options?: StorageOptions) => Promise<boolean>;
|
||||
setDontShowIdentitiesCurrentTab: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEmail: (options?: StorageOptions) => Promise<string>;
|
||||
setEmail: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEmailVerified: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEmailVerified: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableAlwaysOnTop: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableAlwaysOnTop: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableAutoFillOnPageLoad: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableAutoFillOnPageLoad: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableBiometric: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableBiometric: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableBrowserIntegration: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableBrowserIntegration: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableBrowserIntegrationFingerprint: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableBrowserIntegrationFingerprint: (
|
||||
value: boolean,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEnableCloseToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableCloseToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableFullWidth: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableFullWidth: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableGravitars: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableGravitars: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableMinimizeToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableMinimizeToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableStartToTray: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableStartToTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEnableTray: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEnableTray: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getEncryptedCiphers: (options?: StorageOptions) => Promise<{ [id: string]: CipherData }>;
|
||||
setEncryptedCiphers: (
|
||||
value: { [id: string]: CipherData },
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedCollections: (options?: StorageOptions) => Promise<{ [id: string]: CollectionData }>;
|
||||
setEncryptedCollections: (
|
||||
value: { [id: string]: CollectionData },
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise<string>;
|
||||
setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEncryptedFolders: (options?: StorageOptions) => Promise<{ [id: string]: FolderData }>;
|
||||
setEncryptedFolders: (
|
||||
value: { [id: string]: FolderData },
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedOrganizationKeys: (options?: StorageOptions) => Promise<any>;
|
||||
setEncryptedOrganizationKeys: (
|
||||
value: Map<string, SymmetricCryptoKey>,
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedPasswordGenerationHistory: (
|
||||
options?: StorageOptions,
|
||||
) => Promise<GeneratedPasswordHistory[]>;
|
||||
setEncryptedPasswordGenerationHistory: (
|
||||
value: GeneratedPasswordHistory[],
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedPinProtected: (options?: StorageOptions) => Promise<string>;
|
||||
setEncryptedPinProtected: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEncryptedPolicies: (options?: StorageOptions) => Promise<{ [id: string]: PolicyData }>;
|
||||
setEncryptedPolicies: (
|
||||
value: { [id: string]: PolicyData },
|
||||
options?: StorageOptions,
|
||||
) => Promise<void>;
|
||||
getEncryptedPrivateKey: (options?: StorageOptions) => Promise<string>;
|
||||
setEncryptedPrivateKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEncryptedProviderKeys: (options?: StorageOptions) => Promise<any>;
|
||||
setEncryptedProviderKeys: (value: any, options?: StorageOptions) => Promise<void>;
|
||||
getEncryptedSends: (options?: StorageOptions) => Promise<{ [id: string]: SendData }>;
|
||||
setEncryptedSends: (value: { [id: string]: SendData }, options?: StorageOptions) => Promise<void>;
|
||||
getEntityId: (options?: StorageOptions) => Promise<string>;
|
||||
getEnvironmentUrls: (options?: StorageOptions) => Promise<EnvironmentUrls>;
|
||||
setEnvironmentUrls: (value: EnvironmentUrls, options?: StorageOptions) => Promise<void>;
|
||||
getEquivalentDomains: (options?: StorageOptions) => Promise<any>;
|
||||
setEquivalentDomains: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getEventCollection: (options?: StorageOptions) => Promise<EventData[]>;
|
||||
setEventCollection: (value: EventData[], options?: StorageOptions) => Promise<void>;
|
||||
getEverBeenUnlocked: (options?: StorageOptions) => Promise<boolean>;
|
||||
setEverBeenUnlocked: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
getForcePasswordReset: (options?: StorageOptions) => Promise<boolean>;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { TwoFactorProviderType } from "../enums/twoFactorProviderType";
|
||||
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
||||
|
||||
export interface TwoFactorProviderDetails {
|
||||
type: TwoFactorProviderType;
|
||||
name: string;
|
||||
description: string;
|
||||
priority: number;
|
||||
sort: number;
|
||||
premium: boolean;
|
||||
}
|
||||
|
||||
export abstract class TwoFactorService {
|
||||
init: () => void;
|
||||
getSupportedProviders: (win: Window) => TwoFactorProviderDetails[];
|
||||
getDefaultProvider: (webAuthnSupported: boolean) => TwoFactorProviderType;
|
||||
setSelectedProvider: (type: TwoFactorProviderType) => void;
|
||||
clearSelectedProvider: () => void;
|
||||
|
||||
setProviders: (response: IdentityTwoFactorResponse) => void;
|
||||
clearProviders: () => void;
|
||||
getProviders: () => Map<TwoFactorProviderType, { [key: string]: string }>;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
export enum AuthenticationType {
|
||||
Password = 0,
|
||||
Sso = 1,
|
||||
Api = 2,
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
export enum EventType {
|
||||
User_LoggedIn = 1000,
|
||||
User_ChangedPassword = 1001,
|
||||
User_Updated2fa = 1002,
|
||||
User_Disabled2fa = 1003,
|
||||
User_Recovered2fa = 1004,
|
||||
User_FailedLogIn = 1005,
|
||||
User_FailedLogIn2fa = 1006,
|
||||
User_ClientExportedVault = 1007,
|
||||
User_UpdatedTempPassword = 1008,
|
||||
User_MigratedKeyToKeyConnector = 1009,
|
||||
|
||||
Cipher_Created = 1100,
|
||||
Cipher_Updated = 1101,
|
||||
Cipher_Deleted = 1102,
|
||||
Cipher_AttachmentCreated = 1103,
|
||||
Cipher_AttachmentDeleted = 1104,
|
||||
Cipher_Shared = 1105,
|
||||
Cipher_UpdatedCollections = 1106,
|
||||
Cipher_ClientViewed = 1107,
|
||||
Cipher_ClientToggledPasswordVisible = 1108,
|
||||
Cipher_ClientToggledHiddenFieldVisible = 1109,
|
||||
Cipher_ClientToggledCardCodeVisible = 1110,
|
||||
Cipher_ClientCopiedPassword = 1111,
|
||||
Cipher_ClientCopiedHiddenField = 1112,
|
||||
Cipher_ClientCopiedCardCode = 1113,
|
||||
Cipher_ClientAutofilled = 1114,
|
||||
Cipher_SoftDeleted = 1115,
|
||||
Cipher_Restored = 1116,
|
||||
Cipher_ClientToggledCardNumberVisible = 1117,
|
||||
|
||||
Collection_Created = 1300,
|
||||
Collection_Updated = 1301,
|
||||
Collection_Deleted = 1302,
|
||||
|
||||
Group_Created = 1400,
|
||||
Group_Updated = 1401,
|
||||
Group_Deleted = 1402,
|
||||
|
||||
OrganizationUser_Invited = 1500,
|
||||
OrganizationUser_Confirmed = 1501,
|
||||
OrganizationUser_Updated = 1502,
|
||||
OrganizationUser_Removed = 1503,
|
||||
OrganizationUser_UpdatedGroups = 1504,
|
||||
OrganizationUser_UnlinkedSso = 1505,
|
||||
OrganizationUser_ResetPassword_Enroll = 1506,
|
||||
OrganizationUser_ResetPassword_Withdraw = 1507,
|
||||
OrganizationUser_AdminResetPassword = 1508,
|
||||
OrganizationUser_ResetSsoLink = 1509,
|
||||
OrganizationUser_FirstSsoLogin = 1510,
|
||||
|
||||
Organization_Updated = 1600,
|
||||
Organization_PurgedVault = 1601,
|
||||
// Organization_ClientExportedVault = 1602,
|
||||
Organization_VaultAccessed = 1603,
|
||||
Organization_EnabledSso = 1604,
|
||||
Organization_DisabledSso = 1605,
|
||||
Organization_EnabledKeyConnector = 1606,
|
||||
Organization_DisabledKeyConnector = 1607,
|
||||
|
||||
Policy_Updated = 1700,
|
||||
|
||||
ProviderUser_Invited = 1800,
|
||||
ProviderUser_Confirmed = 1801,
|
||||
ProviderUser_Updated = 1802,
|
||||
ProviderUser_Removed = 1803,
|
||||
|
||||
ProviderOrganization_Created = 1900,
|
||||
ProviderOrganization_Added = 1901,
|
||||
ProviderOrganization_Removed = 1902,
|
||||
ProviderOrganization_VaultAccessed = 1903,
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
export type LinkedIdType = LoginLinkedId | CardLinkedId | IdentityLinkedId;
|
||||
|
||||
// LoginView
|
||||
export enum LoginLinkedId {
|
||||
Username = 100,
|
||||
Password = 101,
|
||||
}
|
||||
|
||||
// CardView
|
||||
export enum CardLinkedId {
|
||||
CardholderName = 300,
|
||||
ExpMonth = 301,
|
||||
ExpYear = 302,
|
||||
Code = 303,
|
||||
Brand = 304,
|
||||
Number = 305,
|
||||
}
|
||||
|
||||
// IdentityView
|
||||
export enum IdentityLinkedId {
|
||||
Title = 400,
|
||||
MiddleName = 401,
|
||||
Address1 = 402,
|
||||
Address2 = 403,
|
||||
Address3 = 404,
|
||||
City = 405,
|
||||
State = 406,
|
||||
PostalCode = 407,
|
||||
Country = 408,
|
||||
Company = 409,
|
||||
Email = 410,
|
||||
Phone = 411,
|
||||
Ssn = 412,
|
||||
Username = 413,
|
||||
PassportNumber = 414,
|
||||
LicenseNumber = 415,
|
||||
FirstName = 416,
|
||||
LastName = 417,
|
||||
FullName = 418,
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export enum PolicyType {
|
||||
TwoFactorAuthentication = 0, // Requires users to have 2fa enabled
|
||||
MasterPassword = 1, // Sets minimum requirements for master password complexity
|
||||
PasswordGenerator = 2, // Sets minimum requirements/default type for generated passwords/passphrases
|
||||
SingleOrg = 3, // Allows users to only be apart of one organization
|
||||
RequireSso = 4, // Requires users to authenticate with SSO
|
||||
PersonalOwnership = 5, // Disables personal vault ownership for adding/cloning items
|
||||
DisableSend = 6, // Disables the ability to create and edit Bitwarden Sends
|
||||
SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
|
||||
ResetPassword = 8, // Allows orgs to use reset password : also can enable auto-enrollment during invite flow
|
||||
MaximumVaultTimeout = 9, // Sets the maximum allowed vault timeout
|
||||
DisablePersonalVaultExport = 10, // Disable personal vault export
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export enum SecureNoteType {
|
||||
Generic = 0,
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export enum SendType {
|
||||
Text = 0,
|
||||
File = 1,
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { I18nService } from "../abstractions/i18n.service";
|
||||
|
||||
import { IFrameComponent } from "./iframe_component";
|
||||
|
||||
export class CaptchaIFrame extends IFrameComponent {
|
||||
constructor(
|
||||
win: Window,
|
||||
webVaultUrl: string,
|
||||
private i18nService: I18nService,
|
||||
successCallback: (message: string) => any,
|
||||
errorCallback: (message: string) => any,
|
||||
infoCallback: (message: string) => any,
|
||||
) {
|
||||
super(
|
||||
win,
|
||||
webVaultUrl,
|
||||
"captcha-connector.html",
|
||||
"hcaptcha_iframe",
|
||||
successCallback,
|
||||
errorCallback,
|
||||
(message: string) => {
|
||||
const parsedMessage = JSON.parse(message);
|
||||
if (typeof parsedMessage !== "string") {
|
||||
this.iframe.height = parsedMessage.height.toString();
|
||||
this.iframe.width = parsedMessage.width.toString();
|
||||
} else {
|
||||
infoCallback(parsedMessage);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
init(siteKey: string): void {
|
||||
super.initComponent(
|
||||
this.createParams({ siteKey: siteKey, locale: this.i18nService.translationLocale }, 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
export abstract class IFrameComponent {
|
||||
iframe: HTMLIFrameElement;
|
||||
private connectorLink: HTMLAnchorElement;
|
||||
private parseFunction = this.parseMessage.bind(this);
|
||||
|
||||
constructor(
|
||||
private win: Window,
|
||||
protected webVaultUrl: string,
|
||||
private path: string,
|
||||
private iframeId: string,
|
||||
public successCallback?: (message: string) => any,
|
||||
public errorCallback?: (message: string) => any,
|
||||
public infoCallback?: (message: string) => any,
|
||||
) {
|
||||
this.connectorLink = win.document.createElement("a");
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.sendMessage("stop");
|
||||
}
|
||||
|
||||
start() {
|
||||
this.sendMessage("start");
|
||||
}
|
||||
|
||||
sendMessage(message: any) {
|
||||
if (!this.iframe || !this.iframe.src || !this.iframe.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.iframe.contentWindow.postMessage(message, this.iframe.src);
|
||||
}
|
||||
|
||||
base64Encode(str: string): string {
|
||||
return btoa(
|
||||
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
return String.fromCharCode(("0x" + p1) as any);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.win.removeEventListener("message", this.parseFunction, false);
|
||||
}
|
||||
|
||||
protected createParams(data: any, version: number) {
|
||||
return new URLSearchParams({
|
||||
data: this.base64Encode(JSON.stringify(data)),
|
||||
parent: encodeURIComponent(this.win.document.location.href),
|
||||
v: version.toString(),
|
||||
});
|
||||
}
|
||||
|
||||
protected initComponent(params: URLSearchParams): void {
|
||||
this.connectorLink.href = `${this.webVaultUrl}/${this.path}?${params}`;
|
||||
this.iframe = this.win.document.getElementById(this.iframeId) as HTMLIFrameElement;
|
||||
this.iframe.src = this.connectorLink.href;
|
||||
|
||||
this.win.addEventListener("message", this.parseFunction, false);
|
||||
}
|
||||
|
||||
private parseMessage(event: MessageEvent) {
|
||||
if (!this.validMessage(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parts: string[] = event.data.split("|");
|
||||
if (parts[0] === "success" && this.successCallback) {
|
||||
this.successCallback(parts[1]);
|
||||
} else if (parts[0] === "error" && this.errorCallback) {
|
||||
this.errorCallback(parts[1]);
|
||||
} else if (parts[0] === "info" && this.infoCallback) {
|
||||
this.infoCallback(parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
private validMessage(event: MessageEvent) {
|
||||
if (
|
||||
event.origin == null ||
|
||||
event.origin === "" ||
|
||||
event.origin !== (this.connectorLink as any).origin ||
|
||||
event.data == null ||
|
||||
typeof event.data !== "string"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
event.data.indexOf("success|") === 0 ||
|
||||
event.data.indexOf("error|") === 0 ||
|
||||
event.data.indexOf("info|") === 0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { LinkedIdType } from "../enums/linkedIdType";
|
||||
import { ItemView } from "../models/view/itemView";
|
||||
|
||||
export class LinkedMetadata {
|
||||
constructor(
|
||||
readonly propertyKey: string,
|
||||
private readonly _i18nKey?: string,
|
||||
) {}
|
||||
|
||||
get i18nKey() {
|
||||
return this._i18nKey ?? this.propertyKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A decorator used to set metadata used by Linked custom fields. Apply it to a class property or getter to make it
|
||||
* available as a Linked custom field option.
|
||||
* @param id - A unique value that is saved in the Field model. It is used to look up the decorated class property.
|
||||
* @param i18nKey - The i18n key used to describe the decorated class property in the UI. If it is null, then the name
|
||||
* of the class property will be used as the i18n key.
|
||||
*/
|
||||
export function linkedFieldOption(id: LinkedIdType, i18nKey?: string) {
|
||||
return (prototype: ItemView, propertyKey: string) => {
|
||||
if (prototype.linkedFieldOptions == null) {
|
||||
prototype.linkedFieldOptions = new Map<LinkedIdType, LinkedMetadata>();
|
||||
}
|
||||
|
||||
prototype.linkedFieldOptions.set(id, new LinkedMetadata(propertyKey, i18nKey));
|
||||
};
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import { ApiService } from "../../abstractions/api.service";
|
||||
import { AppIdService } from "../../abstractions/appId.service";
|
||||
import { CryptoService } from "../../abstractions/crypto.service";
|
||||
import { EnvironmentService } from "../../abstractions/environment.service";
|
||||
import { KeyConnectorService } from "../../abstractions/keyConnector.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { MessagingService } from "../../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
import { TokenService } from "../../abstractions/token.service";
|
||||
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
||||
import { ApiLogInCredentials } from "../../models/domain/logInCredentials";
|
||||
import { ApiTokenRequest } from "../../models/request/identityToken/apiTokenRequest";
|
||||
import { IdentityTokenResponse } from "../../models/response/identityTokenResponse";
|
||||
|
||||
import { LogInStrategy } from "./logIn.strategy";
|
||||
|
||||
export class ApiLogInStrategy extends LogInStrategy {
|
||||
tokenRequest: ApiTokenRequest;
|
||||
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
messagingService: MessagingService,
|
||||
logService: LogService,
|
||||
stateService: StateService,
|
||||
twoFactorService: TwoFactorService,
|
||||
private environmentService: EnvironmentService,
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
);
|
||||
}
|
||||
|
||||
async onSuccessfulLogin(tokenResponse: IdentityTokenResponse) {
|
||||
if (tokenResponse.apiUseKeyConnector) {
|
||||
const keyConnectorUrl = this.environmentService.getKeyConnectorUrl();
|
||||
await this.keyConnectorService.getAndSetKey(keyConnectorUrl);
|
||||
}
|
||||
}
|
||||
|
||||
async logIn(credentials: ApiLogInCredentials) {
|
||||
this.tokenRequest = new ApiTokenRequest(
|
||||
credentials.clientId,
|
||||
credentials.clientSecret,
|
||||
await this.buildTwoFactor(),
|
||||
await this.buildDeviceRequest(),
|
||||
);
|
||||
|
||||
return this.startLogIn();
|
||||
}
|
||||
|
||||
protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
|
||||
await super.saveAccountInformation(tokenResponse);
|
||||
await this.stateService.setApiKeyClientId(this.tokenRequest.clientId);
|
||||
await this.stateService.setApiKeyClientSecret(this.tokenRequest.clientSecret);
|
||||
}
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
import { ApiService } from "../../abstractions/api.service";
|
||||
import { AppIdService } from "../../abstractions/appId.service";
|
||||
import { CryptoService } from "../../abstractions/crypto.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { MessagingService } from "../../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
import { TokenService } from "../../abstractions/token.service";
|
||||
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
||||
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
|
||||
import { Account, AccountProfile, AccountTokens } from "../../models/domain/account";
|
||||
import { AuthResult } from "../../models/domain/authResult";
|
||||
import {
|
||||
ApiLogInCredentials,
|
||||
PasswordLogInCredentials,
|
||||
SsoLogInCredentials,
|
||||
} from "../../models/domain/logInCredentials";
|
||||
import { DeviceRequest } from "../../models/request/deviceRequest";
|
||||
import { ApiTokenRequest } from "../../models/request/identityToken/apiTokenRequest";
|
||||
import { PasswordTokenRequest } from "../../models/request/identityToken/passwordTokenRequest";
|
||||
import { SsoTokenRequest } from "../../models/request/identityToken/ssoTokenRequest";
|
||||
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequestTwoFactor";
|
||||
import { KeysRequest } from "../../models/request/keysRequest";
|
||||
import { IdentityCaptchaResponse } from "../../models/response/identityCaptchaResponse";
|
||||
import { IdentityTokenResponse } from "../../models/response/identityTokenResponse";
|
||||
import { IdentityTwoFactorResponse } from "../../models/response/identityTwoFactorResponse";
|
||||
|
||||
export abstract class LogInStrategy {
|
||||
protected abstract tokenRequest: ApiTokenRequest | PasswordTokenRequest | SsoTokenRequest;
|
||||
protected captchaBypassToken: string = null;
|
||||
|
||||
constructor(
|
||||
protected cryptoService: CryptoService,
|
||||
protected apiService: ApiService,
|
||||
protected tokenService: TokenService,
|
||||
protected appIdService: AppIdService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected messagingService: MessagingService,
|
||||
protected logService: LogService,
|
||||
protected stateService: StateService,
|
||||
protected twoFactorService: TwoFactorService,
|
||||
) {}
|
||||
|
||||
abstract logIn(
|
||||
credentials: ApiLogInCredentials | PasswordLogInCredentials | SsoLogInCredentials,
|
||||
): Promise<AuthResult>;
|
||||
|
||||
async logInTwoFactor(
|
||||
twoFactor: TokenRequestTwoFactor,
|
||||
captchaResponse: string = null,
|
||||
): Promise<AuthResult> {
|
||||
this.tokenRequest.setTwoFactor(twoFactor);
|
||||
return this.startLogIn();
|
||||
}
|
||||
|
||||
protected async startLogIn(): Promise<AuthResult> {
|
||||
this.twoFactorService.clearSelectedProvider();
|
||||
|
||||
const response = await this.apiService.postIdentityToken(this.tokenRequest);
|
||||
|
||||
if (response instanceof IdentityTwoFactorResponse) {
|
||||
return this.processTwoFactorResponse(response);
|
||||
} else if (response instanceof IdentityCaptchaResponse) {
|
||||
return this.processCaptchaResponse(response);
|
||||
} else if (response instanceof IdentityTokenResponse) {
|
||||
return this.processTokenResponse(response);
|
||||
}
|
||||
|
||||
throw new Error("Invalid response object.");
|
||||
}
|
||||
|
||||
protected onSuccessfulLogin(response: IdentityTokenResponse): Promise<void> {
|
||||
// Implemented in subclass if required
|
||||
return null;
|
||||
}
|
||||
|
||||
protected async buildDeviceRequest() {
|
||||
const appId = await this.appIdService.getAppId();
|
||||
return new DeviceRequest(appId, this.platformUtilsService);
|
||||
}
|
||||
|
||||
protected async buildTwoFactor(userProvidedTwoFactor?: TokenRequestTwoFactor) {
|
||||
if (userProvidedTwoFactor != null) {
|
||||
return userProvidedTwoFactor;
|
||||
}
|
||||
|
||||
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken();
|
||||
if (storedTwoFactorToken != null) {
|
||||
return new TokenRequestTwoFactor(TwoFactorProviderType.Remember, storedTwoFactorToken, false);
|
||||
}
|
||||
|
||||
return new TokenRequestTwoFactor();
|
||||
}
|
||||
|
||||
protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
|
||||
const accountInformation = await this.tokenService.decodeToken(tokenResponse.accessToken);
|
||||
await this.stateService.addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: accountInformation.sub,
|
||||
email: accountInformation.email,
|
||||
hasPremiumPersonally: accountInformation.premium,
|
||||
kdfIterations: tokenResponse.kdfIterations,
|
||||
kdfType: tokenResponse.kdf,
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: tokenResponse.accessToken,
|
||||
refreshToken: tokenResponse.refreshToken,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
protected async processTokenResponse(response: IdentityTokenResponse): Promise<AuthResult> {
|
||||
const result = new AuthResult();
|
||||
result.resetMasterPassword = response.resetMasterPassword;
|
||||
result.forcePasswordReset = response.forcePasswordReset;
|
||||
|
||||
await this.saveAccountInformation(response);
|
||||
|
||||
if (response.twoFactorToken != null) {
|
||||
await this.tokenService.setTwoFactorToken(response);
|
||||
}
|
||||
|
||||
const newSsoUser = response.key == null;
|
||||
if (!newSsoUser) {
|
||||
await this.cryptoService.setEncKey(response.key);
|
||||
await this.cryptoService.setEncPrivateKey(
|
||||
response.privateKey ?? (await this.createKeyPairForOldAccount()),
|
||||
);
|
||||
}
|
||||
|
||||
await this.onSuccessfulLogin(response);
|
||||
|
||||
await this.stateService.setBiometricLocked(false);
|
||||
this.messagingService.send("loggedIn");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async processTwoFactorResponse(response: IdentityTwoFactorResponse): Promise<AuthResult> {
|
||||
const result = new AuthResult();
|
||||
result.twoFactorProviders = response.twoFactorProviders2;
|
||||
this.twoFactorService.setProviders(response);
|
||||
this.captchaBypassToken = response.captchaToken ?? null;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async processCaptchaResponse(response: IdentityCaptchaResponse): Promise<AuthResult> {
|
||||
const result = new AuthResult();
|
||||
result.captchaSiteKey = response.siteKey;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async createKeyPairForOldAccount() {
|
||||
try {
|
||||
const [publicKey, privateKey] = await this.cryptoService.makeKeyPair();
|
||||
await this.apiService.postAccountKeys(new KeysRequest(publicKey, privateKey.encryptedString));
|
||||
return privateKey.encryptedString;
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
import { ApiService } from "../../abstractions/api.service";
|
||||
import { AppIdService } from "../../abstractions/appId.service";
|
||||
import { AuthService } from "../../abstractions/auth.service";
|
||||
import { CryptoService } from "../../abstractions/crypto.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { MessagingService } from "../../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
import { TokenService } from "../../abstractions/token.service";
|
||||
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
||||
import { HashPurpose } from "../../enums/hashPurpose";
|
||||
import { AuthResult } from "../../models/domain/authResult";
|
||||
import { PasswordLogInCredentials } from "../../models/domain/logInCredentials";
|
||||
import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey";
|
||||
import { PasswordTokenRequest } from "../../models/request/identityToken/passwordTokenRequest";
|
||||
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequestTwoFactor";
|
||||
|
||||
import { LogInStrategy } from "./logIn.strategy";
|
||||
|
||||
export class PasswordLogInStrategy extends LogInStrategy {
|
||||
get email() {
|
||||
return this.tokenRequest.email;
|
||||
}
|
||||
|
||||
get masterPasswordHash() {
|
||||
return this.tokenRequest.masterPasswordHash;
|
||||
}
|
||||
|
||||
tokenRequest: PasswordTokenRequest;
|
||||
|
||||
private localHashedPassword: string;
|
||||
private key: SymmetricCryptoKey;
|
||||
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
messagingService: MessagingService,
|
||||
logService: LogService,
|
||||
stateService: StateService,
|
||||
twoFactorService: TwoFactorService,
|
||||
private authService: AuthService,
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
);
|
||||
}
|
||||
|
||||
async onSuccessfulLogin() {
|
||||
await this.cryptoService.setKey(this.key);
|
||||
await this.cryptoService.setKeyHash(this.localHashedPassword);
|
||||
}
|
||||
|
||||
async logInTwoFactor(
|
||||
twoFactor: TokenRequestTwoFactor,
|
||||
captchaResponse: string,
|
||||
): Promise<AuthResult> {
|
||||
this.tokenRequest.captchaResponse = captchaResponse ?? this.captchaBypassToken;
|
||||
return super.logInTwoFactor(twoFactor);
|
||||
}
|
||||
|
||||
async logIn(credentials: PasswordLogInCredentials) {
|
||||
const { email, masterPassword, captchaToken, twoFactor } = credentials;
|
||||
|
||||
this.key = await this.authService.makePreloginKey(masterPassword, email);
|
||||
|
||||
// Hash the password early (before authentication) so we don't persist it in memory in plaintext
|
||||
this.localHashedPassword = await this.cryptoService.hashPassword(
|
||||
masterPassword,
|
||||
this.key,
|
||||
HashPurpose.LocalAuthorization,
|
||||
);
|
||||
const hashedPassword = await this.cryptoService.hashPassword(masterPassword, this.key);
|
||||
|
||||
this.tokenRequest = new PasswordTokenRequest(
|
||||
email,
|
||||
hashedPassword,
|
||||
captchaToken,
|
||||
await this.buildTwoFactor(twoFactor),
|
||||
await this.buildDeviceRequest(),
|
||||
);
|
||||
|
||||
return this.startLogIn();
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
import { ApiService } from "../../abstractions/api.service";
|
||||
import { AppIdService } from "../../abstractions/appId.service";
|
||||
import { CryptoService } from "../../abstractions/crypto.service";
|
||||
import { KeyConnectorService } from "../../abstractions/keyConnector.service";
|
||||
import { LogService } from "../../abstractions/log.service";
|
||||
import { MessagingService } from "../../abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
import { TokenService } from "../../abstractions/token.service";
|
||||
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
||||
import { SsoLogInCredentials } from "../../models/domain/logInCredentials";
|
||||
import { SsoTokenRequest } from "../../models/request/identityToken/ssoTokenRequest";
|
||||
import { IdentityTokenResponse } from "../../models/response/identityTokenResponse";
|
||||
|
||||
import { LogInStrategy } from "./logIn.strategy";
|
||||
|
||||
export class SsoLogInStrategy extends LogInStrategy {
|
||||
tokenRequest: SsoTokenRequest;
|
||||
orgId: string;
|
||||
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
messagingService: MessagingService,
|
||||
logService: LogService,
|
||||
stateService: StateService,
|
||||
twoFactorService: TwoFactorService,
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
platformUtilsService,
|
||||
messagingService,
|
||||
logService,
|
||||
stateService,
|
||||
twoFactorService,
|
||||
);
|
||||
}
|
||||
|
||||
async onSuccessfulLogin(tokenResponse: IdentityTokenResponse) {
|
||||
const newSsoUser = tokenResponse.key == null;
|
||||
|
||||
if (tokenResponse.keyConnectorUrl != null) {
|
||||
if (!newSsoUser) {
|
||||
await this.keyConnectorService.getAndSetKey(tokenResponse.keyConnectorUrl);
|
||||
} else {
|
||||
await this.keyConnectorService.convertNewSsoUserToKeyConnector(tokenResponse, this.orgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async logIn(credentials: SsoLogInCredentials) {
|
||||
this.orgId = credentials.orgId;
|
||||
this.tokenRequest = new SsoTokenRequest(
|
||||
credentials.code,
|
||||
credentials.codeVerifier,
|
||||
credentials.redirectUrl,
|
||||
await this.buildTwoFactor(credentials.twoFactor),
|
||||
await this.buildDeviceRequest(),
|
||||
);
|
||||
|
||||
return this.startLogIn();
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
import { I18nService } from "../abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
|
||||
|
||||
export class WebAuthnIFrame {
|
||||
private iframe: HTMLIFrameElement = null;
|
||||
private connectorLink: HTMLAnchorElement;
|
||||
private parseFunction = this.parseMessage.bind(this);
|
||||
|
||||
constructor(
|
||||
private win: Window,
|
||||
private webVaultUrl: string,
|
||||
private webAuthnNewTab: boolean,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private successCallback: Function, // eslint-disable-line
|
||||
private errorCallback: Function, // eslint-disable-line
|
||||
private infoCallback: Function, // eslint-disable-line
|
||||
) {
|
||||
this.connectorLink = win.document.createElement("a");
|
||||
}
|
||||
|
||||
init(data: any): void {
|
||||
const params = new URLSearchParams({
|
||||
data: this.base64Encode(JSON.stringify(data)),
|
||||
parent: encodeURIComponent(this.win.document.location.href),
|
||||
btnText: encodeURIComponent(this.i18nService.t("webAuthnAuthenticate")),
|
||||
v: "1",
|
||||
});
|
||||
|
||||
if (this.webAuthnNewTab) {
|
||||
// Firefox fallback which opens the webauthn page in a new tab
|
||||
params.append("locale", this.i18nService.translationLocale);
|
||||
this.platformUtilsService.launchUri(
|
||||
`${this.webVaultUrl}/webauthn-fallback-connector.html?${params}`,
|
||||
);
|
||||
} else {
|
||||
this.connectorLink.href = `${this.webVaultUrl}/webauthn-connector.html?${params}`;
|
||||
this.iframe = this.win.document.getElementById("webauthn_iframe") as HTMLIFrameElement;
|
||||
this.iframe.allow = "publickey-credentials-get " + new URL(this.webVaultUrl).origin;
|
||||
this.iframe.src = this.connectorLink.href;
|
||||
|
||||
this.win.addEventListener("message", this.parseFunction, false);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.sendMessage("stop");
|
||||
}
|
||||
|
||||
start() {
|
||||
this.sendMessage("start");
|
||||
}
|
||||
|
||||
sendMessage(message: any) {
|
||||
if (!this.iframe || !this.iframe.src || !this.iframe.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.iframe.contentWindow.postMessage(message, this.iframe.src);
|
||||
}
|
||||
|
||||
base64Encode(str: string): string {
|
||||
return btoa(
|
||||
encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
return String.fromCharCode(("0x" + p1) as any);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.win.removeEventListener("message", this.parseFunction, false);
|
||||
}
|
||||
|
||||
private parseMessage(event: MessageEvent) {
|
||||
if (!this.validMessage(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parts: string[] = event.data.split("|");
|
||||
if (parts[0] === "success" && this.successCallback) {
|
||||
this.successCallback(parts[1]);
|
||||
} else if (parts[0] === "error" && this.errorCallback) {
|
||||
this.errorCallback(parts[1]);
|
||||
} else if (parts[0] === "info" && this.infoCallback) {
|
||||
this.infoCallback(parts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
private validMessage(event: MessageEvent) {
|
||||
if (
|
||||
event.origin == null ||
|
||||
event.origin === "" ||
|
||||
event.origin !== (this.connectorLink as any).origin ||
|
||||
event.data == null ||
|
||||
typeof event.data !== "string"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
event.data.indexOf("success|") === 0 ||
|
||||
event.data.indexOf("error|") === 0 ||
|
||||
event.data.indexOf("info|") === 0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class CardApi extends BaseResponse {
|
||||
cardholderName: string;
|
||||
brand: string;
|
||||
number: string;
|
||||
expMonth: string;
|
||||
expYear: string;
|
||||
code: string;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.cardholderName = this.getResponseProperty("CardholderName");
|
||||
this.brand = this.getResponseProperty("Brand");
|
||||
this.number = this.getResponseProperty("Number");
|
||||
this.expMonth = this.getResponseProperty("ExpMonth");
|
||||
this.expYear = this.getResponseProperty("ExpYear");
|
||||
this.code = this.getResponseProperty("Code");
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { FieldType } from "../../enums/fieldType";
|
||||
import { LinkedIdType } from "../../enums/linkedIdType";
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class FieldApi extends BaseResponse {
|
||||
name: string;
|
||||
value: string;
|
||||
type: FieldType;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.type = this.getResponseProperty("Type");
|
||||
this.name = this.getResponseProperty("Name");
|
||||
this.value = this.getResponseProperty("Value");
|
||||
this.linkedId = this.getResponseProperty("linkedId");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class IdentityApi extends BaseResponse {
|
||||
title: string;
|
||||
firstName: string;
|
||||
middleName: string;
|
||||
lastName: string;
|
||||
address1: string;
|
||||
address2: string;
|
||||
address3: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postalCode: string;
|
||||
country: string;
|
||||
company: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
ssn: string;
|
||||
username: string;
|
||||
passportNumber: string;
|
||||
licenseNumber: string;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.title = this.getResponseProperty("Title");
|
||||
this.firstName = this.getResponseProperty("FirstName");
|
||||
this.middleName = this.getResponseProperty("MiddleName");
|
||||
this.lastName = this.getResponseProperty("LastName");
|
||||
this.address1 = this.getResponseProperty("Address1");
|
||||
this.address2 = this.getResponseProperty("Address2");
|
||||
this.address3 = this.getResponseProperty("Address3");
|
||||
this.city = this.getResponseProperty("City");
|
||||
this.state = this.getResponseProperty("State");
|
||||
this.postalCode = this.getResponseProperty("PostalCode");
|
||||
this.country = this.getResponseProperty("Country");
|
||||
this.company = this.getResponseProperty("Company");
|
||||
this.email = this.getResponseProperty("Email");
|
||||
this.phone = this.getResponseProperty("Phone");
|
||||
this.ssn = this.getResponseProperty("SSN");
|
||||
this.username = this.getResponseProperty("Username");
|
||||
this.passportNumber = this.getResponseProperty("PassportNumber");
|
||||
this.licenseNumber = this.getResponseProperty("LicenseNumber");
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
import { LoginUriApi } from "./loginUriApi";
|
||||
|
||||
export class LoginApi extends BaseResponse {
|
||||
uris: LoginUriApi[];
|
||||
username: string;
|
||||
password: string;
|
||||
passwordRevisionDate: string;
|
||||
totp: string;
|
||||
autofillOnPageLoad: boolean;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.username = this.getResponseProperty("Username");
|
||||
this.password = this.getResponseProperty("Password");
|
||||
this.passwordRevisionDate = this.getResponseProperty("PasswordRevisionDate");
|
||||
this.totp = this.getResponseProperty("Totp");
|
||||
this.autofillOnPageLoad = this.getResponseProperty("AutofillOnPageLoad");
|
||||
|
||||
const uris = this.getResponseProperty("Uris");
|
||||
if (uris != null) {
|
||||
this.uris = uris.map((u: any) => new LoginUriApi(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { UriMatchType } from "../../enums/uriMatchType";
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class LoginUriApi extends BaseResponse {
|
||||
uri: string;
|
||||
match: UriMatchType = null;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.uri = this.getResponseProperty("Uri");
|
||||
const match = this.getResponseProperty("Match");
|
||||
this.match = match != null ? match : null;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SecureNoteType } from "../../enums/secureNoteType";
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class SecureNoteApi extends BaseResponse {
|
||||
type: SecureNoteType;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.type = this.getResponseProperty("Type");
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class SendFileApi extends BaseResponse {
|
||||
id: string;
|
||||
fileName: string;
|
||||
size: string;
|
||||
sizeName: string;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.id = this.getResponseProperty("Id");
|
||||
this.fileName = this.getResponseProperty("FileName");
|
||||
this.size = this.getResponseProperty("Size");
|
||||
this.sizeName = this.getResponseProperty("SizeName");
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { BaseResponse } from "../response/baseResponse";
|
||||
|
||||
export class SendTextApi extends BaseResponse {
|
||||
text: string;
|
||||
hidden: boolean;
|
||||
|
||||
constructor(data: any = null) {
|
||||
super(data);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.text = this.getResponseProperty("Text");
|
||||
this.hidden = this.getResponseProperty("Hidden") || false;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import { AttachmentResponse } from "../response/attachmentResponse";
|
||||
|
||||
export class AttachmentData {
|
||||
id: string;
|
||||
url: string;
|
||||
fileName: string;
|
||||
key: string;
|
||||
size: string;
|
||||
sizeName: string;
|
||||
|
||||
constructor(response?: AttachmentResponse) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
this.id = response.id;
|
||||
this.url = response.url;
|
||||
this.fileName = response.fileName;
|
||||
this.key = response.key;
|
||||
this.size = response.size;
|
||||
this.sizeName = response.sizeName;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { CardApi } from "../api/cardApi";
|
||||
|
||||
export class CardData {
|
||||
cardholderName: string;
|
||||
brand: string;
|
||||
number: string;
|
||||
expMonth: string;
|
||||
expYear: string;
|
||||
code: string;
|
||||
|
||||
constructor(data?: CardApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cardholderName = data.cardholderName;
|
||||
this.brand = data.brand;
|
||||
this.number = data.number;
|
||||
this.expMonth = data.expMonth;
|
||||
this.expYear = data.expYear;
|
||||
this.code = data.code;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
import { CipherRepromptType } from "../../enums/cipherRepromptType";
|
||||
import { CipherType } from "../../enums/cipherType";
|
||||
import { CipherResponse } from "../response/cipherResponse";
|
||||
|
||||
import { AttachmentData } from "./attachmentData";
|
||||
import { CardData } from "./cardData";
|
||||
import { FieldData } from "./fieldData";
|
||||
import { IdentityData } from "./identityData";
|
||||
import { LoginData } from "./loginData";
|
||||
import { PasswordHistoryData } from "./passwordHistoryData";
|
||||
import { SecureNoteData } from "./secureNoteData";
|
||||
|
||||
export class CipherData {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
folderId: string;
|
||||
userId: string;
|
||||
edit: boolean;
|
||||
viewPassword: boolean;
|
||||
organizationUseTotp: boolean;
|
||||
favorite: boolean;
|
||||
revisionDate: string;
|
||||
type: CipherType;
|
||||
name: string;
|
||||
notes: string;
|
||||
login?: LoginData;
|
||||
secureNote?: SecureNoteData;
|
||||
card?: CardData;
|
||||
identity?: IdentityData;
|
||||
fields?: FieldData[];
|
||||
attachments?: AttachmentData[];
|
||||
passwordHistory?: PasswordHistoryData[];
|
||||
collectionIds?: string[];
|
||||
deletedDate: string;
|
||||
reprompt: CipherRepromptType;
|
||||
|
||||
constructor(response?: CipherResponse, userId?: string, collectionIds?: string[]) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = response.id;
|
||||
this.organizationId = response.organizationId;
|
||||
this.folderId = response.folderId;
|
||||
this.userId = userId;
|
||||
this.edit = response.edit;
|
||||
this.viewPassword = response.viewPassword;
|
||||
this.organizationUseTotp = response.organizationUseTotp;
|
||||
this.favorite = response.favorite;
|
||||
this.revisionDate = response.revisionDate;
|
||||
this.type = response.type;
|
||||
this.name = response.name;
|
||||
this.notes = response.notes;
|
||||
this.collectionIds = collectionIds != null ? collectionIds : response.collectionIds;
|
||||
this.deletedDate = response.deletedDate;
|
||||
this.reprompt = response.reprompt;
|
||||
|
||||
switch (this.type) {
|
||||
case CipherType.Login:
|
||||
this.login = new LoginData(response.login);
|
||||
break;
|
||||
case CipherType.SecureNote:
|
||||
this.secureNote = new SecureNoteData(response.secureNote);
|
||||
break;
|
||||
case CipherType.Card:
|
||||
this.card = new CardData(response.card);
|
||||
break;
|
||||
case CipherType.Identity:
|
||||
this.identity = new IdentityData(response.identity);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.fields != null) {
|
||||
this.fields = response.fields.map((f) => new FieldData(f));
|
||||
}
|
||||
if (response.attachments != null) {
|
||||
this.attachments = response.attachments.map((a) => new AttachmentData(a));
|
||||
}
|
||||
if (response.passwordHistory != null) {
|
||||
this.passwordHistory = response.passwordHistory.map((ph) => new PasswordHistoryData(ph));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { CollectionDetailsResponse } from "../response/collectionResponse";
|
||||
|
||||
export class CollectionData {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
name: string;
|
||||
externalId: string;
|
||||
readOnly: boolean;
|
||||
|
||||
constructor(response: CollectionDetailsResponse) {
|
||||
this.id = response.id;
|
||||
this.organizationId = response.organizationId;
|
||||
this.name = response.name;
|
||||
this.externalId = response.externalId;
|
||||
this.readOnly = response.readOnly;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { EventType } from "../../enums/eventType";
|
||||
|
||||
export class EventData {
|
||||
type: EventType;
|
||||
cipherId: string;
|
||||
date: string;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { FieldType } from "../../enums/fieldType";
|
||||
import { LinkedIdType } from "../../enums/linkedIdType";
|
||||
import { FieldApi } from "../api/fieldApi";
|
||||
|
||||
export class FieldData {
|
||||
type: FieldType;
|
||||
name: string;
|
||||
value: string;
|
||||
linkedId: LinkedIdType;
|
||||
|
||||
constructor(response?: FieldApi) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
this.type = response.type;
|
||||
this.name = response.name;
|
||||
this.value = response.value;
|
||||
this.linkedId = response.linkedId;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { FolderResponse } from "../response/folderResponse";
|
||||
|
||||
export class FolderData {
|
||||
id: string;
|
||||
userId: string;
|
||||
name: string;
|
||||
revisionDate: string;
|
||||
|
||||
constructor(response: FolderResponse, userId: string) {
|
||||
this.userId = userId;
|
||||
this.name = response.name;
|
||||
this.id = response.id;
|
||||
this.revisionDate = response.revisionDate;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import { IdentityApi } from "../api/identityApi";
|
||||
|
||||
export class IdentityData {
|
||||
title: string;
|
||||
firstName: string;
|
||||
middleName: string;
|
||||
lastName: string;
|
||||
address1: string;
|
||||
address2: string;
|
||||
address3: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postalCode: string;
|
||||
country: string;
|
||||
company: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
ssn: string;
|
||||
username: string;
|
||||
passportNumber: string;
|
||||
licenseNumber: string;
|
||||
|
||||
constructor(data?: IdentityApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.title = data.title;
|
||||
this.firstName = data.firstName;
|
||||
this.middleName = data.middleName;
|
||||
this.lastName = data.lastName;
|
||||
this.address1 = data.address1;
|
||||
this.address2 = data.address2;
|
||||
this.address3 = data.address3;
|
||||
this.city = data.city;
|
||||
this.state = data.state;
|
||||
this.postalCode = data.postalCode;
|
||||
this.country = data.country;
|
||||
this.company = data.company;
|
||||
this.email = data.email;
|
||||
this.phone = data.phone;
|
||||
this.ssn = data.ssn;
|
||||
this.username = data.username;
|
||||
this.passportNumber = data.passportNumber;
|
||||
this.licenseNumber = data.licenseNumber;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { LoginApi } from "../api/loginApi";
|
||||
|
||||
import { LoginUriData } from "./loginUriData";
|
||||
|
||||
export class LoginData {
|
||||
uris: LoginUriData[];
|
||||
username: string;
|
||||
password: string;
|
||||
passwordRevisionDate: string;
|
||||
totp: string;
|
||||
autofillOnPageLoad: boolean;
|
||||
|
||||
constructor(data?: LoginApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.username = data.username;
|
||||
this.password = data.password;
|
||||
this.passwordRevisionDate = data.passwordRevisionDate;
|
||||
this.totp = data.totp;
|
||||
this.autofillOnPageLoad = data.autofillOnPageLoad;
|
||||
|
||||
if (data.uris) {
|
||||
this.uris = data.uris.map((u) => new LoginUriData(u));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { UriMatchType } from "../../enums/uriMatchType";
|
||||
import { LoginUriApi } from "../api/loginUriApi";
|
||||
|
||||
export class LoginUriData {
|
||||
uri: string;
|
||||
match: UriMatchType = null;
|
||||
|
||||
constructor(data?: LoginUriApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
this.uri = data.uri;
|
||||
this.match = data.match;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { PasswordHistoryResponse } from "../response/passwordHistoryResponse";
|
||||
|
||||
export class PasswordHistoryData {
|
||||
password: string;
|
||||
lastUsedDate: string;
|
||||
|
||||
constructor(response?: PasswordHistoryResponse) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.password = response.password;
|
||||
this.lastUsedDate = response.lastUsedDate;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { PolicyType } from "../../enums/policyType";
|
||||
import { PolicyResponse } from "../response/policyResponse";
|
||||
|
||||
export class PolicyData {
|
||||
id: string;
|
||||
organizationId: string;
|
||||
type: PolicyType;
|
||||
data: any;
|
||||
enabled: boolean;
|
||||
|
||||
constructor(response: PolicyResponse) {
|
||||
this.id = response.id;
|
||||
this.organizationId = response.organizationId;
|
||||
this.type = response.type;
|
||||
this.data = response.data;
|
||||
this.enabled = response.enabled;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { SecureNoteType } from "../../enums/secureNoteType";
|
||||
import { SecureNoteApi } from "../api/secureNoteApi";
|
||||
|
||||
export class SecureNoteData {
|
||||
type: SecureNoteType;
|
||||
|
||||
constructor(data?: SecureNoteApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.type = data.type;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
import { SendType } from "../../enums/sendType";
|
||||
import { SendResponse } from "../response/sendResponse";
|
||||
|
||||
import { SendFileData } from "./sendFileData";
|
||||
import { SendTextData } from "./sendTextData";
|
||||
|
||||
export class SendData {
|
||||
id: string;
|
||||
accessId: string;
|
||||
userId: string;
|
||||
type: SendType;
|
||||
name: string;
|
||||
notes: string;
|
||||
file: SendFileData;
|
||||
text: SendTextData;
|
||||
key: string;
|
||||
maxAccessCount?: number;
|
||||
accessCount: number;
|
||||
revisionDate: string;
|
||||
expirationDate: string;
|
||||
deletionDate: string;
|
||||
password: string;
|
||||
disabled: boolean;
|
||||
hideEmail: boolean;
|
||||
|
||||
constructor(response?: SendResponse, userId?: string) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = response.id;
|
||||
this.accessId = response.accessId;
|
||||
this.userId = userId;
|
||||
this.type = response.type;
|
||||
this.name = response.name;
|
||||
this.notes = response.notes;
|
||||
this.key = response.key;
|
||||
this.maxAccessCount = response.maxAccessCount;
|
||||
this.accessCount = response.accessCount;
|
||||
this.revisionDate = response.revisionDate;
|
||||
this.expirationDate = response.expirationDate;
|
||||
this.deletionDate = response.deletionDate;
|
||||
this.password = response.password;
|
||||
this.disabled = response.disable;
|
||||
this.hideEmail = response.hideEmail;
|
||||
|
||||
switch (this.type) {
|
||||
case SendType.Text:
|
||||
this.text = new SendTextData(response.text);
|
||||
break;
|
||||
case SendType.File:
|
||||
this.file = new SendFileData(response.file);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { SendFileApi } from "../api/sendFileApi";
|
||||
|
||||
export class SendFileData {
|
||||
id: string;
|
||||
fileName: string;
|
||||
size: string;
|
||||
sizeName: string;
|
||||
|
||||
constructor(data?: SendFileApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.id = data.id;
|
||||
this.fileName = data.fileName;
|
||||
this.size = data.size;
|
||||
this.sizeName = data.sizeName;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { SendTextApi } from "../api/sendTextApi";
|
||||
|
||||
export class SendTextData {
|
||||
text: string;
|
||||
hidden: boolean;
|
||||
|
||||
constructor(data?: SendTextApi) {
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.text = data.text;
|
||||
this.hidden = data.hidden;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,11 @@
|
||||
import { AuthenticationStatus } from "../../enums/authenticationStatus";
|
||||
import { KdfType } from "../../enums/kdfType";
|
||||
import { UriMatchType } from "../../enums/uriMatchType";
|
||||
import { CipherData } from "../data/cipherData";
|
||||
import { CollectionData } from "../data/collectionData";
|
||||
import { EventData } from "../data/eventData";
|
||||
import { FolderData } from "../data/folderData";
|
||||
import { OrganizationData } from "../data/organizationData";
|
||||
import { PolicyData } from "../data/policyData";
|
||||
import { ProviderData } from "../data/providerData";
|
||||
import { SendData } from "../data/sendData";
|
||||
import { CipherView } from "../view/cipherView";
|
||||
import { CollectionView } from "../view/collectionView";
|
||||
import { FolderView } from "../view/folderView";
|
||||
import { SendView } from "../view/sendView";
|
||||
|
||||
import { EncString } from "./encString";
|
||||
import { EnvironmentUrls } from "./environmentUrls";
|
||||
import { GeneratedPasswordHistory } from "./generatedPasswordHistory";
|
||||
import { Policy } from "./policy";
|
||||
import { SymmetricCryptoKey } from "./symmetricCryptoKey";
|
||||
|
||||
export class EncryptionPair<TEncrypted, TDecrypted> {
|
||||
@@ -31,27 +19,15 @@ export class DataEncryptionPair<TEncrypted, TDecrypted> {
|
||||
}
|
||||
|
||||
export class AccountData {
|
||||
ciphers?: DataEncryptionPair<CipherData, CipherView> = new DataEncryptionPair<
|
||||
CipherData,
|
||||
CipherView
|
||||
>();
|
||||
folders?: DataEncryptionPair<FolderData, FolderView> = new DataEncryptionPair<
|
||||
FolderData,
|
||||
FolderView
|
||||
>();
|
||||
ciphers?: any = new DataEncryptionPair<any, any>();
|
||||
folders?: DataEncryptionPair<any, any> = new DataEncryptionPair<any, any>();
|
||||
localData?: any;
|
||||
sends?: DataEncryptionPair<SendData, SendView> = new DataEncryptionPair<SendData, SendView>();
|
||||
collections?: DataEncryptionPair<CollectionData, CollectionView> = new DataEncryptionPair<
|
||||
CollectionData,
|
||||
CollectionView
|
||||
>();
|
||||
policies?: DataEncryptionPair<PolicyData, Policy> = new DataEncryptionPair<PolicyData, Policy>();
|
||||
passwordGenerationHistory?: EncryptionPair<
|
||||
GeneratedPasswordHistory[],
|
||||
GeneratedPasswordHistory[]
|
||||
> = new EncryptionPair<GeneratedPasswordHistory[], GeneratedPasswordHistory[]>();
|
||||
sends?: any = new DataEncryptionPair<any, any>();
|
||||
collections?: DataEncryptionPair<any, any> = new DataEncryptionPair<any, any>();
|
||||
policies?: DataEncryptionPair<any, any> = new DataEncryptionPair<any, any>();
|
||||
passwordGenerationHistory?: EncryptionPair<any[], any[]> = new EncryptionPair<any[], any[]>();
|
||||
addEditCipherInfo?: any;
|
||||
eventCollection?: EventData[];
|
||||
eventCollection?: any[];
|
||||
organizations?: { [id: string]: OrganizationData };
|
||||
providers?: { [id: string]: ProviderData };
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { CryptoService } from "../../abstractions/crypto.service";
|
||||
import { Utils } from "../../misc/utils";
|
||||
import { AttachmentData } from "../data/attachmentData";
|
||||
import { AttachmentView } from "../view/attachmentView";
|
||||
|
||||
import Domain from "./domainBase";
|
||||
import { EncString } from "./encString";
|
||||
import { SymmetricCryptoKey } from "./symmetricCryptoKey";
|
||||
|
||||
export class Attachment extends Domain {
|
||||
id: string;
|
||||
url: string;
|
||||
size: string;
|
||||
sizeName: string; // Readable size, ex: "4.2 KB" or "1.43 GB"
|
||||
key: EncString;
|
||||
fileName: EncString;
|
||||
|
||||
constructor(obj?: AttachmentData) {
|
||||
super();
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.size = obj.size;
|
||||
this.buildDomainModel(
|
||||
this,
|
||||
obj,
|
||||
{
|
||||
id: null,
|
||||
url: null,
|
||||
sizeName: null,
|
||||
fileName: null,
|
||||
key: null,
|
||||
},
|
||||
["id", "url", "sizeName"],
|
||||
);
|
||||
}
|
||||
|
||||
async decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<AttachmentView> {
|
||||
const view = await this.decryptObj(
|
||||
new AttachmentView(this),
|
||||
{
|
||||
fileName: null,
|
||||
},
|
||||
orgId,
|
||||
encKey,
|
||||
);
|
||||
|
||||
if (this.key != null) {
|
||||
let cryptoService: CryptoService;
|
||||
const containerService = (Utils.global as any).bitwardenContainerService;
|
||||
if (containerService) {
|
||||
cryptoService = containerService.getCryptoService();
|
||||
} else {
|
||||
throw new Error("global bitwardenContainerService not initialized.");
|
||||
}
|
||||
|
||||
try {
|
||||
const orgKey = await cryptoService.getOrgKey(orgId);
|
||||
const decValue = await cryptoService.decryptToBytes(this.key, orgKey ?? encKey);
|
||||
view.key = new SymmetricCryptoKey(decValue);
|
||||
} catch (e) {
|
||||
// TODO: error?
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
toAttachmentData(): AttachmentData {
|
||||
const a = new AttachmentData();
|
||||
a.size = this.size;
|
||||
this.buildDataModel(
|
||||
this,
|
||||
a,
|
||||
{
|
||||
id: null,
|
||||
url: null,
|
||||
sizeName: null,
|
||||
fileName: null,
|
||||
key: null,
|
||||
},
|
||||
["id", "url", "sizeName"],
|
||||
);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
|
||||
import { Utils } from "../../misc/utils";
|
||||
|
||||
export class AuthResult {
|
||||
captchaSiteKey = "";
|
||||
resetMasterPassword = false;
|
||||
forcePasswordReset = false;
|
||||
twoFactorProviders: Map<TwoFactorProviderType, { [key: string]: string }> = null;
|
||||
|
||||
get requiresCaptcha() {
|
||||
return !Utils.isNullOrWhitespace(this.captchaSiteKey);
|
||||
}
|
||||
|
||||
get requiresTwoFactor() {
|
||||
return this.twoFactorProviders != null;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
import { CardData } from "../data/cardData";
|
||||
import { CardView } from "../view/cardView";
|
||||
|
||||
import Domain from "./domainBase";
|
||||
import { EncString } from "./encString";
|
||||
import { SymmetricCryptoKey } from "./symmetricCryptoKey";
|
||||
|
||||
export class Card extends Domain {
|
||||
cardholderName: EncString;
|
||||
brand: EncString;
|
||||
number: EncString;
|
||||
expMonth: EncString;
|
||||
expYear: EncString;
|
||||
code: EncString;
|
||||
|
||||
constructor(obj?: CardData) {
|
||||
super();
|
||||
if (obj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.buildDomainModel(
|
||||
this,
|
||||
obj,
|
||||
{
|
||||
cardholderName: null,
|
||||
brand: null,
|
||||
number: null,
|
||||
expMonth: null,
|
||||
expYear: null,
|
||||
code: null,
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
decrypt(orgId: string, encKey?: SymmetricCryptoKey): Promise<CardView> {
|
||||
return this.decryptObj(
|
||||
new CardView(),
|
||||
{
|
||||
cardholderName: null,
|
||||
brand: null,
|
||||
number: null,
|
||||
expMonth: null,
|
||||
expYear: null,
|
||||
code: null,
|
||||
},
|
||||
orgId,
|
||||
encKey,
|
||||
);
|
||||
}
|
||||
|
||||
toCardData(): CardData {
|
||||
const c = new CardData();
|
||||
this.buildDataModel(this, c, {
|
||||
cardholderName: null,
|
||||
brand: null,
|
||||
number: null,
|
||||
expMonth: null,
|
||||
expYear: null,
|
||||
code: null,
|
||||
});
|
||||
return c;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user