diff --git a/package-lock.json b/package-lock.json index dedb1036..cef06d62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4572,14 +4572,14 @@ } }, "googleapis": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-28.1.0.tgz", - "integrity": "sha512-+kDXcTq5YUGjrzNOjE6eDaSQ/92bpBrDqj5TGz/AwhnXDqNVGMQey6eRQNMPdrJMYYBSZGYHza1CSIxO/LHEeA==", + "version": "29.0.0", + "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-29.0.0.tgz", + "integrity": "sha512-qac2RSPObw80AOvSPV9hus8VyRxrdaTnsUmttdO6hO12fBE5jI/R9XytUOuB3Z/4LP+1NpprNyKSHm9xXuJx2w==", "requires": { "google-auth-library": "1.4.0", "pify": "3.0.0", "qs": "6.5.1", - "string-template": "1.0.0", + "url-template": "2.0.8", "uuid": "3.2.1" } }, @@ -8961,11 +8961,6 @@ "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "dev": true }, - "string-template": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz", - "integrity": "sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y=" - }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -10068,6 +10063,11 @@ "prepend-http": "1.0.4" } }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", diff --git a/package.json b/package.json index 6c362dfd..1a975580 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,7 @@ "electron-log": "2.2.14", "electron-store": "1.3.0", "electron-updater": "2.21.4", - "googleapis": "28.1.0", + "googleapis": "29.0.0", "keytar": "4.1.0", "ldapjs": "1.0.2", "lunr": "2.1.6", diff --git a/src/app/tabs/dashboard.component.html b/src/app/tabs/dashboard.component.html index 8cd5ca7b..bc12410b 100644 --- a/src/app/tabs/dashboard.component.html +++ b/src/app/tabs/dashboard.component.html @@ -1,3 +1,7 @@ The dashboard!! + + + + diff --git a/src/app/tabs/dashboard.component.ts b/src/app/tabs/dashboard.component.ts index 1a233db0..4cf47c1a 100644 --- a/src/app/tabs/dashboard.component.ts +++ b/src/app/tabs/dashboard.component.ts @@ -12,6 +12,10 @@ import { I18nService } from 'jslib/abstractions/i18n.service'; import { ModalComponent } from 'jslib/angular/components/modal.component'; +import { AzureDirectoryService } from '../../services/azure-directory.service'; +import { GSuiteDirectoryService } from '../../services/gsuite-directory.service'; +import { LdapDirectoryService } from '../../services/ldap-directory.service'; + @Component({ selector: 'app-dashboard', templateUrl: 'dashboard.component.html', @@ -20,5 +24,20 @@ export class DashboardComponent { @ViewChild('settings', { read: ViewContainerRef }) settingsModal: ViewContainerRef; constructor(analytics: Angulartics2, toasterService: ToasterService, - i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver) {} + i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver) { } + + gsuite() { + const gsuite = new GSuiteDirectoryService(); + const entries = gsuite.getEntries(); + } + + ldap() { + const gsuite = new LdapDirectoryService(); + const entries = gsuite.getEntries(); + } + + azuread() { + const gsuite = new AzureDirectoryService(); + const entries = gsuite.getEntries(); + } } diff --git a/src/services/azure-directory.service.ts b/src/services/azure-directory.service.ts index a31dbf18..4e0b8f22 100644 --- a/src/services/azure-directory.service.ts +++ b/src/services/azure-directory.service.ts @@ -1,12 +1,74 @@ import * as graph from '@microsoft/microsoft-graph-client'; +import * as https from 'https'; +import * as querystring from 'querystring'; import { DirectoryService } from 'src/services/directory.service'; +const Key = ''; +const ApplicationId = ''; +const Tenant = ''; + export class AzureDirectoryService implements DirectoryService { - getEntries(force = false) { + private client: graph.Client; + + async getEntries(force = false) { + this.client = graph.Client.init({ + authProvider: (done) => { + const data = querystring.stringify({ + client_id: ApplicationId, + client_secret: Key, + grant_type: 'client_credentials', + scope: 'https://graph.microsoft.com/.default', + }); + + const req = https.request({ + host: 'login.microsoftonline.com', + path: '/' + Tenant + '/oauth2/v2.0/token', + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': Buffer.byteLength(data), + }, + }, (res) => { + res.setEncoding('utf8'); + res.on('data', (chunk: string) => { + const d = JSON.parse(chunk); + if (res.statusCode === 200 && d.access_token != null) { + done(null, d.access_token); + } else if (d.error != null && d.error_description != null) { + done(d.error + ' (' + res.statusCode + '): ' + d.error_description, null); + } else { + done('Unknown error (' + res.statusCode + ').', null); + } + }); + }).on('error', (err) => { + done(err, null); + }); + + req.write(data); + req.end(); + }, + }); + + await this.getUsers(); + await this.getGroups(); } - private getUsers() { + private async getUsers() { + const request = this.client.api('/users/delta'); + const users = await request.get(); + console.log(users); + } + private async getGroups() { + const request = this.client.api('/groups/delta'); + const groups = await request.get(); + console.log(groups); + + groups.value.forEach(async (g: any) => { + const membersRequest = this.client.api('/groups/' + g.id + '/members'); + const members = await membersRequest.get(); + console.log(members); + }); } } diff --git a/src/services/gsuite-directory.service.ts b/src/services/gsuite-directory.service.ts index 43f8be16..87de4ef8 100644 --- a/src/services/gsuite-directory.service.ts +++ b/src/services/gsuite-directory.service.ts @@ -1,14 +1,69 @@ +import { JWT } from 'google-auth-library'; import { google, GoogleApis } from 'googleapis'; import { Admin } from 'googleapis/build/src/apis/admin/directory_v1'; import { DirectoryService } from 'src/services/directory.service'; +const PrivateKey = ''; +const ClientEmail = ''; +const AdminEmail = ''; +const Domain = ''; + export class GSuiteDirectoryService implements DirectoryService { - getEntries(force = false) { + private client: JWT; + private service: Admin; + private authParams: any; + + constructor() { + this.service = google.admin('directory_v1'); + } + + async getEntries(force = false) { + await this.auth(); + await this.getUsers(); + await this.getGroups(); } private async getUsers() { - const service = google.admin('directory_v1'); - const groups = await service.groups.list(); + const response = await this.service.users.list(this.authParams); + console.log(response); + } + + private async getGroups() { + const response = await this.service.groups.list(this.authParams); + console.log(response); + + if (response.data.groups.length === 0) { + return; + } + + response.data.groups.forEach(async (g) => { + const params: any = Object.assign({ + groupKey: g.id, + }, this.authParams); + const members = await this.service.members.list(params); + console.log(members); + }); + } + + private async auth() { + this.client = new google.auth.JWT({ + email: ClientEmail, + key: PrivateKey, + subject: AdminEmail, + scopes: [ + 'https://www.googleapis.com/auth/admin.directory.user.readonly', + 'https://www.googleapis.com/auth/admin.directory.group.readonly', + 'https://www.googleapis.com/auth/admin.directory.group.member.readonly', + ], + }); + + await this.client.authorize(); + this.authParams = { + auth: this.client, + domain: Domain, + }; + + // TODO: add customer? } } diff --git a/src/services/ldap-directory.service.ts b/src/services/ldap-directory.service.ts index 7521c4d3..6a94632e 100644 --- a/src/services/ldap-directory.service.ts +++ b/src/services/ldap-directory.service.ts @@ -2,37 +2,63 @@ import * as ldap from 'ldapjs'; import { DirectoryService } from 'src/services/directory.service'; +const Url = 'ldap://ldap.forumsys.com:389'; +const Username = 'cn=read-only-admin,dc=example,dc=com'; +const Password = 'password'; + export class LdapDirectoryService implements DirectoryService { - getEntries(force = false) { + private client: ldap.Client; + + async getEntries(force = false) { + await this.auth(); + await this.getUsers(); } private getUsers() { - const client = ldap.createClient({ - url: 'ldap://127.0.0.1:1389' - }); - const options: ldap.SearchOptions = { - filter: '(&(l=Seattle)(email=*@foo.com))', + filter: null, scope: 'sub', - attributes: ['dn', 'sn', 'cn'] + attributes: ['dn', 'sn', 'cn'], }; - client.search('o=example', options, (error, response) => { - if (error != null) { + return new Promise((resolve, reject) => { + this.client.search('dc=example,dc=com', options, (err, res) => { + if (err != null) { + console.error('search error: ' + err); + reject(err); + return; + } + res.on('searchEntry', (entry) => { + console.log(entry); + }); + res.on('searchReference', (referral) => { + console.log('referral: ' + referral.uris.join()); + }); + res.on('error', (resErr) => { + console.error('error: ' + resErr.message); + reject(resErr); + }); + res.on('end', (result) => { + console.log('status: ' + result.status); + }); - } + resolve(); + }); + }); + } - response.on('searchEntry', (entry) => { - console.log('entry: ' + JSON.stringify(entry.object)); + private async auth() { + return new Promise((resolve, reject) => { + this.client = ldap.createClient({ + url: Url, }); - response.on('searchReference', (referral) => { - console.log('referral: ' + referral.uris.join()); - }); - response.on('error', (err) => { - console.error('error: ' + err.message); - }); - response.on('end', (result) => { - console.log('status: ' + result.status); + + this.client.bind(Username, Password, (err) => { + if (err != null) { + reject(err); + } else { + resolve(); + } }); }); } diff --git a/webpack.renderer.js b/webpack.renderer.js index 28f2584c..687edc51 100644 --- a/webpack.renderer.js +++ b/webpack.renderer.js @@ -46,7 +46,7 @@ const common = { }, plugins: [], resolve: { - extensions: ['.tsx', '.ts', '.js'], + extensions: ['.tsx', '.ts', '.js', '.json'], alias: { jslib: path.join(__dirname, 'jslib/src') }, @@ -136,6 +136,7 @@ const renderer = { filename: '[name].js.map', include: ['app/main.js'] }), + new webpack.DefinePlugin({ 'global.GENTLY': false }), extractCss ] };