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

Compare commits

...

64 Commits

Author SHA1 Message Date
Kyle Spearrin
8c8b4da595 no minimize 2018-09-14 15:48:50 -04:00
Kyle Spearrin
1a7536270a bump version 2018-09-14 12:19:16 -04:00
Kyle Spearrin
d92e3c8d7b preserveWhitespaces 2018-09-13 12:04:13 -04:00
Kyle Spearrin
c30aedf491 update jslib 2018-09-12 13:22:54 -04:00
Kyle Spearrin
0e96a462ee update libs and move to webpack 4 2018-09-12 10:17:06 -04:00
Kyle Spearrin
3ef60cb3a0 update jslib 2018-09-11 08:45:46 -04:00
Kyle Spearrin
34b7638e11 trim email also 2018-09-08 08:13:40 -04:00
Kyle Spearrin
63ef932469 dont use group deltas since they do not update on membership changes 2018-09-07 08:41:55 -04:00
Kyle Spearrin
e09163fc72 update lunr 2018-09-03 21:51:37 -04:00
Kyle Spearrin
6a737f6d7d Fix !== null checks 2018-08-30 21:48:17 -04:00
Kyle Spearrin
ccc7b7b213 update jslib 2018-08-29 09:22:37 -04:00
Kyle Spearrin
1e98bc6430 fall back to userPrincipalName in other conditions 2018-08-29 08:49:59 -04:00
Kyle Spearrin
c63a945057 update jslib 2018-08-28 23:17:53 -04:00
Kyle Spearrin
a13d9fa00f add csp 2018-08-28 12:15:12 -04:00
Kyle Spearrin
1518d5eafc update jslib 2018-08-27 23:05:39 -04:00
Kyle Spearrin
c74800fd8c update bootstrap 2018-08-21 15:28:12 -04:00
Kyle Spearrin
9e282efe28 npm audit fix 2018-08-21 15:18:55 -04:00
Kyle Spearrin
26efc9158d ignore notifications service 2018-08-20 22:22:48 -04:00
Kyle Spearrin
e2d3d35d71 update jslib 2018-08-20 17:08:27 -04:00
Kyle Spearrin
c115bf84f0 setUrlsFromStorage on init factory 2018-08-20 17:08:07 -04:00
Kyle Spearrin
5b56d32492 update electron 2018-08-18 21:44:10 -04:00
Kyle Spearrin
2fe294ad8a fix click issue on 2fa provider selection 2018-08-17 08:56:31 -04:00
Kyle Spearrin
1343897fa9 update jslib 2018-08-17 08:32:38 -04:00
Kyle Spearrin
9b2b0e4ea6 update jslib 2018-08-16 15:13:34 -04:00
Kyle Spearrin
489e775b08 update jslib 2018-08-15 09:01:30 -04:00
Kyle Spearrin
0d76a45181 bump version 2018-08-14 21:44:34 -04:00
Kyle Spearrin
4787f9a462 prelogin kdf info 2018-08-14 15:13:44 -04:00
Kyle Spearrin
b228e12c81 update jslib 2018-08-13 23:41:14 -04:00
Kyle Spearrin
0e28100ec6 add papaparse types cause whoknowswhy 2018-08-08 17:00:33 -04:00
Kyle Spearrin
d2c1697144 switch to gulp file to get google fonts 2018-08-08 12:53:09 -04:00
Kyle Spearrin
b924ea8dd1 update packages for node 10 2018-08-08 12:28:32 -04:00
Kyle Spearrin
30936d3ad1 update jslib 2018-08-07 09:26:14 -04:00
Kyle Spearrin
289589dce9 toaster message paragraph styles 2018-08-02 08:48:59 -04:00
Kyle Spearrin
48734b8109 update jslib 2018-07-31 23:49:46 -04:00
Kyle Spearrin
2e69a41943 update jslib 2018-07-31 11:26:33 -04:00
Kyle Spearrin
f414a3ac0a update jslib 2018-07-30 17:08:49 -04:00
Kyle Spearrin
81833b134c update jslib 2018-07-25 14:30:40 -04:00
Kyle Spearrin
5a5b74a0d5 bump version 2018-07-24 15:29:48 -04:00
Kyle Spearrin
5a7a230193 update libs 2018-07-24 15:29:00 -04:00
Jacob
bc5ab6252e Fetch image from bitwarden/brand (#7)
That was the last of them, sorry for all the pull request spams :P
2018-07-19 10:51:35 -04:00
Kyle Spearrin
0e4d5e0973 update jslib 2018-07-18 09:56:19 -04:00
Kyle Spearrin
08e254e34c version bump 2018-07-17 08:49:46 -04:00
Kyle Spearrin
2c20796ea1 make sure entry ids are unique 2018-07-17 08:49:15 -04:00
Kyle Spearrin
8b9d7a7e2e remove sync service ref 2018-07-13 10:51:14 -04:00
Kyle Spearrin
1a0709b02c update jslib 2018-07-13 09:31:32 -04:00
Kyle Spearrin
0f386ee8d2 remember email on login 2018-07-13 09:29:12 -04:00
Kyle Spearrin
c0b41155e9 update jslib 2018-07-09 09:14:46 -04:00
Kyle Spearrin
ddd1165728 dummy module update 2018-07-07 23:57:24 -04:00
Kyle Spearrin
651dbe59c8 update jslib 2018-07-07 23:52:19 -04:00
Kyle Spearrin
aeb6f28f9a update jslib 2018-07-05 14:55:06 -04:00
Kyle Spearrin
012eefad4e update jslib 2018-07-05 14:42:58 -04:00
Kyle Spearrin
b05346d4a3 update jslib 2018-06-30 13:51:32 -04:00
Kyle Spearrin
854e6e84fe ignore jslib importers 2018-06-28 08:07:02 -04:00
Kyle Spearrin
20436bf07d tolowercase all the emails 2018-06-28 07:53:58 -04:00
Kyle Spearrin
4110e4b8cb update jslib 2018-06-13 22:14:28 -04:00
Kyle Spearrin
e179edc2e0 update jslib 2018-06-13 17:15:21 -04:00
Kyle Spearrin
133ef7eb16 load DuoWebSDK as a module 2018-06-11 13:33:03 -04:00
Kyle Spearrin
5a98982fc2 move dummy module into project 2018-06-11 08:54:34 -04:00
Kyle Spearrin
f6e92bf597 bump version 2018-06-08 16:08:12 -04:00
Kyle Spearrin
af4a8d5ae8 update jslib 2018-06-04 12:06:04 -04:00
Kyle Spearrin
c3704bbb67 bump version 2018-06-01 16:42:01 -04:00
Kyle Spearrin
8620f2f80d update jslib 2018-06-01 12:34:11 -04:00
Kyle Spearrin
e0124474cf update jslib 2018-06-01 12:00:58 -04:00
Kyle Spearrin
ac21b78225 Update README.md 2018-06-01 09:32:08 -04:00
29 changed files with 6735 additions and 4839 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ node_modules
npm-debug.log
vwd.webinfo
dist/
css/
*.crx
*.pem
build/

View File

@@ -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>
[![Platforms](https://imgur.com/SLv9paA.png "Windows, macOS, and Linux")](https://help.bitwarden.com/article/directory-sync/#download-and-install)
![Directory Connector](http://imgur.com/I6FjN4j.png "Dashboard")
![Directory Connector](https://raw.githubusercontent.com/bitwarden/brand/master/screenshots/directory-connector-macos.png "Dashboard")
# Build/Run

31
gulpfile.js Normal file
View 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

Submodule jslib updated: e0d5a4d8b7...85587e0672

11089
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -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"
}
}

View File

@@ -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">

View File

@@ -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';
}

View File

@@ -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}}

View File

@@ -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>

View File

@@ -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';

View File

@@ -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
View 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 {
}

View File

@@ -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 });

View File

@@ -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;

View File

@@ -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="">

View File

@@ -1,4 +1,4 @@
import { app, BrowserWindow } from 'electron';
import { app } from 'electron';
import * as path from 'path';
import { MenuMain } from './main/menu.main';

View File

@@ -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"
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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 :

View File

@@ -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;

View File

@@ -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);

View File

@@ -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",

View File

@@ -48,6 +48,7 @@
"check-preblock",
"check-separator",
"check-type"
]
],
"max-classes-per-file": false
}
}

1
webfonts.list Normal file
View 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

View File

@@ -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);

View File

@@ -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);