mirror of
https://github.com/bitwarden/directory-connector
synced 2025-12-11 05:43:26 +00:00
sync logic
This commit is contained in:
@@ -71,7 +71,7 @@ const containerService = new ContainerService(cryptoService, platformUtilsServic
|
|||||||
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
const authService = new AuthService(cryptoService, apiService, userService, tokenService, appIdService,
|
||||||
i18nService, platformUtilsService, messagingService, false);
|
i18nService, platformUtilsService, messagingService, false);
|
||||||
const configurationService = new ConfigurationService(storageService, secureStorageService);
|
const configurationService = new ConfigurationService(storageService, secureStorageService);
|
||||||
const syncSevrice = new SyncService(configurationService, logService);
|
const syncSevrice = new SyncService(configurationService, logService, cryptoFunctionService, apiService);
|
||||||
|
|
||||||
const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService);
|
const analytics = new Analytics(window, () => true, platformUtilsService, storageService, appIdService);
|
||||||
containerService.attachToWindow(window);
|
containerService.attachToWindow(window);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class DashboardComponent {
|
|||||||
constructor(private i18nService: I18nService, private syncService: SyncService) { }
|
constructor(private i18nService: I18nService, private syncService: SyncService) { }
|
||||||
|
|
||||||
async sync() {
|
async sync() {
|
||||||
this.syncPromise = this.syncService.sync(false, true);
|
this.syncPromise = this.syncService.sync(false, false);
|
||||||
await this.syncPromise;
|
await this.syncPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ export class DashboardComponent {
|
|||||||
|
|
||||||
this.simPromise = new Promise(async (resolve, reject) => {
|
this.simPromise = new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const result = await this.syncService.sync(!this.simSinceLast, false);
|
const result = await this.syncService.sync(!this.simSinceLast, true);
|
||||||
this.simUsers = result[1];
|
this.simUsers = result[1];
|
||||||
this.simGroups = result[0];
|
this.simGroups = result[0];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -51,7 +51,7 @@ export class DashboardComponent {
|
|||||||
const userMap = new Map<string, UserEntry>();
|
const userMap = new Map<string, UserEntry>();
|
||||||
if (this.simUsers != null) {
|
if (this.simUsers != null) {
|
||||||
this.sort(this.simUsers);
|
this.sort(this.simUsers);
|
||||||
this.simUsers.forEach((u) => {
|
for (const u of this.simUsers) {
|
||||||
userMap.set(u.externalId, u);
|
userMap.set(u.externalId, u);
|
||||||
if (u.deleted) {
|
if (u.deleted) {
|
||||||
this.simDeletedUsers.push(u);
|
this.simDeletedUsers.push(u);
|
||||||
@@ -60,29 +60,29 @@ export class DashboardComponent {
|
|||||||
} else {
|
} else {
|
||||||
this.simEnabledUsers.push(u);
|
this.simEnabledUsers.push(u);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userMap.size > 0 && this.simGroups != null) {
|
if (userMap.size > 0 && this.simGroups != null) {
|
||||||
this.sort(this.simGroups);
|
this.sort(this.simGroups);
|
||||||
this.simGroups.forEach((g) => {
|
for (const g of this.simGroups) {
|
||||||
if (g.userMemberExternalIds == null) {
|
if (g.userMemberExternalIds == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g.userMemberExternalIds.forEach((uid) => {
|
for (const uid of g.userMemberExternalIds) {
|
||||||
if (userMap.has(uid)) {
|
if (userMap.has(uid)) {
|
||||||
if ((g as any).users == null) {
|
if ((g as any).users == null) {
|
||||||
(g as any).users = [];
|
(g as any).users = [];
|
||||||
}
|
}
|
||||||
(g as any).users.push(userMap.get(uid));
|
(g as any).users.push(userMap.get(uid));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if ((g as any).users != null) {
|
if ((g as any).users != null) {
|
||||||
this.sort((g as any).users);
|
this.sort((g as any).users);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||||
const type = await this.configurationService.getDirectoryType();
|
const type = await this.configurationService.getDirectoryType();
|
||||||
if (type !== DirectoryType.AzureActiveDirectory) {
|
if (type !== DirectoryType.AzureActiveDirectory) {
|
||||||
return;
|
return;
|
||||||
@@ -47,7 +47,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
let users: UserEntry[];
|
let users: UserEntry[];
|
||||||
if (this.syncConfig.users) {
|
if (this.syncConfig.users) {
|
||||||
users = await this.getUsers(force);
|
users = await this.getUsers(force, !test);
|
||||||
}
|
}
|
||||||
|
|
||||||
let groups: GroupEntry[];
|
let groups: GroupEntry[];
|
||||||
@@ -57,7 +57,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
const groupForce = force ||
|
const groupForce = force ||
|
||||||
(users != null && users.filter((u) => !u.deleted && !u.disabled).length > 0);
|
(users != null && users.filter((u) => !u.deleted && !u.disabled).length > 0);
|
||||||
|
|
||||||
groups = await this.getGroups(groupForce, setFilter);
|
groups = await this.getGroups(groupForce, !test, setFilter);
|
||||||
if (setFilter != null && users != null) {
|
if (setFilter != null && users != null) {
|
||||||
users = users.filter((u) => {
|
users = users.filter((u) => {
|
||||||
if (u.disabled || u.deleted) {
|
if (u.disabled || u.deleted) {
|
||||||
@@ -72,7 +72,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
return [groups, users];
|
return [groups, users];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getUsers(force: boolean): Promise<UserEntry[]> {
|
private async getUsers(force: boolean, saveDelta: boolean): Promise<UserEntry[]> {
|
||||||
const entries: UserEntry[] = [];
|
const entries: UserEntry[] = [];
|
||||||
|
|
||||||
let res: any = null;
|
let res: any = null;
|
||||||
@@ -95,7 +95,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
while (true) {
|
while (true) {
|
||||||
const users: graphType.User[] = res.value;
|
const users: graphType.User[] = res.value;
|
||||||
if (users != null) {
|
if (users != null) {
|
||||||
users.forEach((user) => {
|
for (const user of users) {
|
||||||
const entry = this.buildUser(user);
|
const entry = this.buildUser(user);
|
||||||
if (this.filterOutResult(filter, entry.email)) {
|
if (this.filterOutResult(filter, entry.email)) {
|
||||||
return;
|
return;
|
||||||
@@ -107,11 +107,11 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res[NextLink] == null) {
|
if (res[NextLink] == null) {
|
||||||
if (res[DeltaLink] != null) {
|
if (res[DeltaLink] != null && saveDelta) {
|
||||||
await this.configurationService.saveUserDeltaToken(res[DeltaLink]);
|
await this.configurationService.saveUserDeltaToken(res[DeltaLink]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -138,7 +138,8 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getGroups(force: boolean, setFilter: [boolean, Set<string>]): Promise<GroupEntry[]> {
|
private async getGroups(force: boolean, saveDelta: boolean,
|
||||||
|
setFilter: [boolean, Set<string>]): Promise<GroupEntry[]> {
|
||||||
const entries: GroupEntry[] = [];
|
const entries: GroupEntry[] = [];
|
||||||
const changedGroupIds: string[] = [];
|
const changedGroupIds: string[] = [];
|
||||||
const token = await this.configurationService.getGroupDeltaToken();
|
const token = await this.configurationService.getGroupDeltaToken();
|
||||||
@@ -179,7 +180,7 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (res[NextLink] == null) {
|
if (res[NextLink] == null) {
|
||||||
if (res[DeltaLink] != null) {
|
if (res[DeltaLink] != null && saveDelta) {
|
||||||
await this.configurationService.saveGroupDeltaToken(res[DeltaLink]);
|
await this.configurationService.saveGroupDeltaToken(res[DeltaLink]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -232,13 +233,13 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
const memRes = await memReq.get();
|
const memRes = await memReq.get();
|
||||||
const members: any = memRes.value;
|
const members: any = memRes.value;
|
||||||
if (members != null) {
|
if (members != null) {
|
||||||
members.forEach((member: any) => {
|
for (const member of members) {
|
||||||
if (member[ObjectType] === '#microsoft.graph.group') {
|
if (member[ObjectType] === '#microsoft.graph.group') {
|
||||||
entry.groupMemberReferenceIds.add((member as graphType.Group).id);
|
entry.groupMemberReferenceIds.add((member as graphType.Group).id);
|
||||||
} else if (member[ObjectType] === '#microsoft.graph.user') {
|
} else if (member[ObjectType] === '#microsoft.graph.user') {
|
||||||
entry.userMemberExternalIds.add((member as graphType.User).id);
|
entry.userMemberExternalIds.add((member as graphType.User).id);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -266,9 +267,9 @@ export class AzureDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
const set = new Set<string>();
|
const set = new Set<string>();
|
||||||
const pieces = parts[1].split(',');
|
const pieces = parts[1].split(',');
|
||||||
pieces.forEach((p) => {
|
for (const p of pieces) {
|
||||||
set.add(p.trim().toLowerCase());
|
set.add(p.trim().toLowerCase());
|
||||||
});
|
}
|
||||||
|
|
||||||
return [exclude, set];
|
return [exclude, set];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ const Keys = {
|
|||||||
groupDelta: 'groupDeltaToken',
|
groupDelta: 'groupDeltaToken',
|
||||||
lastUserSync: 'lastUserSync',
|
lastUserSync: 'lastUserSync',
|
||||||
lastGroupSync: 'lastGroupSync',
|
lastGroupSync: 'lastGroupSync',
|
||||||
|
lastSyncHash: 'lastSyncHash',
|
||||||
|
organizationId: 'organizationId',
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ConfigurationService {
|
export class ConfigurationService {
|
||||||
@@ -145,4 +147,28 @@ export class ConfigurationService {
|
|||||||
return this.storageService.save(Keys.lastGroupSync, date);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveOrganizationId(id: string) {
|
||||||
|
if (id == null) {
|
||||||
|
return this.storageService.remove(Keys.organizationId);
|
||||||
|
} else {
|
||||||
|
return this.storageService.save(Keys.organizationId, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ import { GroupEntry } from '../models/groupEntry';
|
|||||||
import { UserEntry } from '../models/userEntry';
|
import { UserEntry } from '../models/userEntry';
|
||||||
|
|
||||||
export interface DirectoryService {
|
export interface DirectoryService {
|
||||||
getEntries(force?: boolean): Promise<[GroupEntry[], UserEntry[]]>;
|
getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
this.service = google.admin<Admin>('directory_v1');
|
this.service = google.admin<Admin>('directory_v1');
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||||
const type = await this.configurationService.getDirectoryType();
|
const type = await this.configurationService.getDirectoryType();
|
||||||
if (type !== DirectoryType.GSuite) {
|
if (type !== DirectoryType.GSuite) {
|
||||||
return;
|
return;
|
||||||
@@ -76,7 +76,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
const filter = this.createSet(this.syncConfig.userFilter);
|
const filter = this.createSet(this.syncConfig.userFilter);
|
||||||
if (res.data.users != null) {
|
if (res.data.users != null) {
|
||||||
res.data.users.forEach((user) => {
|
for (const user of res.data.users) {
|
||||||
if (this.filterOutResult(filter, user.primaryEmail)) {
|
if (this.filterOutResult(filter, user.primaryEmail)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logService.info('Querying deleted users.');
|
this.logService.info('Querying deleted users.');
|
||||||
@@ -96,7 +96,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (delRes.data.users != null) {
|
if (delRes.data.users != null) {
|
||||||
delRes.data.users.forEach((user) => {
|
for (const user of delRes.data.users) {
|
||||||
if (this.filterOutResult(filter, user.primaryEmail)) {
|
if (this.filterOutResult(filter, user.primaryEmail)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entries.push(entry);
|
entries.push(entry);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
@@ -164,7 +164,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (memRes.data.members != null) {
|
if (memRes.data.members != null) {
|
||||||
memRes.data.members.forEach((member) => {
|
for (const member of memRes.data.members) {
|
||||||
if (member.role.toLowerCase() !== 'member') {
|
if (member.role.toLowerCase() !== 'member') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
} else if (member.type.toLowerCase() === 'group') {
|
} else if (member.type.toLowerCase() === 'group') {
|
||||||
entry.groupMemberReferenceIds.add(member.id);
|
entry.groupMemberReferenceIds.add(member.id);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -223,9 +223,9 @@ export class GSuiteDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
const set = new Set<string>();
|
const set = new Set<string>();
|
||||||
const pieces = parts[1].split(',');
|
const pieces = parts[1].split(',');
|
||||||
pieces.forEach((p) => {
|
for (const p of pieces) {
|
||||||
set.add(p.trim().toLowerCase());
|
set.add(p.trim().toLowerCase());
|
||||||
});
|
}
|
||||||
|
|
||||||
return [exclude, set];
|
return [exclude, set];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
constructor(private configurationService: ConfigurationService, private logService: LogService) { }
|
constructor(private configurationService: ConfigurationService, private logService: LogService) { }
|
||||||
|
|
||||||
async getEntries(force = false): Promise<[GroupEntry[], UserEntry[]]> {
|
async getEntries(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||||
const type = await this.configurationService.getDirectoryType();
|
const type = await this.configurationService.getDirectoryType();
|
||||||
if (type !== DirectoryType.Ldap) {
|
if (type !== DirectoryType.Ldap) {
|
||||||
return;
|
return;
|
||||||
@@ -61,7 +61,6 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
private async getUsers(force: boolean): Promise<UserEntry[]> {
|
private async getUsers(force: boolean): Promise<UserEntry[]> {
|
||||||
const lastSync = await this.configurationService.getLastUserSyncDate();
|
const lastSync = await this.configurationService.getLastUserSyncDate();
|
||||||
|
|
||||||
let filter = this.buildBaseFilter(this.syncConfig.userObjectClass, this.syncConfig.userFilter);
|
let filter = this.buildBaseFilter(this.syncConfig.userObjectClass, this.syncConfig.userFilter);
|
||||||
filter = this.buildRevisionFilter(filter, force, lastSync);
|
filter = this.buildRevisionFilter(filter, force, lastSync);
|
||||||
|
|
||||||
@@ -121,7 +120,6 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
const entries: GroupEntry[] = [];
|
const entries: GroupEntry[] = [];
|
||||||
|
|
||||||
const lastSync = await this.configurationService.getLastUserSyncDate();
|
const lastSync = await this.configurationService.getLastUserSyncDate();
|
||||||
|
|
||||||
const originalFilter = this.buildBaseFilter(this.syncConfig.groupObjectClass, this.syncConfig.groupFilter);
|
const originalFilter = this.buildBaseFilter(this.syncConfig.groupObjectClass, this.syncConfig.groupFilter);
|
||||||
let filter = originalFilter;
|
let filter = originalFilter;
|
||||||
const revisionFilter = this.buildRevisionFilter(filter, force, lastSync);
|
const revisionFilter = this.buildRevisionFilter(filter, force, lastSync);
|
||||||
@@ -151,12 +149,12 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
return se;
|
return se;
|
||||||
});
|
});
|
||||||
|
|
||||||
groupSearchEntries.forEach((se) => {
|
for (const se of groupSearchEntries) {
|
||||||
const group = this.buildGroup(se, userIdMap);
|
const group = this.buildGroup(se, userIdMap);
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
entries.push(group);
|
entries.push(group);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
@@ -181,13 +179,13 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
|
|
||||||
const members = this.getAttrVals(searchEntry, this.syncConfig.memberAttribute);
|
const members = this.getAttrVals(searchEntry, this.syncConfig.memberAttribute);
|
||||||
if (members != null) {
|
if (members != null) {
|
||||||
members.forEach((memDn) => {
|
for (const memDn of members) {
|
||||||
if (userMap.has(memDn) && !group.userMemberExternalIds.has(userMap.get(memDn))) {
|
if (userMap.has(memDn) && !group.userMemberExternalIds.has(userMap.get(memDn))) {
|
||||||
group.userMemberExternalIds.add(userMap.get(memDn));
|
group.userMemberExternalIds.add(userMap.get(memDn));
|
||||||
} else if (!group.groupMemberReferenceIds.has(memDn)) {
|
} else if (!group.groupMemberReferenceIds.has(memDn)) {
|
||||||
group.groupMemberReferenceIds.add(memDn);
|
group.groupMemberReferenceIds.add(memDn);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return group;
|
return group;
|
||||||
@@ -326,9 +324,14 @@ export class LdapDirectoryService implements DirectoryService {
|
|||||||
const pass = this.dirConfig.password == null || this.dirConfig.password.trim() === '' ? null :
|
const pass = this.dirConfig.password == null || this.dirConfig.password.trim() === '' ? null :
|
||||||
this.dirConfig.password;
|
this.dirConfig.password;
|
||||||
|
|
||||||
|
if (user == null || pass == null) {
|
||||||
|
reject('Username and/or password re not configured.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.client.bind(user, pass, (err) => {
|
this.client.bind(user, pass, (err) => {
|
||||||
if (err != null) {
|
if (err != null) {
|
||||||
reject(err);
|
reject('Error authenticating: ' + err.message);
|
||||||
} else {
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { ImportDirectoryRequest } from 'jslib/models/request/importDirectoryRequ
|
|||||||
import { ImportDirectoryRequestGroup } from 'jslib/models/request/importDirectoryRequestGroup';
|
import { ImportDirectoryRequestGroup } from 'jslib/models/request/importDirectoryRequestGroup';
|
||||||
import { ImportDirectoryRequestUser } from 'jslib/models/request/importDirectoryRequestUser';
|
import { ImportDirectoryRequestUser } from 'jslib/models/request/importDirectoryRequestUser';
|
||||||
|
|
||||||
|
import { ApiService } from 'jslib/abstractions/api.service';
|
||||||
|
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||||
import { LogService } from 'jslib/abstractions/log.service';
|
import { LogService } from 'jslib/abstractions/log.service';
|
||||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
|
||||||
@@ -15,6 +17,7 @@ import { ConfigurationService } from './configuration.service';
|
|||||||
import { DirectoryService } from './directory.service';
|
import { DirectoryService } from './directory.service';
|
||||||
import { GSuiteDirectoryService } from './gsuite-directory.service';
|
import { GSuiteDirectoryService } from './gsuite-directory.service';
|
||||||
import { LdapDirectoryService } from './ldap-directory.service';
|
import { LdapDirectoryService } from './ldap-directory.service';
|
||||||
|
import { Utils } from 'jslib/misc/utils';
|
||||||
|
|
||||||
const Keys = {
|
const Keys = {
|
||||||
};
|
};
|
||||||
@@ -22,9 +25,10 @@ const Keys = {
|
|||||||
export class SyncService {
|
export class SyncService {
|
||||||
private dirType: DirectoryType;
|
private dirType: DirectoryType;
|
||||||
|
|
||||||
constructor(private configurationService: ConfigurationService, private logService: LogService) { }
|
constructor(private configurationService: ConfigurationService, private logService: LogService,
|
||||||
|
private cryptoFunctionService: CryptoFunctionService, private apiService: ApiService) { }
|
||||||
|
|
||||||
async sync(force = true, sendToServer = true): Promise<[GroupEntry[], UserEntry[]]> {
|
async sync(force: boolean, test: boolean): Promise<[GroupEntry[], UserEntry[]]> {
|
||||||
this.dirType = await this.configurationService.getDirectoryType();
|
this.dirType = await this.configurationService.getDirectoryType();
|
||||||
if (this.dirType == null) {
|
if (this.dirType == null) {
|
||||||
throw new Error('No directory configured.');
|
throw new Error('No directory configured.');
|
||||||
@@ -41,7 +45,7 @@ export class SyncService {
|
|||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const entries = await directoryService.getEntries(force);
|
const entries = await directoryService.getEntries(force, test);
|
||||||
const groups = entries[0];
|
const groups = entries[0];
|
||||||
const users = entries[1];
|
const users = entries[1];
|
||||||
|
|
||||||
@@ -49,27 +53,48 @@ export class SyncService {
|
|||||||
this.flattenUsersToGroups(groups, null, groups);
|
this.flattenUsersToGroups(groups, null, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(groups);
|
if (test || groups == null || groups.length === 0 || users == null || users.length === 0) {
|
||||||
console.log(users);
|
|
||||||
|
|
||||||
if (!sendToServer) {
|
|
||||||
// TODO: restore deltas
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sendToServer || groups == null || groups.length === 0 || users == null || users.length === 0) {
|
|
||||||
return [groups, users];
|
return [groups, users];
|
||||||
}
|
}
|
||||||
|
|
||||||
const req = this.buildRequest(groups, users, syncConfig.removeDisabled);
|
const req = this.buildRequest(groups, users, syncConfig.removeDisabled);
|
||||||
|
const reqJson = JSON.stringify(req);
|
||||||
|
|
||||||
|
let hash: string = null;
|
||||||
|
const hashBuf = await this.cryptoFunctionService.hash(this.apiService.baseUrl + reqJson, 'sha256');
|
||||||
|
if (hashBuf != null) {
|
||||||
|
hash = Utils.fromBufferToB64(hashBuf);
|
||||||
|
}
|
||||||
|
const lastHash = await this.configurationService.getLastSyncHash();
|
||||||
|
|
||||||
|
if (lastHash == null || hash !== lastHash) {
|
||||||
|
const orgId = await this.configurationService.getOrganizationId();
|
||||||
|
if (orgId == null) {
|
||||||
|
throw new Error('Organization not set.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.apiService.postImportDirectory(orgId, req);
|
||||||
|
await this.configurationService.saveLastSyncHash(hash);
|
||||||
|
if (syncConfig.groups) {
|
||||||
|
await this.configurationService.saveLastGroupSyncDate(now);
|
||||||
|
}
|
||||||
|
if (syncConfig.users) {
|
||||||
|
await this.configurationService.saveLastUserSyncDate(now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [groups, users];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO: restore deltas
|
if (!test) {
|
||||||
// failed sync result
|
await this.configurationService.saveGroupDeltaToken(startingGroupDelta);
|
||||||
|
await this.configurationService.saveUserDeltaToken(startingUserDelta);
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private flattenUsersToGroups(currentGroups: GroupEntry[], currentGroupsUsers: string[], allGroups: GroupEntry[]) {
|
private flattenUsersToGroups(currentGroups: GroupEntry[], currentGroupsUsers: string[], allGroups: GroupEntry[]) {
|
||||||
currentGroups.forEach((group) => {
|
for (const group of currentGroups) {
|
||||||
const groupsInThisGroup = allGroups.filter((g) => group.groupMemberReferenceIds.has(g.referenceId));
|
const groupsInThisGroup = allGroups.filter((g) => group.groupMemberReferenceIds.has(g.referenceId));
|
||||||
let usersInThisGroup = Array.from(group.userMemberExternalIds);
|
let usersInThisGroup = Array.from(group.userMemberExternalIds);
|
||||||
|
|
||||||
@@ -79,7 +104,7 @@ export class SyncService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.flattenUsersToGroups(groupsInThisGroup, usersInThisGroup, allGroups);
|
this.flattenUsersToGroups(groupsInThisGroup, usersInThisGroup, allGroups);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getDirectoryService(): DirectoryService {
|
private getDirectoryService(): DirectoryService {
|
||||||
@@ -99,23 +124,23 @@ export class SyncService {
|
|||||||
const model = new ImportDirectoryRequest();
|
const model = new ImportDirectoryRequest();
|
||||||
|
|
||||||
if (groups != null) {
|
if (groups != null) {
|
||||||
groups.forEach((g) => {
|
for (const g of groups) {
|
||||||
const ig = new ImportDirectoryRequestGroup();
|
const ig = new ImportDirectoryRequestGroup();
|
||||||
ig.name = g.name;
|
ig.name = g.name;
|
||||||
ig.externalId = g.externalId;
|
ig.externalId = g.externalId;
|
||||||
ig.users = Array.from(g.userMemberExternalIds);
|
ig.users = Array.from(g.userMemberExternalIds);
|
||||||
model.groups.push(ig);
|
model.groups.push(ig);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (users != null) {
|
if (users != null) {
|
||||||
users.forEach((u) => {
|
for (const u of users) {
|
||||||
const iu = new ImportDirectoryRequestUser();
|
const iu = new ImportDirectoryRequestUser();
|
||||||
iu.email = u.email;
|
iu.email = u.email;
|
||||||
iu.externalId = u.externalId;
|
iu.externalId = u.externalId;
|
||||||
iu.deleted = u.deleted || (removeDisabled && u.disabled);
|
iu.deleted = u.deleted || (removeDisabled && u.disabled);
|
||||||
model.users.push(iu);
|
model.users.push(iu);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|||||||
Reference in New Issue
Block a user