mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-05 23:53:21 +00:00
[refactor] Implement StateService (#192)
* [refactor(Account Switching)] Implement StateService * [bug] Migration service updates * [bug] Fix organizationId coming in as null * [bug] Use correct storage location * [bug] Fix secure storage issues * [bug] Small fixes * [bug] lint fixes * [bug] Undo comment * [bug] Make method names match super * update jslib * Add index signature to keys * Run prettier * Start dbus * Start dbus a different way * Update build.yml * Add eval * Init keyring as well * Remove eval * Add eval's back * Remove unused import * Remove unnecessary null checks * Change userId to be entityId instead of clientId * Remove config service * lint fixes * Add clientKeys to account Co-authored-by: Robyn MacCallum <robyntmaccallum@gmail.com>
This commit is contained in:
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -98,7 +98,11 @@ jobs:
|
||||
|
||||
- name: Version Test
|
||||
run: |
|
||||
sudo apt install libsecret-1-0
|
||||
sudo apt install libsecret-1-0 dbus-x11 gnome-keyring
|
||||
eval $(dbus-launch --sh-syntax)
|
||||
|
||||
eval $(echo -n "" | /usr/bin/gnome-keyring-daemon --login)
|
||||
eval $(/usr/bin/gnome-keyring-daemon --components=secrets --start)
|
||||
|
||||
mkdir -p test/linux
|
||||
unzip ./dist-cli/bwdc-linux-$_PACKAGE_VERSION.zip -d ./test/linux
|
||||
|
||||
2
jslib
2
jslib
Submodule jslib updated: 8fc3cf50d2...9e26336549
68
src/abstractions/state.service.ts
Normal file
68
src/abstractions/state.service.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
||||
|
||||
import { StorageOptions } from "jslib-common/models/domain/storageOptions";
|
||||
|
||||
import { DirectoryType } from "src/enums/directoryType";
|
||||
|
||||
import { Account } from "src/models/account";
|
||||
import { AzureConfiguration } from "src/models/azureConfiguration";
|
||||
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";
|
||||
import { LdapConfiguration } from "src/models/ldapConfiguration";
|
||||
import { OktaConfiguration } from "src/models/oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "src/models/oneLoginConfiguration";
|
||||
import { SyncConfiguration } from "src/models/syncConfiguration";
|
||||
|
||||
export abstract class StateService extends BaseStateServiceAbstraction<Account> {
|
||||
getDirectory: <IConfiguration>(type: DirectoryType) => Promise<IConfiguration>;
|
||||
setDirectory: (
|
||||
type: DirectoryType,
|
||||
config:
|
||||
| LdapConfiguration
|
||||
| GSuiteConfiguration
|
||||
| AzureConfiguration
|
||||
| OktaConfiguration
|
||||
| OneLoginConfiguration
|
||||
) => Promise<any>;
|
||||
getLdapKey: (options?: StorageOptions) => Promise<string>;
|
||||
setLdapKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getGsuiteKey: (options?: StorageOptions) => Promise<string>;
|
||||
setGsuiteKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getAzureKey: (options?: StorageOptions) => Promise<string>;
|
||||
setAzureKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getOktaKey: (options?: StorageOptions) => Promise<string>;
|
||||
setOktaKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getOneLoginKey: (options?: StorageOptions) => Promise<string>;
|
||||
setOneLoginKey: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getLdapConfiguration: (options?: StorageOptions) => Promise<LdapConfiguration>;
|
||||
setLdapConfiguration: (value: LdapConfiguration, options?: StorageOptions) => Promise<void>;
|
||||
getGsuiteConfiguration: (options?: StorageOptions) => Promise<GSuiteConfiguration>;
|
||||
setGsuiteConfiguration: (value: GSuiteConfiguration, options?: StorageOptions) => Promise<void>;
|
||||
getAzureConfiguration: (options?: StorageOptions) => Promise<AzureConfiguration>;
|
||||
setAzureConfiguration: (value: AzureConfiguration, options?: StorageOptions) => Promise<void>;
|
||||
getOktaConfiguration: (options?: StorageOptions) => Promise<OktaConfiguration>;
|
||||
setOktaConfiguration: (value: OktaConfiguration, options?: StorageOptions) => Promise<void>;
|
||||
getOneLoginConfiguration: (options?: StorageOptions) => Promise<OneLoginConfiguration>;
|
||||
setOneLoginConfiguration: (
|
||||
value: OneLoginConfiguration,
|
||||
options?: StorageOptions
|
||||
) => Promise<void>;
|
||||
getOrganizationId: (options?: StorageOptions) => Promise<string>;
|
||||
setOrganizationId: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getSync: (options?: StorageOptions) => Promise<SyncConfiguration>;
|
||||
setSync: (value: SyncConfiguration, options?: StorageOptions) => Promise<void>;
|
||||
getDirectoryType: (options?: StorageOptions) => Promise<DirectoryType>;
|
||||
setDirectoryType: (value: DirectoryType, options?: StorageOptions) => Promise<void>;
|
||||
getUserDelta: (options?: StorageOptions) => Promise<string>;
|
||||
setUserDelta: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getLastUserSync: (options?: StorageOptions) => Promise<Date>;
|
||||
setLastUserSync: (value: Date, options?: StorageOptions) => Promise<void>;
|
||||
getLastGroupSync: (options?: StorageOptions) => Promise<Date>;
|
||||
setLastGroupSync: (value: Date, options?: StorageOptions) => Promise<void>;
|
||||
getGroupDelta: (options?: StorageOptions) => Promise<string>;
|
||||
setGroupDelta: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getLastSyncHash: (options?: StorageOptions) => Promise<string>;
|
||||
setLastSyncHash: (value: string, options?: StorageOptions) => Promise<void>;
|
||||
getSyncingDir: (options?: StorageOptions) => Promise<boolean>;
|
||||
setSyncingDir: (value: boolean, options?: StorageOptions) => Promise<void>;
|
||||
clearSyncSettings: (syncHashToo: boolean) => Promise<void>;
|
||||
}
|
||||
@@ -1,24 +1,19 @@
|
||||
import {
|
||||
Component,
|
||||
ComponentFactoryResolver,
|
||||
Input,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
} from "@angular/core";
|
||||
import { Component, Input, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { EnvironmentComponent } from "./environment.component";
|
||||
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
import { ModalService } from "jslib-angular/services/modal.service";
|
||||
|
||||
import { HtmlStorageLocation } from "jslib-common/enums/htmlStorageLocation";
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
import { ConfigurationService } from "../../services/configuration.service";
|
||||
|
||||
@Component({
|
||||
selector: "app-apiKey",
|
||||
@@ -36,14 +31,12 @@ export class ApiKeyComponent {
|
||||
|
||||
constructor(
|
||||
private authService: AuthService,
|
||||
private apiKeyService: ApiKeyService,
|
||||
private router: Router,
|
||||
private i18nService: I18nService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private configurationService: ConfigurationService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private modalService: ModalService,
|
||||
private logService: LogService
|
||||
private logService: LogService,
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
async submit() {
|
||||
@@ -85,8 +78,8 @@ export class ApiKeyComponent {
|
||||
try {
|
||||
this.formPromise = this.authService.logInApiKey(this.clientId, this.clientSecret);
|
||||
await this.formPromise;
|
||||
const organizationId = await this.apiKeyService.getEntityId();
|
||||
await this.configurationService.saveOrganizationId(organizationId);
|
||||
const organizationId = await this.stateService.getEntityId();
|
||||
await this.stateService.setOrganizationId(organizationId);
|
||||
this.router.navigate([this.successRoute]);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
|
||||
@@ -16,13 +16,12 @@ import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||
import { UserService } from "jslib-common/abstractions/user.service";
|
||||
|
||||
import { ConfigurationService } from "../services/configuration.service";
|
||||
import { SyncService } from "../services/sync.service";
|
||||
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
const BroadcasterSubscriptionId = "AppComponent";
|
||||
|
||||
@Component({
|
||||
@@ -36,7 +35,6 @@ export class AppComponent implements OnInit {
|
||||
|
||||
constructor(
|
||||
private broadcasterService: BroadcasterService,
|
||||
private userService: UserService,
|
||||
private tokenService: TokenService,
|
||||
private authService: AuthService,
|
||||
private router: Router,
|
||||
@@ -46,7 +44,6 @@ export class AppComponent implements OnInit {
|
||||
private ngZone: NgZone,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private messagingService: MessagingService,
|
||||
private configurationService: ConfigurationService,
|
||||
private syncService: SyncService,
|
||||
private stateService: StateService,
|
||||
private logService: LogService
|
||||
@@ -58,21 +55,21 @@ export class AppComponent implements OnInit {
|
||||
switch (message.command) {
|
||||
case "syncScheduleStarted":
|
||||
case "syncScheduleStopped":
|
||||
this.stateService.save("syncingDir", message.command === "syncScheduleStarted");
|
||||
this.stateService.setSyncingDir(message.command === "syncScheduleStarted");
|
||||
break;
|
||||
case "logout":
|
||||
this.logOut(!!message.expired);
|
||||
break;
|
||||
case "checkDirSync":
|
||||
try {
|
||||
const syncConfig = await this.configurationService.getSync();
|
||||
const syncConfig = await this.stateService.getSync();
|
||||
if (syncConfig.interval == null || syncConfig.interval < 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
const syncInterval = syncConfig.interval * 60000;
|
||||
const lastGroupSync = await this.configurationService.getLastGroupSyncDate();
|
||||
const lastUserSync = await this.configurationService.getLastUserSyncDate();
|
||||
const lastGroupSync = await this.stateService.getLastGroupSync();
|
||||
const lastUserSync = await this.stateService.getLastUserSync();
|
||||
let lastSync: Date = null;
|
||||
if (lastGroupSync != null && lastUserSync == null) {
|
||||
lastSync = lastGroupSync;
|
||||
@@ -119,10 +116,8 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async logOut(expired: boolean) {
|
||||
const userId = await this.userService.getUserId();
|
||||
|
||||
await this.tokenService.clearToken();
|
||||
await this.userService.clear();
|
||||
await this.stateService.clean();
|
||||
|
||||
this.authService.logOut(async () => {
|
||||
if (expired) {
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { CanActivate, Router } from "@angular/router";
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { CanActivate } from "@angular/router";
|
||||
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuardService implements CanActivate {
|
||||
constructor(
|
||||
private apiKeyService: ApiKeyService,
|
||||
private router: Router,
|
||||
private messagingService: MessagingService
|
||||
) {}
|
||||
constructor(private stateService: StateService, private messagingService: MessagingService) {}
|
||||
|
||||
async canActivate() {
|
||||
const isAuthed = await this.apiKeyService.isAuthenticated();
|
||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
||||
if (!isAuthed) {
|
||||
this.messagingService.send("logout");
|
||||
return false;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { CanActivate, Router } from "@angular/router";
|
||||
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
@Injectable()
|
||||
export class LaunchGuardService implements CanActivate {
|
||||
constructor(private apiKeyService: ApiKeyService, private router: Router) {}
|
||||
constructor(private stateService: StateService, private router: Router) {}
|
||||
|
||||
async canActivate() {
|
||||
const isAuthed = await this.apiKeyService.isAuthenticated();
|
||||
const isAuthed = await this.stateService.getIsAuthenticated();
|
||||
if (!isAuthed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,23 +9,16 @@ import { ElectronRendererStorageService } from "jslib-electron/services/electron
|
||||
import { AuthGuardService } from "./auth-guard.service";
|
||||
import { LaunchGuardService } from "./launch-guard.service";
|
||||
|
||||
import { ConfigurationService } from "../../services/configuration.service";
|
||||
import { I18nService } from "../../services/i18n.service";
|
||||
import { SyncService } from "../../services/sync.service";
|
||||
|
||||
import { BroadcasterService } from "jslib-angular/services/broadcaster.service";
|
||||
import { JslibServicesModule } from "jslib-angular/services/jslib-services.module";
|
||||
import { ModalService } from "jslib-angular/services/modal.service";
|
||||
import { ValidationService } from "jslib-angular/services/validation.service";
|
||||
|
||||
import { ApiKeyService } from "jslib-common/services/apiKey.service";
|
||||
import { ConstantsService } from "jslib-common/services/constants.service";
|
||||
import { ContainerService } from "jslib-common/services/container.service";
|
||||
|
||||
import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
|
||||
|
||||
import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service";
|
||||
import { ApiKeyService as ApiKeyServiceAbstraction } from "jslib-common/abstractions/apiKey.service";
|
||||
import { AppIdService as AppIdServiceAbstraction } from "jslib-common/abstractions/appId.service";
|
||||
import { AuthService as AuthServiceAbstraction } from "jslib-common/abstractions/auth.service";
|
||||
import { BroadcasterService as BroadcasterServiceAbstraction } from "jslib-common/abstractions/broadcaster.service";
|
||||
@@ -36,23 +29,24 @@ import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from "jslib-common/abstractions/keyConnector.service";
|
||||
import { LogService as LogServiceAbstraction } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service";
|
||||
import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "jslib-common/abstractions/passwordGeneration.service";
|
||||
import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { PolicyService as PolicyServiceAbstraction } from "jslib-common/abstractions/policy.service";
|
||||
import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service";
|
||||
import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service";
|
||||
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||
import { TokenService as TokenServiceAbstraction } from "jslib-common/abstractions/token.service";
|
||||
import { UserService as UserServiceAbstraction } from "jslib-common/abstractions/user.service";
|
||||
import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service";
|
||||
|
||||
import { StateService as StateServiceAbstraction } from "../../abstractions/state.service";
|
||||
|
||||
import { ApiService, refreshToken } from "../../services/api.service";
|
||||
import { AuthService } from "../../services/auth.service";
|
||||
import { StateService } from "../../services/state.service";
|
||||
import { StateMigrationService } from "../../services/stateMigration.service";
|
||||
|
||||
function refreshTokenCallback(injector: Injector) {
|
||||
return () => {
|
||||
const apiKeyService = injector.get(ApiKeyServiceAbstraction);
|
||||
const stateService = injector.get(StateServiceAbstraction);
|
||||
const authService = injector.get(AuthServiceAbstraction);
|
||||
return refreshToken(apiKeyService, authService);
|
||||
return refreshToken(stateService, authService);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -61,13 +55,11 @@ export function initFactory(
|
||||
i18nService: I18nService,
|
||||
authService: AuthService,
|
||||
platformUtilsService: PlatformUtilsServiceAbstraction,
|
||||
storageService: StorageServiceAbstraction,
|
||||
userService: UserServiceAbstraction,
|
||||
apiService: ApiServiceAbstraction,
|
||||
stateService: StateServiceAbstraction,
|
||||
cryptoService: CryptoServiceAbstraction
|
||||
): Function {
|
||||
return async () => {
|
||||
await stateService.init();
|
||||
await environmentService.setUrlsFromStorage();
|
||||
await i18nService.init();
|
||||
authService.init();
|
||||
@@ -77,7 +69,7 @@ export function initFactory(
|
||||
window.document.title = i18nService.t("bitwardenDirectoryConnector");
|
||||
|
||||
let installAction = null;
|
||||
const installedVersion = await storageService.get<string>(ConstantsService.installedVersionKey);
|
||||
const installedVersion = await stateService.getInstalledVersion();
|
||||
const currentVersion = await platformUtilsService.getApplicationVersion();
|
||||
if (installedVersion == null) {
|
||||
installAction = "install";
|
||||
@@ -86,16 +78,9 @@ export function initFactory(
|
||||
}
|
||||
|
||||
if (installAction != null) {
|
||||
await storageService.save(ConstantsService.installedVersionKey, currentVersion);
|
||||
await stateService.setInstalledVersion(currentVersion);
|
||||
}
|
||||
|
||||
window.setTimeout(async () => {
|
||||
if (await userService.isAuthenticated()) {
|
||||
const profile = await apiService.getProfile();
|
||||
stateService.save("profileOrganizations", profile.organizations);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
const containerService = new ContainerService(cryptoService);
|
||||
containerService.attachToWindow(window);
|
||||
};
|
||||
@@ -113,9 +98,6 @@ export function initFactory(
|
||||
I18nServiceAbstraction,
|
||||
AuthServiceAbstraction,
|
||||
PlatformUtilsServiceAbstraction,
|
||||
StorageServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
],
|
||||
@@ -139,15 +121,11 @@ export function initFactory(
|
||||
useFactory: (
|
||||
i18nService: I18nServiceAbstraction,
|
||||
messagingService: MessagingServiceAbstraction,
|
||||
storageService: StorageServiceAbstraction
|
||||
) => new ElectronPlatformUtilsService(i18nService, messagingService, true, storageService),
|
||||
deps: [I18nServiceAbstraction, MessagingServiceAbstraction, StorageServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: CryptoFunctionServiceAbstraction,
|
||||
useClass: NodeCryptoFunctionService,
|
||||
deps: [],
|
||||
stateService: StateServiceAbstraction
|
||||
) => new ElectronPlatformUtilsService(i18nService, messagingService, true, stateService),
|
||||
deps: [I18nServiceAbstraction, MessagingServiceAbstraction, StateServiceAbstraction],
|
||||
},
|
||||
{ provide: CryptoFunctionServiceAbstraction, useClass: NodeCryptoFunctionService, deps: [] },
|
||||
{
|
||||
provide: ApiServiceAbstraction,
|
||||
useFactory: (
|
||||
@@ -172,18 +150,12 @@ export function initFactory(
|
||||
Injector,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: ApiKeyServiceAbstraction,
|
||||
useClass: ApiKeyService,
|
||||
deps: [TokenServiceAbstraction, StorageServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: AuthServiceAbstraction,
|
||||
useClass: AuthService,
|
||||
deps: [
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
UserServiceAbstraction,
|
||||
TokenServiceAbstraction,
|
||||
AppIdServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
@@ -191,32 +163,42 @@ export function initFactory(
|
||||
MessagingServiceAbstraction,
|
||||
VaultTimeoutServiceAbstraction,
|
||||
LogServiceAbstraction,
|
||||
ApiKeyServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
KeyConnectorServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
],
|
||||
},
|
||||
{
|
||||
provide: ConfigurationService,
|
||||
useClass: ConfigurationService,
|
||||
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
||||
},
|
||||
{
|
||||
provide: SyncService,
|
||||
useClass: SyncService,
|
||||
deps: [
|
||||
ConfigurationService,
|
||||
LogServiceAbstraction,
|
||||
CryptoFunctionServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
I18nServiceAbstraction,
|
||||
EnvironmentServiceAbstraction,
|
||||
StateServiceAbstraction,
|
||||
],
|
||||
},
|
||||
AuthGuardService,
|
||||
LaunchGuardService,
|
||||
{
|
||||
provide: StateMigrationServiceAbstraction,
|
||||
useClass: StateMigrationService,
|
||||
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
||||
},
|
||||
{
|
||||
provide: StateServiceAbstraction,
|
||||
useClass: StateService,
|
||||
deps: [
|
||||
StorageServiceAbstraction,
|
||||
"SECURE_STORAGE",
|
||||
LogServiceAbstraction,
|
||||
StateMigrationServiceAbstraction,
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
export class ServicesModule {}
|
||||
|
||||
@@ -4,17 +4,17 @@ import { BroadcasterService } from "jslib-common/abstractions/broadcaster.servic
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
import { SyncService } from "../../services/sync.service";
|
||||
|
||||
import { GroupEntry } from "../../models/groupEntry";
|
||||
import { SimResult } from "../../models/simResult";
|
||||
import { UserEntry } from "../../models/userEntry";
|
||||
import { ConfigurationService } from "../../services/configuration.service";
|
||||
|
||||
import { ConnectorUtils } from "../../utils";
|
||||
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
const BroadcasterSubscriptionId = "DashboardComponent";
|
||||
|
||||
@Component({
|
||||
@@ -38,7 +38,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private syncService: SyncService,
|
||||
private configurationService: ConfigurationService,
|
||||
private broadcasterService: BroadcasterService,
|
||||
private ngZone: NgZone,
|
||||
private messagingService: MessagingService,
|
||||
@@ -62,7 +61,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
});
|
||||
|
||||
this.syncRunning = !!(await this.stateService.get("syncingDir"));
|
||||
this.syncRunning = !!(await this.stateService.getSyncingDir());
|
||||
this.updateLastSync();
|
||||
}
|
||||
|
||||
@@ -122,7 +121,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async updateLastSync() {
|
||||
this.lastGroupSync = await this.configurationService.getLastGroupSyncDate();
|
||||
this.lastUserSync = await this.configurationService.getLastUserSyncDate();
|
||||
this.lastGroupSync = await this.stateService.getLastGroupSync();
|
||||
this.lastUserSync = await this.stateService.getLastUserSync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ChangeDetectorRef, Component, NgZone, OnInit } from "@angular/core";
|
||||
|
||||
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
|
||||
import { ConfigurationService } from "../../services/configuration.service";
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
|
||||
const BroadcasterSubscriptionId = "MoreComponent";
|
||||
|
||||
@@ -22,10 +22,10 @@ export class MoreComponent implements OnInit {
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService,
|
||||
private messagingService: MessagingService,
|
||||
private configurationService: ConfigurationService,
|
||||
private broadcasterService: BroadcasterService,
|
||||
private ngZone: NgZone,
|
||||
private changeDetectorRef: ChangeDetectorRef
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -71,7 +71,7 @@ export class MoreComponent implements OnInit {
|
||||
}
|
||||
|
||||
async clearCache() {
|
||||
await this.configurationService.clearStatefulSettings(true);
|
||||
await this.stateService.clearSyncSettings(true);
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("syncCacheCleared"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,6 @@ import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angula
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StateService } from "jslib-common/abstractions/state.service";
|
||||
|
||||
import { ProfileOrganizationResponse } from "jslib-common/models/response/profileOrganizationResponse";
|
||||
|
||||
import { ConfigurationService } from "../../services/configuration.service";
|
||||
|
||||
import { DirectoryType } from "../../enums/directoryType";
|
||||
|
||||
@@ -17,6 +12,7 @@ import { OktaConfiguration } from "../../models/oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "../../models/oneLoginConfiguration";
|
||||
import { SyncConfiguration } from "../../models/syncConfiguration";
|
||||
|
||||
import { StateService } from "../../abstractions/state.service";
|
||||
import { ConnectorUtils } from "../../utils";
|
||||
|
||||
@Component({
|
||||
@@ -40,14 +36,13 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private configurationService: ConfigurationService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private ngZone: NgZone,
|
||||
private stateService: StateService,
|
||||
private logService: LogService
|
||||
private logService: LogService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
this.directoryOptions = [
|
||||
{ name: i18nService.t("select"), value: null },
|
||||
{ name: this.i18nService.t("select"), value: null },
|
||||
{ name: "Active Directory / LDAP", value: DirectoryType.Ldap },
|
||||
{ name: "Azure Active Directory", value: DirectoryType.AzureActiveDirectory },
|
||||
{ name: "G Suite (Google)", value: DirectoryType.GSuite },
|
||||
@@ -57,25 +52,22 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
this.directory = await this.configurationService.getDirectoryType();
|
||||
this.directory = await this.stateService.getDirectoryType();
|
||||
this.ldap =
|
||||
(await this.configurationService.getDirectory<LdapConfiguration>(DirectoryType.Ldap)) ||
|
||||
this.ldap;
|
||||
(await this.stateService.getDirectory<LdapConfiguration>(DirectoryType.Ldap)) || this.ldap;
|
||||
this.gsuite =
|
||||
(await this.configurationService.getDirectory<GSuiteConfiguration>(DirectoryType.GSuite)) ||
|
||||
(await this.stateService.getDirectory<GSuiteConfiguration>(DirectoryType.GSuite)) ||
|
||||
this.gsuite;
|
||||
this.azure =
|
||||
(await this.configurationService.getDirectory<AzureConfiguration>(
|
||||
(await this.stateService.getDirectory<AzureConfiguration>(
|
||||
DirectoryType.AzureActiveDirectory
|
||||
)) || this.azure;
|
||||
this.okta =
|
||||
(await this.configurationService.getDirectory<OktaConfiguration>(DirectoryType.Okta)) ||
|
||||
this.okta;
|
||||
(await this.stateService.getDirectory<OktaConfiguration>(DirectoryType.Okta)) || this.okta;
|
||||
this.oneLogin =
|
||||
(await this.configurationService.getDirectory<OneLoginConfiguration>(
|
||||
DirectoryType.OneLogin
|
||||
)) || this.oneLogin;
|
||||
this.sync = (await this.configurationService.getSync()) || this.sync;
|
||||
(await this.stateService.getDirectory<OneLoginConfiguration>(DirectoryType.OneLogin)) ||
|
||||
this.oneLogin;
|
||||
this.sync = (await this.stateService.getSync()) || this.sync;
|
||||
}
|
||||
|
||||
async ngOnDestroy() {
|
||||
@@ -87,13 +79,13 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
if (this.ldap != null && this.ldap.ad) {
|
||||
this.ldap.pagedSearch = true;
|
||||
}
|
||||
await this.configurationService.saveDirectoryType(this.directory);
|
||||
await this.configurationService.saveDirectory(DirectoryType.Ldap, this.ldap);
|
||||
await this.configurationService.saveDirectory(DirectoryType.GSuite, this.gsuite);
|
||||
await this.configurationService.saveDirectory(DirectoryType.AzureActiveDirectory, this.azure);
|
||||
await this.configurationService.saveDirectory(DirectoryType.Okta, this.okta);
|
||||
await this.configurationService.saveDirectory(DirectoryType.OneLogin, this.oneLogin);
|
||||
await this.configurationService.saveSync(this.sync);
|
||||
await this.stateService.setDirectoryType(this.directory);
|
||||
await this.stateService.setDirectory(DirectoryType.Ldap, this.ldap);
|
||||
await this.stateService.setDirectory(DirectoryType.GSuite, this.gsuite);
|
||||
await this.stateService.setDirectory(DirectoryType.AzureActiveDirectory, this.azure);
|
||||
await this.stateService.setDirectory(DirectoryType.Okta, this.okta);
|
||||
await this.stateService.setDirectory(DirectoryType.OneLogin, this.oneLogin);
|
||||
await this.stateService.setSync(this.sync);
|
||||
}
|
||||
|
||||
parseKeyFile() {
|
||||
|
||||
157
src/bwdc.ts
157
src/bwdc.ts
@@ -5,22 +5,21 @@ import { LogLevelType } from "jslib-common/enums/logLevelType";
|
||||
|
||||
import { AuthService } from "./services/auth.service";
|
||||
|
||||
import { ConfigurationService } from "./services/configuration.service";
|
||||
import { I18nService } from "./services/i18n.service";
|
||||
import { KeytarSecureStorageService } from "./services/keytarSecureStorage.service";
|
||||
import { LowdbStorageService } from "./services/lowdbStorage.service";
|
||||
import { NodeApiService } from "./services/nodeApi.service";
|
||||
import { StateService } from "./services/state.service";
|
||||
import { StateMigrationService } from "./services/stateMigration.service";
|
||||
import { SyncService } from "./services/sync.service";
|
||||
|
||||
import { CliPlatformUtilsService } from "jslib-node/cli/services/cliPlatformUtils.service";
|
||||
import { ConsoleLogService } from "jslib-node/cli/services/consoleLog.service";
|
||||
import { NodeCryptoFunctionService } from "jslib-node/services/nodeCryptoFunction.service";
|
||||
|
||||
import { ApiKeyService } from "jslib-common/services/apiKey.service";
|
||||
import { AppIdService } from "jslib-common/services/appId.service";
|
||||
import { CipherService } from "jslib-common/services/cipher.service";
|
||||
import { CollectionService } from "jslib-common/services/collection.service";
|
||||
import { ConstantsService } from "jslib-common/services/constants.service";
|
||||
import { ContainerService } from "jslib-common/services/container.service";
|
||||
import { CryptoService } from "jslib-common/services/crypto.service";
|
||||
import { EnvironmentService } from "jslib-common/services/environment.service";
|
||||
@@ -28,14 +27,15 @@ import { FileUploadService } from "jslib-common/services/fileUpload.service";
|
||||
import { FolderService } from "jslib-common/services/folder.service";
|
||||
import { KeyConnectorService } from "jslib-common/services/keyConnector.service";
|
||||
import { NoopMessagingService } from "jslib-common/services/noopMessaging.service";
|
||||
import { OrganizationService } from "jslib-common/services/organization.service";
|
||||
import { PasswordGenerationService } from "jslib-common/services/passwordGeneration.service";
|
||||
import { PolicyService } from "jslib-common/services/policy.service";
|
||||
import { ProviderService } from "jslib-common/services/provider.service";
|
||||
import { SearchService } from "jslib-common/services/search.service";
|
||||
import { SendService } from "jslib-common/services/send.service";
|
||||
import { SettingsService } from "jslib-common/services/settings.service";
|
||||
import { SyncService as LoginSyncService } from "jslib-common/services/sync.service";
|
||||
import { TokenService } from "jslib-common/services/token.service";
|
||||
import { UserService } from "jslib-common/services/user.service";
|
||||
|
||||
import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service";
|
||||
|
||||
@@ -54,18 +54,14 @@ export class Main {
|
||||
secureStorageService: StorageServiceAbstraction;
|
||||
i18nService: I18nService;
|
||||
platformUtilsService: CliPlatformUtilsService;
|
||||
constantsService: ConstantsService;
|
||||
cryptoService: CryptoService;
|
||||
tokenService: TokenService;
|
||||
appIdService: AppIdService;
|
||||
apiService: NodeApiService;
|
||||
environmentService: EnvironmentService;
|
||||
apiKeyService: ApiKeyService;
|
||||
userService: UserService;
|
||||
containerService: ContainerService;
|
||||
cryptoFunctionService: NodeCryptoFunctionService;
|
||||
authService: AuthService;
|
||||
configurationService: ConfigurationService;
|
||||
collectionService: CollectionService;
|
||||
cipherService: CipherService;
|
||||
fileUploadService: FileUploadService;
|
||||
@@ -79,6 +75,10 @@ export class Main {
|
||||
loginSyncService: LoginSyncService;
|
||||
keyConnectorService: KeyConnectorService;
|
||||
program: Program;
|
||||
stateService: StateService;
|
||||
stateMigrationService: StateMigrationService;
|
||||
organizationService: OrganizationService;
|
||||
providerService: ProviderService;
|
||||
|
||||
constructor() {
|
||||
const applicationName = "Bitwarden Directory Connector";
|
||||
@@ -119,22 +119,36 @@ export class Main {
|
||||
this.secureStorageService = plaintextSecrets
|
||||
? this.storageService
|
||||
: new KeytarSecureStorageService(applicationName);
|
||||
this.cryptoService = new CryptoService(
|
||||
|
||||
this.stateMigrationService = new StateMigrationService(
|
||||
this.storageService,
|
||||
this.secureStorageService
|
||||
);
|
||||
|
||||
this.stateService = new StateService(
|
||||
this.storageService,
|
||||
this.secureStorageService,
|
||||
this.logService,
|
||||
this.stateMigrationService,
|
||||
process.env.BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS !== "true"
|
||||
);
|
||||
|
||||
this.cryptoService = new CryptoService(
|
||||
this.cryptoFunctionService,
|
||||
this.platformUtilsService,
|
||||
this.logService
|
||||
this.logService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.appIdService = new AppIdService(this.storageService);
|
||||
this.tokenService = new TokenService(this.storageService);
|
||||
this.tokenService = new TokenService(this.stateService);
|
||||
this.messagingService = new NoopMessagingService();
|
||||
this.environmentService = new EnvironmentService(this.storageService);
|
||||
this.environmentService = new EnvironmentService(this.stateService);
|
||||
this.apiService = new NodeApiService(
|
||||
this.tokenService,
|
||||
this.platformUtilsService,
|
||||
this.environmentService,
|
||||
() => refreshToken(this.apiKeyService, this.authService),
|
||||
() => refreshToken(this.stateService, this.authService),
|
||||
async (expired: boolean) => await this.logout(),
|
||||
"Bitwarden_DC/" +
|
||||
this.platformUtilsService.getApplicationVersion() +
|
||||
@@ -143,21 +157,22 @@ export class Main {
|
||||
")",
|
||||
(clientId, clientSecret) => this.authService.logInApiKey(clientId, clientSecret)
|
||||
);
|
||||
this.apiKeyService = new ApiKeyService(this.tokenService, this.storageService);
|
||||
this.userService = new UserService(this.tokenService, this.storageService);
|
||||
this.containerService = new ContainerService(this.cryptoService);
|
||||
|
||||
this.organizationService = new OrganizationService(this.stateService);
|
||||
|
||||
this.keyConnectorService = new KeyConnectorService(
|
||||
this.storageService,
|
||||
this.userService,
|
||||
this.stateService,
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.tokenService,
|
||||
this.logService
|
||||
this.logService,
|
||||
this.organizationService
|
||||
);
|
||||
|
||||
this.authService = new AuthService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.userService,
|
||||
this.tokenService,
|
||||
this.appIdService,
|
||||
this.i18nService,
|
||||
@@ -165,84 +180,91 @@ export class Main {
|
||||
this.messagingService,
|
||||
null,
|
||||
this.logService,
|
||||
this.apiKeyService,
|
||||
this.cryptoFunctionService,
|
||||
this.environmentService,
|
||||
this.keyConnectorService
|
||||
);
|
||||
this.configurationService = new ConfigurationService(
|
||||
this.storageService,
|
||||
this.secureStorageService,
|
||||
process.env.BITWARDENCLI_CONNECTOR_PLAINTEXT_SECRETS !== "true"
|
||||
this.keyConnectorService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.syncService = new SyncService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.cryptoFunctionService,
|
||||
this.apiService,
|
||||
this.messagingService,
|
||||
this.i18nService,
|
||||
this.environmentService
|
||||
this.environmentService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.policyService = new PolicyService(
|
||||
this.stateService,
|
||||
this.organizationService,
|
||||
this.apiService
|
||||
);
|
||||
|
||||
this.passwordGenerationService = new PasswordGenerationService(
|
||||
this.cryptoService,
|
||||
this.storageService,
|
||||
null
|
||||
this.policyService,
|
||||
this.stateService
|
||||
);
|
||||
this.policyService = new PolicyService(this.userService, this.storageService, this.apiService);
|
||||
this.settingsService = new SettingsService(this.userService, this.storageService);
|
||||
|
||||
this.settingsService = new SettingsService(this.stateService);
|
||||
|
||||
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
|
||||
|
||||
this.cipherService = new CipherService(
|
||||
this.cryptoService,
|
||||
this.userService,
|
||||
this.settingsService,
|
||||
this.apiService,
|
||||
this.fileUploadService,
|
||||
this.storageService,
|
||||
this.i18nService,
|
||||
() => searchService,
|
||||
this.logService
|
||||
);
|
||||
this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService);
|
||||
this.folderService = new FolderService(
|
||||
this.cryptoService,
|
||||
this.userService,
|
||||
this.apiService,
|
||||
this.storageService,
|
||||
this.i18nService,
|
||||
this.cipherService
|
||||
);
|
||||
this.collectionService = new CollectionService(
|
||||
this.cryptoService,
|
||||
this.userService,
|
||||
this.storageService,
|
||||
this.i18nService
|
||||
);
|
||||
this.sendService = new SendService(
|
||||
this.cryptoService,
|
||||
this.userService,
|
||||
this.apiService,
|
||||
this.fileUploadService,
|
||||
this.storageService,
|
||||
this.i18nService,
|
||||
this.cryptoFunctionService
|
||||
this.logService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService);
|
||||
|
||||
this.folderService = new FolderService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.i18nService,
|
||||
this.cipherService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.collectionService = new CollectionService(
|
||||
this.cryptoService,
|
||||
this.i18nService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.sendService = new SendService(
|
||||
this.cryptoService,
|
||||
this.apiService,
|
||||
this.fileUploadService,
|
||||
this.i18nService,
|
||||
this.cryptoFunctionService,
|
||||
this.stateService
|
||||
);
|
||||
|
||||
this.providerService = new ProviderService(this.stateService);
|
||||
|
||||
this.loginSyncService = new LoginSyncService(
|
||||
this.userService,
|
||||
this.apiService,
|
||||
this.settingsService,
|
||||
this.folderService,
|
||||
this.cipherService,
|
||||
this.cryptoService,
|
||||
this.collectionService,
|
||||
this.storageService,
|
||||
this.messagingService,
|
||||
this.policyService,
|
||||
this.sendService,
|
||||
this.logService,
|
||||
this.tokenService,
|
||||
this.keyConnectorService,
|
||||
this.stateService,
|
||||
this.organizationService,
|
||||
this.providerService,
|
||||
async (expired: boolean) => this.messagingService.send("logout", { expired: expired })
|
||||
);
|
||||
|
||||
@@ -256,11 +278,12 @@ export class Main {
|
||||
|
||||
async logout() {
|
||||
await this.tokenService.clearToken();
|
||||
await this.apiKeyService.clear();
|
||||
await this.stateService.clean();
|
||||
}
|
||||
|
||||
private async init() {
|
||||
await this.storageService.init();
|
||||
await this.stateService.init();
|
||||
this.containerService.attachToWindow(global);
|
||||
await this.environmentService.setUrlsFromStorage();
|
||||
// Dev Server URLs. Comment out the line above.
|
||||
@@ -269,16 +292,14 @@ export class Main {
|
||||
// api: 'http://localhost:4000',
|
||||
// identity: 'http://localhost:33656',
|
||||
// });
|
||||
const locale = await this.storageService.get<string>(ConstantsService.localeKey);
|
||||
const locale = await this.stateService.getLocale();
|
||||
await this.i18nService.init(locale);
|
||||
this.authService.init();
|
||||
|
||||
const installedVersion = await this.storageService.get<string>(
|
||||
ConstantsService.installedVersionKey
|
||||
);
|
||||
const installedVersion = await this.stateService.getInstalledVersion();
|
||||
const currentVersion = await this.platformUtilsService.getApplicationVersion();
|
||||
if (installedVersion == null || installedVersion !== currentVersion) {
|
||||
await this.storageService.save(ConstantsService.installedVersionKey, currentVersion);
|
||||
await this.stateService.setInstalledVersion(currentVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,16 @@ import * as program from "commander";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
|
||||
import { ConfigurationService } from "../services/configuration.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { MessageResponse } from "jslib-node/cli/models/response/messageResponse";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
export class ClearCacheCommand {
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private i18nService: I18nService
|
||||
) {}
|
||||
constructor(private i18nService: I18nService, private stateService: StateService) {}
|
||||
|
||||
async run(cmd: program.OptionValues): Promise<Response> {
|
||||
try {
|
||||
await this.configurationService.clearStatefulSettings(true);
|
||||
await this.stateService.clearSyncSettings(true);
|
||||
const res = new MessageResponse(this.i18nService.t("syncCacheCleared"), null);
|
||||
return Response.success(res);
|
||||
} catch (e) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as program from "commander";
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
|
||||
import { ConfigurationService } from "../services/configuration.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { DirectoryType } from "../enums/directoryType";
|
||||
|
||||
@@ -33,7 +33,7 @@ export class ConfigCommand {
|
||||
constructor(
|
||||
private environmentService: EnvironmentService,
|
||||
private i18nService: I18nService,
|
||||
private configurationService: ConfigurationService
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
async run(setting: string, value: string, options: program.OptionValues): Promise<Response> {
|
||||
@@ -126,35 +126,32 @@ export class ConfigCommand {
|
||||
}
|
||||
|
||||
private async loadConfig() {
|
||||
this.directory = await this.configurationService.getDirectoryType();
|
||||
this.directory = await this.stateService.getDirectoryType();
|
||||
this.ldap =
|
||||
(await this.configurationService.getDirectory<LdapConfiguration>(DirectoryType.Ldap)) ||
|
||||
this.ldap;
|
||||
(await this.stateService.getDirectory<LdapConfiguration>(DirectoryType.Ldap)) || this.ldap;
|
||||
this.gsuite =
|
||||
(await this.configurationService.getDirectory<GSuiteConfiguration>(DirectoryType.GSuite)) ||
|
||||
(await this.stateService.getDirectory<GSuiteConfiguration>(DirectoryType.GSuite)) ||
|
||||
this.gsuite;
|
||||
this.azure =
|
||||
(await this.configurationService.getDirectory<AzureConfiguration>(
|
||||
(await this.stateService.getDirectory<AzureConfiguration>(
|
||||
DirectoryType.AzureActiveDirectory
|
||||
)) || this.azure;
|
||||
this.okta =
|
||||
(await this.configurationService.getDirectory<OktaConfiguration>(DirectoryType.Okta)) ||
|
||||
this.okta;
|
||||
(await this.stateService.getDirectory<OktaConfiguration>(DirectoryType.Okta)) || this.okta;
|
||||
this.oneLogin =
|
||||
(await this.configurationService.getDirectory<OneLoginConfiguration>(
|
||||
DirectoryType.OneLogin
|
||||
)) || this.oneLogin;
|
||||
this.sync = (await this.configurationService.getSync()) || this.sync;
|
||||
(await this.stateService.getDirectory<OneLoginConfiguration>(DirectoryType.OneLogin)) ||
|
||||
this.oneLogin;
|
||||
this.sync = (await this.stateService.getSync()) || this.sync;
|
||||
}
|
||||
|
||||
private async saveConfig() {
|
||||
ConnectorUtils.adjustConfigForSave(this.ldap, this.sync);
|
||||
await this.configurationService.saveDirectoryType(this.directory);
|
||||
await this.configurationService.saveDirectory(DirectoryType.Ldap, this.ldap);
|
||||
await this.configurationService.saveDirectory(DirectoryType.GSuite, this.gsuite);
|
||||
await this.configurationService.saveDirectory(DirectoryType.AzureActiveDirectory, this.azure);
|
||||
await this.configurationService.saveDirectory(DirectoryType.Okta, this.okta);
|
||||
await this.configurationService.saveDirectory(DirectoryType.OneLogin, this.oneLogin);
|
||||
await this.configurationService.saveSync(this.sync);
|
||||
await this.stateService.setDirectoryType(this.directory);
|
||||
await this.stateService.setDirectory(DirectoryType.Ldap, this.ldap);
|
||||
await this.stateService.setDirectory(DirectoryType.GSuite, this.gsuite);
|
||||
await this.stateService.setDirectory(DirectoryType.AzureActiveDirectory, this.azure);
|
||||
await this.stateService.setDirectory(DirectoryType.Okta, this.okta);
|
||||
await this.stateService.setDirectory(DirectoryType.OneLogin, this.oneLogin);
|
||||
await this.stateService.setSync(this.sync);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import * as program from "commander";
|
||||
|
||||
import { ConfigurationService } from "../services/configuration.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||
|
||||
export class LastSyncCommand {
|
||||
constructor(private configurationService: ConfigurationService) {}
|
||||
constructor(private stateService: StateService) {}
|
||||
|
||||
async run(object: string): Promise<Response> {
|
||||
try {
|
||||
switch (object.toLowerCase()) {
|
||||
case "groups":
|
||||
const groupsDate = await this.configurationService.getLastGroupSyncDate();
|
||||
const groupsDate = await this.stateService.getLastGroupSync();
|
||||
const groupsRes = new StringResponse(
|
||||
groupsDate == null ? null : groupsDate.toISOString()
|
||||
);
|
||||
return Response.success(groupsRes);
|
||||
case "users":
|
||||
const usersDate = await this.configurationService.getLastUserSyncDate();
|
||||
const usersDate = await this.stateService.getLastUserSync();
|
||||
const usersRes = new StringResponse(usersDate == null ? null : usersDate.toISOString());
|
||||
return Response.success(usersRes);
|
||||
default:
|
||||
|
||||
11
src/main.ts
11
src/main.ts
@@ -13,12 +13,15 @@ import { TrayMain } from "jslib-electron/tray.main";
|
||||
import { UpdaterMain } from "jslib-electron/updater.main";
|
||||
import { WindowMain } from "jslib-electron/window.main";
|
||||
|
||||
import { StateService } from "./services/state.service";
|
||||
|
||||
export class Main {
|
||||
logService: ElectronLogService;
|
||||
i18nService: I18nService;
|
||||
storageService: ElectronStorageService;
|
||||
messagingService: ElectronMainMessagingService;
|
||||
keytarStorageListener: KeytarStorageListener;
|
||||
stateService: StateService;
|
||||
|
||||
windowMain: WindowMain;
|
||||
messagingMain: MessagingMain;
|
||||
@@ -51,9 +54,10 @@ export class Main {
|
||||
this.logService = new ElectronLogService(null, app.getPath("userData"));
|
||||
this.i18nService = new I18nService("en", "./locales/");
|
||||
this.storageService = new ElectronStorageService(app.getPath("userData"));
|
||||
this.stateService = new StateService(this.storageService, null, this.logService, null);
|
||||
|
||||
this.windowMain = new WindowMain(
|
||||
this.storageService,
|
||||
this.stateService,
|
||||
this.logService,
|
||||
false,
|
||||
800,
|
||||
@@ -61,6 +65,7 @@ export class Main {
|
||||
(arg) => this.processDeepLink(arg),
|
||||
null
|
||||
);
|
||||
|
||||
this.menuMain = new MenuMain(this);
|
||||
this.updaterMain = new UpdaterMain(
|
||||
this.i18nService,
|
||||
@@ -77,7 +82,9 @@ export class Main {
|
||||
},
|
||||
"bitwardenDirectoryConnector"
|
||||
);
|
||||
this.trayMain = new TrayMain(this.windowMain, this.i18nService, this.storageService);
|
||||
|
||||
this.trayMain = new TrayMain(this.windowMain, this.i18nService, this.stateService);
|
||||
|
||||
this.messagingMain = new MessagingMain(
|
||||
this.windowMain,
|
||||
this.menuMain,
|
||||
|
||||
2
src/models/IConfiguration.ts
Normal file
2
src/models/IConfiguration.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// tslint:disable-next-line
|
||||
export interface IConfiguration {}
|
||||
47
src/models/account.ts
Normal file
47
src/models/account.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Account as BaseAccount } from "jslib-common/models/domain/account";
|
||||
|
||||
import { DirectoryType } from "src/enums/directoryType";
|
||||
|
||||
import { AzureConfiguration } from "./azureConfiguration";
|
||||
import { GSuiteConfiguration } from "./gsuiteConfiguration";
|
||||
import { LdapConfiguration } from "./ldapConfiguration";
|
||||
import { OktaConfiguration } from "./oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "./oneLoginConfiguration";
|
||||
import { SyncConfiguration } from "./syncConfiguration";
|
||||
|
||||
export class Account extends BaseAccount {
|
||||
directoryConfigurations?: DirectoryConfigurations = new DirectoryConfigurations();
|
||||
directorySettings: DirectorySettings = new DirectorySettings();
|
||||
clientKeys: ClientKeys = new ClientKeys();
|
||||
|
||||
constructor(init: Partial<Account>) {
|
||||
super(init);
|
||||
this.directoryConfigurations = init.directoryConfigurations ?? new DirectoryConfigurations();
|
||||
this.directorySettings = init.directorySettings ?? new DirectorySettings();
|
||||
}
|
||||
}
|
||||
|
||||
export class ClientKeys {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}
|
||||
|
||||
export class DirectoryConfigurations {
|
||||
ldap: LdapConfiguration;
|
||||
gsuite: GSuiteConfiguration;
|
||||
azure: AzureConfiguration;
|
||||
okta: OktaConfiguration;
|
||||
oneLogin: OneLoginConfiguration;
|
||||
}
|
||||
|
||||
export class DirectorySettings {
|
||||
organizationId?: string;
|
||||
sync?: SyncConfiguration;
|
||||
directoryType?: DirectoryType;
|
||||
userDelta?: string;
|
||||
groupDelta?: string;
|
||||
lastUserSync?: Date;
|
||||
lastGroupSync?: Date;
|
||||
lastSyncHash?: string;
|
||||
syncingDir?: boolean;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
export class AzureConfiguration {
|
||||
import { IConfiguration } from "./IConfiguration";
|
||||
|
||||
export class AzureConfiguration implements IConfiguration {
|
||||
identityAuthority: string;
|
||||
tenant: string;
|
||||
applicationId: string;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export class GSuiteConfiguration {
|
||||
import { IConfiguration } from "./IConfiguration";
|
||||
|
||||
export class GSuiteConfiguration implements IConfiguration {
|
||||
clientEmail: string;
|
||||
privateKey: string;
|
||||
domain: string;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export class LdapConfiguration {
|
||||
import { IConfiguration } from "./IConfiguration";
|
||||
|
||||
export class LdapConfiguration implements IConfiguration {
|
||||
ssl = false;
|
||||
startTls = false;
|
||||
tlsCaPath: string;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export class OktaConfiguration {
|
||||
import { IConfiguration } from "./IConfiguration";
|
||||
|
||||
export class OktaConfiguration implements IConfiguration {
|
||||
orgUrl: string;
|
||||
token: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export class OneLoginConfiguration {
|
||||
import { IConfiguration } from "./IConfiguration";
|
||||
|
||||
export class OneLoginConfiguration implements IConfiguration {
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
region = "us";
|
||||
|
||||
@@ -16,7 +16,6 @@ import { UpdateCommand } from "jslib-node/cli/commands/update.command";
|
||||
|
||||
import { BaseProgram } from "jslib-node/cli/baseProgram";
|
||||
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { Response } from "jslib-node/cli/models/response";
|
||||
import { StringResponse } from "jslib-node/cli/models/response/stringResponse";
|
||||
|
||||
@@ -32,11 +31,8 @@ const writeLn = (s: string, finalLine: boolean = false, error: boolean = false)
|
||||
};
|
||||
|
||||
export class Program extends BaseProgram {
|
||||
private apiKeyService: ApiKeyService;
|
||||
|
||||
constructor(private main: Main) {
|
||||
super(main.userService, writeLn);
|
||||
this.apiKeyService = main.apiKeyService;
|
||||
super(main.stateService, writeLn);
|
||||
}
|
||||
|
||||
async run() {
|
||||
@@ -107,7 +103,7 @@ export class Program extends BaseProgram {
|
||||
this.main.passwordGenerationService,
|
||||
this.main.cryptoFunctionService,
|
||||
this.main.platformUtilsService,
|
||||
this.main.userService,
|
||||
this.main.stateService,
|
||||
this.main.cryptoService,
|
||||
this.main.policyService,
|
||||
"connector",
|
||||
@@ -197,7 +193,7 @@ export class Program extends BaseProgram {
|
||||
})
|
||||
.action(async (object: string) => {
|
||||
await this.exitIfNotAuthed();
|
||||
const command = new LastSyncCommand(this.main.configurationService);
|
||||
const command = new LastSyncCommand(this.main.stateService);
|
||||
const response = await command.run(object);
|
||||
this.processResponse(response);
|
||||
});
|
||||
@@ -235,7 +231,7 @@ export class Program extends BaseProgram {
|
||||
const command = new ConfigCommand(
|
||||
this.main.environmentService,
|
||||
this.main.i18nService,
|
||||
this.main.configurationService
|
||||
this.main.stateService
|
||||
);
|
||||
const response = await command.run(setting, value, options);
|
||||
this.processResponse(response);
|
||||
@@ -266,10 +262,7 @@ export class Program extends BaseProgram {
|
||||
writeLn("", true);
|
||||
})
|
||||
.action(async (options: program.OptionValues) => {
|
||||
const command = new ClearCacheCommand(
|
||||
this.main.configurationService,
|
||||
this.main.i18nService
|
||||
);
|
||||
const command = new ClearCacheCommand(this.main.i18nService, this.main.stateService);
|
||||
const response = await command.run(options);
|
||||
this.processResponse(response);
|
||||
});
|
||||
@@ -310,10 +303,10 @@ export class Program extends BaseProgram {
|
||||
}
|
||||
|
||||
async exitIfAuthed() {
|
||||
const authed = await this.apiKeyService.isAuthenticated();
|
||||
const authed = await this.stateService.getIsAuthenticated();
|
||||
if (authed) {
|
||||
const type = await this.apiKeyService.getEntityType();
|
||||
const id = await this.apiKeyService.getEntityId();
|
||||
const type = await this.stateService.getEntityType();
|
||||
const id = await this.stateService.getEntityId();
|
||||
this.processResponse(
|
||||
Response.error("You are already logged in as " + type + "." + id + "."),
|
||||
true
|
||||
@@ -322,7 +315,7 @@ export class Program extends BaseProgram {
|
||||
}
|
||||
|
||||
async exitIfNotAuthed() {
|
||||
const authed = await this.apiKeyService.isAuthenticated();
|
||||
const authed = await this.stateService.getIsAuthenticated();
|
||||
if (!authed) {
|
||||
this.processResponse(Response.error("You are not logged in."), true);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { AuthService } from "jslib-common/abstractions/auth.service";
|
||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { ApiService as ApiServiceBase } from "jslib-common/services/api.service";
|
||||
|
||||
export async function refreshToken(apiKeyService: ApiKeyService, authService: AuthService) {
|
||||
export async function refreshToken(stateService: StateService, authService: AuthService) {
|
||||
try {
|
||||
const clientId = await apiKeyService.getClientId();
|
||||
const clientSecret = await apiKeyService.getClientSecret();
|
||||
const clientId = await stateService.getApiKeyClientId();
|
||||
const clientSecret = await stateService.getApiKeyClientSecret();
|
||||
if (clientId != null && clientSecret != null) {
|
||||
await authService.logInApiKey(clientId, clientSecret);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { ApiService } from "jslib-common/abstractions/api.service";
|
||||
import { ApiKeyService } from "jslib-common/abstractions/apiKey.service";
|
||||
import { AppIdService } from "jslib-common/abstractions/appId.service";
|
||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||
@@ -10,21 +9,25 @@ import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||
import { UserService } from "jslib-common/abstractions/user.service";
|
||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { AuthService as AuthServiceBase } from "jslib-common/services/auth.service";
|
||||
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account";
|
||||
|
||||
import { AccountKeys, AccountProfile, AccountTokens } from "jslib-common/models/domain/account";
|
||||
import { AuthResult } from "jslib-common/models/domain/authResult";
|
||||
|
||||
import { DeviceRequest } from "jslib-common/models/request/deviceRequest";
|
||||
import { TokenRequest } from "jslib-common/models/request/tokenRequest";
|
||||
|
||||
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
|
||||
|
||||
export class AuthService extends AuthServiceBase {
|
||||
constructor(
|
||||
cryptoService: CryptoService,
|
||||
apiService: ApiService,
|
||||
userService: UserService,
|
||||
tokenService: TokenService,
|
||||
appIdService: AppIdService,
|
||||
i18nService: I18nService,
|
||||
@@ -32,15 +35,14 @@ export class AuthService extends AuthServiceBase {
|
||||
messagingService: MessagingService,
|
||||
vaultTimeoutService: VaultTimeoutService,
|
||||
logService: LogService,
|
||||
private apiKeyService: ApiKeyService,
|
||||
cryptoFunctionService: CryptoFunctionService,
|
||||
environmentService: EnvironmentService,
|
||||
keyConnectorService: KeyConnectorService
|
||||
keyConnectorService: KeyConnectorService,
|
||||
stateService: StateService
|
||||
) {
|
||||
super(
|
||||
cryptoService,
|
||||
apiService,
|
||||
userService,
|
||||
tokenService,
|
||||
appIdService,
|
||||
i18nService,
|
||||
@@ -49,8 +51,9 @@ export class AuthService extends AuthServiceBase {
|
||||
vaultTimeoutService,
|
||||
logService,
|
||||
cryptoFunctionService,
|
||||
environmentService,
|
||||
keyConnectorService,
|
||||
environmentService,
|
||||
stateService,
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -64,12 +67,13 @@ export class AuthService extends AuthServiceBase {
|
||||
}
|
||||
|
||||
async logOut(callback: Function) {
|
||||
this.apiKeyService.clear();
|
||||
this.stateService.clean();
|
||||
super.logOut(callback);
|
||||
}
|
||||
|
||||
private async organizationLogInHelper(clientId: string, clientSecret: string) {
|
||||
const appId = await this.appIdService.getAppId();
|
||||
const entityId = clientId.split("organization.")[1];
|
||||
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
||||
const request = new TokenRequest(
|
||||
null,
|
||||
@@ -88,9 +92,33 @@ export class AuthService extends AuthServiceBase {
|
||||
|
||||
const tokenResponse = response as IdentityTokenResponse;
|
||||
result.resetMasterPassword = tokenResponse.resetMasterPassword;
|
||||
await this.tokenService.setToken(tokenResponse.accessToken);
|
||||
await this.apiKeyService.setInformation(clientId, clientSecret);
|
||||
|
||||
await this.stateService.addAccount(
|
||||
new Account({
|
||||
profile: {
|
||||
...new AccountProfile(),
|
||||
...{
|
||||
userId: entityId,
|
||||
apiKeyClientId: clientId,
|
||||
entityId: entityId,
|
||||
},
|
||||
},
|
||||
tokens: {
|
||||
...new AccountTokens(),
|
||||
...{
|
||||
accessToken: tokenResponse.accessToken,
|
||||
refreshToken: tokenResponse.refreshToken,
|
||||
},
|
||||
},
|
||||
keys: {
|
||||
...new AccountKeys(),
|
||||
...{
|
||||
apiKeyClientSecret: clientSecret,
|
||||
},
|
||||
},
|
||||
directorySettings: new DirectorySettings(),
|
||||
directoryConfigurations: new DirectoryConfigurations(),
|
||||
})
|
||||
);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
import { UserEntry } from "../models/userEntry";
|
||||
|
||||
import { BaseDirectoryService } from "./baseDirectory.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
const AzurePublicIdentityAuhtority = "login.microsoftonline.com";
|
||||
const AzureGovermentIdentityAuhtority = "login.microsoftonline.us";
|
||||
@@ -40,28 +40,28 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
|
||||
private accessTokenExpiration: Date;
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService
|
||||
private i18nService: I18nService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
super();
|
||||
this.init();
|
||||
}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
const type = await this.stateService.getDirectoryType();
|
||||
if (type !== DirectoryType.AzureActiveDirectory) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirConfig = await this.configurationService.getDirectory<AzureConfiguration>(
|
||||
this.dirConfig = await this.stateService.getDirectory<AzureConfiguration>(
|
||||
DirectoryType.AzureActiveDirectory
|
||||
);
|
||||
if (this.dirConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.syncConfig = await this.configurationService.getSync();
|
||||
this.syncConfig = await this.stateService.getSync();
|
||||
if (this.syncConfig == null) {
|
||||
return;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
|
||||
const entries: UserEntry[] = [];
|
||||
|
||||
let res: any = null;
|
||||
const token = await this.configurationService.getUserDeltaToken();
|
||||
const token = await this.stateService.getUserDelta();
|
||||
if (!force && token != null) {
|
||||
try {
|
||||
const deltaReq = this.client.api(token);
|
||||
@@ -168,7 +168,7 @@ export class AzureDirectoryService extends BaseDirectoryService implements IDire
|
||||
|
||||
if (res[NextLink] == null) {
|
||||
if (res[DeltaLink] != null && saveDelta) {
|
||||
await this.configurationService.saveUserDeltaToken(res[DeltaLink]);
|
||||
await this.stateService.setUserDelta(res[DeltaLink]);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
import { DirectoryType } from "../enums/directoryType";
|
||||
|
||||
import { StorageService } from "jslib-common/abstractions/storage.service";
|
||||
import { AzureConfiguration } from "../models/azureConfiguration";
|
||||
import { GSuiteConfiguration } from "../models/gsuiteConfiguration";
|
||||
import { LdapConfiguration } from "../models/ldapConfiguration";
|
||||
import { OktaConfiguration } from "../models/oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "../models/oneLoginConfiguration";
|
||||
import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
|
||||
const StoredSecurely = "[STORED SECURELY]";
|
||||
const Keys = {
|
||||
ldap: "ldapPassword",
|
||||
gsuite: "gsuitePrivateKey",
|
||||
azure: "azureKey",
|
||||
okta: "oktaToken",
|
||||
oneLogin: "oneLoginClientSecret",
|
||||
directoryConfigPrefix: "directoryConfig_",
|
||||
sync: "syncConfig",
|
||||
directoryType: "directoryType",
|
||||
userDelta: "userDeltaToken",
|
||||
groupDelta: "groupDeltaToken",
|
||||
lastUserSync: "lastUserSync",
|
||||
lastGroupSync: "lastGroupSync",
|
||||
lastSyncHash: "lastSyncHash",
|
||||
organizationId: "organizationId",
|
||||
};
|
||||
|
||||
export class ConfigurationService {
|
||||
constructor(
|
||||
private storageService: StorageService,
|
||||
private secureStorageService: StorageService,
|
||||
private useSecureStorageForSecrets = true
|
||||
) {}
|
||||
|
||||
async getDirectory<T>(type: DirectoryType): Promise<T> {
|
||||
const config = await this.storageService.get<T>(Keys.directoryConfigPrefix + type);
|
||||
if (config == null) {
|
||||
return config;
|
||||
}
|
||||
|
||||
if (this.useSecureStorageForSecrets) {
|
||||
switch (type) {
|
||||
case DirectoryType.Ldap:
|
||||
(config as any).password = await this.secureStorageService.get<string>(Keys.ldap);
|
||||
break;
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
(config as any).key = await this.secureStorageService.get<string>(Keys.azure);
|
||||
break;
|
||||
case DirectoryType.Okta:
|
||||
(config as any).token = await this.secureStorageService.get<string>(Keys.okta);
|
||||
break;
|
||||
case DirectoryType.GSuite:
|
||||
(config as any).privateKey = await this.secureStorageService.get<string>(Keys.gsuite);
|
||||
break;
|
||||
case DirectoryType.OneLogin:
|
||||
(config as any).clientSecret = await this.secureStorageService.get<string>(Keys.oneLogin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
async saveDirectory(
|
||||
type: DirectoryType,
|
||||
config:
|
||||
| LdapConfiguration
|
||||
| GSuiteConfiguration
|
||||
| AzureConfiguration
|
||||
| OktaConfiguration
|
||||
| OneLoginConfiguration
|
||||
): Promise<any> {
|
||||
const savedConfig: any = Object.assign({}, config);
|
||||
if (this.useSecureStorageForSecrets) {
|
||||
switch (type) {
|
||||
case DirectoryType.Ldap:
|
||||
if (savedConfig.password == null) {
|
||||
await this.secureStorageService.remove(Keys.ldap);
|
||||
} else {
|
||||
await this.secureStorageService.save(Keys.ldap, savedConfig.password);
|
||||
savedConfig.password = StoredSecurely;
|
||||
}
|
||||
break;
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
if (savedConfig.key == null) {
|
||||
await this.secureStorageService.remove(Keys.azure);
|
||||
} else {
|
||||
await this.secureStorageService.save(Keys.azure, savedConfig.key);
|
||||
savedConfig.key = StoredSecurely;
|
||||
}
|
||||
break;
|
||||
case DirectoryType.Okta:
|
||||
if (savedConfig.token == null) {
|
||||
await this.secureStorageService.remove(Keys.okta);
|
||||
} else {
|
||||
await this.secureStorageService.save(Keys.okta, savedConfig.token);
|
||||
savedConfig.token = StoredSecurely;
|
||||
}
|
||||
break;
|
||||
case DirectoryType.GSuite:
|
||||
if (savedConfig.privateKey == null) {
|
||||
await this.secureStorageService.remove(Keys.gsuite);
|
||||
} else {
|
||||
(config as GSuiteConfiguration).privateKey = savedConfig.privateKey =
|
||||
savedConfig.privateKey.replace(/\\n/g, "\n");
|
||||
await this.secureStorageService.save(Keys.gsuite, savedConfig.privateKey);
|
||||
savedConfig.privateKey = StoredSecurely;
|
||||
}
|
||||
break;
|
||||
case DirectoryType.OneLogin:
|
||||
if (savedConfig.clientSecret == null) {
|
||||
await this.secureStorageService.remove(Keys.oneLogin);
|
||||
} else {
|
||||
await this.secureStorageService.save(Keys.oneLogin, savedConfig.clientSecret);
|
||||
savedConfig.clientSecret = StoredSecurely;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
await this.storageService.save(Keys.directoryConfigPrefix + type, savedConfig);
|
||||
}
|
||||
|
||||
getSync(): Promise<SyncConfiguration> {
|
||||
return this.storageService.get<SyncConfiguration>(Keys.sync);
|
||||
}
|
||||
|
||||
saveSync(config: SyncConfiguration) {
|
||||
return this.storageService.save(Keys.sync, config);
|
||||
}
|
||||
|
||||
getDirectoryType(): Promise<DirectoryType> {
|
||||
return this.storageService.get<DirectoryType>(Keys.directoryType);
|
||||
}
|
||||
|
||||
async saveDirectoryType(type: DirectoryType) {
|
||||
const currentType = await this.getDirectoryType();
|
||||
if (type !== currentType) {
|
||||
await this.clearStatefulSettings();
|
||||
}
|
||||
|
||||
return this.storageService.save(Keys.directoryType, type);
|
||||
}
|
||||
|
||||
getUserDeltaToken(): Promise<string> {
|
||||
return this.storageService.get<string>(Keys.userDelta);
|
||||
}
|
||||
|
||||
saveUserDeltaToken(token: string) {
|
||||
if (token == null) {
|
||||
return this.storageService.remove(Keys.userDelta);
|
||||
} else {
|
||||
return this.storageService.save(Keys.userDelta, token);
|
||||
}
|
||||
}
|
||||
|
||||
getGroupDeltaToken(): Promise<string> {
|
||||
return this.storageService.get<string>(Keys.groupDelta);
|
||||
}
|
||||
|
||||
saveGroupDeltaToken(token: string) {
|
||||
if (token == null) {
|
||||
return this.storageService.remove(Keys.groupDelta);
|
||||
} else {
|
||||
return this.storageService.save(Keys.groupDelta, token);
|
||||
}
|
||||
}
|
||||
|
||||
async getLastUserSyncDate(): Promise<Date> {
|
||||
const dateString = await this.storageService.get<string>(Keys.lastUserSync);
|
||||
if (dateString == null) {
|
||||
return null;
|
||||
}
|
||||
return new Date(dateString);
|
||||
}
|
||||
|
||||
saveLastUserSyncDate(date: Date) {
|
||||
if (date == null) {
|
||||
return this.storageService.remove(Keys.lastUserSync);
|
||||
} else {
|
||||
return this.storageService.save(Keys.lastUserSync, date);
|
||||
}
|
||||
}
|
||||
|
||||
async getLastGroupSyncDate(): Promise<Date> {
|
||||
const dateString = await this.storageService.get<string>(Keys.lastGroupSync);
|
||||
if (dateString == null) {
|
||||
return null;
|
||||
}
|
||||
return new Date(dateString);
|
||||
}
|
||||
|
||||
saveLastGroupSyncDate(date: Date) {
|
||||
if (date == null) {
|
||||
return this.storageService.remove(Keys.lastGroupSync);
|
||||
} else {
|
||||
return this.storageService.save(Keys.lastGroupSync, date);
|
||||
}
|
||||
}
|
||||
|
||||
getLastSyncHash(): Promise<string> {
|
||||
return this.storageService.get<string>(Keys.lastSyncHash);
|
||||
}
|
||||
|
||||
saveLastSyncHash(hash: string) {
|
||||
if (hash == null) {
|
||||
return this.storageService.remove(Keys.lastSyncHash);
|
||||
} else {
|
||||
return this.storageService.save(Keys.lastSyncHash, hash);
|
||||
}
|
||||
}
|
||||
|
||||
getOrganizationId(): Promise<string> {
|
||||
return this.storageService.get<string>(Keys.organizationId);
|
||||
}
|
||||
|
||||
async saveOrganizationId(id: string) {
|
||||
const currentId = await this.getOrganizationId();
|
||||
if (currentId !== id) {
|
||||
await this.clearStatefulSettings();
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
return this.storageService.remove(Keys.organizationId);
|
||||
} else {
|
||||
return this.storageService.save(Keys.organizationId, id);
|
||||
}
|
||||
}
|
||||
|
||||
async clearStatefulSettings(hashToo = false) {
|
||||
await this.saveUserDeltaToken(null);
|
||||
await this.saveGroupDeltaToken(null);
|
||||
await this.saveLastGroupSyncDate(null);
|
||||
await this.saveLastUserSyncDate(null);
|
||||
if (hashToo) {
|
||||
await this.saveLastSyncHash(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@ import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
import { UserEntry } from "../models/userEntry";
|
||||
|
||||
import { BaseDirectoryService } from "./baseDirectory.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
export class GSuiteDirectoryService extends BaseDirectoryService implements IDirectoryService {
|
||||
private client: JWT;
|
||||
@@ -23,28 +23,28 @@ export class GSuiteDirectoryService extends BaseDirectoryService implements IDir
|
||||
private syncConfig: SyncConfiguration;
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService
|
||||
private i18nService: I18nService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
super();
|
||||
this.service = google.admin("directory_v1");
|
||||
}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
const type = await this.stateService.getDirectoryType();
|
||||
if (type !== DirectoryType.GSuite) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirConfig = await this.configurationService.getDirectory<GSuiteConfiguration>(
|
||||
this.dirConfig = await this.stateService.getDirectory<GSuiteConfiguration>(
|
||||
DirectoryType.GSuite
|
||||
);
|
||||
if (this.dirConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.syncConfig = await this.configurationService.getSync();
|
||||
this.syncConfig = await this.stateService.getSync();
|
||||
if (this.syncConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -10,11 +10,11 @@ import { LdapConfiguration } from "../models/ldapConfiguration";
|
||||
import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
import { UserEntry } from "../models/userEntry";
|
||||
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
|
||||
@@ -26,25 +26,23 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
private syncConfig: SyncConfiguration;
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService
|
||||
private i18nService: I18nService,
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
const type = await this.stateService.getDirectoryType();
|
||||
if (type !== DirectoryType.Ldap) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirConfig = await this.configurationService.getDirectory<LdapConfiguration>(
|
||||
DirectoryType.Ldap
|
||||
);
|
||||
this.dirConfig = await this.stateService.getDirectory<LdapConfiguration>(DirectoryType.Ldap);
|
||||
if (this.dirConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.syncConfig = await this.configurationService.getSync();
|
||||
this.syncConfig = await this.stateService.getSync();
|
||||
if (this.syncConfig == null) {
|
||||
return;
|
||||
}
|
||||
@@ -71,7 +69,7 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
}
|
||||
|
||||
private async getUsers(force: boolean): Promise<UserEntry[]> {
|
||||
const lastSync = await this.configurationService.getLastUserSyncDate();
|
||||
const lastSync = await this.stateService.getLastUserSync();
|
||||
let filter = this.buildBaseFilter(this.syncConfig.userObjectClass, this.syncConfig.userFilter);
|
||||
filter = this.buildRevisionFilter(filter, force, lastSync);
|
||||
|
||||
@@ -147,7 +145,7 @@ export class LdapDirectoryService implements IDirectoryService {
|
||||
private async getGroups(force: boolean): Promise<GroupEntry[]> {
|
||||
const entries: GroupEntry[] = [];
|
||||
|
||||
const lastSync = await this.configurationService.getLastUserSyncDate();
|
||||
const lastSync = await this.stateService.getLastUserSync();
|
||||
const originalFilter = this.buildBaseFilter(
|
||||
this.syncConfig.groupObjectClass,
|
||||
this.syncConfig.groupFilter
|
||||
|
||||
@@ -6,13 +6,13 @@ import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
import { UserEntry } from "../models/userEntry";
|
||||
|
||||
import { BaseDirectoryService } from "./baseDirectory.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
|
||||
import * as https from "https";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
const DelayBetweenBuildGroupCallsInMilliseconds = 500;
|
||||
|
||||
@@ -22,27 +22,25 @@ export class OktaDirectoryService extends BaseDirectoryService implements IDirec
|
||||
private lastBuildGroupCall: number;
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService
|
||||
private i18nService: I18nService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
const type = await this.stateService.getDirectoryType();
|
||||
if (type !== DirectoryType.Okta) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirConfig = await this.configurationService.getDirectory<OktaConfiguration>(
|
||||
DirectoryType.Okta
|
||||
);
|
||||
this.dirConfig = await this.stateService.getDirectory<OktaConfiguration>(DirectoryType.Okta);
|
||||
if (this.dirConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.syncConfig = await this.configurationService.getSync();
|
||||
this.syncConfig = await this.stateService.getSync();
|
||||
if (this.syncConfig == null) {
|
||||
return;
|
||||
}
|
||||
@@ -68,7 +66,7 @@ export class OktaDirectoryService extends BaseDirectoryService implements IDirec
|
||||
|
||||
private async getUsers(force: boolean): Promise<UserEntry[]> {
|
||||
const entries: UserEntry[] = [];
|
||||
const lastSync = await this.configurationService.getLastUserSyncDate();
|
||||
const lastSync = await this.stateService.getLastUserSync();
|
||||
const oktaFilter = this.buildOktaFilter(this.syncConfig.userFilter, force, lastSync);
|
||||
const setFilter = this.createCustomSet(this.syncConfig.userFilter);
|
||||
|
||||
@@ -124,7 +122,7 @@ export class OktaDirectoryService extends BaseDirectoryService implements IDirec
|
||||
setFilter: [boolean, Set<string>]
|
||||
): Promise<GroupEntry[]> {
|
||||
const entries: GroupEntry[] = [];
|
||||
const lastSync = await this.configurationService.getLastGroupSyncDate();
|
||||
const lastSync = await this.stateService.getLastGroupSync();
|
||||
const oktaFilter = this.buildOktaFilter(this.syncConfig.groupFilter, force, lastSync);
|
||||
|
||||
this.logService.info("Querying groups.");
|
||||
|
||||
@@ -6,11 +6,11 @@ import { SyncConfiguration } from "../models/syncConfiguration";
|
||||
import { UserEntry } from "../models/userEntry";
|
||||
|
||||
import { BaseDirectoryService } from "./baseDirectory.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
|
||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
|
||||
// Basic email validation: something@something.something
|
||||
const ValidEmailRegex = /^\S+@\S+\.\S+$/;
|
||||
@@ -22,27 +22,27 @@ export class OneLoginDirectoryService extends BaseDirectoryService implements ID
|
||||
private allUsers: any[] = [];
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private i18nService: I18nService
|
||||
private i18nService: I18nService,
|
||||
private stateService: StateService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
const type = await this.configurationService.getDirectoryType();
|
||||
const type = await this.stateService.getDirectoryType();
|
||||
if (type !== DirectoryType.OneLogin) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirConfig = await this.configurationService.getDirectory<OneLoginConfiguration>(
|
||||
this.dirConfig = await this.stateService.getDirectory<OneLoginConfiguration>(
|
||||
DirectoryType.OneLogin
|
||||
);
|
||||
if (this.dirConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.syncConfig = await this.configurationService.getSync();
|
||||
this.syncConfig = await this.stateService.getSync();
|
||||
if (this.syncConfig == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
535
src/services/state.service.ts
Normal file
535
src/services/state.service.ts
Normal file
@@ -0,0 +1,535 @@
|
||||
import { StateService as BaseStateService } from "jslib-common/services/state.service";
|
||||
|
||||
import { State } from "jslib-common/models/domain/state";
|
||||
import { StorageOptions } from "jslib-common/models/domain/storageOptions";
|
||||
|
||||
import { Account } from "src/models/account";
|
||||
import { AzureConfiguration } from "src/models/azureConfiguration";
|
||||
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";
|
||||
import { IConfiguration } from "src/models/IConfiguration";
|
||||
import { LdapConfiguration } from "src/models/ldapConfiguration";
|
||||
import { OktaConfiguration } from "src/models/oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "src/models/oneLoginConfiguration";
|
||||
|
||||
import { LogService } from "jslib-common/abstractions/log.service";
|
||||
import { StorageService } from "jslib-common/abstractions/storage.service";
|
||||
import { StateService as StateServiceAbstraction } from "src/abstractions/state.service";
|
||||
import { DirectoryType } from "src/enums/directoryType";
|
||||
import { SyncConfiguration } from "src/models/syncConfiguration";
|
||||
import { StateMigrationService } from "./stateMigration.service";
|
||||
|
||||
const SecureStorageKeys = {
|
||||
ldap: "ldapPassword",
|
||||
gsuite: "gsuitePrivateKey",
|
||||
azure: "azureKey",
|
||||
okta: "oktaToken",
|
||||
oneLogin: "oneLoginClientSecret",
|
||||
userDelta: "userDeltaToken",
|
||||
groupDelta: "groupDeltaToken",
|
||||
lastUserSync: "lastUserSync",
|
||||
lastGroupSync: "lastGroupSync",
|
||||
lastSyncHash: "lastSyncHash",
|
||||
};
|
||||
|
||||
const StoredSecurely = "[STORED SECURELY]";
|
||||
|
||||
export class StateService extends BaseStateService<Account> implements StateServiceAbstraction {
|
||||
constructor(
|
||||
protected storageService: StorageService,
|
||||
protected secureStorageService: StorageService,
|
||||
protected logService: LogService,
|
||||
protected stateMigrationService: StateMigrationService,
|
||||
private useSecureStorageForSecrets = true
|
||||
) {
|
||||
super(storageService, secureStorageService, logService, stateMigrationService);
|
||||
}
|
||||
|
||||
async getDirectory<T extends IConfiguration>(type: DirectoryType): Promise<T> {
|
||||
const config = await this.getConfiguration(type);
|
||||
if (config == null) {
|
||||
return config as T;
|
||||
}
|
||||
|
||||
if (this.useSecureStorageForSecrets) {
|
||||
switch (type) {
|
||||
case DirectoryType.Ldap:
|
||||
(config as any).password = await this.getLdapKey();
|
||||
break;
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
(config as any).key = await this.getAzureKey();
|
||||
break;
|
||||
case DirectoryType.Okta:
|
||||
(config as any).token = await this.getOktaKey();
|
||||
break;
|
||||
case DirectoryType.GSuite:
|
||||
(config as any).privateKey = await this.getGsuiteKey();
|
||||
break;
|
||||
case DirectoryType.OneLogin:
|
||||
(config as any).clientSecret = await this.getOneLoginKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return config as T;
|
||||
}
|
||||
|
||||
async setDirectory(
|
||||
type: DirectoryType,
|
||||
config:
|
||||
| LdapConfiguration
|
||||
| GSuiteConfiguration
|
||||
| AzureConfiguration
|
||||
| OktaConfiguration
|
||||
| OneLoginConfiguration
|
||||
): Promise<any> {
|
||||
const savedConfig: any = Object.assign({}, config);
|
||||
if (this.useSecureStorageForSecrets) {
|
||||
switch (type) {
|
||||
case DirectoryType.Ldap:
|
||||
await this.setLdapKey(savedConfig.password);
|
||||
savedConfig.password = StoredSecurely;
|
||||
await this.setLdapConfiguration(savedConfig);
|
||||
break;
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
await this.setAzureKey(savedConfig.key);
|
||||
savedConfig.key = StoredSecurely;
|
||||
await this.setAzureConfiguration(savedConfig);
|
||||
break;
|
||||
case DirectoryType.Okta:
|
||||
await this.setOktaKey(savedConfig.token);
|
||||
savedConfig.token = StoredSecurely;
|
||||
await this.setOktaConfiguration(savedConfig);
|
||||
break;
|
||||
case DirectoryType.GSuite:
|
||||
if (savedConfig.privateKey == null) {
|
||||
await this.setGsuiteKey(null);
|
||||
} else {
|
||||
(config as GSuiteConfiguration).privateKey = savedConfig.privateKey =
|
||||
savedConfig.privateKey.replace(/\\n/g, "\n");
|
||||
await this.setGsuiteKey(savedConfig.privateKey);
|
||||
savedConfig.privateKey = StoredSecurely;
|
||||
}
|
||||
await this.setGsuiteConfiguration(savedConfig);
|
||||
break;
|
||||
case DirectoryType.OneLogin:
|
||||
await this.setOneLoginKey(savedConfig.clientSecret);
|
||||
savedConfig.clientSecret = StoredSecurely;
|
||||
await this.setOneLoginConfiguration(savedConfig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getLdapKey(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.ldap}`
|
||||
);
|
||||
}
|
||||
|
||||
async setLdapKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.ldap}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getGsuiteKey(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.gsuite}`
|
||||
);
|
||||
}
|
||||
|
||||
async setGsuiteKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.gsuite}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getAzureKey(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.azure}`
|
||||
);
|
||||
}
|
||||
|
||||
async setAzureKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.azure}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getOktaKey(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.okta}`
|
||||
);
|
||||
}
|
||||
|
||||
async setOktaKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.okta}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getOneLoginKey(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.oneLogin}`
|
||||
);
|
||||
}
|
||||
|
||||
async setOneLoginKey(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.oneLogin}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getUserDelta(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.userDelta}`
|
||||
);
|
||||
}
|
||||
|
||||
async setUserDelta(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.userDelta}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getGroupDelta(options?: StorageOptions): Promise<string> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return null;
|
||||
}
|
||||
return await this.secureStorageService.get<string>(
|
||||
`${options.userId}_${SecureStorageKeys.groupDelta}`
|
||||
);
|
||||
}
|
||||
|
||||
async setGroupDelta(value: string, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
await this.secureStorageService.save(
|
||||
`${options.userId}_${SecureStorageKeys.groupDelta}`,
|
||||
value,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
async getConfiguration(type: DirectoryType): Promise<IConfiguration> {
|
||||
switch (type) {
|
||||
case DirectoryType.Ldap:
|
||||
return await this.getLdapConfiguration();
|
||||
case DirectoryType.GSuite:
|
||||
return await this.getGsuiteConfiguration();
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
return await this.getAzureConfiguration();
|
||||
case DirectoryType.Okta:
|
||||
return await this.getOktaConfiguration();
|
||||
case DirectoryType.OneLogin:
|
||||
return await this.getOneLoginConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
async getLdapConfiguration(options?: StorageOptions): Promise<LdapConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directoryConfigurations?.ldap;
|
||||
}
|
||||
|
||||
async setLdapConfiguration(value: LdapConfiguration, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directoryConfigurations.ldap = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getGsuiteConfiguration(options?: StorageOptions): Promise<GSuiteConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directoryConfigurations?.gsuite;
|
||||
}
|
||||
|
||||
async setGsuiteConfiguration(
|
||||
value: GSuiteConfiguration,
|
||||
options?: StorageOptions
|
||||
): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directoryConfigurations.gsuite = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getAzureConfiguration(options?: StorageOptions): Promise<AzureConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directoryConfigurations?.azure;
|
||||
}
|
||||
|
||||
async setAzureConfiguration(value: AzureConfiguration, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directoryConfigurations.azure = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getOktaConfiguration(options?: StorageOptions): Promise<OktaConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directoryConfigurations?.okta;
|
||||
}
|
||||
|
||||
async setOktaConfiguration(value: OktaConfiguration, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directoryConfigurations.okta = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getOneLoginConfiguration(options?: StorageOptions): Promise<OneLoginConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directoryConfigurations?.oneLogin;
|
||||
}
|
||||
|
||||
async setOneLoginConfiguration(
|
||||
value: OneLoginConfiguration,
|
||||
options?: StorageOptions
|
||||
): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directoryConfigurations.oneLogin = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getOrganizationId(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.organizationId;
|
||||
}
|
||||
|
||||
async setOrganizationId(value: string, options?: StorageOptions): Promise<void> {
|
||||
const currentId = await this.getOrganizationId();
|
||||
if (currentId !== value) {
|
||||
await this.clearSyncSettings();
|
||||
}
|
||||
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.organizationId = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getSync(options?: StorageOptions): Promise<SyncConfiguration> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.sync;
|
||||
}
|
||||
|
||||
async setSync(value: SyncConfiguration, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.sync = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getDirectoryType(options?: StorageOptions): Promise<DirectoryType> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.directoryType;
|
||||
}
|
||||
|
||||
async setDirectoryType(value: DirectoryType, options?: StorageOptions): Promise<void> {
|
||||
const currentType = await this.getDirectoryType();
|
||||
if (value !== currentType) {
|
||||
await this.clearSyncSettings();
|
||||
}
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.directoryType = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getLastUserSync(options?: StorageOptions): Promise<Date> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.lastUserSync;
|
||||
}
|
||||
|
||||
async setLastUserSync(value: Date, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.lastUserSync = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getLastGroupSync(options?: StorageOptions): Promise<Date> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.lastGroupSync;
|
||||
}
|
||||
|
||||
async setLastGroupSync(value: Date, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.lastGroupSync = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getLastSyncHash(options?: StorageOptions): Promise<string> {
|
||||
return (
|
||||
await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions()))
|
||||
)?.directorySettings?.lastSyncHash;
|
||||
}
|
||||
|
||||
async setLastSyncHash(value: string, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
account.directorySettings.lastSyncHash = value;
|
||||
await this.saveAccount(
|
||||
account,
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
async getSyncingDir(options?: StorageOptions): Promise<boolean> {
|
||||
return (await this.getAccount(this.reconcileOptions(options, this.defaultInMemoryOptions)))
|
||||
?.directorySettings?.syncingDir;
|
||||
}
|
||||
|
||||
async setSyncingDir(value: boolean, options?: StorageOptions): Promise<void> {
|
||||
const account = await this.getAccount(
|
||||
this.reconcileOptions(options, this.defaultInMemoryOptions)
|
||||
);
|
||||
account.directorySettings.syncingDir = value;
|
||||
await this.saveAccount(account, this.reconcileOptions(options, this.defaultInMemoryOptions));
|
||||
}
|
||||
|
||||
async clearSyncSettings(hashToo = false) {
|
||||
await this.setUserDelta(null);
|
||||
await this.setGroupDelta(null);
|
||||
await this.setLastGroupSync(null);
|
||||
await this.setLastUserSync(null);
|
||||
if (hashToo) {
|
||||
await this.setLastSyncHash(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected async scaffoldNewAccountStorage(account: Account): Promise<void> {
|
||||
await this.scaffoldNewAccountDiskStorage(account);
|
||||
}
|
||||
|
||||
protected async scaffoldNewAccountDiskStorage(account: Account): Promise<void> {
|
||||
const storedState =
|
||||
(await this.storageService.get<State<Account>>(
|
||||
"state",
|
||||
await this.defaultOnDiskLocalOptions()
|
||||
)) ?? new State<Account>();
|
||||
const storedAccount = storedState.accounts[account.profile.userId];
|
||||
if (storedAccount != null) {
|
||||
account.settings = storedAccount.settings;
|
||||
account.directorySettings = storedAccount.directorySettings;
|
||||
account.directoryConfigurations = storedAccount.directoryConfigurations;
|
||||
}
|
||||
storedState.accounts[account.profile.userId] = account;
|
||||
await this.saveStateToStorage(storedState, await this.defaultOnDiskLocalOptions());
|
||||
}
|
||||
}
|
||||
170
src/services/stateMigration.service.ts
Normal file
170
src/services/stateMigration.service.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { HtmlStorageLocation } from "jslib-common/enums/htmlStorageLocation";
|
||||
import { State } from "jslib-common/models/domain/state";
|
||||
|
||||
import { StateMigrationService as BaseStateMigrationService } from "jslib-common/services/stateMigration.service";
|
||||
|
||||
import { DirectoryType } from "src/enums/directoryType";
|
||||
|
||||
import { Account, DirectoryConfigurations, DirectorySettings } from "src/models/account";
|
||||
import { AzureConfiguration } from "src/models/azureConfiguration";
|
||||
import { GSuiteConfiguration } from "src/models/gsuiteConfiguration";
|
||||
import { LdapConfiguration } from "src/models/ldapConfiguration";
|
||||
import { OktaConfiguration } from "src/models/oktaConfiguration";
|
||||
import { OneLoginConfiguration } from "src/models/oneLoginConfiguration";
|
||||
import { SyncConfiguration } from "src/models/syncConfiguration";
|
||||
|
||||
const SecureStorageKeys: { [key: string]: any } = {
|
||||
ldap: "ldapPassword",
|
||||
gsuite: "gsuitePrivateKey",
|
||||
azure: "azureKey",
|
||||
okta: "oktaToken",
|
||||
oneLogin: "oneLoginClientSecret",
|
||||
directoryConfigPrefix: "directoryConfig_",
|
||||
sync: "syncConfig",
|
||||
directoryType: "directoryType",
|
||||
userDelta: "userDeltaToken",
|
||||
groupDelta: "groupDeltaToken",
|
||||
organizationId: "organizationId",
|
||||
};
|
||||
|
||||
const Keys: { [key: string]: any } = {
|
||||
state: "state",
|
||||
entityId: "entityId",
|
||||
directoryType: "directoryType",
|
||||
organizationId: "organizationId",
|
||||
lastUserSync: "lastUserSync",
|
||||
lastGroupSync: "lastGroupSync",
|
||||
lastSyncHash: "lastSyncHash",
|
||||
syncingDir: "syncingDir",
|
||||
syncConfig: "syncConfig",
|
||||
};
|
||||
|
||||
const ClientKeys: { [key: string]: any } = {
|
||||
clientIdOld: "clientId",
|
||||
clientId: "apikey_clientId",
|
||||
clientSecretOld: "clientSecret",
|
||||
clientSecret: "apikey_clientSecret",
|
||||
};
|
||||
|
||||
export class StateMigrationService extends BaseStateMigrationService {
|
||||
async needsMigration(): Promise<boolean> {
|
||||
const currentStateVersion = (
|
||||
await this.storageService.get<State<Account>>("state", {
|
||||
htmlStorageLocation: HtmlStorageLocation.Local,
|
||||
})
|
||||
)?.globals?.stateVersion;
|
||||
return currentStateVersion == null || currentStateVersion < this.latestVersion;
|
||||
}
|
||||
|
||||
async migrate(): Promise<void> {
|
||||
let currentStateVersion =
|
||||
(await this.storageService.get<State<Account>>("state"))?.globals?.stateVersion ?? 1;
|
||||
while (currentStateVersion < this.latestVersion) {
|
||||
switch (currentStateVersion) {
|
||||
case 1:
|
||||
await this.migrateClientKeys();
|
||||
await this.migrateStateFrom1To2();
|
||||
break;
|
||||
}
|
||||
currentStateVersion += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this migration when we are confident existing api keys are all migrated. Probably 1-2 releases.
|
||||
protected async migrateClientKeys() {
|
||||
const oldClientId = await this.storageService.get<string>(ClientKeys.clientIdOld);
|
||||
const oldClientSecret = await this.storageService.get<string>(ClientKeys.clientSecretOld);
|
||||
|
||||
if (oldClientId != null) {
|
||||
await this.storageService.save(ClientKeys.clientId, oldClientId);
|
||||
await this.storageService.remove(ClientKeys.clientIdOld);
|
||||
}
|
||||
|
||||
if (oldClientSecret != null) {
|
||||
await this.storageService.save(ClientKeys.clientSecret, oldClientSecret);
|
||||
await this.storageService.remove(ClientKeys.clientSecretOld);
|
||||
}
|
||||
}
|
||||
|
||||
protected async migrateStateFrom1To2(useSecureStorageForSecrets: boolean = true): Promise<void> {
|
||||
await super.migrateStateFrom1To2();
|
||||
const state = await this.storageService.get<State<Account>>(Keys.state);
|
||||
const userId = await this.storageService.get<string>(Keys.entityId);
|
||||
|
||||
if (userId != null) {
|
||||
state.accounts[userId] = new Account({
|
||||
directorySettings: {
|
||||
directoryType: await this.storageService.get<DirectoryType>(Keys.directoryType),
|
||||
organizationId: await this.storageService.get<string>(Keys.organizationId),
|
||||
lastUserSync: await this.storageService.get<Date>(Keys.lastUserSync),
|
||||
lastGroupSync: await this.storageService.get<Date>(Keys.lastGroupSync),
|
||||
lastSyncHash: await this.storageService.get<string>(Keys.lastSyncHash),
|
||||
syncingDir: await this.storageService.get<boolean>(Keys.syncingDir),
|
||||
sync: await this.storageService.get<SyncConfiguration>(Keys.syncConfig),
|
||||
},
|
||||
profile: {
|
||||
entityId: await this.storageService.get<string>(Keys.entityId),
|
||||
},
|
||||
directoryConfigurations: new DirectoryConfigurations(),
|
||||
clientKeys: {
|
||||
clientId: await this.storageService.get<string>(ClientKeys.clientId),
|
||||
clientSecret: await this.storageService.get<string>(ClientKeys.clientSecret),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (const key in DirectoryType) {
|
||||
if (await this.storageService.has(SecureStorageKeys.directoryConfigPrefix + key)) {
|
||||
switch (+key) {
|
||||
case DirectoryType.Ldap:
|
||||
state.accounts[userId].directoryConfigurations.ldap =
|
||||
await this.storageService.get<LdapConfiguration>(
|
||||
SecureStorageKeys.directoryConfigPrefix + key
|
||||
);
|
||||
break;
|
||||
case DirectoryType.GSuite:
|
||||
state.accounts[userId].directoryConfigurations.gsuite =
|
||||
await this.storageService.get<GSuiteConfiguration>(
|
||||
SecureStorageKeys.directoryConfigPrefix + key
|
||||
);
|
||||
break;
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
state.accounts[userId].directoryConfigurations.azure =
|
||||
await this.storageService.get<AzureConfiguration>(
|
||||
SecureStorageKeys.directoryConfigPrefix + key
|
||||
);
|
||||
break;
|
||||
case DirectoryType.Okta:
|
||||
state.accounts[userId].directoryConfigurations.okta =
|
||||
await this.storageService.get<OktaConfiguration>(
|
||||
SecureStorageKeys.directoryConfigPrefix + key
|
||||
);
|
||||
break;
|
||||
case DirectoryType.OneLogin:
|
||||
state.accounts[userId].directoryConfigurations.oneLogin =
|
||||
await this.storageService.get<OneLoginConfiguration>(
|
||||
SecureStorageKeys.directoryConfigPrefix + key
|
||||
);
|
||||
break;
|
||||
}
|
||||
await this.storageService.remove(SecureStorageKeys.directoryConfigPrefix + key);
|
||||
}
|
||||
}
|
||||
|
||||
state.globals.environmentUrls = await this.storageService.get("environmentUrls");
|
||||
|
||||
await this.storageService.save("state", state);
|
||||
|
||||
if (useSecureStorageForSecrets) {
|
||||
for (const key in SecureStorageKeys) {
|
||||
if (await this.secureStorageService.has(SecureStorageKeys[key])) {
|
||||
await this.secureStorageService.save(
|
||||
`${userId}_${SecureStorageKeys[key]}`,
|
||||
await this.secureStorageService.get(SecureStorageKeys[key])
|
||||
);
|
||||
await this.secureStorageService.remove(SecureStorageKeys[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||
|
||||
import { Utils } from "jslib-common/misc/utils";
|
||||
|
||||
import { StateService } from "../abstractions/state.service";
|
||||
import { AzureDirectoryService } from "./azure-directory.service";
|
||||
import { ConfigurationService } from "./configuration.service";
|
||||
import { IDirectoryService } from "./directory.service";
|
||||
import { GSuiteDirectoryService } from "./gsuite-directory.service";
|
||||
import { LdapDirectoryService } from "./ldap-directory.service";
|
||||
@@ -27,17 +27,17 @@ export class SyncService {
|
||||
private dirType: DirectoryType;
|
||||
|
||||
constructor(
|
||||
private configurationService: ConfigurationService,
|
||||
private logService: LogService,
|
||||
private cryptoFunctionService: CryptoFunctionService,
|
||||
private apiService: ApiService,
|
||||
private messagingService: MessagingService,
|
||||
private i18nService: I18nService,
|
||||
private environmentService: EnvironmentService
|
||||
private environmentService: EnvironmentService,
|
||||
private stateService: StateService
|
||||
) {}
|
||||
|
||||
async sync(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||
this.dirType = await this.configurationService.getDirectoryType();
|
||||
this.dirType = await this.stateService.getDirectoryType();
|
||||
if (this.dirType == null) {
|
||||
throw new Error("No directory configured.");
|
||||
}
|
||||
@@ -47,9 +47,9 @@ export class SyncService {
|
||||
throw new Error("Cannot load directory service.");
|
||||
}
|
||||
|
||||
const syncConfig = await this.configurationService.getSync();
|
||||
const startingGroupDelta = await this.configurationService.getGroupDeltaToken();
|
||||
const startingUserDelta = await this.configurationService.getUserDeltaToken();
|
||||
const syncConfig = await this.stateService.getSync();
|
||||
const startingGroupDelta = await this.stateService.getGroupDelta();
|
||||
const startingUserDelta = await this.stateService.getUserDelta();
|
||||
const now = new Date();
|
||||
|
||||
this.messagingService.send("dirSyncStarted");
|
||||
@@ -90,7 +90,7 @@ export class SyncService {
|
||||
);
|
||||
const reqJson = JSON.stringify(req);
|
||||
|
||||
const orgId = await this.configurationService.getOrganizationId();
|
||||
const orgId = await this.stateService.getOrganizationId();
|
||||
if (orgId == null) {
|
||||
throw new Error("Organization not set.");
|
||||
}
|
||||
@@ -112,11 +112,11 @@ export class SyncService {
|
||||
if (hashBuff != null) {
|
||||
hash = Utils.fromBufferToB64(hashBuff);
|
||||
}
|
||||
const lastHash = await this.configurationService.getLastSyncHash();
|
||||
const lastHash = await this.stateService.getLastSyncHash();
|
||||
|
||||
if (lastHash == null || (hash !== lastHash && hashLegacy !== lastHash)) {
|
||||
await this.apiService.postPublicImportDirectory(req);
|
||||
await this.configurationService.saveLastSyncHash(hash);
|
||||
await this.stateService.setLastSyncHash(hash);
|
||||
} else {
|
||||
groups = null;
|
||||
users = null;
|
||||
@@ -127,8 +127,8 @@ export class SyncService {
|
||||
return [groups, users];
|
||||
} catch (e) {
|
||||
if (!test) {
|
||||
await this.configurationService.saveGroupDeltaToken(startingGroupDelta);
|
||||
await this.configurationService.saveUserDeltaToken(startingUserDelta);
|
||||
await this.stateService.setGroupDelta(startingGroupDelta);
|
||||
await this.stateService.setUserDelta(startingUserDelta);
|
||||
}
|
||||
|
||||
this.messagingService.send("dirSyncCompleted", { successfully: false });
|
||||
@@ -200,35 +200,15 @@ export class SyncService {
|
||||
private getDirectoryService(): IDirectoryService {
|
||||
switch (this.dirType) {
|
||||
case DirectoryType.GSuite:
|
||||
return new GSuiteDirectoryService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.i18nService
|
||||
);
|
||||
return new GSuiteDirectoryService(this.logService, this.i18nService, this.stateService);
|
||||
case DirectoryType.AzureActiveDirectory:
|
||||
return new AzureDirectoryService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.i18nService
|
||||
);
|
||||
return new AzureDirectoryService(this.logService, this.i18nService, this.stateService);
|
||||
case DirectoryType.Ldap:
|
||||
return new LdapDirectoryService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.i18nService
|
||||
);
|
||||
return new LdapDirectoryService(this.logService, this.i18nService, this.stateService);
|
||||
case DirectoryType.Okta:
|
||||
return new OktaDirectoryService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.i18nService
|
||||
);
|
||||
return new OktaDirectoryService(this.logService, this.i18nService, this.stateService);
|
||||
case DirectoryType.OneLogin:
|
||||
return new OneLoginDirectoryService(
|
||||
this.configurationService,
|
||||
this.logService,
|
||||
this.i18nService
|
||||
);
|
||||
return new OneLoginDirectoryService(this.logService, this.i18nService, this.stateService);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -263,10 +243,10 @@ export class SyncService {
|
||||
|
||||
private async saveSyncTimes(syncConfig: SyncConfiguration, time: Date) {
|
||||
if (syncConfig.groups) {
|
||||
await this.configurationService.saveLastGroupSyncDate(time);
|
||||
await this.stateService.setLastGroupSync(time);
|
||||
}
|
||||
if (syncConfig.users) {
|
||||
await this.configurationService.saveLastUserSyncDate(time);
|
||||
await this.stateService.setLastUserSync(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user