mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
dca69a5428 | ||
|
|
6b1fa0f50c | ||
|
|
3ab35dc4e0 | ||
|
|
2aa1fc1acb | ||
|
|
e6643fa4cb | ||
|
|
4848dd8502 | ||
|
|
4b08d7b4b2 | ||
|
|
839189c772 | ||
|
|
a06ff45c21 | ||
|
|
c598efcb9f | ||
|
|
878476d195 | ||
|
|
82e599fc13 | ||
|
|
79b76687a0 | ||
|
|
af5349c4cb | ||
|
|
3de35b481e | ||
|
|
008bb308e7 | ||
|
|
9b44fc4a35 |
@@ -14,7 +14,9 @@ Supported directories:
|
||||
|
||||
The application is written using Electron with Angular and installs on Windows, macOS, and Linux distributions.
|
||||
|
||||
<a href="https://bitwarden.com/#download"><img src="https://imgur.com/SLv9paA.png" width="500" height="113"></a>
|
||||
[](https://help.bitwarden.com/article/directory-sync/#download-and-install)
|
||||
|
||||

|
||||
|
||||
# Build/Run
|
||||
|
||||
|
||||
2
jslib
2
jslib
Submodule jslib updated: 9de9c1655c...9df96a3288
1909
package-lock.json
generated
1909
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -110,20 +110,21 @@
|
||||
"@angular/compiler-cli": "5.2.0",
|
||||
"@microsoft/microsoft-graph-types": "^1.2.0",
|
||||
"@ngtools/webpack": "1.10.2",
|
||||
"@types/keytar": "^4.0.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/semver": "5.5.0",
|
||||
"@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": "1.8.4",
|
||||
"electron-builder": "^20.8.1",
|
||||
"electron-rebuild": "1.7.3",
|
||||
"electron-reload": "1.2.2",
|
||||
"electron": "2.0.5",
|
||||
"electron-builder": "^20.25.0",
|
||||
"electron-rebuild": "1.8.1",
|
||||
"electron-reload": "1.2.5",
|
||||
"extract-text-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^1.1.5",
|
||||
"font-awesome": "4.7.0",
|
||||
@@ -160,11 +161,11 @@
|
||||
"bootstrap": "4.1.0",
|
||||
"core-js": "2.4.1",
|
||||
"electron-log": "2.2.14",
|
||||
"electron-store": "1.3.0",
|
||||
"electron-updater": "2.21.4",
|
||||
"electron-updater": "3.0.3",
|
||||
"googleapis": "29.0.0",
|
||||
"keytar": "4.1.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",
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -69,7 +69,9 @@ export class AppComponent implements OnInit {
|
||||
private platformUtilsService: PlatformUtilsService, private ngZone: NgZone,
|
||||
private componentFactoryResolver: ComponentFactoryResolver, private messagingService: MessagingService,
|
||||
private configurationService: ConfigurationService, private syncService: SyncService,
|
||||
private stateService: StateService, private apiService: ApiService) { }
|
||||
private stateService: StateService, private apiService: ApiService) {
|
||||
(window as any).BitwardenToasterService = toasterService;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => {
|
||||
|
||||
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';
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { remote } from 'electron';
|
||||
|
||||
import {
|
||||
APP_INITIALIZER,
|
||||
NgModule,
|
||||
@@ -9,7 +11,6 @@ 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 { ElectronStorageService } from 'jslib/electron/services/electronStorage.service';
|
||||
import { isDev } from 'jslib/electron/utils';
|
||||
|
||||
import { AuthGuardService } from './auth-guard.service';
|
||||
@@ -31,6 +32,7 @@ import { ConstantsService } from 'jslib/services/constants.service';
|
||||
import { ContainerService } from 'jslib/services/container.service';
|
||||
import { CryptoService } from 'jslib/services/crypto.service';
|
||||
import { EnvironmentService } from 'jslib/services/environment.service';
|
||||
import { LowdbStorageService } from 'jslib/services/lowdbStorage.service';
|
||||
import { NodeCryptoFunctionService } from 'jslib/services/nodeCryptoFunction.service';
|
||||
import { StateService } from 'jslib/services/state.service';
|
||||
import { TokenService } from 'jslib/services/token.service';
|
||||
@@ -57,21 +59,21 @@ const stateService = new StateService();
|
||||
const platformUtilsService = new ElectronPlatformUtilsService(i18nService, true);
|
||||
const broadcasterService = new BroadcasterService();
|
||||
const messagingService = new ElectronRendererMessagingService(broadcasterService);
|
||||
const storageService: StorageServiceAbstraction = new ElectronStorageService();
|
||||
const storageService: StorageServiceAbstraction = new LowdbStorageService(null, remote.app.getPath('userData'));
|
||||
const secureStorageService: StorageServiceAbstraction = new ElectronRendererSecureStorageService();
|
||||
const cryptoFunctionService: CryptoFunctionServiceAbstraction = new NodeCryptoFunctionService();
|
||||
const cryptoService = new CryptoService(storageService, secureStorageService, cryptoFunctionService);
|
||||
const appIdService = new AppIdService(storageService);
|
||||
const tokenService = new TokenService(storageService);
|
||||
const apiService = new ApiService(tokenService, platformUtilsService,
|
||||
(expired: boolean) => messagingService.send('logout', { expired: expired }));
|
||||
async (expired: boolean) => messagingService.send('logout', { expired: expired }));
|
||||
const environmentService = new EnvironmentService(apiService, storageService);
|
||||
const userService = new UserService(tokenService, storageService);
|
||||
const containerService = new ContainerService(cryptoService, platformUtilsService);
|
||||
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
||||
i18nService, platformUtilsService, messagingService, false);
|
||||
const configurationService = new ConfigurationService(storageService, secureStorageService);
|
||||
const syncSevrice = new SyncService(configurationService, logService, cryptoFunctionService, apiService,
|
||||
const syncService = new SyncService(configurationService, logService, cryptoFunctionService, apiService,
|
||||
messagingService, i18nService);
|
||||
|
||||
const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService);
|
||||
@@ -134,7 +136,7 @@ export function initFactory(): Function {
|
||||
{ provide: StateServiceAbstraction, useValue: stateService },
|
||||
{ provide: LogServiceAbstraction, useValue: logService },
|
||||
{ provide: ConfigurationService, useValue: configurationService },
|
||||
{ provide: SyncService, useValue: syncSevrice },
|
||||
{ provide: SyncService, useValue: syncService },
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: initFactory,
|
||||
|
||||
@@ -197,17 +197,17 @@
|
||||
<small class="text-muted form-text" *ngIf="directory === directoryType.Okta">{{'ex' | i18n}} exclude:joe@company.com | profile.firstName eq "John"</small>
|
||||
<small class="text-muted form-text" *ngIf="directory === directoryType.GSuite">{{'ex' | i18n}} exclude:joe@company.com | orgName=Engineering</small>
|
||||
</div>
|
||||
<div class="form-group" [hidden]="directory != directoryType.Ldap">
|
||||
<label for="userPath">{{'userPath' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="userPath" name="UserPath" [(ngModel)]="sync.userPath">
|
||||
<small class="text-muted form-text">{{'ex' | i18n}} CN=Users</small>
|
||||
</div>
|
||||
<div [hidden]="directory != directoryType.Ldap || ldap.ad">
|
||||
<div class="form-group">
|
||||
<label for="userObjectClass">{{'userObjectClass' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="userObjectClass" name="UserObjectClass" [(ngModel)]="sync.userObjectClass">
|
||||
<small class="text-muted form-text">{{'ex' | i18n}} inetOrgPerson</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="userPath">{{'userPath' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="userPath" name="UserPath" [(ngModel)]="sync.userPath">
|
||||
<small class="text-muted form-text">{{'ex' | i18n}} CN=Users</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="userEmailAttribute">{{'userEmailAttribute' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="userEmailAttribute" name="UserEmailAttribute" [(ngModel)]="sync.userEmailAttribute">
|
||||
@@ -231,17 +231,18 @@
|
||||
<small class="text-muted form-text" *ngIf="directory === directoryType.Okta">{{'ex' | i18n}} include:Sales,IT | type eq "APP_GROUP"</small>
|
||||
<small class="text-muted form-text" *ngIf="directory === directoryType.GSuite">{{'ex' | i18n}} include:Sales,IT</small>
|
||||
</div>
|
||||
<div class="form-group" [hidden]="directory != directoryType.Ldap">
|
||||
<label for="groupPath">{{'groupPath' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="groupPath" name="GroupPath" [(ngModel)]="sync.groupPath">
|
||||
<small class="text-muted form-text" *ngIf="!ldap.ad">{{'ex' | i18n}} CN=Groups</small>
|
||||
<small class="text-muted form-text" *ngIf="ldap.ad">{{'ex' | i18n}} CN=Users</small>
|
||||
</div>
|
||||
<div [hidden]="directory != directoryType.Ldap || ldap.ad">
|
||||
<div class="form-group">
|
||||
<label for="groupObjectClass">{{'groupObjectClass' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="groupObjectClass" name="GroupObjectClass" [(ngModel)]="sync.groupObjectClass">
|
||||
<small class="text-muted form-text">{{'ex' | i18n}} groupOfUniqueNames</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="groupPath">{{'groupPath' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="groupPath" name="GroupPath" [(ngModel)]="sync.groupPath">
|
||||
<small class="text-muted form-text">{{'ex' | i18n}} CN=Groups</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="groupNameAttribute">{{'groupNameAttribute' | i18n}}</label>
|
||||
<input type="text" class="form-control" id="groupNameAttribute" name="GroupNameAttribute" [(ngModel)]="sync.groupNameAttribute">
|
||||
|
||||
@@ -80,13 +80,18 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
this.sync.creationDateAttribute = 'whenCreated';
|
||||
this.sync.revisionDateAttribute = 'whenChanged';
|
||||
this.sync.emailPrefixAttribute = 'sAMAccountName';
|
||||
this.sync.groupPath = 'CN=Users';
|
||||
this.sync.userPath = 'CN=Users';
|
||||
this.sync.memberAttribute = 'member';
|
||||
this.sync.userObjectClass = 'person';
|
||||
this.sync.groupObjectClass = 'group';
|
||||
this.sync.userEmailAttribute = 'mail';
|
||||
this.sync.groupNameAttribute = 'name';
|
||||
|
||||
if (this.sync.groupPath == null) {
|
||||
this.sync.groupPath = 'CN=Users';
|
||||
}
|
||||
if (this.sync.userPath == null) {
|
||||
this.sync.userPath = 'CN=Users';
|
||||
}
|
||||
}
|
||||
|
||||
if (this.sync.interval != null) {
|
||||
|
||||
@@ -5,10 +5,11 @@ import { MenuMain } from './main/menu.main';
|
||||
import { MessagingMain } from './main/messaging.main';
|
||||
import { I18nService } from './services/i18n.service';
|
||||
|
||||
import { LowdbStorageService } from 'jslib/services/lowdbStorage.service';
|
||||
|
||||
import { KeytarStorageListener } from 'jslib/electron/keytarStorageListener';
|
||||
import { ElectronLogService } from 'jslib/electron/services/electronLog.service';
|
||||
import { ElectronMainMessagingService } from 'jslib/electron/services/electronMainMessaging.service';
|
||||
import { ElectronStorageService } from 'jslib/electron/services/electronStorage.service';
|
||||
import { TrayMain } from 'jslib/electron/tray.main';
|
||||
import { UpdaterMain } from 'jslib/electron/updater.main';
|
||||
import { WindowMain } from 'jslib/electron/window.main';
|
||||
@@ -16,7 +17,7 @@ import { WindowMain } from 'jslib/electron/window.main';
|
||||
export class Main {
|
||||
logService: ElectronLogService;
|
||||
i18nService: I18nService;
|
||||
storageService: ElectronStorageService;
|
||||
storageService: LowdbStorageService;
|
||||
messagingService: ElectronMainMessagingService;
|
||||
keytarStorageListener: KeytarStorageListener;
|
||||
|
||||
@@ -50,7 +51,7 @@ export class Main {
|
||||
|
||||
this.logService = new ElectronLogService(null, app.getPath('userData'));
|
||||
this.i18nService = new I18nService('en', './locales/');
|
||||
this.storageService = new ElectronStorageService();
|
||||
this.storageService = new LowdbStorageService(null, app.getPath('userData'));
|
||||
|
||||
this.windowMain = new WindowMain(this.storageService, 800, 600);
|
||||
this.menuMain = new MenuMain(this);
|
||||
@@ -71,6 +72,7 @@ export class Main {
|
||||
}
|
||||
|
||||
bootstrap() {
|
||||
this.storageService.init();
|
||||
this.keytarStorageListener.init();
|
||||
this.windowMain.init().then(async () => {
|
||||
await this.i18nService.init(app.getLocale());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "bitwarden-directory-connector",
|
||||
"productName": "Bitwarden Directory Connector",
|
||||
"description": "Sync your user directory to your Bitwarden organization.",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.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-store": "1.3.0",
|
||||
"electron-updater": "2.21.4",
|
||||
"keytar": "4.1.0"
|
||||
"electron-updater": "3.0.3",
|
||||
"keytar": "4.2.1",
|
||||
"lowdb": "1.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +128,11 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
entry.referenceId = user.id;
|
||||
entry.externalId = user.id;
|
||||
entry.email = user.mail || user.userPrincipalName;
|
||||
|
||||
if (entry.email != null) {
|
||||
entry.email = entry.email.toLowerCase();
|
||||
}
|
||||
|
||||
entry.disabled = user.accountEnabled == null ? false : !user.accountEnabled;
|
||||
|
||||
if ((user as any)['@removed'] != null && (user as any)['@removed'].reason === 'changed') {
|
||||
@@ -134,6 +144,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
|
||||
private async getGroups(force: boolean, saveDelta: boolean,
|
||||
setFilter: [boolean, Set<string>]): Promise<GroupEntry[]> {
|
||||
const entryIds = new Set<string>();
|
||||
const entries: GroupEntry[] = [];
|
||||
const changedGroupIds: string[] = [];
|
||||
const token = await this.configurationService.getGroupDeltaToken();
|
||||
@@ -161,12 +172,16 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
if (groups != null) {
|
||||
for (const group of groups) {
|
||||
if (getFullResults) {
|
||||
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);
|
||||
} else {
|
||||
changedGroupIds.push(group.id);
|
||||
}
|
||||
@@ -197,12 +212,16 @@ export class AzureDirectoryService extends BaseDirectoryService implements Direc
|
||||
const allGroups: graphType.Group[] = res.value;
|
||||
if (allGroups != null) {
|
||||
for (const group of allGroups) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,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.toLowerCase() : null;
|
||||
entry.disabled = user.suspended || false;
|
||||
entry.deleted = deleted;
|
||||
return entry;
|
||||
|
||||
@@ -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.toLowerCase();
|
||||
}
|
||||
|
||||
if (!user.deleted && (user.email == null || user.email.trim() === '')) {
|
||||
return 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.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);
|
||||
}
|
||||
@@ -85,7 +81,7 @@ export class SyncService {
|
||||
throw new Error('Organization not set.');
|
||||
}
|
||||
|
||||
const res = await this.apiService.postImportDirectory(orgId, req);
|
||||
await this.apiService.postImportDirectory(orgId, req);
|
||||
await this.configurationService.saveLastSyncHash(hash);
|
||||
} else {
|
||||
groups = null;
|
||||
@@ -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.toLowerCase();
|
||||
}
|
||||
iu.externalId = u.externalId;
|
||||
iu.deleted = u.deleted || (removeDisabled && u.disabled);
|
||||
model.users.push(iu);
|
||||
|
||||
@@ -11,11 +11,21 @@
|
||||
"types": [],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"jslib/*": [ "jslib/src/*" ],
|
||||
"@angular/*": [ "node_modules/@angular/*" ],
|
||||
"angular2-toaster": [ "node_modules/angular2-toaster" ],
|
||||
"angulartics2": [ "node_modules/angulartics2" ],
|
||||
"electron": [ "node_modules/electron" ]
|
||||
"jslib/*": [
|
||||
"jslib/src/*"
|
||||
],
|
||||
"@angular/*": [
|
||||
"node_modules/@angular/*"
|
||||
],
|
||||
"angular2-toaster": [
|
||||
"node_modules/angular2-toaster"
|
||||
],
|
||||
"angulartics2": [
|
||||
"node_modules/angulartics2"
|
||||
],
|
||||
"electron": [
|
||||
"node_modules/electron"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
@@ -23,7 +33,10 @@
|
||||
"jslib/node_modules",
|
||||
"jslib/src/services/webCryptoFunction.service.ts",
|
||||
"jslib/src/services/search.service.ts",
|
||||
"jslib/src/services/nodeApi.service.ts",
|
||||
"jslib/src/services/export.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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user