mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c8b4da595 | ||
|
|
1a7536270a | ||
|
|
d92e3c8d7b | ||
|
|
c30aedf491 | ||
|
|
0e96a462ee | ||
|
|
3ef60cb3a0 | ||
|
|
34b7638e11 | ||
|
|
63ef932469 | ||
|
|
e09163fc72 | ||
|
|
6a737f6d7d | ||
|
|
ccc7b7b213 | ||
|
|
1e98bc6430 | ||
|
|
c63a945057 | ||
|
|
a13d9fa00f | ||
|
|
1518d5eafc | ||
|
|
c74800fd8c | ||
|
|
9e282efe28 | ||
|
|
26efc9158d | ||
|
|
e2d3d35d71 | ||
|
|
c115bf84f0 | ||
|
|
5b56d32492 | ||
|
|
2fe294ad8a | ||
|
|
1343897fa9 | ||
|
|
9b2b0e4ea6 | ||
|
|
489e775b08 | ||
|
|
0d76a45181 | ||
|
|
4787f9a462 | ||
|
|
b228e12c81 | ||
|
|
0e28100ec6 | ||
|
|
d2c1697144 | ||
|
|
b924ea8dd1 | ||
|
|
30936d3ad1 | ||
|
|
289589dce9 | ||
|
|
48734b8109 | ||
|
|
2e69a41943 | ||
|
|
f414a3ac0a | ||
|
|
81833b134c | ||
|
|
5a5b74a0d5 | ||
|
|
5a7a230193 | ||
|
|
bc5ab6252e | ||
|
|
0e4d5e0973 | ||
|
|
08e254e34c | ||
|
|
2c20796ea1 | ||
|
|
8b9d7a7e2e | ||
|
|
1a0709b02c | ||
|
|
0f386ee8d2 | ||
|
|
c0b41155e9 | ||
|
|
ddd1165728 | ||
|
|
651dbe59c8 | ||
|
|
aeb6f28f9a | ||
|
|
012eefad4e | ||
|
|
b05346d4a3 | ||
|
|
854e6e84fe | ||
|
|
20436bf07d | ||
|
|
4110e4b8cb | ||
|
|
e179edc2e0 | ||
|
|
133ef7eb16 | ||
|
|
5a98982fc2 | ||
|
|
f6e92bf597 | ||
|
|
af4a8d5ae8 | ||
|
|
c3704bbb67 | ||
|
|
8620f2f80d | ||
|
|
e0124474cf | ||
|
|
ac21b78225 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ node_modules
|
||||
npm-debug.log
|
||||
vwd.webinfo
|
||||
dist/
|
||||
css/
|
||||
*.crx
|
||||
*.pem
|
||||
build/
|
||||
|
||||
@@ -14,9 +14,9 @@ Supported directories:
|
||||
|
||||
The application is written using Electron with Angular and installs on Windows, macOS, and Linux distributions.
|
||||
|
||||
<a href="https://help.bitwarden.com/article/directory-sync/#download-and-install"><img src="https://imgur.com/SLv9paA.png" width="500" height="113"></a>
|
||||
[](https://help.bitwarden.com/article/directory-sync/#download-and-install)
|
||||
|
||||

|
||||

|
||||
|
||||
# Build/Run
|
||||
|
||||
|
||||
31
gulpfile.js
Normal file
31
gulpfile.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const gulp = require('gulp');
|
||||
const googleWebFonts = require('gulp-google-webfonts');
|
||||
const del = require('del');
|
||||
|
||||
const paths = {
|
||||
cssDir: './src/css/',
|
||||
};
|
||||
|
||||
function clean() {
|
||||
return del([paths.cssDir]);
|
||||
}
|
||||
|
||||
function webfonts() {
|
||||
return gulp.src('./webfonts.list')
|
||||
.pipe(googleWebFonts({
|
||||
fontsDir: 'webfonts',
|
||||
cssFilename: 'webfonts.css',
|
||||
format: 'woff',
|
||||
}))
|
||||
.pipe(gulp.dest(paths.cssDir));
|
||||
}
|
||||
|
||||
// ref: https://github.com/angular/angular/issues/22524
|
||||
function cleanupAotIssue() {
|
||||
return del(['./node_modules/@types/uglify-js/node_modules/source-map/source-map.d.ts']);
|
||||
}
|
||||
|
||||
gulp.task('clean', clean);
|
||||
gulp.task('cleanupAotIssue', cleanupAotIssue);
|
||||
gulp.task('webfonts', ['clean'], webfonts);
|
||||
gulp.task('prebuild:renderer', ['webfonts', 'cleanupAotIssue']);
|
||||
2
jslib
2
jslib
Submodule jslib updated: e0d5a4d8b7...85587e0672
11089
package-lock.json
generated
11089
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
117
package.json
117
package.json
@@ -26,8 +26,8 @@
|
||||
"lint:fix": "tslint src/**/*.ts --fix",
|
||||
"build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"",
|
||||
"build:main": "webpack --config webpack.main.js",
|
||||
"build:renderer": "webpack --config webpack.renderer.js",
|
||||
"build:renderer:watch": "webpack --config webpack.renderer.js --watch",
|
||||
"build:renderer": "gulp prebuild:renderer && webpack --config webpack.renderer.js",
|
||||
"build:renderer:watch": "gulp prebuild:renderer && webpack --config webpack.renderer.js --watch",
|
||||
"electron": "npm run build:main && concurrently -k -n Main,Rend -c yellow,cyan \"electron --inspect=5858 ./build --watch\" \"npm run build:renderer:watch\"",
|
||||
"clean:dist": "rimraf ./dist/*",
|
||||
"pack:lin": "npm run clean:dist && build --linux --x64 -p never",
|
||||
@@ -107,68 +107,73 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/compiler-cli": "5.2.0",
|
||||
"@microsoft/microsoft-graph-types": "^1.2.0",
|
||||
"@ngtools/webpack": "1.10.2",
|
||||
"@types/keytar": "^4.0.1",
|
||||
"@angular/compiler-cli": "^6.1.7",
|
||||
"@microsoft/microsoft-graph-types": "^1.4.0",
|
||||
"@ngtools/webpack": "^6.2.1",
|
||||
"@types/ldapjs": "^1.0.3",
|
||||
"@types/lowdb": "^1.0.1",
|
||||
"@types/lunr": "2.1.5",
|
||||
"@types/node": "8.0.19",
|
||||
"@types/node-forge": "0.7.1",
|
||||
"@types/webcrypto": "0.0.28",
|
||||
"clean-webpack-plugin": "^0.1.17",
|
||||
"concurrently": "3.5.1",
|
||||
"copy-webpack-plugin": "^4.2.0",
|
||||
"css-loader": "^0.28.7",
|
||||
"electron": "2.0.2",
|
||||
"electron-builder": "^20.8.1",
|
||||
"electron-rebuild": "1.7.3",
|
||||
"electron-reload": "1.2.2",
|
||||
"extract-text-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"@types/lowdb": "^1.0.5",
|
||||
"@types/lunr": "^2.1.6",
|
||||
"@types/node-forge": "^0.7.5",
|
||||
"@types/papaparse": "^4.5.3",
|
||||
"@types/semver": "^5.5.0",
|
||||
"@types/source-map": "0.5.2",
|
||||
"@types/webcrypto": "^0.0.28",
|
||||
"@types/webpack": "^4.4.11",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"concurrently": "^4.0.1",
|
||||
"copy-webpack-plugin": "^4.5.2",
|
||||
"css-loader": "^1.0.0",
|
||||
"del": "^3.0.0",
|
||||
"electron": "2.0.7",
|
||||
"electron-builder": "^20.25.0",
|
||||
"electron-rebuild": "1.8.1",
|
||||
"electron-reload": "1.2.5",
|
||||
"extract-text-webpack-plugin": "next",
|
||||
"file-loader": "^2.0.0",
|
||||
"font-awesome": "4.7.0",
|
||||
"google-fonts-webpack-plugin": "^0.4.4",
|
||||
"html-loader": "^0.5.1",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-google-webfonts": "^2.0.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"node-loader": "^0.6.0",
|
||||
"node-sass": "^4.7.2",
|
||||
"node-sass": "^4.9.3",
|
||||
"rimraf": "^2.6.2",
|
||||
"sass-loader": "^6.0.6",
|
||||
"ts-loader": "^3.5.0",
|
||||
"tslint": "^5.9.1",
|
||||
"tslint-loader": "^3.5.3",
|
||||
"typescript": "^2.7.1",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-merge": "^4.1.0",
|
||||
"webpack-node-externals": "^1.6.0"
|
||||
"sass-loader": "^7.1.0",
|
||||
"ts-loader": "^5.1.0",
|
||||
"tslint": "^5.11.0",
|
||||
"tslint-loader": "^3.6.0",
|
||||
"typescript": "^2.7.2",
|
||||
"webpack": "^4.18.0",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-merge": "^4.1.4",
|
||||
"webpack-node-externals": "^1.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "5.2.0",
|
||||
"@angular/common": "5.2.0",
|
||||
"@angular/compiler": "5.2.0",
|
||||
"@angular/core": "5.2.0",
|
||||
"@angular/forms": "5.2.0",
|
||||
"@angular/http": "5.2.0",
|
||||
"@angular/platform-browser": "5.2.0",
|
||||
"@angular/platform-browser-dynamic": "5.2.0",
|
||||
"@angular/router": "5.2.0",
|
||||
"@angular/upgrade": "5.2.0",
|
||||
"@microsoft/microsoft-graph-client": "1.0.0",
|
||||
"@okta/okta-sdk-nodejs": "1.1.0",
|
||||
"angular2-toaster": "4.0.2",
|
||||
"angulartics2": "5.0.1",
|
||||
"bootstrap": "4.1.0",
|
||||
"core-js": "2.4.1",
|
||||
"@angular/animations": "6.1.7",
|
||||
"@angular/common": "6.1.7",
|
||||
"@angular/compiler": "6.1.7",
|
||||
"@angular/core": "6.1.7",
|
||||
"@angular/forms": "6.1.7",
|
||||
"@angular/http": "6.1.7",
|
||||
"@angular/platform-browser": "6.1.7",
|
||||
"@angular/platform-browser-dynamic": "6.1.7",
|
||||
"@angular/router": "6.1.7",
|
||||
"@angular/upgrade": "6.1.7",
|
||||
"@microsoft/microsoft-graph-client": "1.2.0",
|
||||
"@okta/okta-sdk-nodejs": "1.2.0",
|
||||
"angular2-toaster": "6.1.0",
|
||||
"angulartics2": "6.3.0",
|
||||
"bootstrap": "4.1.3",
|
||||
"core-js": "2.5.7",
|
||||
"electron-log": "2.2.14",
|
||||
"electron-updater": "2.21.4",
|
||||
"googleapis": "29.0.0",
|
||||
"keytar": "4.1.0",
|
||||
"electron-updater": "3.0.3",
|
||||
"googleapis": "33.0.0",
|
||||
"keytar": "4.2.1",
|
||||
"ldapjs": "1.0.2",
|
||||
"lowdb": "1.0.0",
|
||||
"lunr": "2.1.6",
|
||||
"node-forge": "0.7.1",
|
||||
"rxjs": "5.5.6",
|
||||
"zone.js": "0.8.19"
|
||||
"lunr": "2.3.3",
|
||||
"node-forge": "0.7.6",
|
||||
"rxjs": "6.3.2",
|
||||
"zone.js": "0.8.26"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label for="email">{{'emailAddress' | i18n}}</label>
|
||||
<input id="email" type="text" name="Email" [(ngModel)]="email" class="form-control" appAutoFocus>
|
||||
<input id="email" type="text" name="Email" [(ngModel)]="email" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row-main">
|
||||
|
||||
@@ -13,7 +13,7 @@ import { EnvironmentComponent } from './environment.component';
|
||||
|
||||
import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from 'jslib/angular/components/login.component';
|
||||
import { ModalComponent } from 'jslib/angular/components/modal.component';
|
||||
@@ -27,8 +27,9 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
|
||||
constructor(authService: AuthService, router: Router,
|
||||
analytics: Angulartics2, toasterService: ToasterService,
|
||||
i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver) {
|
||||
super(authService, router, analytics, toasterService, i18nService);
|
||||
i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
|
||||
storageService: StorageService) {
|
||||
super(authService, router, analytics, toasterService, i18nService, storageService);
|
||||
super.successRoute = '/tabs/dashboard';
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p *ngFor="let p of providers">
|
||||
<a href="#" (click)="choose(p)">
|
||||
<a href="#" appStopClick (click)="choose(p)">
|
||||
<strong>{{p.name}}</strong>
|
||||
</a>
|
||||
<br /> {{p.description}}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</ng-container>
|
||||
<ng-container *ngIf="selectedProviderType === providerType.Yubikey">
|
||||
<p>{{'insertYubiKey' | i18n}}</p>
|
||||
<img src="../../images/yubikey.jpg" alt="">
|
||||
<p><img src="../../images/yubikey.jpg" class="img-fluid rounded" alt=""></p>
|
||||
<div class="form-group">
|
||||
<label for="code">{{'verificationCode' | i18n}}</label>
|
||||
<input id="code" type="password" name="Code" [(ngModel)]="token" appAutofocus class="form-control">
|
||||
@@ -31,7 +31,7 @@
|
||||
<iframe id="duo_iframe"></iframe>
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="form-group" *ngIf="selectedProviderType !== null && selectedProviderType !== providerType.U2f">
|
||||
<div class="form-group" *ngIf="selectedProviderType != null && selectedProviderType !== providerType.U2f">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="remember" [(ngModel)]="remember" name="Remember">
|
||||
<label class="form-check-label" for="remember">{{'rememberMe' | i18n}}</label>
|
||||
|
||||
@@ -19,7 +19,6 @@ import { AuthService } from 'jslib/abstractions/auth.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { SyncService } from 'jslib/abstractions/sync.service';
|
||||
|
||||
import { ModalComponent } from 'jslib/angular/components/modal.component';
|
||||
import { TwoFactorComponent as BaseTwoFactorComponent } from 'jslib/angular/components/two-factor.component';
|
||||
|
||||
@@ -50,7 +50,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
clearQueryParams: true,
|
||||
},
|
||||
}),
|
||||
ToasterModule,
|
||||
ToasterModule.forRoot(),
|
||||
],
|
||||
declarations: [
|
||||
ApiActionDirective,
|
||||
|
||||
16
src/app/dummy.module.ts
Normal file
16
src/app/dummy.module.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { InputVerbatimDirective } from 'jslib/angular/directives/input-verbatim.directive';
|
||||
import { TrueFalseValueDirective } from 'jslib/angular/directives/true-false-value.directive';
|
||||
import { SearchPipe } from 'jslib/angular/pipes/search.pipe';
|
||||
|
||||
@NgModule({
|
||||
imports: [],
|
||||
declarations: [
|
||||
InputVerbatimDirective,
|
||||
TrueFalseValueDirective,
|
||||
SearchPipe,
|
||||
],
|
||||
})
|
||||
export class DummyModule {
|
||||
}
|
||||
@@ -5,8 +5,6 @@ import { isDev } from 'jslib/electron/utils';
|
||||
|
||||
// tslint:disable-next-line
|
||||
require('../scss/styles.scss');
|
||||
// tslint:disable-next-line
|
||||
require('../../jslib/src/misc/duo.js');
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
@@ -14,4 +12,4 @@ if (!isDev()) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
platformBrowserDynamic().bootstrapModule(AppModule, { preserveWhitespaces: true });
|
||||
|
||||
@@ -67,7 +67,7 @@ const appIdService = new AppIdService(storageService);
|
||||
const tokenService = new TokenService(storageService);
|
||||
const apiService = new ApiService(tokenService, platformUtilsService,
|
||||
async (expired: boolean) => messagingService.send('logout', { expired: expired }));
|
||||
const environmentService = new EnvironmentService(apiService, storageService);
|
||||
const environmentService = new EnvironmentService(apiService, storageService, null);
|
||||
const userService = new UserService(tokenService, storageService);
|
||||
const containerService = new ContainerService(cryptoService, platformUtilsService);
|
||||
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
||||
@@ -78,12 +78,10 @@ const syncService = new SyncService(configurationService, logService, cryptoFunc
|
||||
|
||||
const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService);
|
||||
containerService.attachToWindow(window);
|
||||
environmentService.setUrlsFromStorage().then(() => {
|
||||
// Do nothing
|
||||
});
|
||||
|
||||
export function initFactory(): Function {
|
||||
return async () => {
|
||||
await environmentService.setUrlsFromStorage();
|
||||
await i18nService.init();
|
||||
await authService.init();
|
||||
const htmlEl = window.document.documentElement;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: *; child-src *; frame-src *; connect-src *;">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Bitwarden Directory Connector</title>
|
||||
<base href="">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import { app } from 'electron';
|
||||
import * as path from 'path';
|
||||
|
||||
import { MenuMain } from './main/menu.main';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "bitwarden-directory-connector",
|
||||
"productName": "Bitwarden Directory Connector",
|
||||
"description": "Sync your user directory to your Bitwarden organization.",
|
||||
"version": "2.0.2",
|
||||
"version": "2.3.0",
|
||||
"author": "8bit Solutions LLC <hello@bitwarden.com> (https://bitwarden.com)",
|
||||
"homepage": "https://bitwarden.com",
|
||||
"license": "GPL-3.0",
|
||||
@@ -13,8 +13,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"electron-log": "2.2.14",
|
||||
"electron-updater": "2.21.4",
|
||||
"keytar": "4.1.0",
|
||||
"electron-updater": "3.0.3",
|
||||
"keytar": "4.2.1",
|
||||
"lowdb": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,16 @@ $fa-font-path: "~font-awesome/fonts";
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toast-message {
|
||||
p {
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.toast-danger, &.toast-error {
|
||||
background-image: none !important;
|
||||
background-color: $danger;
|
||||
|
||||
@@ -59,7 +59,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
let groups: GroupEntry[];
|
||||
if (this.syncConfig.groups) {
|
||||
const setFilter = this.createCustomSet(this.syncConfig.groupFilter);
|
||||
groups = await this.getGroups(this.forceGroup(force, users), !test, setFilter);
|
||||
groups = await this.getGroups(setFilter);
|
||||
users = this.filterUsersFromGroupsSet(users, groups, setFilter);
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
}
|
||||
|
||||
private async getUsers(force: boolean, saveDelta: boolean): Promise<UserEntry[]> {
|
||||
const entryIds = new Set<string>();
|
||||
const entries: UserEntry[] = [];
|
||||
|
||||
let res: any = null;
|
||||
@@ -90,6 +91,9 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
const users: graphType.User[] = res.value;
|
||||
if (users != null) {
|
||||
for (const user of users) {
|
||||
if (user.id == null || entryIds.has(user.id)) {
|
||||
continue;
|
||||
}
|
||||
const entry = this.buildUser(user);
|
||||
if (this.filterOutResult(setFilter, entry.email)) {
|
||||
continue;
|
||||
@@ -101,6 +105,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
}
|
||||
|
||||
entries.push(entry);
|
||||
entryIds.add(user.id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +127,17 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
const entry = new UserEntry();
|
||||
entry.referenceId = user.id;
|
||||
entry.externalId = user.id;
|
||||
entry.email = user.mail || user.userPrincipalName;
|
||||
entry.email = user.mail;
|
||||
|
||||
if (user.userPrincipalName && (entry.email == null || entry.email === '' ||
|
||||
entry.email.indexOf('onmicrosoft.com') > -1)) {
|
||||
entry.email = user.userPrincipalName;
|
||||
}
|
||||
|
||||
if (entry.email != null) {
|
||||
entry.email = entry.email.trim().toLowerCase();
|
||||
}
|
||||
|
||||
entry.disabled = user.accountEnabled == null ? false : !user.accountEnabled;
|
||||
|
||||
if ((user as any)['@removed'] != null && (user as any)['@removed'].reason === 'changed') {
|
||||
@@ -132,77 +147,25 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
return entry;
|
||||
}
|
||||
|
||||
private async getGroups(force: boolean, saveDelta: boolean,
|
||||
setFilter: [boolean, Set<string>]): Promise<GroupEntry[]> {
|
||||
private async getGroups(setFilter: [boolean, Set<string>]): Promise<GroupEntry[]> {
|
||||
const entryIds = new Set<string>();
|
||||
const entries: GroupEntry[] = [];
|
||||
const changedGroupIds: string[] = [];
|
||||
const token = await this.configurationService.getGroupDeltaToken();
|
||||
const getFullResults = token == null || force;
|
||||
let res: any = null;
|
||||
let errored = false;
|
||||
|
||||
try {
|
||||
if (!getFullResults) {
|
||||
try {
|
||||
const deltaReq = this.client.api(token);
|
||||
res = await deltaReq.get();
|
||||
} catch {
|
||||
res = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (res == null) {
|
||||
const groupReq = this.client.api('/groups/delta');
|
||||
res = await groupReq.get();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const groups: graphType.Group[] = res.value;
|
||||
if (groups != null) {
|
||||
for (const group of groups) {
|
||||
if (getFullResults) {
|
||||
if (this.filterOutResult(setFilter, group.displayName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry = await this.buildGroup(group);
|
||||
entries.push(entry);
|
||||
} else {
|
||||
changedGroupIds.push(group.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res[NextLink] == null) {
|
||||
if (res[DeltaLink] != null && saveDelta) {
|
||||
await this.configurationService.saveGroupDeltaToken(res[DeltaLink]);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
const nextReq = this.client.api(res[NextLink]);
|
||||
res = await nextReq.get();
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
errored = true;
|
||||
}
|
||||
|
||||
if (!errored && (getFullResults || changedGroupIds.length === 0)) {
|
||||
return entries;
|
||||
}
|
||||
|
||||
const allGroupsReq = this.client.api('/groups');
|
||||
res = await allGroupsReq.get();
|
||||
const groupsReq = this.client.api('/groups');
|
||||
let res = await groupsReq.get();
|
||||
while (true) {
|
||||
const allGroups: graphType.Group[] = res.value;
|
||||
if (allGroups != null) {
|
||||
for (const group of allGroups) {
|
||||
const groups: graphType.Group[] = res.value;
|
||||
if (groups != null) {
|
||||
for (const group of groups) {
|
||||
if (group.id == null || entryIds.has(group.id)) {
|
||||
continue;
|
||||
}
|
||||
if (this.filterOutResult(setFilter, group.displayName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry = await this.buildGroup(group);
|
||||
entries.push(entry);
|
||||
entryIds.add(group.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { JWT } from 'google-auth-library';
|
||||
import {
|
||||
admin_directory_v1,
|
||||
google,
|
||||
GoogleApis,
|
||||
} from 'googleapis';
|
||||
import {
|
||||
Admin,
|
||||
Schema$Group,
|
||||
Schema$User,
|
||||
} from 'googleapis/build/src/apis/admin/directory_v1';
|
||||
|
||||
import { DirectoryType } from '../enums/directoryType';
|
||||
|
||||
@@ -25,7 +20,7 @@ import { LogService } from 'jslib/abstractions/log.service';
|
||||
|
||||
export class GSuiteDirectoryService extends BaseDirectoryService implements DirectoryService {
|
||||
private client: JWT;
|
||||
private service: Admin;
|
||||
private service: admin_directory_v1.Admin;
|
||||
private authParams: any;
|
||||
private dirConfig: GSuiteConfiguration;
|
||||
private syncConfig: SyncConfiguration;
|
||||
@@ -33,7 +28,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire
|
||||
constructor(private configurationService: ConfigurationService, private logService: LogService,
|
||||
private i18nService: I18nService) {
|
||||
super();
|
||||
this.service = google.admin<Admin>('directory_v1');
|
||||
this.service = google.admin('directory_v1');
|
||||
}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
@@ -117,7 +112,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire
|
||||
return entries;
|
||||
}
|
||||
|
||||
private buildUser(user: Schema$User, deleted: boolean) {
|
||||
private buildUser(user: admin_directory_v1.Schema$User, deleted: boolean) {
|
||||
if ((user.emails == null || user.emails === '') && !deleted) {
|
||||
return null;
|
||||
}
|
||||
@@ -125,7 +120,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire
|
||||
const entry = new UserEntry();
|
||||
entry.referenceId = user.id;
|
||||
entry.externalId = user.id;
|
||||
entry.email = user.primaryEmail;
|
||||
entry.email = user.primaryEmail != null ? user.primaryEmail.trim().toLowerCase() : null;
|
||||
entry.disabled = user.suspended || false;
|
||||
entry.deleted = deleted;
|
||||
return entry;
|
||||
@@ -151,7 +146,7 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements Dire
|
||||
return entries;
|
||||
}
|
||||
|
||||
private async buildGroup(group: Schema$Group) {
|
||||
private async buildGroup(group: admin_directory_v1.Schema$Group) {
|
||||
const entry = new GroupEntry();
|
||||
entry.referenceId = group.id;
|
||||
entry.externalId = group.id;
|
||||
|
||||
@@ -108,10 +108,14 @@ export class LdapDirectoryService implements DirectoryService {
|
||||
this.syncConfig.emailPrefixAttribute != null && this.syncConfig.emailSuffix != null) {
|
||||
const prefixAttr = this.getAttr(searchEntry, this.syncConfig.emailPrefixAttribute);
|
||||
if (prefixAttr != null) {
|
||||
user.email = (prefixAttr + this.syncConfig.emailSuffix).toLowerCase();
|
||||
user.email = prefixAttr + this.syncConfig.emailSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
if (user.email != null) {
|
||||
user.email = user.email.trim().toLowerCase();
|
||||
}
|
||||
|
||||
if (!user.deleted && (user.email == null || user.email.trim() === '')) {
|
||||
return null;
|
||||
}
|
||||
@@ -324,7 +328,7 @@ export class LdapDirectoryService implements DirectoryService {
|
||||
':' + this.dirConfig.port;
|
||||
|
||||
this.client = ldap.createClient({
|
||||
url: url.toLowerCase(),
|
||||
url: url.trim().toLowerCase(),
|
||||
});
|
||||
|
||||
const user = this.dirConfig.username == null || this.dirConfig.username.trim() === '' ? null :
|
||||
|
||||
@@ -104,7 +104,7 @@ export class OktaDirectoryService extends BaseDirectoryService implements Direct
|
||||
const entry = new UserEntry();
|
||||
entry.externalId = user.id;
|
||||
entry.referenceId = user.id;
|
||||
entry.email = user.profile.email;
|
||||
entry.email = user.profile.email != null ? user.profile.email.trim().toLowerCase() : null;
|
||||
entry.deleted = user.status === 'DEPROVISIONED';
|
||||
entry.disabled = user.status === 'SUSPENDED';
|
||||
return entry;
|
||||
|
||||
@@ -13,7 +13,6 @@ import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { LogService } from 'jslib/abstractions/log.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@@ -24,9 +23,6 @@ import { GSuiteDirectoryService } from './gsuite-directory.service';
|
||||
import { LdapDirectoryService } from './ldap-directory.service';
|
||||
import { OktaDirectoryService } from './okta-directory.service';
|
||||
|
||||
const Keys = {
|
||||
};
|
||||
|
||||
export class SyncService {
|
||||
private dirType: DirectoryType;
|
||||
|
||||
@@ -73,7 +69,7 @@ export class SyncService {
|
||||
const reqJson = JSON.stringify(req);
|
||||
|
||||
let hash: string = null;
|
||||
const hashBuf = await this.cryptoFunctionService.hash(this.apiService.baseUrl + reqJson, 'sha256');
|
||||
const hashBuf = await this.cryptoFunctionService.hash(this.apiService.apiBaseUrl + reqJson, 'sha256');
|
||||
if (hashBuf != null) {
|
||||
hash = Utils.fromBufferToB64(hashBuf);
|
||||
}
|
||||
@@ -149,6 +145,9 @@ export class SyncService {
|
||||
for (const u of users) {
|
||||
const iu = new ImportDirectoryRequestUser();
|
||||
iu.email = u.email;
|
||||
if (iu.email != null) {
|
||||
iu.email = iu.email.trim().toLowerCase();
|
||||
}
|
||||
iu.externalId = u.externalId;
|
||||
iu.deleted = u.deleted || (removeDisabled && u.disabled);
|
||||
model.users.push(iu);
|
||||
|
||||
@@ -25,9 +25,15 @@
|
||||
],
|
||||
"electron": [
|
||||
"node_modules/electron"
|
||||
],
|
||||
"node": [
|
||||
"node_modules/@types/node"
|
||||
]
|
||||
}
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"preserveWhitespaces": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"jslib/node_modules",
|
||||
@@ -35,7 +41,9 @@
|
||||
"jslib/src/services/search.service.ts",
|
||||
"jslib/src/services/nodeApi.service.ts",
|
||||
"jslib/src/services/export.service.ts",
|
||||
"jslib/src/services/notifications.service.ts",
|
||||
"jslib/src/angular/components/export.component.ts",
|
||||
"jslib/src/importers",
|
||||
"dist",
|
||||
"jslib/dist",
|
||||
"build",
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"check-preblock",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
],
|
||||
"max-classes-per-file": false
|
||||
}
|
||||
}
|
||||
|
||||
1
webfonts.list
Normal file
1
webfonts.list
Normal file
@@ -0,0 +1 @@
|
||||
Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext
|
||||
@@ -1,5 +1,4 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
@@ -11,48 +10,52 @@ const common = {
|
||||
{
|
||||
test: /\.ts$/,
|
||||
enforce: 'pre',
|
||||
loader: 'tslint-loader'
|
||||
loader: 'tslint-loader',
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules\/(?!(@bitwarden)\/).*/
|
||||
exclude: /node_modules\/(?!(@bitwarden)\/).*/,
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
plugins: [],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {
|
||||
jslib: path.join(__dirname, 'jslib/src')
|
||||
}
|
||||
jslib: path.join(__dirname, 'jslib/src'),
|
||||
},
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.resolve(__dirname, 'build')
|
||||
}
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
},
|
||||
};
|
||||
|
||||
const main = {
|
||||
mode: 'production',
|
||||
target: 'electron-main',
|
||||
node: {
|
||||
__dirname: false,
|
||||
__filename: false
|
||||
__filename: false,
|
||||
},
|
||||
entry: {
|
||||
'main': './src/main.ts'
|
||||
'main': './src/main.ts',
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.node$/,
|
||||
loader: 'node-loader'
|
||||
loader: 'node-loader',
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin([
|
||||
path.resolve(__dirname, 'build/*')
|
||||
path.resolve(__dirname, 'build/*'),
|
||||
]),
|
||||
new CopyWebpackPlugin([
|
||||
'./src/package.json',
|
||||
@@ -60,7 +63,7 @@ const main = {
|
||||
{ from: './src/locales', to: 'locales' },
|
||||
]),
|
||||
],
|
||||
externals: [nodeExternals()]
|
||||
externals: [nodeExternals()],
|
||||
};
|
||||
|
||||
module.exports = merge(common, main);
|
||||
|
||||
@@ -2,21 +2,13 @@ const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const GoogleFontsPlugin = require("google-fonts-webpack-plugin");
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin;
|
||||
|
||||
const isVendorModule = (module) => {
|
||||
if (!module.context) {
|
||||
return false;
|
||||
}
|
||||
return module.context.indexOf('node_modules') !== -1;
|
||||
};
|
||||
|
||||
const extractCss = new ExtractTextPlugin({
|
||||
filename: '[name].css',
|
||||
disable: false,
|
||||
allChunks: true
|
||||
allChunks: true,
|
||||
});
|
||||
|
||||
const common = {
|
||||
@@ -25,11 +17,11 @@ const common = {
|
||||
{
|
||||
test: /\.ts$/,
|
||||
enforce: 'pre',
|
||||
loader: 'tslint-loader'
|
||||
loader: 'tslint-loader',
|
||||
},
|
||||
{
|
||||
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
|
||||
loader: '@ngtools/webpack'
|
||||
loader: '@ngtools/webpack',
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
@@ -39,39 +31,54 @@ const common = {
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'images/',
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
}],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [],
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js', '.json'],
|
||||
alias: {
|
||||
jslib: path.join(__dirname, 'jslib/src')
|
||||
jslib: path.join(__dirname, 'jslib/src'),
|
||||
},
|
||||
symlinks: false,
|
||||
modules: [path.resolve('node_modules')]
|
||||
modules: [path.resolve('node_modules')],
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
path: path.resolve(__dirname, 'build')
|
||||
}
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
},
|
||||
};
|
||||
|
||||
const renderer = {
|
||||
mode: 'production',
|
||||
target: 'electron-renderer',
|
||||
node: {
|
||||
__dirname: false
|
||||
__dirname: false,
|
||||
},
|
||||
entry: {
|
||||
'app/main': './src/app/main.ts'
|
||||
'app/main': './src/app/main.ts',
|
||||
},
|
||||
optimization: {
|
||||
minimize: false,
|
||||
splitChunks: {
|
||||
cacheGroups: {
|
||||
commons: {
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: 'app/vendor',
|
||||
chunks: (chunk) => {
|
||||
return chunk.name === 'app/main';
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
loader: 'html-loader'
|
||||
loader: 'html-loader',
|
||||
},
|
||||
{
|
||||
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
|
||||
@@ -80,9 +87,9 @@ const renderer = {
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/'
|
||||
}
|
||||
}]
|
||||
outputPath: 'fonts/',
|
||||
},
|
||||
}],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
@@ -93,40 +100,27 @@ const renderer = {
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
}
|
||||
},
|
||||
],
|
||||
publicPath: '../'
|
||||
publicPath: '../',
|
||||
})
|
||||
},
|
||||
]
|
||||
// Hide System.import warnings. ref: https://github.com/angular/angular/issues/21560
|
||||
{
|
||||
test: /[\/\\]@angular[\/\\].+\.js$/,
|
||||
parser: { system: true },
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new GoogleFontsPlugin({
|
||||
fonts: [
|
||||
{
|
||||
family: 'Open Sans',
|
||||
variants: ['300', '300italic', '400', '400italic', '600', '600italic',
|
||||
'700', '700italic', '800', '800italic'],
|
||||
subsets: ['cyrillic', 'cyrillic-ext', 'greek', 'greek-ext', 'latin', 'latin-ext']
|
||||
}
|
||||
],
|
||||
formats: ['woff2'],
|
||||
path: 'fonts/',
|
||||
filename: 'css/fonts.css'
|
||||
}),
|
||||
new AngularCompilerPlugin({
|
||||
tsConfigPath: 'tsconfig.json',
|
||||
entryModule: 'src/app/app.module#AppModule',
|
||||
sourceMap: true
|
||||
sourceMap: true,
|
||||
}),
|
||||
// ref: https://github.com/angular/angular/issues/20357
|
||||
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)esm5/,
|
||||
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)fesm5/,
|
||||
path.resolve(__dirname, './src')),
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'app/vendor',
|
||||
chunks: ['app/main'],
|
||||
minChunks: isVendorModule
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/index.html',
|
||||
filename: 'index.html',
|
||||
@@ -137,8 +131,8 @@ const renderer = {
|
||||
include: ['app/main.js']
|
||||
}),
|
||||
new webpack.DefinePlugin({ 'global.GENTLY': false }),
|
||||
extractCss
|
||||
]
|
||||
extractCss,
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = merge(common, renderer);
|
||||
|
||||
Reference in New Issue
Block a user