1
0
mirror of https://github.com/bitwarden/directory-connector synced 2025-12-05 23:53:21 +00:00

Compare commits

...

35 Commits

Author SHA1 Message Date
Thomas Rittson
acc3473731 Use injectable services 2022-03-28 13:07:56 +10:00
Thomas Rittson
c80805ded6 Basic changes to build 2022-03-28 09:21:20 +10:00
Thomas Rittson
c75d26b618 Update to use new JslibModule (#254) 2022-03-21 23:08:12 +01:00
Joseph Flinn
13a13dd18f Adding a manual trigger to the build pipeline in the directory-connector project (#256) 2022-03-21 15:05:12 -07:00
Vince Grassia
954b23d91f Fix Node caching error (#255) 2022-03-21 14:57:44 -07:00
Micaiah Martin
b9d35c3dc7 Updated actions & applied linting (#253) 2022-03-17 12:27:57 -04:00
github-actions[bot]
536f48b3c7 Bump version to 2.10.0 (#252)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-03-16 10:51:01 -06:00
Vince Grassia
8cd768c7c2 Add Node caching (#251) 2022-03-16 11:18:37 -04:00
Chad Scharf
b233d2e87d Update SECURITY.md (#250)
* Update SECURITY.md

Add link to our HackerOne program for submitting potential security issues.

* Revise language on SECURITY.md
2022-03-15 20:53:33 +01:00
Thomas Rittson
1f6d8c1458 Update jslib (#248) 2022-03-15 15:15:27 +10:00
Joseph Flinn
ae05183aa3 Update hotfix release branch name to hotfix-rc (#247) 2022-03-09 12:46:27 -08:00
Robyn MacCallum
8374103a15 Move delta tokens out of secure storage (#246) 2022-03-09 07:51:27 -05:00
Thomas Rittson
dd9e03843a Use saveAccount to scaffold new account (#245) 2022-03-07 07:03:27 +10:00
Oscar Hinton
e38ce53ed5 Add eslint (#243) 2022-03-03 11:09:04 +01:00
Micaiah Martin
0c21bcf847 [BEEEP] - Ignored workflow files from triggering builds (#241) 2022-02-25 09:11:11 -05:00
Micaiah Martin
1c6b94e640 Added dry run logic (#242) 2022-02-25 08:10:49 -06:00
Thomas Rittson
ef1c47ab19 Update jslib (#240) 2022-02-24 09:37:37 -05:00
Chad Scharf
64ff16e895 We're Hiring (#239)
Added link to README.md for Bitwarden Careers page.
2022-02-22 14:03:34 +01:00
Micaiah Martin
89860d6770 Added reusable linting workflow (#238) 2022-02-18 13:28:30 -06:00
Thomas Rittson
91ff43a17f Exclude jslib from prettier hook (#236) 2022-02-17 10:37:14 +10:00
Matt Gibson
0f19ebc928 Enforce Hold label (#234)
* Enforce Hold label

* Linting

Co-authored-by: Micaiah Martin <77340197+mimartin12@users.noreply.github.com>
2022-02-16 08:43:38 -06:00
Addison Beck
b48a1d5856 [lib] Update jslib (#235) 2022-02-15 15:07:15 -05:00
github-actions[bot]
7776009a31 Bumped version to 2.9.10 (#232)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-02-11 14:21:25 -08:00
Matt Gibson
ff816035ce Add rxjs (#231) 2022-02-11 15:44:04 -06:00
Thomas Rittson
fe384b14f0 Update jslib (#230) 2022-02-11 00:31:31 -05:00
Thomas Rittson
adeb84f44e Update jslib (#229) 2022-02-11 15:02:57 +10:00
github-actions[bot]
dc2e17c5db Bumped version to 2.9.9 (#228)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-02-10 08:54:51 -08:00
Vincent Salucci
f3d8b39ac5 [Help] Update links to new pattern (#227)
* [Help] Update links to new pattern

* Update jslib

* Updated bwdc cli link
2022-02-09 09:59:50 -06:00
Oscar Hinton
3be1f2eac6 Client & Version headers (#226) 2022-02-08 15:28:19 +01:00
Thomas Rittson
1146c8f5bf [Tech debt] Refactor authService (#213)
* Add OrganizationLogInStrategy

* Use noop TwoFactorService
2022-02-07 21:38:46 -06:00
Thomas Rittson
910bfb945d Make husky pre-commit hook executable (#223) 2022-02-08 08:30:26 +10:00
Addison Beck
4e886c1c15 [chore] Update jslib (#225) 2022-02-07 12:08:33 -05:00
Robyn MacCallum
a4b85f1e30 Fix group only sync errors for AD (#224) 2022-02-07 10:32:37 -05:00
Addison Beck
7c85c9fddd Update jslib (#222) 2022-02-03 14:47:36 -05:00
Vincent Salucci
68c964acaa [Icons] FF - old font cleanup (#221)
* [Icons] Remove FA

* Webpack renderer correction
2022-02-03 10:31:35 -06:00
58 changed files with 2861 additions and 1088 deletions

9
.eslintignore Normal file
View File

@@ -0,0 +1,9 @@
dist
build
build-cli
jslib
webpack.cli.js
webpack.main.js
webpack.renderer.js
**/node_modules

32
.eslintrc.json Normal file
View File

@@ -0,0 +1,32 @@
{
"root": true,
"env": {
"browser": true,
"node": true
},
"extends": ["./jslib/shared/eslintrc.json"],
"rules": {
"import/order": [
"error",
{
"alphabetize": {
"order": "asc"
},
"newlines-between": "always",
"pathGroups": [
{
"pattern": "jslib-*/**",
"group": "external",
"position": "after"
},
{
"pattern": "src/**/*",
"group": "parent",
"position": "before"
}
],
"pathGroupsExcludedImportTypes": ["builtin"]
}
]
}
}

View File

@@ -5,6 +5,9 @@ on:
push: push:
branches-ignore: branches-ignore:
- 'l10n_master' - 'l10n_master'
paths-ignore:
- '.github/workflows/**'
workflow_dispatch: {}
jobs: jobs:
@@ -13,7 +16,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up CLOC - name: Set up CLOC
run: | run: |
@@ -31,7 +34,7 @@ jobs:
package_version: ${{ steps.retrieve-version.outputs.package_version }} package_version: ${{ steps.retrieve-version.outputs.package_version }}
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Get Package Version - name: Get Package Version
id: retrieve-version id: retrieve-version
@@ -50,11 +53,13 @@ jobs:
_PKG_FETCH_VERSION: 3.2 _PKG_FETCH_VERSION: 3.2
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -89,12 +94,10 @@ jobs:
run: npm run dist:cli:lin run: npm run dist:cli:lin
- name: Zip - name: Zip
run: | run: zip -j ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip ./dist-cli/linux/bwdc ./keytar/linux/build/Release/keytar.node
zip -j ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip ./dist-cli/linux/bwdc ./keytar/linux/build/Release/keytar.node
- name: Create checksums - name: Create checksums
run: | run: sha256sum ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip | cut -d " " -f 1 > ./dist-cli/bwdc-linux-sha256-$_PACKAGE_VERSION.txt
sha256sum ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip | cut -d " " -f 1 > ./dist-cli/bwdc-linux-sha256-$_PACKAGE_VERSION.txt
- name: Version Test - name: Version Test
run: | run: |
@@ -118,14 +121,14 @@ jobs:
fi fi
- name: Upload Linux Zip to GitHub - name: Upload Linux Zip to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-linux-${{ env._PACKAGE_VERSION }}.zip name: bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
path: ./dist-cli/bwdc-linux-${{ env._PACKAGE_VERSION }}.zip path: ./dist-cli/bwdc-linux-${{ env._PACKAGE_VERSION }}.zip
if-no-files-found: error if-no-files-found: error
- name: Upload Linux checksum to GitHub - name: Upload Linux checksum to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt name: bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
path: ./dist-cli/bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt path: ./dist-cli/bwdc-linux-sha256-${{ env._PACKAGE_VERSION }}.txt
@@ -142,11 +145,13 @@ jobs:
_PKG_FETCH_VERSION: 3.2 _PKG_FETCH_VERSION: 3.2
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -181,12 +186,10 @@ jobs:
run: npm run dist:cli:mac run: npm run dist:cli:mac
- name: Zip - name: Zip
run: | run: zip -j ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip ./dist-cli/macos/bwdc ./keytar/macos/build/Release/keytar.node
zip -j ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip ./dist-cli/macos/bwdc ./keytar/macos/build/Release/keytar.node
- name: Create checksums - name: Create checksums
run: | run: sha256sum ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip | cut -d " " -f 1 > ./dist-cli/bwdc-macos-sha256-$_PACKAGE_VERSION.txt
sha256sum ./dist-cli/bwdc-macos-$_PACKAGE_VERSION.zip | cut -d " " -f 1 > ./dist-cli/bwdc-macos-sha256-$_PACKAGE_VERSION.txt
- name: Version Test - name: Version Test
run: | run: |
@@ -204,14 +207,14 @@ jobs:
fi fi
- name: Upload Mac Zip to GitHub - name: Upload Mac Zip to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-macos-${{ env._PACKAGE_VERSION }}.zip name: bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
path: ./dist-cli/bwdc-macos-${{ env._PACKAGE_VERSION }}.zip path: ./dist-cli/bwdc-macos-${{ env._PACKAGE_VERSION }}.zip
if-no-files-found: error if-no-files-found: error
- name: Upload Mac checksum to GitHub - name: Upload Mac checksum to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt name: bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
path: ./dist-cli/bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt path: ./dist-cli/bwdc-macos-sha256-${{ env._PACKAGE_VERSION }}.txt
@@ -228,7 +231,7 @@ jobs:
_WIN_PKG_VERSION: 3.2 _WIN_PKG_VERSION: 3.2
steps: steps:
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Setup Windows builder - name: Setup Windows builder
run: | run: |
@@ -236,8 +239,10 @@ jobs:
choco install reshack --no-progress choco install reshack --no-progress
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -328,8 +333,7 @@ jobs:
- name: Zip - name: Zip
shell: cmd shell: cmd
run: | run: 7z a ./dist-cli/bwdc-windows-%_PACKAGE_VERSION%.zip ./dist-cli/windows/bwdc.exe ./keytar/windows/keytar.node
7z a ./dist-cli/bwdc-windows-%_PACKAGE_VERSION%.zip ./dist-cli/windows/bwdc.exe ./keytar/windows/keytar.node
- name: Version Test - name: Version Test
run: | run: |
@@ -347,14 +351,14 @@ jobs:
-t sha256 | Out-File ./dist-cli/bwdc-windows-sha256-${env:_PACKAGE_VERSION}.txt -t sha256 | Out-File ./dist-cli/bwdc-windows-sha256-${env:_PACKAGE_VERSION}.txt
- name: Upload Windows Zip to GitHub - name: Upload Windows Zip to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-windows-${{ env._PACKAGE_VERSION }}.zip name: bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
path: ./dist-cli/bwdc-windows-${{ env._PACKAGE_VERSION }}.zip path: ./dist-cli/bwdc-windows-${{ env._PACKAGE_VERSION }}.zip
if-no-files-found: error if-no-files-found: error
- name: Upload Windows checksum to GitHub - name: Upload Windows checksum to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt name: bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
path: ./dist-cli/bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt path: ./dist-cli/bwdc-windows-sha256-${{ env._PACKAGE_VERSION }}.txt
@@ -368,14 +372,19 @@ jobs:
env: env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
steps: steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up .NET - name: Set up .NET
uses: actions/setup-dotnet@a71d1eb2c86af85faa8c772c03fb365e377e45ea uses: actions/setup-dotnet@9211491ffb35dd6a6657ca4f45d43dfe6e97c829
with: with:
dotnet-version: "3.1.x" dotnet-version: "3.1.x"
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -396,9 +405,6 @@ jobs:
- name: Install AST - name: Install AST
uses: bitwarden/gh-actions/install-ast@f135c42c8596cb535c5bcb7523c0b2eef89709ac uses: bitwarden/gh-actions/install-ast@f135c42c8596cb535c5bcb7523c0b2eef89709ac
- name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
- name: Install Node dependencies - name: Install Node dependencies
run: npm install run: npm install
@@ -416,28 +422,28 @@ jobs:
SIGNING_CERT_NAME: ${{ secrets.SIGNING_CERT_NAME }} SIGNING_CERT_NAME: ${{ secrets.SIGNING_CERT_NAME }}
- name: Upload Portable Executable to GitHub - name: Upload Portable Executable to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe name: Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
path: ./dist/Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe path: ./dist/Bitwarden-Connector-Portable-${{ env._PACKAGE_VERSION }}.exe
if-no-files-found: error if-no-files-found: error
- name: Upload Installer Executable to GitHub - name: Upload Installer Executable to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe
if-no-files-found: error if-no-files-found: error
- name: Upload Installer Executable Blockmap to GitHub - name: Upload Installer Executable Blockmap to GitHub
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap name: Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap path: ./dist/Bitwarden-Connector-Installer-${{ env._PACKAGE_VERSION }}.exe.blockmap
if-no-files-found: error if-no-files-found: error
- name: Upload latest auto-update artifact - name: Upload latest auto-update artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: latest.yml name: latest.yml
path: ./dist/latest.yml path: ./dist/latest.yml
@@ -451,9 +457,14 @@ jobs:
env: env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
steps: steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -470,9 +481,6 @@ jobs:
sudo apt-get -y install pkg-config libxss-dev libsecret-1-dev sudo apt-get -y install pkg-config libxss-dev libsecret-1-dev
sudo apt-get -y install rpm sudo apt-get -y install rpm
- name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
- name: NPM Install - name: NPM Install
run: npm install run: npm install
@@ -483,14 +491,14 @@ jobs:
run: npm run dist:lin run: npm run dist:lin
- name: Upload AppImage - name: Upload AppImage
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-x86_64.AppImage
if-no-files-found: error if-no-files-found: error
- name: Upload latest auto-update artifact - name: Upload latest auto-update artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: latest-linux.yml name: latest-linux.yml
path: ./dist/latest-linux.yml path: ./dist/latest-linux.yml
@@ -504,9 +512,14 @@ jobs:
env: env:
_PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }}
steps: steps:
- name: Checkout repo
uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846
- name: Set up Node - name: Set up Node
uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea uses: actions/setup-node@9ced9a43a244f3ac94f13bfd896db8c8f30da67a # v3.0.0
with: with:
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
node-version: '16' node-version: '16'
- name: Update NPM - name: Update NPM
@@ -525,9 +538,6 @@ jobs:
echo "GitHub event: $GITHUB_EVENT" echo "GitHub event: $GITHUB_EVENT"
shell: bash shell: bash
- name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4
- name: Decrypt secrets - name: Decrypt secrets
env: env:
DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }} DECRYPT_FILE_PASSWORD: ${{ secrets.DECRYPT_FILE_PASSWORD }}
@@ -594,28 +604,28 @@ jobs:
"Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip" "Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip"
- name: Upload .zip artifact - name: Upload .zip artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}-mac.zip
if-no-files-found: error if-no-files-found: error
- name: Upload .dmg artifact - name: Upload .dmg artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg
if-no-files-found: error if-no-files-found: error
- name: Upload .dmg Blockmap artifact - name: Upload .dmg Blockmap artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap name: Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap path: ./dist/Bitwarden-Connector-${{ env._PACKAGE_VERSION }}.dmg.blockmap
if-no-files-found: error if-no-files-found: error
- name: Upload latest auto-update artifact - name: Upload latest auto-update artifact
uses: actions/upload-artifact@ee69f02b3dfdecd58bb31b4d133da38ba6fe3700 # v2.2.3 uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535
with: with:
name: latest-mac.yml name: latest-mac.yml
path: ./dist/latest-mac.yml path: ./dist/latest-mac.yml
@@ -666,21 +676,21 @@ jobs:
fi fi
- name: Login to Azure - Prod Subscription - name: Login to Azure - Prod Subscription
uses: Azure/login@77f1b2e3fb80c0e8645114159d17008b8a2e475a uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf
if: failure() if: failure()
with: with:
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }}
- name: Retrieve secrets - name: Retrieve secrets
id: retrieve-secrets id: retrieve-secrets
uses: Azure/get-keyvault-secrets@80ccd3fafe5662407cc2e55f202ee34bfff8c403 uses: Azure/get-keyvault-secrets@b5c723b9ac7870c022b8c35befe620b7009b336f
if: failure() if: failure()
with: with:
keyvault: "bitwarden-prod-kv" keyvault: "bitwarden-prod-kv"
secrets: "devops-alerts-slack-webhook-url" secrets: "devops-alerts-slack-webhook-url"
- name: Notify Slack on failure - name: Notify Slack on failure
uses: act10ns/slack@e4e71685b9b239384b0f676a63c32367f59c2522 # v1.2.2 uses: act10ns/slack@da3191ebe2e67f49b46880b4633f5591a96d1d33
if: failure() if: failure()
env: env:
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }} SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }}

16
.github/workflows/enforce-labels.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
---
name: Enforce PR labels
on:
pull_request:
types: [labeled, unlabeled, opened, edited, synchronize]
jobs:
enforce-label:
name: EnforceLabel
runs-on: ubuntu-20.04
steps:
- name: Enforce Label
uses: yogevbd/enforce-label-action@8d1e1709b1011e6d90400a0e6cf7c0b77aa5efeb
with:
BANNED_LABELS: "hold"
BANNED_LABELS_DESCRIPTION: "PRs on hold cannot be merged"

View File

@@ -12,6 +12,7 @@ on:
options: options:
- Initial Release - Initial Release
- Redeploy - Redeploy
- Dry Run
jobs: jobs:
setup: setup:
@@ -19,16 +20,17 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:
- name: Branch check - name: Branch check
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
run: | run: |
if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix" ]]; then if [[ "$GITHUB_REF" != "refs/heads/rc" ]] && [[ "$GITHUB_REF" != "refs/heads/hotfix-rc" ]]; then
echo "===================================" echo "==================================="
echo "[!] Can only release from the 'rc' or 'hotfix' branches" echo "[!] Can only release from the 'rc' or 'hotfix-rc' branches"
echo "===================================" echo "==================================="
exit 1 exit 1
fi fi
- name: Checkout repo - name: Checkout repo
uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
- name: Retrieve Directory Connector release version - name: Retrieve Directory Connector release version
id: retrieve-version id: retrieve-version
@@ -66,7 +68,8 @@ jobs:
branch: ${{ steps.branch.outputs.branch-name }} branch: ${{ steps.branch.outputs.branch-name }}
- name: Create release - name: Create release
uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5 if: ${{ github.event.inputs.release_type != 'Dry Run' }}
uses: ncipollo/release-action@40bb172bd05f266cf9ba4ff965cb61e9ee5f6d01 # v1.9.0
env: env:
PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }} PKG_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
with: with:

11
.github/workflows/workflow-linter.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
---
name: Workflow Linter
on:
pull_request:
paths:
- .github/workflows/**
jobs:
call-workflow:
uses: bitwarden/gh-actions/.github/workflows/workflow-linter.yml@master

0
.husky/pre-commit Normal file → Executable file
View File

View File

@@ -1,5 +1,6 @@
# Build directories # Build directories
build build
build-cli
dist dist
jslib jslib

View File

@@ -15,7 +15,7 @@ Supported directories:
The application is written using Electron with Angular and installs on Windows, macOS, and Linux distributions. The application is written using Electron with Angular and installs on Windows, macOS, and Linux distributions.
[![Platforms](https://imgur.com/SLv9paA.png "Windows, macOS, and Linux")](https://help.bitwarden.com/article/directory-sync/#download-and-install) [![Platforms](https://imgur.com/SLv9paA.png "Windows, macOS, and Linux")](https://bitwarden.com/help/directory-sync/#download-and-install)
![Directory Connector](https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/directory-connector-macos.png "Dashboard") ![Directory Connector](https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/directory-connector-macos.png "Dashboard")
@@ -42,7 +42,7 @@ bwdc config --help
**Detailed Documentation** **Detailed Documentation**
We provide detailed documentation and examples for using the Directory Connector CLI in our help center at https://help.bitwarden.com/article/directory-sync/#command-line-interface. We provide detailed documentation and examples for using the Directory Connector CLI in our help center at https://bitwarden.com/help/directory-sync-cli/.
## Build/Run ## Build/Run
@@ -74,6 +74,10 @@ You can then run commands from the `./build-cli` folder:
node ./build-cli/bwdc.js --help node ./build-cli/bwdc.js --help
``` ```
## We're Hiring!
Interested in contributing in a big way? Consider joining our team! We're hiring for many positions. Please take a look at our [Careers page](https://bitwarden.com/careers/) to see what opportunities are currently open as well as what it's like to work at Bitwarden.
## Contribute ## Contribute
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file. Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.

View File

@@ -1,39 +1,11 @@
Bitwarden believes that working with security researchers across the globe is crucial to keeping our Bitwarden believes that working with security researchers across the globe is crucial to keeping our users safe. If you believe you've found a security issue in our product or service, we encourage you to please submit a report through our [HackerOne Program](https://hackerone.com/bitwarden/). We welcome working with you to resolve the issue promptly. Thanks in advance!
users safe. If you believe you've found a security issue in our product or service, we encourage you to
notify us. We welcome working with you to resolve the issue promptly. Thanks in advance!
# Disclosure Policy # Disclosure Policy
- Let us know as soon as possible upon discovery of a potential security issue, and we'll make every - Let us know as soon as possible upon discovery of a potential security issue, and we'll make every effort to quickly resolve the issue.
effort to quickly resolve the issue. - Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a third-party. We may publicly disclose the issue before resolving it, if appropriate.
- Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a - Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our service. Only interact with accounts you own or with explicit permission of the account holder.
third-party. We may publicly disclose the issue before resolving it, if appropriate. - If you would like to encrypt your report, please use the PGP key with long ID `0xDE6887086F892325FEC04CC0D847525B6931381F` (available in the public keyserver pool).
- Make a good faith effort to avoid privacy violations, destruction of data, and interruption or
degradation of our service. Only interact with accounts you own or with explicit permission of the
account holder.
- If you would like to encrypt your report, please use the PGP key with long ID
`0xDE6887086F892325FEC04CC0D847525B6931381F` (available in the public keyserver pool).
# In-scope
- Security issues in any current release of Bitwarden. This includes the web vault, browser extension,
and mobile apps (iOS and Android). Product downloads are available at https://bitwarden.com. Source
code is available at https://github.com/bitwarden.
# Exclusions
The following bug classes are out-of scope:
- Bugs that are already reported on any of Bitwarden's issue trackers (https://github.com/bitwarden),
or that we already know of. Note that some of our issue tracking is private.
- Issues in an upstream software dependency (ex: Xamarin, ASP.NET) which are already reported to the
upstream maintainer.
- Attacks requiring physical access to a user's device.
- Self-XSS
- Issues related to software or protocols not under Bitwarden's control
- Vulnerabilities in outdated versions of Bitwarden
- Missing security best practices that do not directly lead to a vulnerability
- Issues that do not have any impact on the general public
While researching, we'd like to ask you to refrain from: While researching, we'd like to ask you to refrain from:
@@ -42,4 +14,8 @@ While researching, we'd like to ask you to refrain from:
- Social engineering (including phishing) of Bitwarden staff or contractors - Social engineering (including phishing) of Bitwarden staff or contractors
- Any physical attempts against Bitwarden property or data centers - Any physical attempts against Bitwarden property or data centers
# We want to help you!
If you have something that you feel is close to exploitation, or if you'd like some information regarding the internal API, or generally have any questions regarding the app that would help in your efforts, please email us at https://bitwarden.com/contact and ask for that information. As stated above, Bitwarden wants to help you find issues, and is more than willing to help.
Thank you for helping keep Bitwarden and our users safe! Thank you for helping keep Bitwarden and our users safe!

2
jslib

Submodule jslib updated: 92a65b7b36...9950fb42a1

2645
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,8 +26,8 @@
"symlink:lin": "rm -rf ./jslib && ln -s ../jslib ./jslib", "symlink:lin": "rm -rf ./jslib && ln -s ../jslib ./jslib",
"rebuild": "electron-rebuild", "rebuild": "electron-rebuild",
"reset": "rimraf ./node_modules/keytar/* && npm install", "reset": "rimraf ./node_modules/keytar/* && npm install",
"lint": "tslint 'src/**/*.ts' && prettier --check .", "lint": "eslint . && prettier --check .",
"lint:fix": "tslint 'src/**/*.ts' --fix", "lint:fix": "eslint . --fix",
"build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"", "build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"",
"build:main": "webpack --config webpack.main.js", "build:main": "webpack --config webpack.main.js",
"build:renderer": "webpack --config webpack.renderer.js", "build:renderer": "webpack --config webpack.renderer.js",
@@ -143,6 +143,8 @@
"@types/ldapjs": "^1.0.10", "@types/ldapjs": "^1.0.10",
"@types/node": "^16.11.12", "@types/node": "^16.11.12",
"@types/proper-lockfile": "^4.1.1", "@types/proper-lockfile": "^4.1.1",
"@typescript-eslint/eslint-plugin": "^5.12.1",
"@typescript-eslint/parser": "^5.12.1",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"concurrently": "^6.0.2", "concurrently": "^6.0.2",
"copy-webpack-plugin": "^10.0.0", "copy-webpack-plugin": "^10.0.0",
@@ -152,7 +154,10 @@
"electron-notarize": "^1.1.1", "electron-notarize": "^1.1.1",
"electron-rebuild": "^3.2.5", "electron-rebuild": "^3.2.5",
"electron-reload": "^1.5.0", "electron-reload": "^1.5.0",
"font-awesome": "4.7.0", "eslint": "^8.9.0",
"eslint-config-prettier": "^8.4.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.4",
"html-loader": "^3.0.1", "html-loader": "^3.0.1",
"html-webpack-plugin": "^5.5.0", "html-webpack-plugin": "^5.5.0",
"husky": "^7.0.4", "husky": "^7.0.4",
@@ -168,8 +173,6 @@
"tapable": "^1.1.3", "tapable": "^1.1.3",
"ts-loader": "^9.2.5", "ts-loader": "^9.2.5",
"tsconfig-paths-webpack-plugin": "^3.5.1", "tsconfig-paths-webpack-plugin": "^3.5.1",
"tslint": "~6.1.0",
"tslint-loader": "^3.5.4",
"typescript": "4.3.5", "typescript": "4.3.5",
"webpack": "^5.64.4", "webpack": "^5.64.4",
"webpack-cli": "^4.9.1", "webpack-cli": "^4.9.1",
@@ -211,6 +214,7 @@
"npm": "~8" "npm": "~8"
}, },
"lint-staged": { "lint-staged": {
"*": "prettier --ignore-unknown --write" "./!(jslib)**": "prettier --ignore-unknown --write",
"*.ts": "eslint --fix"
} }
} }

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
require("dotenv").config(); require("dotenv").config();
const { notarize } = require("electron-notarize"); const { notarize } = require("electron-notarize");

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires, no-console */
exports.default = async function (configuration) { exports.default = async function (configuration) {
if (parseInt(process.env.ELECTRON_BUILDER_SIGN) === 1 && configuration.path.slice(-4) == ".exe") { if (parseInt(process.env.ELECTRON_BUILDER_SIGN) === 1 && configuration.path.slice(-4) == ".exe") {
console.log(`[*] Signing file: ${configuration.path}`); console.log(`[*] Signing file: ${configuration.path}`);

View File

@@ -1,9 +1,7 @@
import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service"; import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service";
import { StorageOptions } from "jslib-common/models/domain/storageOptions"; import { StorageOptions } from "jslib-common/models/domain/storageOptions";
import { DirectoryType } from "src/enums/directoryType"; import { DirectoryType } from "src/enums/directoryType";
import { Account } from "src/models/account"; import { Account } from "src/models/account";
import { AzureConfiguration } from "src/models/azureConfiguration"; import { AzureConfiguration } from "src/models/azureConfiguration";
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration"; import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";

View File

@@ -1,19 +1,17 @@
import { Component, Input, ViewChild, ViewContainerRef } from "@angular/core"; import { Component, Input, ViewChild, ViewContainerRef } from "@angular/core";
import { Router } from "@angular/router"; import { Router } from "@angular/router";
import { EnvironmentComponent } from "./environment.component"; import { ModalService } from "jslib-angular/services/modal.service";
import { AuthService } from "jslib-common/abstractions/auth.service"; import { AuthService } from "jslib-common/abstractions/auth.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { Utils } from "jslib-common/misc/utils";
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { StateService } from "../../abstractions/state.service"; import { StateService } from "../../abstractions/state.service";
import { ModalService } from "jslib-angular/services/modal.service"; import { EnvironmentComponent } from "./environment.component";
import { HtmlStorageLocation } from "jslib-common/enums/htmlStorageLocation";
import { Utils } from "jslib-common/misc/utils";
@Component({ @Component({
selector: "app-apiKey", selector: "app-apiKey",
@@ -22,12 +20,12 @@ import { Utils } from "jslib-common/misc/utils";
export class ApiKeyComponent { export class ApiKeyComponent {
@ViewChild("environment", { read: ViewContainerRef, static: true }) @ViewChild("environment", { read: ViewContainerRef, static: true })
environmentModal: ViewContainerRef; environmentModal: ViewContainerRef;
@Input() clientId: string = ""; @Input() clientId = "";
@Input() clientSecret: string = ""; @Input() clientSecret = "";
formPromise: Promise<any>; formPromise: Promise<any>;
successRoute = "/tabs/dashboard"; successRoute = "/tabs/dashboard";
showSecret: boolean = false; showSecret = false;
constructor( constructor(
private authService: AuthService, private authService: AuthService,
@@ -76,7 +74,9 @@ export class ApiKeyComponent {
} }
try { try {
this.formPromise = this.authService.logInApiKey(this.clientId, this.clientSecret); this.formPromise = this.authService.logIn(
new ApiLogInCredentials(this.clientId, this.clientSecret)
);
await this.formPromise; await this.formPromise;
const organizationId = await this.stateService.getEntityId(); const organizationId = await this.stateService.getEntityId();
await this.stateService.setOrganizationId(organizationId); await this.stateService.setOrganizationId(organizationId);

View File

@@ -1,11 +1,10 @@
import { Component } from "@angular/core"; import { Component } from "@angular/core";
import { EnvironmentComponent as BaseEnvironmentComponent } from "jslib-angular/components/environment.component";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { EnvironmentComponent as BaseEnvironmentComponent } from "jslib-angular/components/environment.component";
@Component({ @Component({
selector: "app-environment", selector: "app-environment",
templateUrl: "environment.component.html", templateUrl: "environment.component.html",

View File

@@ -1,10 +1,9 @@
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router"; import { RouterModule, Routes } from "@angular/router";
import { ApiKeyComponent } from "./accounts/apiKey.component";
import { AuthGuardService } from "./services/auth-guard.service"; import { AuthGuardService } from "./services/auth-guard.service";
import { LaunchGuardService } from "./services/launch-guard.service"; import { LaunchGuardService } from "./services/launch-guard.service";
import { ApiKeyComponent } from "./accounts/apiKey.component";
import { DashboardComponent } from "./tabs/dashboard.component"; import { DashboardComponent } from "./tabs/dashboard.component";
import { MoreComponent } from "./tabs/more.component"; import { MoreComponent } from "./tabs/more.component";
import { SettingsComponent } from "./tabs/settings.component"; import { SettingsComponent } from "./tabs/settings.component";

View File

@@ -18,9 +18,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { TokenService } from "jslib-common/abstractions/token.service"; import { TokenService } from "jslib-common/abstractions/token.service";
import { SyncService } from "../services/sync.service";
import { StateService } from "../abstractions/state.service"; import { StateService } from "../abstractions/state.service";
import { SyncService } from "../services/sync.service";
const BroadcasterSubscriptionId = "AppComponent"; const BroadcasterSubscriptionId = "AppComponent";

View File

@@ -1,71 +1,40 @@
import "core-js/stable"; import "core-js/stable";
import "zone.js/dist/zone"; import "zone.js/dist/zone";
import { AppRoutingModule } from "./app-routing.module";
import { ServicesModule } from "./services/services.module";
import { NgModule } from "@angular/core"; import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms"; import { FormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser"; import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { AppComponent } from "./app.component"; import { JslibModule } from "jslib-angular/jslib.module";
import { CalloutComponent } from "jslib-angular/components/callout.component";
import { IconComponent } from "jslib-angular/components/icon.component";
import { BitwardenToastModule } from "jslib-angular/components/toastr.component";
import { ApiKeyComponent } from "./accounts/apiKey.component"; import { ApiKeyComponent } from "./accounts/apiKey.component";
import { EnvironmentComponent } from "./accounts/environment.component"; import { EnvironmentComponent } from "./accounts/environment.component";
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { ServicesModule } from "./services/services.module";
import { DashboardComponent } from "./tabs/dashboard.component"; import { DashboardComponent } from "./tabs/dashboard.component";
import { MoreComponent } from "./tabs/more.component"; import { MoreComponent } from "./tabs/more.component";
import { SettingsComponent } from "./tabs/settings.component"; import { SettingsComponent } from "./tabs/settings.component";
import { TabsComponent } from "./tabs/tabs.component"; import { TabsComponent } from "./tabs/tabs.component";
import { A11yTitleDirective } from "jslib-angular/directives/a11y-title.directive";
import { ApiActionDirective } from "jslib-angular/directives/api-action.directive";
import { AutofocusDirective } from "jslib-angular/directives/autofocus.directive";
import { BlurClickDirective } from "jslib-angular/directives/blur-click.directive";
import { BoxRowDirective } from "jslib-angular/directives/box-row.directive";
import { FallbackSrcDirective } from "jslib-angular/directives/fallback-src.directive";
import { StopClickDirective } from "jslib-angular/directives/stop-click.directive";
import { StopPropDirective } from "jslib-angular/directives/stop-prop.directive";
import { I18nPipe } from "jslib-angular/pipes/i18n.pipe";
import { SearchCiphersPipe } from "jslib-angular/pipes/search-ciphers.pipe";
@NgModule({ @NgModule({
imports: [ imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
AppRoutingModule, AppRoutingModule,
BrowserAnimationsModule,
BrowserModule,
FormsModule,
JslibModule,
ServicesModule, ServicesModule,
BitwardenToastModule.forRoot({
maxOpened: 5,
autoDismiss: true,
closeButton: true,
}),
], ],
declarations: [ declarations: [
A11yTitleDirective,
ApiActionDirective,
ApiKeyComponent, ApiKeyComponent,
AppComponent, AppComponent,
AutofocusDirective,
BlurClickDirective,
BoxRowDirective,
CalloutComponent,
DashboardComponent, DashboardComponent,
EnvironmentComponent, EnvironmentComponent,
FallbackSrcDirective,
I18nPipe,
IconComponent,
MoreComponent, MoreComponent,
SearchCiphersPipe,
SettingsComponent, SettingsComponent,
StopClickDirective,
StopPropDirective,
TabsComponent, TabsComponent,
], ],
providers: [], providers: [],

View File

@@ -0,0 +1,5 @@
import { InjectionToken } from "@angular/core";
export const USE_SECURE_STORAGE_FOR_SECRETS = new InjectionToken<boolean>(
"USE_SECURE_STORAGE_FOR_SECRETS"
);

View File

@@ -1,24 +1,6 @@
import { APP_INITIALIZER, Injector, NgModule } from "@angular/core"; import { APP_INITIALIZER, Injector, NgModule } from "@angular/core";
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
import { ElectronPlatformUtilsService } from "jslib-electron/services/electronPlatformUtils.service";
import { ElectronRendererMessagingService } from "jslib-electron/services/electronRendererMessaging.service";
import { ElectronRendererSecureStorageService } from "jslib-electron/services/electronRendererSecureStorage.service";
import { ElectronRendererStorageService } from "jslib-electron/services/electronRendererStorage.service";
import { AuthGuardService } from "./auth-guard.service";
import { LaunchGuardService } from "./launch-guard.service";
import { I18nService } from "../../services/i18n.service";
import { SyncService } from "../../services/sync.service";
import { JslibServicesModule } from "jslib-angular/services/jslib-services.module"; import { JslibServicesModule } from "jslib-angular/services/jslib-services.module";
import { ContainerService } from "jslib-common/services/container.service";
import { NodeApiService } from "jslib-node/services/nodeApi.service";
import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service"; import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service";
import { AppIdService as AppIdServiceAbstraction } from "jslib-common/abstractions/appId.service"; import { AppIdService as AppIdServiceAbstraction } from "jslib-common/abstractions/appId.service";
import { AuthService as AuthServiceAbstraction } from "jslib-common/abstractions/auth.service"; import { AuthService as AuthServiceAbstraction } from "jslib-common/abstractions/auth.service";
@@ -27,6 +9,12 @@ import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstract
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service"; import { EnvironmentService as EnvironmentServiceAbstraction } from "jslib-common/abstractions/environment.service";
import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service"; import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service";
import {
CLIENT_TYPE,
SECURE_STORAGE,
STATE_FACTORY,
WINDOW_TOKEN,
} from "jslib-common/abstractions/injectionTokens";
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-common/abstractions/keyConnector.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-common/abstractions/keyConnector.service";
import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service"; import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service";
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service"; import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
@@ -34,21 +22,32 @@ import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-c
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service"; import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service"; import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service"; import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
import { ClientType } from "jslib-common/enums/clientType";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { GlobalState } from "jslib-common/models/domain/globalState";
import { ContainerService } from "jslib-common/services/container.service";
import { ElectronLogService } from "jslib-electron/services/electronLog.service";
import { ElectronPlatformUtilsService } from "jslib-electron/services/electronPlatformUtils.service";
import { ElectronRendererMessagingService } from "jslib-electron/services/electronRendererMessaging.service";
import { ElectronRendererSecureStorageService } from "jslib-electron/services/electronRendererSecureStorage.service";
import { ElectronRendererStorageService } from "jslib-electron/services/electronRendererStorage.service";
import { NodeApiService } from "jslib-node/services/nodeApi.service";
import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
import { StateService as StateServiceAbstraction } from "../../abstractions/state.service"; import { StateService as StateServiceAbstraction } from "../../abstractions/state.service";
import { Account } from "../../models/account";
import { ApiService, refreshToken } from "../../services/api.service"; import { refreshToken } from "../../services/api.service";
import { AuthService } from "../../services/auth.service"; import { AuthService } from "../../services/auth.service";
import { I18nService } from "../../services/i18n.service";
import { NoopTwoFactorService } from "../../services/noop/noopTwoFactor.service";
import { StateService } from "../../services/state.service"; import { StateService } from "../../services/state.service";
import { StateMigrationService } from "../../services/stateMigration.service"; import { StateMigrationService } from "../../services/stateMigration.service";
import { SyncService } from "../../services/sync.service";
import { Account } from "../../models/account"; import { AuthGuardService } from "./auth-guard.service";
import { USE_SECURE_STORAGE_FOR_SECRETS } from "./injectionTokens";
import { GlobalStateFactory } from "jslib-common/factories/globalStateFactory"; import { LaunchGuardService } from "./launch-guard.service";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { GlobalState } from "jslib-common/models/domain/globalState";
function refreshTokenCallback(injector: Injector) { function refreshTokenCallback(injector: Injector) {
return () => { return () => {
@@ -61,16 +60,14 @@ function refreshTokenCallback(injector: Injector) {
export function initFactory( export function initFactory(
environmentService: EnvironmentServiceAbstraction, environmentService: EnvironmentServiceAbstraction,
i18nService: I18nService, i18nService: I18nService,
authService: AuthService,
platformUtilsService: PlatformUtilsServiceAbstraction, platformUtilsService: PlatformUtilsServiceAbstraction,
stateService: StateServiceAbstraction, stateService: StateServiceAbstraction,
cryptoService: CryptoServiceAbstraction cryptoService: CryptoServiceAbstraction
): Function { ): () => Promise<void> {
return async () => { return async () => {
await stateService.init(); await stateService.init();
await environmentService.setUrlsFromStorage(); await environmentService.setUrlsFromStorage();
await i18nService.init(); await i18nService.init();
authService.init();
const htmlEl = window.document.documentElement; const htmlEl = window.document.documentElement;
htmlEl.classList.add("os_" + platformUtilsService.getDeviceString()); htmlEl.classList.add("os_" + platformUtilsService.getDeviceString());
htmlEl.classList.add("locale_" + i18nService.translationLocale); htmlEl.classList.add("locale_" + i18nService.translationLocale);
@@ -104,7 +101,6 @@ export function initFactory(
deps: [ deps: [
EnvironmentServiceAbstraction, EnvironmentServiceAbstraction,
I18nServiceAbstraction, I18nServiceAbstraction,
AuthServiceAbstraction,
PlatformUtilsServiceAbstraction, PlatformUtilsServiceAbstraction,
StateServiceAbstraction, StateServiceAbstraction,
CryptoServiceAbstraction, CryptoServiceAbstraction,
@@ -115,23 +111,18 @@ export function initFactory(
{ {
provide: I18nServiceAbstraction, provide: I18nServiceAbstraction,
useFactory: (window: Window) => new I18nService(window.navigator.language, "./locales"), useFactory: (window: Window) => new I18nService(window.navigator.language, "./locales"),
deps: ["WINDOW"], deps: [WINDOW_TOKEN],
}, },
{ {
provide: MessagingServiceAbstraction, provide: MessagingServiceAbstraction,
useClass: ElectronRendererMessagingService, useClass: ElectronRendererMessagingService,
deps: [BroadcasterServiceAbstraction],
}, },
{ provide: StorageServiceAbstraction, useClass: ElectronRendererStorageService }, { provide: StorageServiceAbstraction, useClass: ElectronRendererStorageService },
{ provide: "SECURE_STORAGE", useClass: ElectronRendererSecureStorageService }, { provide: SECURE_STORAGE, useClass: ElectronRendererSecureStorageService },
{ provide: CLIENT_TYPE, useValue: ClientType.DirectoryConnector },
{ {
provide: PlatformUtilsServiceAbstraction, provide: PlatformUtilsServiceAbstraction,
useFactory: ( useClass: ElectronPlatformUtilsService,
i18nService: I18nServiceAbstraction,
messagingService: MessagingServiceAbstraction,
stateService: StateServiceAbstraction
) => new ElectronPlatformUtilsService(i18nService, messagingService, true, stateService),
deps: [I18nServiceAbstraction, MessagingServiceAbstraction, StateServiceAbstraction],
}, },
{ provide: CryptoFunctionServiceAbstraction, useClass: NodeCryptoFunctionService, deps: [] }, { provide: CryptoFunctionServiceAbstraction, useClass: NodeCryptoFunctionService, deps: [] },
{ {
@@ -166,72 +157,32 @@ export function initFactory(
{ {
provide: AuthServiceAbstraction, provide: AuthServiceAbstraction,
useClass: AuthService, useClass: AuthService,
deps: [
CryptoServiceAbstraction,
ApiServiceAbstraction,
TokenServiceAbstraction,
AppIdServiceAbstraction,
I18nServiceAbstraction,
PlatformUtilsServiceAbstraction,
MessagingServiceAbstraction,
VaultTimeoutServiceAbstraction,
LogServiceAbstraction,
CryptoFunctionServiceAbstraction,
EnvironmentServiceAbstraction,
KeyConnectorServiceAbstraction,
StateServiceAbstraction,
],
}, },
{ {
provide: SyncService, provide: SyncService,
useClass: SyncService, useClass: SyncService,
deps: [
LogServiceAbstraction,
CryptoFunctionServiceAbstraction,
ApiServiceAbstraction,
MessagingServiceAbstraction,
I18nServiceAbstraction,
EnvironmentServiceAbstraction,
StateServiceAbstraction,
],
}, },
AuthGuardService, AuthGuardService,
LaunchGuardService, LaunchGuardService,
{
provide: STATE_FACTORY,
useFactory: () => new StateFactory(GlobalState, Account),
},
{
provide: USE_SECURE_STORAGE_FOR_SECRETS,
useValue: true,
},
{ {
provide: StateMigrationServiceAbstraction, provide: StateMigrationServiceAbstraction,
useFactory: ( useClass: StateMigrationService,
storageService: StorageServiceAbstraction,
secureStorageService: StorageServiceAbstraction
) =>
new StateMigrationService(
storageService,
secureStorageService,
new GlobalStateFactory(GlobalState)
),
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
}, },
{ {
provide: StateServiceAbstraction, provide: StateServiceAbstraction,
useFactory: ( useClass: StateService,
storageService: StorageServiceAbstraction, },
secureStorageService: StorageServiceAbstraction, {
logService: LogServiceAbstraction, provide: TwoFactorServiceAbstraction,
stateMigrationService: StateMigrationServiceAbstraction useClass: NoopTwoFactorService,
) =>
new StateService(
storageService,
secureStorageService,
logService,
stateMigrationService,
true, // TODO: It seems like we aren't applying this from settings anywhere. Is toggling secure storage working?
new StateFactory(GlobalState, Account)
),
deps: [
StorageServiceAbstraction,
"SECURE_STORAGE",
LogServiceAbstraction,
StateMigrationServiceAbstraction,
],
}, },
], ],
}) })

View File

@@ -5,16 +5,13 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { SyncService } from "../../services/sync.service"; import { StateService } from "../../abstractions/state.service";
import { GroupEntry } from "../../models/groupEntry"; import { GroupEntry } from "../../models/groupEntry";
import { SimResult } from "../../models/simResult"; import { SimResult } from "../../models/simResult";
import { UserEntry } from "../../models/userEntry"; import { UserEntry } from "../../models/userEntry";
import { SyncService } from "../../services/sync.service";
import { ConnectorUtils } from "../../utils"; import { ConnectorUtils } from "../../utils";
import { StateService } from "../../abstractions/state.service";
const BroadcasterSubscriptionId = "DashboardComponent"; const BroadcasterSubscriptionId = "DashboardComponent";
@Component({ @Component({
@@ -28,7 +25,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
simDisabledUsers: UserEntry[] = []; simDisabledUsers: UserEntry[] = [];
simDeletedUsers: UserEntry[] = []; simDeletedUsers: UserEntry[] = [];
simPromise: Promise<SimResult>; simPromise: Promise<SimResult>;
simSinceLast: boolean = false; simSinceLast = false;
syncPromise: Promise<[GroupEntry[], UserEntry[]]>; syncPromise: Promise<[GroupEntry[], UserEntry[]]>;
startPromise: Promise<any>; startPromise: Promise<any>;
lastGroupSync: Date; lastGroupSync: Date;

View File

@@ -3,16 +3,14 @@ import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angula
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../../abstractions/state.service";
import { DirectoryType } from "../../enums/directoryType"; import { DirectoryType } from "../../enums/directoryType";
import { AzureConfiguration } from "../../models/azureConfiguration"; import { AzureConfiguration } from "../../models/azureConfiguration";
import { GSuiteConfiguration } from "../../models/gsuiteConfiguration"; import { GSuiteConfiguration } from "../../models/gsuiteConfiguration";
import { LdapConfiguration } from "../../models/ldapConfiguration"; import { LdapConfiguration } from "../../models/ldapConfiguration";
import { OktaConfiguration } from "../../models/oktaConfiguration"; import { OktaConfiguration } from "../../models/oktaConfiguration";
import { OneLoginConfiguration } from "../../models/oneLoginConfiguration"; import { OneLoginConfiguration } from "../../models/oneLoginConfiguration";
import { SyncConfiguration } from "../../models/syncConfiguration"; import { SyncConfiguration } from "../../models/syncConfiguration";
import { StateService } from "../../abstractions/state.service";
import { ConnectorUtils } from "../../utils"; import { ConnectorUtils } from "../../utils";
@Component({ @Component({
@@ -29,10 +27,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
oneLogin = new OneLoginConfiguration(); oneLogin = new OneLoginConfiguration();
sync = new SyncConfiguration(); sync = new SyncConfiguration();
directoryOptions: any[]; directoryOptions: any[];
showLdapPassword: boolean = false; showLdapPassword = false;
showAzureKey: boolean = false; showAzureKey = false;
showOktaKey: boolean = false; showOktaKey = false;
showOneLoginSecret: boolean = false; showOneLoginSecret = false;
constructor( constructor(
private i18nService: I18nService, private i18nService: I18nService,

View File

@@ -1,22 +1,13 @@
import * as fs from "fs"; import * as fs from "fs";
import * as path from "path"; import * as path from "path";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service";
import { ClientType } from "jslib-common/enums/clientType";
import { LogLevelType } from "jslib-common/enums/logLevelType"; import { LogLevelType } from "jslib-common/enums/logLevelType";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { AuthService } from "./services/auth.service"; import { GlobalState } from "jslib-common/models/domain/globalState";
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { I18nService } from "./services/i18n.service";
import { KeytarSecureStorageService } from "./services/keytarSecureStorage.service";
import { LowdbStorageService } from "./services/lowdbStorage.service";
import { StateService } from "./services/state.service";
import { StateMigrationService } from "./services/stateMigration.service";
import { SyncService } from "./services/sync.service";
import { CliPlatformUtilsService } from "jslib-node/cli/services/cliPlatformUtils.service";
import { ConsoleLogService } from "jslib-node/cli/services/consoleLog.service";
import { NodeApiService } from "jslib-node/services/nodeApi.service";
import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
import { AppIdService } from "jslib-common/services/appId.service"; import { AppIdService } from "jslib-common/services/appId.service";
import { CipherService } from "jslib-common/services/cipher.service"; import { CipherService } from "jslib-common/services/cipher.service";
import { CollectionService } from "jslib-common/services/collection.service"; import { CollectionService } from "jslib-common/services/collection.service";
@@ -35,22 +26,26 @@ import { SearchService } from "jslib-common/services/search.service";
import { SendService } from "jslib-common/services/send.service"; import { SendService } from "jslib-common/services/send.service";
import { SettingsService } from "jslib-common/services/settings.service"; import { SettingsService } from "jslib-common/services/settings.service";
import { TokenService } from "jslib-common/services/token.service"; import { TokenService } from "jslib-common/services/token.service";
import { CliPlatformUtilsService } from "jslib-node/cli/services/cliPlatformUtils.service";
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service"; import { ConsoleLogService } from "jslib-node/cli/services/consoleLog.service";
import { NodeApiService } from "jslib-node/services/nodeApi.service";
import { Program } from "./program"; import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
import { Account } from "./models/account"; import { Account } from "./models/account";
import { Program } from "./program";
import { AuthService } from "./services/auth.service";
import { I18nService } from "./services/i18n.service";
import { KeytarSecureStorageService } from "./services/keytarSecureStorage.service";
import { LowdbStorageService } from "./services/lowdbStorage.service";
import { NoopTwoFactorService } from "./services/noop/noopTwoFactor.service";
import { StateService } from "./services/state.service";
import { StateMigrationService } from "./services/stateMigration.service";
import { SyncService } from "./services/sync.service";
import { GlobalStateFactory } from "jslib-common/factories/globalStateFactory"; // eslint-disable-next-line
import { StateFactory } from "jslib-common/factories/stateFactory";
import { GlobalState } from "jslib-common/models/domain/globalState";
// tslint:disable-next-line
const packageJson = require("./package.json"); const packageJson = require("./package.json");
export let searchService: SearchService = null; export const searchService: SearchService = null;
export class Main { export class Main {
dataFilePath: string; dataFilePath: string;
logService: ConsoleLogService; logService: ConsoleLogService;
@@ -83,6 +78,7 @@ export class Main {
stateMigrationService: StateMigrationService; stateMigrationService: StateMigrationService;
organizationService: OrganizationService; organizationService: OrganizationService;
providerService: ProviderService; providerService: ProviderService;
twoFactorService: TwoFactorServiceAbstraction;
constructor() { constructor() {
const applicationName = "Bitwarden Directory Connector"; const applicationName = "Bitwarden Directory Connector";
@@ -107,7 +103,10 @@ export class Main {
const plaintextSecrets = process.env.BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS === "true"; const plaintextSecrets = process.env.BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS === "true";
this.i18nService = new I18nService("en", "./locales"); this.i18nService = new I18nService("en", "./locales");
this.platformUtilsService = new CliPlatformUtilsService("connector", packageJson); this.platformUtilsService = new CliPlatformUtilsService(
ClientType.DirectoryConnector,
packageJson
);
this.logService = new ConsoleLogService( this.logService = new ConsoleLogService(
this.platformUtilsService.isDev(), this.platformUtilsService.isDev(),
(level) => process.env.BITWARDENCLI_CONNECTOR_DEBUG !== "true" && level <= LogLevelType.Info (level) => process.env.BITWARDENCLI_CONNECTOR_DEBUG !== "true" && level <= LogLevelType.Info
@@ -127,7 +126,7 @@ export class Main {
this.stateMigrationService = new StateMigrationService( this.stateMigrationService = new StateMigrationService(
this.storageService, this.storageService,
this.secureStorageService, this.secureStorageService,
new GlobalStateFactory(GlobalState) new StateFactory(GlobalState, Account)
); );
this.stateService = new StateService( this.stateService = new StateService(
@@ -160,7 +159,8 @@ export class Main {
" (" + " (" +
this.platformUtilsService.getDeviceString().toUpperCase() + this.platformUtilsService.getDeviceString().toUpperCase() +
")", ")",
(clientId, clientSecret) => this.authService.logInApiKey(clientId, clientSecret) (clientId, clientSecret) =>
this.authService.logIn(new ApiLogInCredentials(clientId, clientSecret))
); );
this.containerService = new ContainerService(this.cryptoService); this.containerService = new ContainerService(this.cryptoService);
@@ -172,23 +172,25 @@ export class Main {
this.apiService, this.apiService,
this.tokenService, this.tokenService,
this.logService, this.logService,
this.organizationService this.organizationService,
this.cryptoFunctionService
); );
this.twoFactorService = new NoopTwoFactorService();
this.authService = new AuthService( this.authService = new AuthService(
this.cryptoService, this.cryptoService,
this.apiService, this.apiService,
this.tokenService, this.tokenService,
this.appIdService, this.appIdService,
this.i18nService,
this.platformUtilsService, this.platformUtilsService,
this.messagingService, this.messagingService,
null,
this.logService, this.logService,
this.cryptoFunctionService,
this.environmentService,
this.keyConnectorService, this.keyConnectorService,
this.stateService this.environmentService,
this.stateService,
this.twoFactorService,
this.i18nService
); );
this.syncService = new SyncService( this.syncService = new SyncService(
@@ -281,7 +283,6 @@ export class Main {
// }); // });
const locale = await this.stateService.getLocale(); const locale = await this.stateService.getLocale();
await this.i18nService.init(locale); await this.i18nService.init(locale);
this.authService.init();
const installedVersion = await this.stateService.getInstalledVersion(); const installedVersion = await this.stateService.getInstalledVersion();
const currentVersion = await this.platformUtilsService.getApplicationVersion(); const currentVersion = await this.platformUtilsService.getApplicationVersion();

View File

@@ -1,9 +1,9 @@
import * as program from "commander"; import * as program from "commander";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { Response } from "jslib-node/cli/models/response"; import { Response } from "jslib-node/cli/models/response";
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"; import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
import { StateService } from "../abstractions/state.service"; import { StateService } from "../abstractions/state.service";
export class ClearCacheCommand { export class ClearCacheCommand {

View File

@@ -2,25 +2,20 @@ import * as program from "commander";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { NodeUtils } from "jslib-common/misc/nodeUtils";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { Response } from "jslib-node/cli/models/response"; import { Response } from "jslib-node/cli/models/response";
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"; import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { AzureConfiguration } from "../models/azureConfiguration"; import { AzureConfiguration } from "../models/azureConfiguration";
import { GSuiteConfiguration } from "../models/gsuiteConfiguration"; import { GSuiteConfiguration } from "../models/gsuiteConfiguration";
import { LdapConfiguration } from "../models/ldapConfiguration"; import { LdapConfiguration } from "../models/ldapConfiguration";
import { OktaConfiguration } from "../models/oktaConfiguration"; import { OktaConfiguration } from "../models/oktaConfiguration";
import { OneLoginConfiguration } from "../models/oneLoginConfiguration"; import { OneLoginConfiguration } from "../models/oneLoginConfiguration";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
import { ConnectorUtils } from "../utils"; import { ConnectorUtils } from "../utils";
import { NodeUtils } from "jslib-common/misc/nodeUtils";
export class ConfigCommand { export class ConfigCommand {
private directory: DirectoryType; private directory: DirectoryType;
private ldap = new LdapConfiguration(); private ldap = new LdapConfiguration();

View File

@@ -1,26 +1,26 @@
import * as program from "commander";
import { StateService } from "../abstractions/state.service";
import { Response } from "jslib-node/cli/models/response"; import { Response } from "jslib-node/cli/models/response";
import { StringResponse } from "jslib-node/cli/models/response/stringResponse"; import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
import { StateService } from "../abstractions/state.service";
export class LastSyncCommand { export class LastSyncCommand {
constructor(private stateService: StateService) {} constructor(private stateService: StateService) {}
async run(object: string): Promise<Response> { async run(object: string): Promise<Response> {
try { try {
switch (object.toLowerCase()) { switch (object.toLowerCase()) {
case "groups": case "groups": {
const groupsDate = await this.stateService.getLastGroupSync(); const groupsDate = await this.stateService.getLastGroupSync();
const groupsRes = new StringResponse( const groupsRes = new StringResponse(
groupsDate == null ? null : groupsDate.toISOString() groupsDate == null ? null : groupsDate.toISOString()
); );
return Response.success(groupsRes); return Response.success(groupsRes);
case "users": }
case "users": {
const usersDate = await this.stateService.getLastUserSync(); const usersDate = await this.stateService.getLastUserSync();
const usersRes = new StringResponse(usersDate == null ? null : usersDate.toISOString()); const usersRes = new StringResponse(usersDate == null ? null : usersDate.toISOString());
return Response.success(usersRes); return Response.success(usersRes);
}
default: default:
return Response.badRequest("Unknown object."); return Response.badRequest("Unknown object.");
} }

View File

@@ -1,10 +1,9 @@
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { SyncService } from "../services/sync.service";
import { Response } from "jslib-node/cli/models/response"; import { Response } from "jslib-node/cli/models/response";
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse"; import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
import { SyncService } from "../services/sync.service";
export class SyncCommand { export class SyncCommand {
constructor(private syncService: SyncService, private i18nService: I18nService) {} constructor(private syncService: SyncService, private i18nService: I18nService) {}

View File

@@ -1,13 +1,11 @@
import * as program from "commander"; import * as program from "commander";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { SyncService } from "../services/sync.service";
import { ConnectorUtils } from "../utils";
import { Response } from "jslib-node/cli/models/response"; import { Response } from "jslib-node/cli/models/response";
import { TestResponse } from "../models/response/testResponse"; import { TestResponse } from "../models/response/testResponse";
import { SyncService } from "../services/sync.service";
import { ConnectorUtils } from "../utils";
export class TestCommand { export class TestCommand {
constructor(private syncService: SyncService, private i18nService: I18nService) {} constructor(private syncService: SyncService, private i18nService: I18nService) {}

View File

@@ -1,10 +1,9 @@
import { app } from "electron";
import * as path from "path"; import * as path from "path";
import { MenuMain } from "./main/menu.main"; import { app } from "electron";
import { MessagingMain } from "./main/messaging.main";
import { I18nService } from "./services/i18n.service";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { GlobalState } from "jslib-common/models/domain/globalState";
import { KeytarStorageListener } from "jslib-electron/keytarStorageListener"; import { KeytarStorageListener } from "jslib-electron/keytarStorageListener";
import { ElectronLogService } from "jslib-electron/services/electronLog.service"; import { ElectronLogService } from "jslib-electron/services/electronLog.service";
import { ElectronMainMessagingService } from "jslib-electron/services/electronMainMessaging.service"; import { ElectronMainMessagingService } from "jslib-electron/services/electronMainMessaging.service";
@@ -13,13 +12,11 @@ import { TrayMain } from "jslib-electron/tray.main";
import { UpdaterMain } from "jslib-electron/updater.main"; import { UpdaterMain } from "jslib-electron/updater.main";
import { WindowMain } from "jslib-electron/window.main"; import { WindowMain } from "jslib-electron/window.main";
import { StateService } from "./services/state.service"; import { MenuMain } from "./main/menu.main";
import { MessagingMain } from "./main/messaging.main";
import { Account } from "./models/account"; import { Account } from "./models/account";
import { I18nService } from "./services/i18n.service";
import { StateFactory } from "jslib-common/factories/stateFactory"; import { StateService } from "./services/state.service";
import { GlobalState } from "jslib-common/models/domain/globalState";
export class Main { export class Main {
logService: ElectronLogService; logService: ElectronLogService;
@@ -53,7 +50,7 @@ export class Main {
const watch = args.some((val) => val === "--watch"); const watch = args.some((val) => val === "--watch");
if (watch) { if (watch) {
// tslint:disable-next-line // eslint-disable-next-line
require("electron-reload")(__dirname, {}); require("electron-reload")(__dirname, {});
} }
@@ -132,7 +129,7 @@ export class Main {
}); });
}, },
(e: any) => { (e: any) => {
// tslint:disable-next-line // eslint-disable-next-line
console.error(e); console.error(e);
} }
); );

View File

@@ -1,9 +1,9 @@
import { Menu, MenuItem, MenuItemConstructorOptions } from "electron"; import { Menu, MenuItemConstructorOptions } from "electron";
import { Main } from "../main";
import { BaseMenu } from "jslib-electron/baseMenu"; import { BaseMenu } from "jslib-electron/baseMenu";
import { Main } from "../main";
export class MenuMain extends BaseMenu { export class MenuMain extends BaseMenu {
menu: Menu; menu: Menu;

View File

@@ -1,4 +1,4 @@
import { app, ipcMain } from "electron"; import { ipcMain } from "electron";
import { TrayMain } from "jslib-electron/tray.main"; import { TrayMain } from "jslib-electron/tray.main";
import { UpdaterMain } from "jslib-electron/updater.main"; import { UpdaterMain } from "jslib-electron/updater.main";

View File

@@ -0,0 +1,62 @@
import { LogInStrategy } from "jslib-common/misc/logInStrategies/logIn.strategy";
import { AccountKeys, AccountProfile, AccountTokens } from "jslib-common/models/domain/account";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { ApiTokenRequest } from "jslib-common/models/request/identityToken/apiTokenRequest";
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account";
export class OrganizationLogInStrategy extends LogInStrategy {
tokenRequest: ApiTokenRequest;
async logIn(credentials: ApiLogInCredentials) {
this.tokenRequest = new ApiTokenRequest(
credentials.clientId,
credentials.clientSecret,
await this.buildTwoFactor(),
await this.buildDeviceRequest()
);
return this.startLogIn();
}
protected async processTokenResponse(response: IdentityTokenResponse): Promise<AuthResult> {
await this.saveAccountInformation(response);
return new AuthResult();
}
protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
const clientId = this.tokenRequest.clientId;
const entityId = clientId.split("organization.")[1];
const clientSecret = this.tokenRequest.clientSecret;
await this.stateService.addAccount(
new Account({
profile: {
...new AccountProfile(),
...{
userId: entityId,
apiKeyClientId: clientId,
entityId: entityId,
},
},
tokens: {
...new AccountTokens(),
...{
accessToken: tokenResponse.accessToken,
refreshToken: tokenResponse.refreshToken,
},
},
keys: {
...new AccountKeys(),
...{
apiKeyClientSecret: clientSecret,
},
},
directorySettings: new DirectorySettings(),
directoryConfigurations: new DirectoryConfigurations(),
})
);
}
}

View File

@@ -1,2 +1,2 @@
// tslint:disable-next-line // eslint-disable-next-line
export interface IConfiguration {} export interface IConfiguration {}

View File

@@ -1,9 +1,9 @@
import { GroupResponse } from "./groupResponse"; import { BaseResponse } from "jslib-node/cli/models/response/baseResponse";
import { UserResponse } from "./userResponse";
import { SimResult } from "../simResult"; import { SimResult } from "../simResult";
import { BaseResponse } from "jslib-node/cli/models/response/baseResponse"; import { GroupResponse } from "./groupResponse";
import { UserResponse } from "./userResponse";
export class TestResponse implements BaseResponse { export class TestResponse implements BaseResponse {
object: string; object: string;

33
src/package-lock.json generated
View File

@@ -1,19 +1,20 @@
{ {
"name": "@bitwarden/directory-connector", "name": "@bitwarden/directory-connector",
"version": "2.9.8", "version": "2.9.9",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@bitwarden/directory-connector", "name": "@bitwarden/directory-connector",
"version": "2.9.8", "version": "2.9.9",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"browser-hrtime": "^1.1.8", "browser-hrtime": "^1.1.8",
"electron-log": "4.4.1", "electron-log": "4.4.1",
"electron-store": "8.0.1", "electron-store": "8.0.1",
"electron-updater": "4.6.1", "electron-updater": "4.6.1",
"keytar": "7.7.0" "keytar": "7.7.0",
"rxjs": "^7.4.0"
} }
}, },
"node_modules/@types/semver": { "node_modules/@types/semver": {
@@ -800,6 +801,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rxjs": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
"integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==",
"dependencies": {
"tslib": "~2.1.0"
}
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -942,6 +951,11 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/tslib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
"node_modules/tunnel-agent": { "node_modules/tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -1595,6 +1609,14 @@
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
}, },
"rxjs": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
"integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==",
"requires": {
"tslib": "~2.1.0"
}
},
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -1704,6 +1726,11 @@
} }
} }
}, },
"tslib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
},
"tunnel-agent": { "tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",

View File

@@ -2,7 +2,7 @@
"name": "@bitwarden/directory-connector", "name": "@bitwarden/directory-connector",
"productName": "Bitwarden Directory Connector", "productName": "Bitwarden Directory Connector",
"description": "Sync your user directory to your Bitwarden organization.", "description": "Sync your user directory to your Bitwarden organization.",
"version": "2.9.8", "version": "2.10.0",
"author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)", "author": "Bitwarden Inc. <hello@bitwarden.com> (https://bitwarden.com)",
"homepage": "https://bitwarden.com", "homepage": "https://bitwarden.com",
"license": "GPL-3.0", "license": "GPL-3.0",
@@ -16,6 +16,7 @@
"electron-log": "4.4.1", "electron-log": "4.4.1",
"electron-store": "8.0.1", "electron-store": "8.0.1",
"electron-updater": "4.6.1", "electron-updater": "4.6.1",
"keytar": "7.7.0" "keytar": "7.7.0",
"rxjs": "^7.4.0"
} }
} }

View File

@@ -1,27 +1,24 @@
import * as chalk from "chalk";
import * as program from "commander";
import * as path from "path"; import * as path from "path";
import { Main } from "./bwdc"; import * as chalk from "chalk";
import * as program from "commander";
import { Utils } from "jslib-common/misc/utils";
import { BaseProgram } from "jslib-node/cli/baseProgram";
import { LoginCommand } from "jslib-node/cli/commands/login.command";
import { LogoutCommand } from "jslib-node/cli/commands/logout.command";
import { UpdateCommand } from "jslib-node/cli/commands/update.command";
import { Response } from "jslib-node/cli/models/response";
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
import { Main } from "./bwdc";
import { ClearCacheCommand } from "./commands/clearCache.command"; import { ClearCacheCommand } from "./commands/clearCache.command";
import { ConfigCommand } from "./commands/config.command"; import { ConfigCommand } from "./commands/config.command";
import { LastSyncCommand } from "./commands/lastSync.command"; import { LastSyncCommand } from "./commands/lastSync.command";
import { SyncCommand } from "./commands/sync.command"; import { SyncCommand } from "./commands/sync.command";
import { TestCommand } from "./commands/test.command"; import { TestCommand } from "./commands/test.command";
import { LoginCommand } from "jslib-node/cli/commands/login.command"; const writeLn = (s: string, finalLine = false, error = false) => {
import { LogoutCommand } from "jslib-node/cli/commands/logout.command";
import { UpdateCommand } from "jslib-node/cli/commands/update.command";
import { BaseProgram } from "jslib-node/cli/baseProgram";
import { Response } from "jslib-node/cli/models/response";
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
import { Utils } from "jslib-common/misc/utils";
const writeLn = (s: string, finalLine: boolean = false, error: boolean = false) => {
const stream = error ? process.stderr : process.stdout; const stream = error ? process.stderr : process.stdout;
if (finalLine && process.platform === "win32") { if (finalLine && process.platform === "win32") {
stream.write(s); stream.write(s);
@@ -106,6 +103,7 @@ export class Program extends BaseProgram {
this.main.stateService, this.main.stateService,
this.main.cryptoService, this.main.cryptoService,
this.main.policyService, this.main.policyService,
this.main.twoFactorService,
"connector" "connector"
); );

View File

@@ -2,16 +2,17 @@ import { AuthService } from "jslib-common/abstractions/auth.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { TokenService } from "jslib-common/abstractions/token.service"; import { TokenService } from "jslib-common/abstractions/token.service";
import { StateService } from "../abstractions/state.service"; import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { ApiService as ApiServiceBase } from "jslib-common/services/api.service"; import { ApiService as ApiServiceBase } from "jslib-common/services/api.service";
import { StateService } from "../abstractions/state.service";
export async function refreshToken(stateService: StateService, authService: AuthService) { export async function refreshToken(stateService: StateService, authService: AuthService) {
try { try {
const clientId = await stateService.getApiKeyClientId(); const clientId = await stateService.getApiKeyClientId();
const clientSecret = await stateService.getApiKeyClientSecret(); const clientSecret = await stateService.getApiKeyClientSecret();
if (clientId != null && clientSecret != null) { if (clientId != null && clientSecret != null) {
await authService.logInApiKey(clientId, clientSecret); await authService.logIn(new ApiLogInCredentials(clientId, clientSecret));
} }
} catch (e) { } catch (e) {
return Promise.reject(e); return Promise.reject(e);

View File

@@ -1,7 +1,8 @@
import { Injectable } from "@angular/core";
import { ApiService } from "jslib-common/abstractions/api.service"; import { ApiService } from "jslib-common/abstractions/api.service";
import { AppIdService } from "jslib-common/abstractions/appId.service"; import { AppIdService } from "jslib-common/abstractions/appId.service";
import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
@@ -9,111 +10,59 @@ import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { TokenService } from "jslib-common/abstractions/token.service"; import { TokenService } from "jslib-common/abstractions/token.service";
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
import { StateService } from "../abstractions/state.service"; import { AuthResult } from "jslib-common/models/domain/authResult";
import { ApiLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { AuthService as AuthServiceBase } from "jslib-common/services/auth.service"; import { AuthService as AuthServiceBase } from "jslib-common/services/auth.service";
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account"; import { StateService } from "../abstractions/state.service";
import { OrganizationLogInStrategy } from "../misc/logInStrategies/organizationLogIn.strategy";
import { AccountKeys, AccountProfile, AccountTokens } from "jslib-common/models/domain/account";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { DeviceRequest } from "jslib-common/models/request/deviceRequest";
import { TokenRequest } from "jslib-common/models/request/tokenRequest";
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
@Injectable()
export class AuthService extends AuthServiceBase { export class AuthService extends AuthServiceBase {
constructor( constructor(
cryptoService: CryptoService, cryptoService: CryptoService,
apiService: ApiService, apiService: ApiService,
tokenService: TokenService, tokenService: TokenService,
appIdService: AppIdService, appIdService: AppIdService,
i18nService: I18nService,
platformUtilsService: PlatformUtilsService, platformUtilsService: PlatformUtilsService,
messagingService: MessagingService, messagingService: MessagingService,
vaultTimeoutService: VaultTimeoutService,
logService: LogService, logService: LogService,
cryptoFunctionService: CryptoFunctionService,
environmentService: EnvironmentService,
keyConnectorService: KeyConnectorService, keyConnectorService: KeyConnectorService,
stateService: StateService environmentService: EnvironmentService,
stateService: StateService,
twoFactorService: TwoFactorService,
i18nService: I18nService
) { ) {
super( super(
cryptoService, cryptoService,
apiService, apiService,
tokenService, tokenService,
appIdService, appIdService,
i18nService,
platformUtilsService, platformUtilsService,
messagingService, messagingService,
vaultTimeoutService,
logService, logService,
cryptoFunctionService,
keyConnectorService, keyConnectorService,
environmentService, environmentService,
stateService, stateService,
false twoFactorService,
i18nService
); );
} }
async logInApiKey(clientId: string, clientSecret: string): Promise<AuthResult> { async logIn(credentials: ApiLogInCredentials): Promise<AuthResult> {
this.selectedTwoFactorProviderType = null; const strategy = new OrganizationLogInStrategy(
if (clientId.startsWith("organization")) { this.cryptoService,
return await this.organizationLogInHelper(clientId, clientSecret); this.apiService,
} this.tokenService,
return await super.logInApiKey(clientId, clientSecret); this.appIdService,
} this.platformUtilsService,
this.messagingService,
private async organizationLogInHelper(clientId: string, clientSecret: string) { this.logService,
const appId = await this.appIdService.getAppId(); this.stateService,
const entityId = clientId.split("organization.")[1]; this.twoFactorService
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
const request = new TokenRequest(
null,
null,
[clientId, clientSecret],
null,
null,
false,
null,
deviceRequest
); );
const response = await this.apiService.postIdentityToken(request); return strategy.logIn(credentials);
const result = new AuthResult();
result.twoFactor = !(response as any).accessToken;
const tokenResponse = response as IdentityTokenResponse;
result.resetMasterPassword = tokenResponse.resetMasterPassword;
await this.stateService.addAccount(
new Account({
profile: {
...new AccountProfile(),
...{
userId: entityId,
apiKeyClientId: clientId,
entityId: entityId,
},
},
tokens: {
...new AccountTokens(),
...{
accessToken: tokenResponse.accessToken,
refreshToken: tokenResponse.refreshToken,
},
},
keys: {
...new AccountKeys(),
...{
apiKeyClientSecret: clientSecret,
},
},
directorySettings: new DirectorySettings(),
directoryConfigurations: new DirectoryConfigurations(),
})
);
return result;
} }
} }

View File

@@ -1,10 +1,14 @@
import * as graph from "@microsoft/microsoft-graph-client";
import * as graphType from "@microsoft/microsoft-graph-types";
import * as https from "https"; import * as https from "https";
import * as querystring from "querystring"; import * as querystring from "querystring";
import { DirectoryType } from "../enums/directoryType"; import * as graph from "@microsoft/microsoft-graph-client";
import * as graphType from "@microsoft/microsoft-graph-types";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { AzureConfiguration } from "../models/azureConfiguration"; import { AzureConfiguration } from "../models/azureConfiguration";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
@@ -13,10 +17,6 @@ import { UserEntry } from "../models/userEntry";
import { BaseDirectoryService } from "./baseDirectory.service"; import { BaseDirectoryService } from "./baseDirectory.service";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
const AzurePublicIdentityAuhtority = "login.microsoftonline.com"; const AzurePublicIdentityAuhtority = "login.microsoftonline.com";
const AzureGovermentIdentityAuhtority = "login.microsoftonline.us"; const AzureGovermentIdentityAuhtority = "login.microsoftonline.us";
@@ -84,7 +84,6 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
} }
private async getCurrentUsers(): Promise<UserEntry[]> { private async getCurrentUsers(): Promise<UserEntry[]> {
const entryIds = new Set<string>();
let entries: UserEntry[] = []; let entries: UserEntry[] = [];
let users: graphType.User[]; let users: graphType.User[];
const setFilter = this.createCustomUserSet(this.syncConfig.userFilter); const setFilter = this.createCustomUserSet(this.syncConfig.userFilter);
@@ -131,6 +130,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
} }
const setFilter = this.createCustomUserSet(this.syncConfig.userFilter); const setFilter = this.createCustomUserSet(this.syncConfig.userFilter);
// eslint-disable-next-line
while (true) { while (true) {
const users: graphType.User[] = res.value; const users: graphType.User[] = res.value;
if (users != null) { if (users != null) {
@@ -312,6 +312,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
const entries: GroupEntry[] = []; const entries: GroupEntry[] = [];
const groupsReq = this.client.api("/groups"); const groupsReq = this.client.api("/groups");
let res = await groupsReq.get(); let res = await groupsReq.get();
// eslint-disable-next-line
while (true) { while (true) {
const groups: graphType.Group[] = res.value; const groups: graphType.Group[] = res.value;
if (groups != null) { if (groups != null) {
@@ -404,6 +405,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
const memReq = this.client.api("/groups/" + group.id + "/members"); const memReq = this.client.api("/groups/" + group.id + "/members");
let memRes = await memReq.get(); let memRes = await memReq.get();
// eslint-disable-next-line
while (true) { while (true) {
const members: any = memRes.value; const members: any = memRes.value;
if (members != null) { if (members != null) {
@@ -486,7 +488,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
} else if (d.error != null && d.error_description != null) { } else if (d.error != null && d.error_description != null) {
const shortError = d.error_description?.split("\n", 1)[0]; const shortError = d.error_description?.split("\n", 1)[0];
const err = new Error(d.error + " (" + res.statusCode + "): " + shortError); const err = new Error(d.error + " (" + res.statusCode + "): " + shortError);
// tslint:disable-next-line // eslint-disable-next-line
console.error(d.error_description); console.error(d.error_description);
done(err, null); done(err, null);
} else { } else {

View File

@@ -1,6 +1,5 @@
import { SyncConfiguration } from "../models/syncConfiguration";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { SyncConfiguration } from "../models/syncConfiguration";
import { UserEntry } from "../models/userEntry"; import { UserEntry } from "../models/userEntry";
export abstract class BaseDirectoryService { export abstract class BaseDirectoryService {

View File

@@ -1,8 +1,11 @@
import { JWT } from "google-auth-library"; import { JWT } from "google-auth-library";
import { admin_directory_v1, google } from "googleapis"; import { admin_directory_v1, google } from "googleapis";
import { DirectoryType } from "../enums/directoryType"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { GSuiteConfiguration } from "../models/gsuiteConfiguration"; import { GSuiteConfiguration } from "../models/gsuiteConfiguration";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
@@ -11,10 +14,6 @@ import { UserEntry } from "../models/userEntry";
import { BaseDirectoryService } from "./baseDirectory.service"; import { BaseDirectoryService } from "./baseDirectory.service";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
export class GSuiteDirectoryService extends BaseDirectoryService implements IDirectoryService { export class GSuiteDirectoryService extends BaseDirectoryService implements IDirectoryService {
private client: JWT; private client: JWT;
private service: admin_directory_v1.Admin; private service: admin_directory_v1.Admin;
@@ -72,6 +71,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
let nextPageToken: string = null; let nextPageToken: string = null;
const filter = this.createCustomSet(this.syncConfig.userFilter); const filter = this.createCustomSet(this.syncConfig.userFilter);
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying users - nextPageToken:" + nextPageToken); this.logService.info("Querying users - nextPageToken:" + nextPageToken);
const p = Object.assign({ query: query, pageToken: nextPageToken }, this.authParams); const p = Object.assign({ query: query, pageToken: nextPageToken }, this.authParams);
@@ -99,6 +99,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
} }
nextPageToken = null; nextPageToken = null;
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying deleted users - nextPageToken:" + nextPageToken); this.logService.info("Querying deleted users - nextPageToken:" + nextPageToken);
const p = Object.assign( const p = Object.assign(
@@ -152,6 +153,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
const entries: GroupEntry[] = []; const entries: GroupEntry[] = [];
let nextPageToken: string = null; let nextPageToken: string = null;
// eslint-disable-next-line
while (true) { while (true) {
this.logService.info("Querying groups - nextPageToken:" + nextPageToken); this.logService.info("Querying groups - nextPageToken:" + nextPageToken);
const p = Object.assign({ pageToken: nextPageToken }, this.authParams); const p = Object.assign({ pageToken: nextPageToken }, this.authParams);
@@ -186,6 +188,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
entry.externalId = group.id; entry.externalId = group.id;
entry.name = group.name; entry.name = group.name;
// eslint-disable-next-line
while (true) { while (true) {
const p = Object.assign({ groupKey: group.id, pageToken: nextPageToken }, this.authParams); const p = Object.assign({ groupKey: group.id, pageToken: nextPageToken }, this.authParams);
const memRes = await this.service.members.list(p); const memRes = await this.service.members.list(p);

View File

@@ -1,10 +1,14 @@
import * as fs from "fs"; import * as fs from "fs";
import * as ldap from "ldapjs";
import { checkServerIdentity, PeerCertificate } from "tls"; import { checkServerIdentity, PeerCertificate } from "tls";
import { DirectoryType } from "../enums/directoryType"; import * as ldap from "ldapjs";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { Utils } from "jslib-common/misc/utils";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { LdapConfiguration } from "../models/ldapConfiguration"; import { LdapConfiguration } from "../models/ldapConfiguration";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
@@ -12,12 +16,6 @@ import { UserEntry } from "../models/userEntry";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
import { Utils } from "jslib-common/misc/utils";
const UserControlAccountDisabled = 2; const UserControlAccountDisabled = 2;
export class LdapDirectoryService implements IDirectoryService { export class LdapDirectoryService implements IDirectoryService {

View File

@@ -1,10 +1,8 @@
import * as lock from "proper-lockfile"; import * as lock from "proper-lockfile";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { LowdbStorageService as LowdbStorageServiceBase } from "jslib-node/services/lowdbStorage.service";
import { Utils } from "jslib-common/misc/utils"; import { Utils } from "jslib-common/misc/utils";
import { LowdbStorageService as LowdbStorageServiceBase } from "jslib-node/services/lowdbStorage.service";
export class LowdbStorageService extends LowdbStorageServiceBase { export class LowdbStorageService extends LowdbStorageServiceBase {
constructor( constructor(

View File

@@ -0,0 +1,40 @@
import {
TwoFactorProviderDetails,
TwoFactorService,
} from "jslib-common/abstractions/twoFactor.service";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { IdentityTwoFactorResponse } from "jslib-common/models/response/identityTwoFactorResponse";
export class NoopTwoFactorService implements TwoFactorService {
init() {
// Noop
}
getSupportedProviders(win: Window): TwoFactorProviderDetails[] {
return null;
}
getDefaultProvider(webAuthnSupported: boolean): TwoFactorProviderType {
return null;
}
setSelectedProvider(type: TwoFactorProviderType) {
// Noop
}
clearSelectedProvider() {
// Noop
}
setProviders(response: IdentityTwoFactorResponse) {
// Noop
}
clearProviders() {
// Noop
}
getProviders(): Map<TwoFactorProviderType, { [key: string]: string }> {
return null;
}
}

View File

@@ -1,5 +1,10 @@
import { DirectoryType } from "../enums/directoryType"; import * as https from "https";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { OktaConfiguration } from "../models/oktaConfiguration"; import { OktaConfiguration } from "../models/oktaConfiguration";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
@@ -8,12 +13,6 @@ import { UserEntry } from "../models/userEntry";
import { BaseDirectoryService } from "./baseDirectory.service"; import { BaseDirectoryService } from "./baseDirectory.service";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import * as https from "https";
import { StateService } from "../abstractions/state.service";
const DelayBetweenBuildGroupCallsInMilliseconds = 500; const DelayBetweenBuildGroupCallsInMilliseconds = 500;
export class OktaDirectoryService extends BaseDirectoryService implements IDirectoryService { export class OktaDirectoryService extends BaseDirectoryService implements IDirectoryService {
@@ -213,6 +212,7 @@ export class OktaDirectoryService extends BaseDirectoryService implements IDirec
if (res.headers != null) { if (res.headers != null) {
const headersMap = new Map<string, string | string[]>(); const headersMap = new Map<string, string | string[]>();
for (const key in res.headers) { for (const key in res.headers) {
// eslint-disable-next-line
if (res.headers.hasOwnProperty(key)) { if (res.headers.hasOwnProperty(key)) {
const val = res.headers[key]; const val = res.headers[key];
headersMap.set(key.toLowerCase(), val); headersMap.set(key.toLowerCase(), val);

View File

@@ -1,5 +1,8 @@
import { DirectoryType } from "../enums/directoryType"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { GroupEntry } from "../models/groupEntry"; import { GroupEntry } from "../models/groupEntry";
import { OneLoginConfiguration } from "../models/oneLoginConfiguration"; import { OneLoginConfiguration } from "../models/oneLoginConfiguration";
import { SyncConfiguration } from "../models/syncConfiguration"; import { SyncConfiguration } from "../models/syncConfiguration";
@@ -8,10 +11,6 @@ import { UserEntry } from "../models/userEntry";
import { BaseDirectoryService } from "./baseDirectory.service"; import { BaseDirectoryService } from "./baseDirectory.service";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateService } from "../abstractions/state.service";
// Basic email validation: something@something.something // Basic email validation: something@something.something
const ValidEmailRegex = /^\S+@\S+\.\S+$/; const ValidEmailRegex = /^\S+@\S+\.\S+$/;

View File

@@ -1,26 +1,26 @@
import { StateService as BaseStateService } from "jslib-common/services/state.service"; import { Inject, Injectable } from "@angular/core";
import { SECURE_STORAGE, STATE_FACTORY } from "jslib-common/abstractions/injectionTokens";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateMigrationService } from "jslib-common/abstractions/stateMigration.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { StateFactory } from "jslib-common/factories/stateFactory";
import { GlobalState } from "jslib-common/models/domain/globalState"; import { GlobalState } from "jslib-common/models/domain/globalState";
import { StorageOptions } from "jslib-common/models/domain/storageOptions"; import { StorageOptions } from "jslib-common/models/domain/storageOptions";
import { StateService as BaseStateService } from "jslib-common/services/state.service";
import { StateFactory } from "jslib-common/factories/stateFactory"; import { StateService as StateServiceAbstraction } from "src/abstractions/state.service";
import { USE_SECURE_STORAGE_FOR_SECRETS } from "src/app/services/injectionTokens";
import { DirectoryType } from "src/enums/directoryType";
import { IConfiguration } from "src/models/IConfiguration";
import { Account } from "src/models/account"; import { Account } from "src/models/account";
import { AzureConfiguration } from "src/models/azureConfiguration"; import { AzureConfiguration } from "src/models/azureConfiguration";
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration"; import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";
import { IConfiguration } from "src/models/IConfiguration";
import { LdapConfiguration } from "src/models/ldapConfiguration"; import { LdapConfiguration } from "src/models/ldapConfiguration";
import { OktaConfiguration } from "src/models/oktaConfiguration"; import { OktaConfiguration } from "src/models/oktaConfiguration";
import { OneLoginConfiguration } from "src/models/oneLoginConfiguration"; import { OneLoginConfiguration } from "src/models/oneLoginConfiguration";
import { SyncConfiguration } from "src/models/syncConfiguration"; import { SyncConfiguration } from "src/models/syncConfiguration";
import { LogService } from "jslib-common/abstractions/log.service";
import { StateMigrationService } from "jslib-common/abstractions/stateMigration.service";
import { StorageService } from "jslib-common/abstractions/storage.service";
import { StateService as StateServiceAbstraction } from "src/abstractions/state.service";
import { DirectoryType } from "src/enums/directoryType";
const SecureStorageKeys = { const SecureStorageKeys = {
ldap: "ldapPassword", ldap: "ldapPassword",
@@ -43,14 +43,18 @@ const keys = {
const StoredSecurely = "[STORED SECURELY]"; const StoredSecurely = "[STORED SECURELY]";
export class StateService extends BaseStateService<Account> implements StateServiceAbstraction { @Injectable()
export class StateService
extends BaseStateService<GlobalState, Account>
implements StateServiceAbstraction
{
constructor( constructor(
protected storageService: StorageService, protected storageService: StorageService,
protected secureStorageService: StorageService, @Inject(SECURE_STORAGE) protected secureStorageService: StorageService,
protected logService: LogService, protected logService: LogService,
protected stateMigrationService: StateMigrationService, protected stateMigrationService: StateMigrationService,
private useSecureStorageForSecrets = true, @Inject(USE_SECURE_STORAGE_FOR_SECRETS) private useSecureStorageForSecrets = true,
protected stateFactory: StateFactory<Account, GlobalState> @Inject(STATE_FACTORY) protected stateFactory: StateFactory<GlobalState, Account>
) { ) {
super(storageService, secureStorageService, logService, stateMigrationService, stateFactory); super(storageService, secureStorageService, logService, stateMigrationService, stateFactory);
} }
@@ -240,50 +244,6 @@ export class StateService extends BaseStateService<Account> implements StateServ
); );
} }
async getUserDelta(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
if (options?.userId == null) {
return null;
}
return await this.secureStorageService.get<string>(
`${options.userId}_${SecureStorageKeys.userDelta}`
);
}
async setUserDelta(value: string, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
if (options?.userId == null) {
return;
}
await this.secureStorageService.save(
`${options.userId}_${SecureStorageKeys.userDelta}`,
value,
options
);
}
async getGroupDelta(options?: StorageOptions): Promise<string> {
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
if (options?.userId == null) {
return null;
}
return await this.secureStorageService.get<string>(
`${options.userId}_${SecureStorageKeys.groupDelta}`
);
}
async setGroupDelta(value: string, options?: StorageOptions): Promise<void> {
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
if (options?.userId == null) {
return;
}
await this.secureStorageService.save(
`${options.userId}_${SecureStorageKeys.groupDelta}`,
value,
options
);
}
async getConfiguration(type: DirectoryType): Promise<IConfiguration> { async getConfiguration(type: DirectoryType): Promise<IConfiguration> {
switch (type) { switch (type) {
case DirectoryType.Ldap: case DirectoryType.Ldap:
@@ -516,6 +476,40 @@ export class StateService extends BaseStateService<Account> implements StateServ
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions)); await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
} }
async getUserDelta(options?: StorageOptions): Promise<string> {
return (
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
)?.directorySettings?.userDelta;
}
async setUserDelta(value: string, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
account.directorySettings.userDelta = value;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
}
async getGroupDelta(options?: StorageOptions): Promise<string> {
return (
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
)?.directorySettings?.groupDelta;
}
async setGroupDelta(value: string, options?: StorageOptions): Promise<void> {
const account = await this.getAccount(
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
account.directorySettings.groupDelta = value;
await this.saveAccount(
account,
this.reconcileOptions(options, await this.defaultOnDiskOptions())
);
}
async clearSyncSettings(hashToo = false) { async clearSyncSettings(hashToo = false) {
await this.setUserDelta(null); await this.setUserDelta(null);
await this.setGroupDelta(null); await this.setGroupDelta(null);
@@ -531,12 +525,12 @@ export class StateService extends BaseStateService<Account> implements StateServ
} }
protected async scaffoldNewAccountDiskStorage(account: Account): Promise<void> { protected async scaffoldNewAccountDiskStorage(account: Account): Promise<void> {
const storedAccount = await this.getAccount( const storageOptions = this.reconcileOptions(
this.reconcileOptions(
{ userId: account.profile.userId }, { userId: account.profile.userId },
await this.defaultOnDiskLocalOptions() await this.defaultOnDiskLocalOptions()
)
); );
const storedAccount = await this.getAccount(storageOptions);
if (storedAccount != null) { if (storedAccount != null) {
account.settings = storedAccount.settings; account.settings = storedAccount.settings;
account.directorySettings = storedAccount.directorySettings; account.directorySettings = storedAccount.directorySettings;
@@ -553,11 +547,7 @@ export class StateService extends BaseStateService<Account> implements StateServ
await this.storageService.remove(keys.tempDirectoryConfigs); await this.storageService.remove(keys.tempDirectoryConfigs);
} }
await this.storageService.save( await this.saveAccount(account, storageOptions);
account.profile.userId,
account,
await this.defaultOnDiskLocalOptions()
);
} }
protected async pushAccounts(): Promise<void> { protected async pushAccounts(): Promise<void> {

View File

@@ -1,9 +1,9 @@
import { StateMigrationService as BaseStateMigrationService } from "jslib-common/services/stateMigration.service"; import { Injectable } from "@angular/core";
import { StateVersion } from "jslib-common/enums/stateVersion"; import { StateVersion } from "jslib-common/enums/stateVersion";
import { StateMigrationService as BaseStateMigrationService } from "jslib-common/services/stateMigration.service";
import { DirectoryType } from "src/enums/directoryType"; import { DirectoryType } from "src/enums/directoryType";
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account"; import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account";
import { AzureConfiguration } from "src/models/azureConfiguration"; import { AzureConfiguration } from "src/models/azureConfiguration";
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration"; import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";
@@ -21,8 +21,6 @@ const SecureStorageKeys: { [key: string]: any } = {
directoryConfigPrefix: "directoryConfig_", directoryConfigPrefix: "directoryConfig_",
sync: "syncConfig", sync: "syncConfig",
directoryType: "directoryType", directoryType: "directoryType",
userDelta: "userDeltaToken",
groupDelta: "groupDeltaToken",
organizationId: "organizationId", organizationId: "organizationId",
}; };
@@ -35,10 +33,17 @@ const Keys: { [key: string]: any } = {
lastSyncHash: "lastSyncHash", lastSyncHash: "lastSyncHash",
syncingDir: "syncingDir", syncingDir: "syncingDir",
syncConfig: "syncConfig", syncConfig: "syncConfig",
userDelta: "userDeltaToken",
groupDelta: "groupDeltaToken",
tempDirectoryConfigs: "tempDirectoryConfigs", tempDirectoryConfigs: "tempDirectoryConfigs",
tempDirectorySettings: "tempDirectorySettings", tempDirectorySettings: "tempDirectorySettings",
}; };
const StateKeys = {
global: "global",
authenticatedAccounts: "authenticatedAccounts",
};
const ClientKeys: { [key: string]: any } = { const ClientKeys: { [key: string]: any } = {
clientIdOld: "clientId", clientIdOld: "clientId",
clientId: "apikey_clientId", clientId: "apikey_clientId",
@@ -46,6 +51,7 @@ const ClientKeys: { [key: string]: any } = {
clientSecret: "apikey_clientSecret", clientSecret: "apikey_clientSecret",
}; };
@Injectable()
export class StateMigrationService extends BaseStateMigrationService { export class StateMigrationService extends BaseStateMigrationService {
async migrate(): Promise<void> { async migrate(): Promise<void> {
let currentStateVersion = await this.getCurrentStateVersion(); let currentStateVersion = await this.getCurrentStateVersion();
@@ -55,6 +61,8 @@ export class StateMigrationService extends BaseStateMigrationService {
await this.migrateClientKeys(); await this.migrateClientKeys();
await this.migrateStateFrom1To2(); await this.migrateStateFrom1To2();
break; break;
case StateVersion.Two:
await this.migrateStateFrom2To3();
} }
currentStateVersion += 1; currentStateVersion += 1;
} }
@@ -76,7 +84,7 @@ export class StateMigrationService extends BaseStateMigrationService {
} }
} }
protected async migrateStateFrom1To2(useSecureStorageForSecrets: boolean = true): Promise<void> { protected async migrateStateFrom1To2(useSecureStorageForSecrets = true): Promise<void> {
// Grabbing a couple of key settings before they get cleared by the base migration // Grabbing a couple of key settings before they get cleared by the base migration
const userId = await this.get<string>(Keys.entityId); const userId = await this.get<string>(Keys.entityId);
const clientId = await this.get<string>(ClientKeys.clientId); const clientId = await this.get<string>(ClientKeys.clientId);
@@ -118,6 +126,8 @@ export class StateMigrationService extends BaseStateMigrationService {
lastSyncHash: await this.get<string>(Keys.lastSyncHash), lastSyncHash: await this.get<string>(Keys.lastSyncHash),
syncingDir: await this.get<boolean>(Keys.syncingDir), syncingDir: await this.get<boolean>(Keys.syncingDir),
sync: await this.get<SyncConfiguration>(Keys.syncConfig), sync: await this.get<SyncConfiguration>(Keys.syncConfig),
userDelta: await this.get<string>(Keys.userDelta),
groupDelta: await this.get<string>(Keys.groupDelta),
}; };
// (userId == null) = no authed account, stored data temporarily to be applied and cleared on next auth // (userId == null) = no authed account, stored data temporarily to be applied and cleared on next auth
@@ -157,4 +167,34 @@ export class StateMigrationService extends BaseStateMigrationService {
} }
} }
} }
protected async migrateStateFrom2To3(useSecureStorageForSecrets = true): Promise<void> {
if (useSecureStorageForSecrets) {
const authenticatedUserIds = await this.get<string[]>(StateKeys.authenticatedAccounts);
await Promise.all(
authenticatedUserIds.map(async (userId) => {
const account = await this.get<Account>(userId);
// Fix for userDelta and groupDelta being put into secure storage when they should not have
if (await this.secureStorageService.has(`${userId}_${Keys.userDelta}`)) {
account.directorySettings.userDelta = await this.secureStorageService.get(
`${userId}_${Keys.userDelta}`
);
await this.secureStorageService.remove(`${userId}_${Keys.userDelta}`);
}
if (await this.secureStorageService.has(`${userId}_${Keys.groupDelta}`)) {
account.directorySettings.groupDelta = await this.secureStorageService.get(
`${userId}_${Keys.groupDelta}`
);
await this.secureStorageService.remove(`${userId}_${Keys.groupDelta}`);
}
await this.set(userId, account);
})
);
}
const globals = await this.getGlobals();
globals.stateVersion = StateVersion.Three;
await this.set(StateKeys.global, globals);
}
} }

View File

@@ -1,10 +1,4 @@
import { DirectoryType } from "../enums/directoryType"; import { Injectable } from "@angular/core";
import { GroupEntry } from "../models/groupEntry";
import { SyncConfiguration } from "../models/syncConfiguration";
import { UserEntry } from "../models/userEntry";
import { OrganizationImportRequest } from "jslib-common/models/request/organizationImportRequest";
import { ApiService } from "jslib-common/abstractions/api.service"; import { ApiService } from "jslib-common/abstractions/api.service";
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service"; import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
@@ -12,10 +6,15 @@ import { EnvironmentService } from "jslib-common/abstractions/environment.servic
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { LogService } from "jslib-common/abstractions/log.service"; import { LogService } from "jslib-common/abstractions/log.service";
import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service";
import { Utils } from "jslib-common/misc/utils"; import { Utils } from "jslib-common/misc/utils";
import { OrganizationImportRequest } from "jslib-common/models/request/organizationImportRequest";
import { StateService } from "../abstractions/state.service"; import { StateService } from "../abstractions/state.service";
import { DirectoryType } from "../enums/directoryType";
import { GroupEntry } from "../models/groupEntry";
import { SyncConfiguration } from "../models/syncConfiguration";
import { UserEntry } from "../models/userEntry";
import { AzureDirectoryService } from "./azure-directory.service"; import { AzureDirectoryService } from "./azure-directory.service";
import { IDirectoryService } from "./directory.service"; import { IDirectoryService } from "./directory.service";
import { GSuiteDirectoryService } from "./gsuite-directory.service"; import { GSuiteDirectoryService } from "./gsuite-directory.service";
@@ -23,6 +22,7 @@ import { LdapDirectoryService } from "./ldap-directory.service";
import { OktaDirectoryService } from "./okta-directory.service"; import { OktaDirectoryService } from "./okta-directory.service";
import { OneLoginDirectoryService } from "./onelogin-directory.service"; import { OneLoginDirectoryService } from "./onelogin-directory.service";
@Injectable()
export class SyncService { export class SyncService {
private dirType: DirectoryType; private dirType: DirectoryType;
@@ -137,6 +137,10 @@ export class SyncService {
} }
private removeDuplicateUsers(users: UserEntry[]) { private removeDuplicateUsers(users: UserEntry[]) {
if (users == null) {
return null;
}
const uniqueUsers = new Array<UserEntry>(); const uniqueUsers = new Array<UserEntry>();
const processedActiveUsers = new Map<string, string>(); const processedActiveUsers = new Map<string, string>();
const processedDeletedUsers = new Map<string, string>(); const processedDeletedUsers = new Map<string, string>();
@@ -219,7 +223,7 @@ export class SyncService {
users: UserEntry[], users: UserEntry[],
removeDisabled: boolean, removeDisabled: boolean,
overwriteExisting: boolean, overwriteExisting: boolean,
largeImport: boolean = false largeImport = false
) { ) {
return new OrganizationImportRequest({ return new OrganizationImportRequest({
groups: (groups ?? []).map((g) => { groups: (groups ?? []).map((g) => {

View File

@@ -1,12 +1,11 @@
import { I18nService } from "jslib-common/abstractions/i18n.service"; import { I18nService } from "jslib-common/abstractions/i18n.service";
import { SyncService } from "./services/sync.service";
import { Entry } from "./models/entry"; import { Entry } from "./models/entry";
import { LdapConfiguration } from "./models/ldapConfiguration"; import { LdapConfiguration } from "./models/ldapConfiguration";
import { SimResult } from "./models/simResult"; import { SimResult } from "./models/simResult";
import { SyncConfiguration } from "./models/syncConfiguration"; import { SyncConfiguration } from "./models/syncConfiguration";
import { UserEntry } from "./models/userEntry"; import { UserEntry } from "./models/userEntry";
import { SyncService } from "./services/sync.service";
export class ConnectorUtils { export class ConnectorUtils {
static async simulate( static async simulate(
@@ -14,6 +13,7 @@ export class ConnectorUtils {
i18nService: I18nService, i18nService: I18nService,
sinceLast: boolean sinceLast: boolean
): Promise<SimResult> { ): Promise<SimResult> {
// eslint-disable-next-line
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const simResult = new SimResult(); const simResult = new SimResult();
try { try {

View File

@@ -1,67 +0,0 @@
{
"extends": "tslint:recommended",
"rules": {
"align": [true, "statements", "members"],
"ban-types": {
"options": [
["Object", "Avoid using the `Object` type. Did you mean `object`?"],
["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"],
["Number", "Avoid using the `Number` type. Did you mean `number`?"],
["String", "Avoid using the `String` type. Did you mean `string`?"],
["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"]
]
},
"member-access": [true, "no-public"],
"member-ordering": [
true,
{
"order": [
"public-static-field",
"public-static-method",
"protected-static-field",
"protected-static-method",
"private-static-field",
"private-static-method",
"public-instance-field",
"protected-instance-field",
"private-instance-field",
"public-constructor",
"protected-constructor",
"private-constructor",
"public-instance-method",
"protected-instance-method",
"private-instance-method"
]
}
],
"no-empty": [true],
"object-literal-sort-keys": false,
"object-literal-shorthand": [true, "never"],
"prefer-for-of": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-module",
"check-operator",
"check-preblock",
"check-separator",
"check-type"
],
"max-classes-per-file": false,
"ordered-imports": true,
"arrow-parens": [true],
"trailing-comma": [
true,
{
"multiline": {
"objects": "always",
"arrays": "always",
"functions": "ignore",
"typeLiterals": "ignore"
},
"singleline": "never"
}
]
}
}

View File

@@ -1,9 +1,10 @@
const path = require("path"); const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin");
const nodeExternals = require("webpack-node-externals");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const webpack = require("webpack");
const nodeExternals = require("webpack-node-externals");
if (process.env.NODE_ENV == null) { if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = "development"; process.env.NODE_ENV = "development";
@@ -11,11 +12,6 @@ if (process.env.NODE_ENV == null) {
const ENV = (process.env.ENV = process.env.NODE_ENV); const ENV = (process.env.ENV = process.env.NODE_ENV);
const moduleRules = [ const moduleRules = [
{
test: /\.ts$/,
enforce: "pre",
loader: "tslint-loader",
},
{ {
test: /\.ts$/, test: /\.ts$/,
use: "ts-loader", use: "ts-loader",
@@ -43,6 +39,7 @@ const plugins = [
resourceRegExp: /^encoding$/, resourceRegExp: /^encoding$/,
contextRegExp: /node-fetch/, contextRegExp: /node-fetch/,
}), }),
new webpack.NormalModuleReplacementPlugin(/@angular\/core/, "jslib-node/angular-core.noop"),
]; ];
const config = { const config = {

View File

@@ -8,11 +8,6 @@ const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const common = { const common = {
module: { module: {
rules: [ rules: [
{
test: /\.ts$/,
enforce: "pre",
loader: "tslint-loader",
},
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
use: "ts-loader", use: "ts-loader",

View File

@@ -9,18 +9,13 @@ const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const common = { const common = {
module: { module: {
rules: [ rules: [
{
test: /\.ts$/,
enforce: "pre",
loader: "tslint-loader",
},
{ {
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
loader: "@ngtools/webpack", loader: "@ngtools/webpack",
}, },
{ {
test: /\.(jpe?g|png|gif|svg)$/i, test: /\.(jpe?g|png|gif|svg)$/i,
exclude: /.*(fontawesome-webfont)\.svg/, exclude: /.*(bwi-font)\.svg/,
generator: { generator: {
filename: "images/[name][ext]", filename: "images/[name][ext]",
}, },