@boxyhq/saml-jackson 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/controller/error.d.ts +5 -0
  2. package/dist/controller/error.js +6 -1
  3. package/dist/controller/oauth.js +18 -4
  4. package/dist/controller/sp-config.d.ts +21 -0
  5. package/dist/controller/sp-config.js +74 -0
  6. package/dist/controller/utils.d.ts +13 -0
  7. package/dist/controller/utils.js +27 -1
  8. package/dist/db/mem.js +7 -3
  9. package/dist/directory-sync/Base.d.ts +15 -0
  10. package/dist/directory-sync/Base.js +39 -0
  11. package/dist/directory-sync/DirectoryConfig.d.ts +43 -0
  12. package/dist/directory-sync/DirectoryConfig.js +186 -0
  13. package/dist/directory-sync/DirectoryGroups.d.ts +26 -0
  14. package/dist/directory-sync/DirectoryGroups.js +254 -0
  15. package/dist/directory-sync/DirectoryUsers.d.ts +22 -0
  16. package/dist/directory-sync/DirectoryUsers.js +175 -0
  17. package/dist/directory-sync/Groups.d.ts +47 -0
  18. package/dist/directory-sync/Groups.js +195 -0
  19. package/dist/directory-sync/Users.d.ts +47 -0
  20. package/dist/directory-sync/Users.js +135 -0
  21. package/dist/directory-sync/WebhookEventsLogger.d.ts +13 -0
  22. package/dist/directory-sync/WebhookEventsLogger.js +57 -0
  23. package/dist/directory-sync/events.d.ts +7 -0
  24. package/dist/directory-sync/events.js +53 -0
  25. package/dist/directory-sync/index.d.ts +6 -0
  26. package/dist/directory-sync/index.js +42 -0
  27. package/dist/directory-sync/request.d.ts +7 -0
  28. package/dist/directory-sync/request.js +30 -0
  29. package/dist/directory-sync/transform.d.ts +7 -0
  30. package/dist/directory-sync/transform.js +26 -0
  31. package/dist/directory-sync/utils.d.ts +39 -0
  32. package/dist/directory-sync/utils.js +140 -0
  33. package/dist/index.d.ts +4 -1
  34. package/dist/index.js +10 -3
  35. package/dist/typings.d.ts +290 -9
  36. package/dist/typings.js +9 -0
  37. package/package.json +17 -14
@@ -1,5 +1,10 @@
1
+ import { ApiError } from '../typings';
1
2
  export declare class JacksonError extends Error {
2
3
  name: string;
3
4
  statusCode: number;
4
5
  constructor(message: string, statusCode?: number);
5
6
  }
7
+ export declare const apiError: (err: any) => {
8
+ data: null;
9
+ error: ApiError;
10
+ };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JacksonError = void 0;
3
+ exports.apiError = exports.JacksonError = void 0;
4
4
  class JacksonError extends Error {
5
5
  constructor(message, statusCode = 500) {
6
6
  super(message);
@@ -10,3 +10,8 @@ class JacksonError extends Error {
10
10
  }
11
11
  }
12
12
  exports.JacksonError = JacksonError;
13
+ const apiError = (err) => {
14
+ const { message, statusCode = 500 } = err;
15
+ return { data: null, error: { message, code: statusCode } };
16
+ };
17
+ exports.apiError = apiError;
@@ -161,6 +161,10 @@ class OAuthController {
161
161
  state,
162
162
  tenant,
163
163
  product,
164
+ access_type,
165
+ resource,
166
+ scope,
167
+ nonce,
164
168
  code_challenge,
165
169
  code_challenge_method,
166
170
  provider,
@@ -206,6 +210,10 @@ class OAuthController {
206
210
  state,
207
211
  tenant,
208
212
  product,
213
+ access_type,
214
+ resource,
215
+ scope,
216
+ nonce,
209
217
  code_challenge,
210
218
  code_challenge_method,
211
219
  provider,
@@ -294,7 +302,7 @@ class OAuthController {
294
302
  publicKey: samlConfig.certs.publicKey,
295
303
  });
296
304
  const sessionId = crypto_1.default.randomBytes(16).toString('hex');
297
- const requested = { client_id, state };
305
+ const requested = { client_id, state, redirect_uri };
298
306
  if (requestedTenant) {
299
307
  requested.tenant = requestedTenant;
300
308
  }
@@ -542,8 +550,9 @@ class OAuthController {
542
550
  * expires_in: 300
543
551
  */
544
552
  token(body) {
553
+ var _a, _b, _c;
545
554
  return __awaiter(this, void 0, void 0, function* () {
546
- const { client_id, client_secret, code_verifier, code, grant_type = 'authorization_code' } = body;
555
+ const { client_id, client_secret, code_verifier, code, grant_type = 'authorization_code', redirect_uri, } = body;
547
556
  metrics.increment('oauthToken');
548
557
  if (grant_type !== 'authorization_code') {
549
558
  throw new error_1.JacksonError('Unsupported grant_type', 400);
@@ -555,6 +564,11 @@ class OAuthController {
555
564
  if (!codeVal || !codeVal.profile) {
556
565
  throw new error_1.JacksonError('Invalid code', 403);
557
566
  }
567
+ if ((_a = codeVal.requested) === null || _a === void 0 ? void 0 : _a.redirect_uri) {
568
+ if (redirect_uri !== codeVal.requested.redirect_uri) {
569
+ throw new error_1.JacksonError(`Invalid request: ${!redirect_uri ? 'redirect_uri missing' : 'redirect_uri mismatch'}`, 400);
570
+ }
571
+ }
558
572
  if (code_verifier) {
559
573
  // PKCE flow
560
574
  let cv = code_verifier;
@@ -594,8 +608,8 @@ class OAuthController {
594
608
  // store details against a token
595
609
  const token = crypto_1.default.randomBytes(20).toString('hex');
596
610
  const tokenVal = Object.assign(Object.assign({}, codeVal.profile), { requested: codeVal.requested });
597
- const requestedOIDCFlow = !!codeVal.requested.oidc;
598
- const requestHasNonce = !!codeVal.requested.nonce;
611
+ const requestedOIDCFlow = !!((_b = codeVal.requested) === null || _b === void 0 ? void 0 : _b.oidc);
612
+ const requestHasNonce = !!((_c = codeVal.requested) === null || _c === void 0 ? void 0 : _c.nonce);
599
613
  if (requestedOIDCFlow) {
600
614
  const { jwtSigningKeys, jwsAlg } = this.opts.openid;
601
615
  if (!jwtSigningKeys || !(0, utils_1.isJWSKeyPairLoaded)(jwtSigningKeys)) {
@@ -0,0 +1,21 @@
1
+ import type { JacksonOption } from '../typings';
2
+ export declare class SPSAMLConfig {
3
+ private opts;
4
+ constructor(opts: JacksonOption);
5
+ private get acsUrl();
6
+ private get entityId();
7
+ private get responseSigned();
8
+ private get assertionSignature();
9
+ private get signatureAlgorithm();
10
+ private get assertionEncryption();
11
+ get(): {
12
+ acsUrl: string;
13
+ entityId: string;
14
+ response: string;
15
+ assertionSignature: string;
16
+ signatureAlgorithm: string;
17
+ assertionEncryption: string;
18
+ };
19
+ toMarkdown(): string;
20
+ toHTML(): string;
21
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SPSAMLConfig = void 0;
4
+ const marked_1 = require("marked");
5
+ // Service Provider SAML Configuration
6
+ class SPSAMLConfig {
7
+ constructor(opts) {
8
+ this.opts = opts;
9
+ }
10
+ get acsUrl() {
11
+ return `${this.opts.externalUrl}${this.opts.samlPath}`;
12
+ }
13
+ get entityId() {
14
+ return `${this.opts.samlAudience}`;
15
+ }
16
+ get responseSigned() {
17
+ return 'Signed';
18
+ }
19
+ get assertionSignature() {
20
+ return 'Signed';
21
+ }
22
+ get signatureAlgorithm() {
23
+ return 'RSA-SHA256';
24
+ }
25
+ get assertionEncryption() {
26
+ return 'Unencrypted';
27
+ }
28
+ get() {
29
+ return {
30
+ acsUrl: this.acsUrl,
31
+ entityId: this.entityId,
32
+ response: this.responseSigned,
33
+ assertionSignature: this.assertionSignature,
34
+ signatureAlgorithm: this.signatureAlgorithm,
35
+ assertionEncryption: this.assertionEncryption,
36
+ };
37
+ }
38
+ toMarkdown() {
39
+ return markdownTemplate
40
+ .replace('{{acsUrl}}', this.acsUrl)
41
+ .replace('{{entityId}}', this.entityId)
42
+ .replace('{{responseSigned}}', this.responseSigned)
43
+ .replace('{{assertionSignature}}', this.assertionSignature)
44
+ .replace('{{signatureAlgorithm}}', this.signatureAlgorithm)
45
+ .replace('{{assertionEncryption}}', this.assertionEncryption);
46
+ }
47
+ toHTML() {
48
+ return marked_1.marked.parse(this.toMarkdown());
49
+ }
50
+ }
51
+ exports.SPSAMLConfig = SPSAMLConfig;
52
+ const markdownTemplate = `
53
+ ## Service Provider (SP) SAML Configuration
54
+
55
+ Your Identity Provider (IdP) will ask for the following information while configuring the SAML application. Share this information with your IT administrator.
56
+
57
+ **ACS (Assertion Consumer Service) URL / Single Sign-On URL / Destination URL** <br />
58
+ {{acsUrl}}
59
+
60
+ **SP Entity ID / Identifier / Audience URI / Audience Restriction** <br />
61
+ {{entityId}}
62
+
63
+ **Response** <br />
64
+ {{responseSigned}}
65
+
66
+ **Assertion Signature** <br />
67
+ {{assertionSignature}}
68
+
69
+ **Signature Algorithm** <br />
70
+ {{signatureAlgorithm}}
71
+
72
+ **Assertion Encryption** <br />
73
+ {{assertionEncryption}}
74
+ `;
@@ -4,10 +4,23 @@ export declare enum IndexNames {
4
4
  EntityID = "entityID",
5
5
  TenantProduct = "tenantProduct"
6
6
  }
7
+ export declare const storeNamespacePrefix: {
8
+ dsync: {
9
+ config: string;
10
+ logs: string;
11
+ users: string;
12
+ groups: string;
13
+ members: string;
14
+ };
15
+ saml: {
16
+ config: string;
17
+ };
18
+ };
7
19
  export declare const relayStatePrefix = "boxyhq_jackson_";
8
20
  export declare const validateAbsoluteUrl: (url: any, message: any) => void;
9
21
  export declare const OAuthErrorResponse: ({ error, error_description, redirect_uri, state, }: OAuthErrorHandlerParams) => string;
10
22
  export declare function getErrorMessage(error: unknown): string;
23
+ export declare const createRandomSecret: (length: number) => Promise<string>;
11
24
  export declare function loadJWSPrivateKey(key: string, alg: string): Promise<jose.KeyLike>;
12
25
  export declare function isJWSKeyPairLoaded(jwsKeyPair: {
13
26
  private: string;
@@ -31,16 +31,33 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
31
31
  step((generator = generator.apply(thisArg, _arguments || [])).next());
32
32
  });
33
33
  };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
34
37
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.generateJwkThumbprint = exports.exportPublicKeyJWK = exports.importJWTPublicKey = exports.isJWSKeyPairLoaded = exports.loadJWSPrivateKey = exports.getErrorMessage = exports.OAuthErrorResponse = exports.validateAbsoluteUrl = exports.relayStatePrefix = exports.IndexNames = void 0;
38
+ exports.generateJwkThumbprint = exports.exportPublicKeyJWK = exports.importJWTPublicKey = exports.isJWSKeyPairLoaded = exports.loadJWSPrivateKey = exports.createRandomSecret = exports.getErrorMessage = exports.OAuthErrorResponse = exports.validateAbsoluteUrl = exports.relayStatePrefix = exports.storeNamespacePrefix = exports.IndexNames = void 0;
36
39
  const error_1 = require("./error");
37
40
  const redirect = __importStar(require("./oauth/redirect"));
41
+ const crypto_1 = __importDefault(require("crypto"));
38
42
  const jose = __importStar(require("jose"));
39
43
  var IndexNames;
40
44
  (function (IndexNames) {
41
45
  IndexNames["EntityID"] = "entityID";
42
46
  IndexNames["TenantProduct"] = "tenantProduct";
43
47
  })(IndexNames = exports.IndexNames || (exports.IndexNames = {}));
48
+ // The namespace prefix for the database store
49
+ exports.storeNamespacePrefix = {
50
+ dsync: {
51
+ config: 'dsync:config',
52
+ logs: 'dsync:logs',
53
+ users: 'dsync:users',
54
+ groups: 'dsync:groups',
55
+ members: 'dsync:members',
56
+ },
57
+ saml: {
58
+ config: 'saml:config',
59
+ },
60
+ };
44
61
  exports.relayStatePrefix = 'boxyhq_jackson_';
45
62
  const validateAbsoluteUrl = (url, message) => {
46
63
  try {
@@ -63,6 +80,15 @@ function getErrorMessage(error) {
63
80
  return String(error);
64
81
  }
65
82
  exports.getErrorMessage = getErrorMessage;
83
+ const createRandomSecret = (length) => __awaiter(void 0, void 0, void 0, function* () {
84
+ return crypto_1.default
85
+ .randomBytes(length)
86
+ .toString('base64')
87
+ .replace(/\+/g, '-')
88
+ .replace(/\//g, '_')
89
+ .replace(/=/g, '');
90
+ });
91
+ exports.createRandomSecret = createRandomSecret;
66
92
  function loadJWSPrivateKey(key, alg) {
67
93
  return __awaiter(this, void 0, void 0, function* () {
68
94
  const pkcs8 = Buffer.from(key, 'base64').toString('ascii');
package/dist/db/mem.js CHANGED
@@ -73,13 +73,17 @@ class Mem {
73
73
  getAll(namespace, pageOffset, pageLimit) {
74
74
  return __awaiter(this, void 0, void 0, function* () {
75
75
  const offsetAndLimitValueCheck = !dbutils.isNumeric(pageOffset) && !dbutils.isNumeric(pageLimit);
76
- let take = Number(offsetAndLimitValueCheck ? this.options.pageLimit : pageLimit);
76
+ const returnValue = [];
77
77
  const skip = Number(offsetAndLimitValueCheck ? 0 : pageOffset);
78
+ let take = Number(offsetAndLimitValueCheck ? this.options.pageLimit : pageLimit);
78
79
  let count = 0;
79
80
  take += skip;
80
- const returnValue = [];
81
81
  if (namespace) {
82
- const val = Array.from(this.indexes[dbutils.keyFromParts(dbutils.createdAtPrefix, namespace)]);
82
+ const index = dbutils.keyFromParts(dbutils.createdAtPrefix, namespace);
83
+ if (this.indexes[index] === undefined) {
84
+ return [];
85
+ }
86
+ const val = Array.from(this.indexes[index]);
83
87
  const iterator = val.reverse().values();
84
88
  for (const value of iterator) {
85
89
  if (count >= take) {
@@ -0,0 +1,15 @@
1
+ import type { Storable, DatabaseStore } from '../typings';
2
+ export declare class Base {
3
+ protected db: DatabaseStore;
4
+ protected tenant: null | string;
5
+ protected product: null | string;
6
+ constructor({ db }: {
7
+ db: DatabaseStore;
8
+ });
9
+ store(type: 'groups' | 'members' | 'users' | 'logs'): Storable;
10
+ setTenant(tenant: string): this;
11
+ setProduct(product: string): this;
12
+ setTenantAndProduct(tenant: string, product: string): this;
13
+ with(tenant: string, product: string): this;
14
+ createId(): string;
15
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Base = void 0;
4
+ const utils_1 = require("../controller/utils");
5
+ const uuid_1 = require("uuid");
6
+ class Base {
7
+ constructor({ db }) {
8
+ this.tenant = null;
9
+ this.product = null;
10
+ this.db = db;
11
+ }
12
+ // Return the database store
13
+ store(type) {
14
+ if (!this.tenant || !this.product) {
15
+ throw new Error('Set tenant and product before using store.');
16
+ }
17
+ return this.db.store(`${utils_1.storeNamespacePrefix.dsync[type]}:${this.tenant}:${this.product}`);
18
+ }
19
+ setTenant(tenant) {
20
+ this.tenant = tenant;
21
+ return this;
22
+ }
23
+ setProduct(product) {
24
+ this.product = product;
25
+ return this;
26
+ }
27
+ // Set the tenant and product
28
+ setTenantAndProduct(tenant, product) {
29
+ return this.setTenant(tenant).setProduct(product);
30
+ }
31
+ // Set the tenant and product
32
+ with(tenant, product) {
33
+ return this.setTenant(tenant).setProduct(product);
34
+ }
35
+ createId() {
36
+ return (0, uuid_1.v4)();
37
+ }
38
+ }
39
+ exports.Base = Base;
@@ -0,0 +1,43 @@
1
+ import type { Directory, JacksonOption, DatabaseStore, DirectoryType, ApiError } from '../typings';
2
+ export declare class DirectoryConfig {
3
+ private _store;
4
+ private opts;
5
+ private db;
6
+ constructor({ db, opts }: {
7
+ db: DatabaseStore;
8
+ opts: JacksonOption;
9
+ });
10
+ private store;
11
+ create({ name, tenant, product, webhook_url, webhook_secret, type, }: {
12
+ name?: string;
13
+ tenant: string;
14
+ product: string;
15
+ webhook_url?: string;
16
+ webhook_secret?: string;
17
+ type?: DirectoryType;
18
+ }): Promise<{
19
+ data: Directory | null;
20
+ error: ApiError | null;
21
+ }>;
22
+ get(id: string): Promise<{
23
+ data: Directory | null;
24
+ error: ApiError | null;
25
+ }>;
26
+ update(id: string, param: Omit<Partial<Directory>, 'id' | 'tenant' | 'prodct' | 'scim'>): Promise<{
27
+ data: Directory | null;
28
+ error: ApiError | null;
29
+ }>;
30
+ getByTenantAndProduct(tenant: string, product: string): Promise<{
31
+ data: Directory | null;
32
+ error: ApiError | null;
33
+ }>;
34
+ list({ pageOffset, pageLimit, }: {
35
+ pageOffset: number;
36
+ pageLimit: number;
37
+ }): Promise<{
38
+ data: Directory[] | null;
39
+ error: ApiError | null;
40
+ }>;
41
+ delete(id: string): Promise<void>;
42
+ private transform;
43
+ }
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.DirectoryConfig = void 0;
36
+ const dbutils = __importStar(require("../db/utils"));
37
+ const utils_1 = require("../controller/utils");
38
+ const error_1 = require("../controller/error");
39
+ const utils_2 = require("../controller/utils");
40
+ class DirectoryConfig {
41
+ constructor({ db, opts }) {
42
+ this._store = null;
43
+ this.opts = opts;
44
+ this.db = db;
45
+ }
46
+ // Return the database store
47
+ store() {
48
+ return this._store || (this._store = this.db.store(utils_2.storeNamespacePrefix.dsync.config));
49
+ }
50
+ // Create the configuration
51
+ create({ name, tenant, product, webhook_url, webhook_secret, type = 'generic-scim-v2', }) {
52
+ return __awaiter(this, void 0, void 0, function* () {
53
+ try {
54
+ if (!tenant || !product) {
55
+ throw new error_1.JacksonError('Missing required parameters.', 400);
56
+ }
57
+ if (!name) {
58
+ name = `scim-${tenant}-${product}`;
59
+ }
60
+ const id = dbutils.keyDigest(dbutils.keyFromParts(tenant, product));
61
+ const hasWebhook = webhook_url && webhook_secret;
62
+ const directory = {
63
+ id,
64
+ name,
65
+ tenant,
66
+ product,
67
+ type,
68
+ log_webhook_events: false,
69
+ scim: {
70
+ path: `${this.opts.scimPath}/${id}`,
71
+ secret: yield (0, utils_1.createRandomSecret)(16),
72
+ },
73
+ webhook: {
74
+ endpoint: hasWebhook ? webhook_url : '',
75
+ secret: hasWebhook ? webhook_secret : '',
76
+ },
77
+ };
78
+ yield this.store().put(id, directory);
79
+ return { data: this.transform(directory), error: null };
80
+ }
81
+ catch (err) {
82
+ return (0, error_1.apiError)(err);
83
+ }
84
+ });
85
+ }
86
+ // Get the configuration by id
87
+ get(id) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ try {
90
+ if (!id) {
91
+ throw new error_1.JacksonError('Missing required parameters.', 400);
92
+ }
93
+ const directory = yield this.store().get(id);
94
+ if (!directory) {
95
+ throw new error_1.JacksonError('Directory configuration not found.', 404);
96
+ }
97
+ return { data: this.transform(directory), error: null };
98
+ }
99
+ catch (err) {
100
+ return (0, error_1.apiError)(err);
101
+ }
102
+ });
103
+ }
104
+ // Update the configuration. Partial updates are supported
105
+ update(id, param) {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ try {
108
+ if (!id) {
109
+ throw new error_1.JacksonError('Missing required parameters.', 400);
110
+ }
111
+ const { name, log_webhook_events, webhook, type } = param;
112
+ const directory = yield this.store().get(id);
113
+ if (name) {
114
+ directory.name = name;
115
+ }
116
+ if (log_webhook_events !== undefined) {
117
+ directory.log_webhook_events = log_webhook_events;
118
+ }
119
+ if (webhook) {
120
+ directory.webhook = webhook;
121
+ }
122
+ if (type) {
123
+ directory.type = type;
124
+ }
125
+ yield this.store().put(id, Object.assign({}, directory));
126
+ return { data: this.transform(directory), error: null };
127
+ }
128
+ catch (err) {
129
+ return (0, error_1.apiError)(err);
130
+ }
131
+ });
132
+ }
133
+ // Get the configuration by tenant and product
134
+ getByTenantAndProduct(tenant, product) {
135
+ return __awaiter(this, void 0, void 0, function* () {
136
+ try {
137
+ if (!tenant || !product) {
138
+ throw new error_1.JacksonError('Missing required parameters.', 400);
139
+ }
140
+ return yield this.get(dbutils.keyDigest(dbutils.keyFromParts(tenant, product)));
141
+ }
142
+ catch (err) {
143
+ return (0, error_1.apiError)(err);
144
+ }
145
+ });
146
+ }
147
+ // Get all configurations
148
+ list({ pageOffset, pageLimit, }) {
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ try {
151
+ const directories = (yield this.store().getAll(pageOffset, pageLimit));
152
+ const transformedDirectories = directories
153
+ ? directories.map((directory) => this.transform(directory))
154
+ : [];
155
+ return {
156
+ data: transformedDirectories,
157
+ error: null,
158
+ };
159
+ }
160
+ catch (err) {
161
+ return (0, error_1.apiError)(err);
162
+ }
163
+ });
164
+ }
165
+ // Delete a configuration by id
166
+ // Note: This feature is not yet implemented
167
+ delete(id) {
168
+ return __awaiter(this, void 0, void 0, function* () {
169
+ if (!id) {
170
+ throw new error_1.JacksonError('Missing required parameter.', 400);
171
+ }
172
+ // TODO: Delete the users and groups associated with the configuration
173
+ yield this.store().delete(id);
174
+ return;
175
+ });
176
+ }
177
+ transform(directory) {
178
+ // Add the flag to ensure SCIM compliance when using Azure AD
179
+ if (directory.type === 'azure-scim-v2') {
180
+ directory.scim.path = `${directory.scim.path}/?aadOptscim062020`;
181
+ }
182
+ directory.scim.endpoint = `${this.opts.externalUrl}${directory.scim.path}`;
183
+ return directory;
184
+ }
185
+ }
186
+ exports.DirectoryConfig = DirectoryConfig;
@@ -0,0 +1,26 @@
1
+ import type { Group, DirectoryConfig, DirectorySyncResponse, Directory, DirectorySyncGroupMember, DirectorySyncRequest, Users, Groups, IDirectoryGroups, EventCallback } from '../typings';
2
+ export declare class DirectoryGroups implements IDirectoryGroups {
3
+ private directories;
4
+ private users;
5
+ private groups;
6
+ private callback;
7
+ constructor({ directories, users, groups, }: {
8
+ directories: DirectoryConfig;
9
+ users: Users;
10
+ groups: Groups;
11
+ });
12
+ create(directory: Directory, body: any): Promise<DirectorySyncResponse>;
13
+ get(group: Group): Promise<DirectorySyncResponse>;
14
+ delete(directory: Directory, group: Group): Promise<DirectorySyncResponse>;
15
+ getAll(queryParams: {
16
+ filter?: string;
17
+ }): Promise<DirectorySyncResponse>;
18
+ updateDisplayName(directory: Directory, group: Group, body: any): Promise<Group>;
19
+ patch(directory: Directory, group: Group, body: any): Promise<DirectorySyncResponse>;
20
+ update(directory: Directory, group: Group, body: any): Promise<DirectorySyncResponse>;
21
+ addGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[] | undefined, sendWebhookEvent?: boolean): Promise<void>;
22
+ removeGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[], sendWebhookEvent?: boolean): Promise<void>;
23
+ addOrRemoveGroupMembers(directory: Directory, group: Group, members: DirectorySyncGroupMember[]): Promise<void>;
24
+ private respondWithError;
25
+ handleRequest(request: DirectorySyncRequest, callback?: EventCallback): Promise<DirectorySyncResponse>;
26
+ }