UNPKG

21.9 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.UserManager = exports.Group = exports.UserAndMetadata = exports.User = exports.RoleAndOrigin = exports.RoleAndDescription = exports.Role = exports.Origin = void 0;
4const errors_1 = require("./errors");
5const httpexecutor_1 = require("./httpexecutor");
6const utilities_1 = require("./utilities");
7/**
8 * Contains information about an origin for a role.
9 *
10 * @category Management
11 */
12class Origin {
13 /**
14 * @internal
15 */
16 constructor(data) {
17 this.type = data.type;
18 this.name = data.name;
19 }
20 /**
21 * @internal
22 */
23 static _fromNsData(data) {
24 return new Origin({
25 type: data.type,
26 name: data.name,
27 });
28 }
29}
30exports.Origin = Origin;
31/**
32 * Contains information about a role.
33 *
34 * @category Management
35 */
36class Role {
37 /**
38 * @internal
39 */
40 constructor(data) {
41 this.name = data.name;
42 this.bucket = data.bucket;
43 this.scope = data.scope;
44 this.collection = data.collection;
45 }
46 /**
47 * @internal
48 */
49 static _fromNsData(data) {
50 return new Role({
51 name: data.role,
52 bucket: data.bucket_name,
53 scope: data.scope_name,
54 collection: data.collection_name,
55 });
56 }
57 /**
58 * @internal
59 */
60 static _toNsStr(role) {
61 if (typeof role === 'string') {
62 return role;
63 }
64 if (role.bucket && role.scope && role.collection) {
65 return `${role.name}[${role.bucket}:${role.scope}:${role.collection}]`;
66 }
67 else if (role.bucket && role.scope) {
68 return `${role.name}[${role.bucket}:${role.scope}]`;
69 }
70 else if (role.bucket) {
71 return `${role.name}[${role.bucket}]`;
72 }
73 else {
74 return role.name;
75 }
76 }
77}
78exports.Role = Role;
79/**
80 * Contains information about a role along with its description.
81 *
82 * @category Management
83 */
84class RoleAndDescription extends Role {
85 /**
86 * @internal
87 */
88 constructor(data) {
89 super(data);
90 this.displayName = data.displayName;
91 this.description = data.description;
92 }
93 /**
94 * @internal
95 */
96 static _fromNsData(data) {
97 return new RoleAndDescription({
98 ...Role._fromNsData(data),
99 displayName: data.name,
100 description: data.description,
101 });
102 }
103}
104exports.RoleAndDescription = RoleAndDescription;
105/**
106 * Contains information about a role along with its origin.
107 *
108 * @category Management
109 */
110class RoleAndOrigin extends Role {
111 /**
112 * @internal
113 */
114 constructor(data) {
115 super(data);
116 this.origins = data.origins;
117 }
118 /**
119 * @internal
120 */
121 static _fromNsData(data) {
122 let origins;
123 if (data.origins) {
124 origins = data.origins.map((originData) => Origin._fromNsData(originData));
125 }
126 else {
127 origins = [];
128 }
129 return new RoleAndOrigin({
130 ...Role._fromNsData(data),
131 origins,
132 });
133 }
134}
135exports.RoleAndOrigin = RoleAndOrigin;
136/**
137 * Contains information about a user.
138 *
139 * @category Management
140 */
141class User {
142 /**
143 * @internal
144 */
145 constructor(data) {
146 this.username = data.username;
147 this.displayName = data.displayName;
148 this.groups = data.groups;
149 this.roles = data.roles;
150 }
151 /**
152 * @internal
153 */
154 static _fromNsData(data) {
155 let roles;
156 if (data.roles) {
157 roles = data.roles
158 .filter((roleData) => {
159 // Check whether or not this role has originated from the user directly
160 // or whether it was through a group.
161 if (!roleData.origins || roleData.origins.length === 0) {
162 return false;
163 }
164 return !!roleData.origins.find((originData) => originData.type === 'user');
165 })
166 .map((roleData) => Role._fromNsData(roleData));
167 }
168 else {
169 roles = [];
170 }
171 return new User({
172 username: data.id,
173 displayName: data.name,
174 groups: data.groups,
175 roles: roles,
176 password: undefined,
177 });
178 }
179 /**
180 * @internal
181 */
182 static _toNsData(user) {
183 let groups = undefined;
184 if (user.groups && user.groups.length > 0) {
185 groups = user.groups;
186 }
187 let roles = undefined;
188 if (user.roles && user.roles.length > 0) {
189 roles = user.roles.map((role) => Role._toNsStr(role)).join(',');
190 }
191 return {
192 name: user.displayName,
193 groups: groups,
194 password: user.password,
195 roles: roles,
196 };
197 }
198}
199exports.User = User;
200/**
201 * Contains information about a user along with some additional meta-data
202 * about that user.
203 *
204 * @category Management
205 */
206class UserAndMetadata extends User {
207 /**
208 * Same as {@link effectiveRoles}, which already contains the roles
209 * including their origins.
210 *
211 * @deprecated Use {@link effectiveRoles} instead.
212 */
213 get effectiveRolesAndOrigins() {
214 return this.effectiveRoles;
215 }
216 /**
217 * @internal
218 */
219 constructor(data) {
220 super(data);
221 this.domain = data.domain;
222 this.effectiveRoles = data.effectiveRoles;
223 this.passwordChanged = data.passwordChanged;
224 this.externalGroups = data.externalGroups;
225 }
226 /**
227 * @internal
228 */
229 static _fromNsData(data) {
230 let effectiveRoles;
231 if (data.roles) {
232 effectiveRoles = data.roles.map((roleData) => RoleAndOrigin._fromNsData(roleData));
233 }
234 else {
235 effectiveRoles = [];
236 }
237 return new UserAndMetadata({
238 ...User._fromNsData(data),
239 domain: data.domain,
240 effectiveRoles: effectiveRoles,
241 effectiveRolesAndOrigins: effectiveRoles,
242 passwordChanged: new Date(data.password_change_date),
243 externalGroups: data.external_groups,
244 });
245 }
246}
247exports.UserAndMetadata = UserAndMetadata;
248/**
249 * Contains information about a group.
250 *
251 * @category Management
252 */
253class Group {
254 /**
255 * @internal
256 */
257 constructor(data) {
258 this.name = data.name;
259 this.description = data.description;
260 this.roles = data.roles;
261 this.ldapGroupReference = data.ldapGroupReference;
262 }
263 /**
264 * @internal
265 */
266 static _fromNsData(data) {
267 let roles;
268 if (data.roles) {
269 roles = data.roles.map((roleData) => Role._fromNsData(roleData));
270 }
271 else {
272 roles = [];
273 }
274 return new Group({
275 name: data.id,
276 description: data.description,
277 roles: roles,
278 ldapGroupReference: data.ldap_group_reference,
279 });
280 }
281 /**
282 * @internal
283 */
284 static _toNsData(group) {
285 let roles = undefined;
286 if (group.roles && group.roles.length > 0) {
287 roles = group.roles.map((role) => Role._toNsStr(role)).join(',');
288 }
289 return {
290 description: group.description,
291 roles: roles,
292 ldap_group_reference: group.ldapGroupReference,
293 };
294 }
295}
296exports.Group = Group;
297/**
298 * UserManager is an interface which enables the management of users,
299 * groups and roles for the cluster.
300 *
301 * @category Management
302 */
303class UserManager {
304 /**
305 * @internal
306 */
307 constructor(cluster) {
308 this._cluster = cluster;
309 }
310 get _http() {
311 return new httpexecutor_1.HttpExecutor(this._cluster.conn);
312 }
313 /**
314 * Returns a specific user by their username.
315 *
316 * @param username The username of the user to fetch.
317 * @param options Optional parameters for this operation.
318 * @param callback A node-style callback to be invoked after execution.
319 */
320 async getUser(username, options, callback) {
321 if (options instanceof Function) {
322 callback = arguments[1];
323 options = undefined;
324 }
325 if (!options) {
326 options = {};
327 }
328 const domainName = options.domainName || 'local';
329 const timeout = options.timeout || this._cluster.managementTimeout;
330 return utilities_1.PromiseHelper.wrapAsync(async () => {
331 const res = await this._http.request({
332 type: httpexecutor_1.HttpServiceType.Management,
333 method: httpexecutor_1.HttpMethod.Get,
334 path: `/settings/rbac/users/${domainName}/${username}`,
335 timeout: timeout,
336 });
337 if (res.statusCode !== 200) {
338 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
339 if (res.statusCode === 404) {
340 throw new errors_1.UserNotFoundError(undefined, errCtx);
341 }
342 throw new errors_1.CouchbaseError('failed to get the user', undefined, errCtx);
343 }
344 const userData = JSON.parse(res.body.toString());
345 return UserAndMetadata._fromNsData(userData);
346 }, callback);
347 }
348 /**
349 * Returns a list of all existing users.
350 *
351 * @param options Optional parameters for this operation.
352 * @param callback A node-style callback to be invoked after execution.
353 */
354 async getAllUsers(options, callback) {
355 if (options instanceof Function) {
356 callback = arguments[0];
357 options = undefined;
358 }
359 if (!options) {
360 options = {};
361 }
362 const domainName = options.domainName || 'local';
363 const timeout = options.timeout || this._cluster.managementTimeout;
364 return utilities_1.PromiseHelper.wrapAsync(async () => {
365 const res = await this._http.request({
366 type: httpexecutor_1.HttpServiceType.Management,
367 method: httpexecutor_1.HttpMethod.Get,
368 path: `/settings/rbac/users/${domainName}`,
369 timeout: timeout,
370 });
371 if (res.statusCode !== 200) {
372 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
373 throw new errors_1.CouchbaseError('failed to get users', undefined, errCtx);
374 }
375 const usersData = JSON.parse(res.body.toString());
376 const users = usersData.map((userData) => UserAndMetadata._fromNsData(userData));
377 return users;
378 }, callback);
379 }
380 /**
381 * Creates or updates an existing user.
382 *
383 * @param user The user to update.
384 * @param options Optional parameters for this operation.
385 * @param callback A node-style callback to be invoked after execution.
386 */
387 async upsertUser(user, options, callback) {
388 if (options instanceof Function) {
389 callback = arguments[1];
390 options = undefined;
391 }
392 if (!options) {
393 options = {};
394 }
395 const domainName = options.domainName || 'local';
396 const timeout = options.timeout || this._cluster.managementTimeout;
397 return utilities_1.PromiseHelper.wrapAsync(async () => {
398 const userData = User._toNsData(user);
399 const res = await this._http.request({
400 type: httpexecutor_1.HttpServiceType.Management,
401 method: httpexecutor_1.HttpMethod.Put,
402 path: `/settings/rbac/users/${domainName}/${user.username}`,
403 contentType: 'application/x-www-form-urlencoded',
404 body: (0, utilities_1.cbQsStringify)(userData),
405 timeout: timeout,
406 });
407 if (res.statusCode !== 200) {
408 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
409 throw new errors_1.CouchbaseError('failed to upsert user', undefined, errCtx);
410 }
411 }, callback);
412 }
413 /**
414 * Change password for the currently authenticatd user.
415 *
416 * @param newPassword The new password to be applied.
417 * @param options Optional parameters for this operation.
418 * @param callback A node-style callback to be invoked after execution.
419 */
420 async changePassword(newPassword, options, callback) {
421 if (options instanceof Function) {
422 callback = arguments[1];
423 options = undefined;
424 }
425 if (!options) {
426 options = {};
427 }
428 const timeout = options.timeout || this._cluster.managementTimeout;
429 return utilities_1.PromiseHelper.wrapAsync(async () => {
430 const passwordData = { password: newPassword };
431 const res = await this._http.request({
432 type: httpexecutor_1.HttpServiceType.Management,
433 method: httpexecutor_1.HttpMethod.Post,
434 path: `/controller/changePassword`,
435 contentType: 'application/x-www-form-urlencoded',
436 body: (0, utilities_1.cbQsStringify)(passwordData),
437 timeout: timeout,
438 });
439 if (res.statusCode !== 200) {
440 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
441 if (res.statusCode === 404) {
442 throw new errors_1.UserNotFoundError(undefined, errCtx);
443 }
444 throw new errors_1.CouchbaseError('failed to change password for the current user', undefined, errCtx);
445 }
446 }, callback);
447 }
448 /**
449 * Drops an existing user.
450 *
451 * @param username The username of the user to drop.
452 * @param options Optional parameters for this operation.
453 * @param callback A node-style callback to be invoked after execution.
454 */
455 async dropUser(username, options, callback) {
456 if (options instanceof Function) {
457 callback = arguments[1];
458 options = undefined;
459 }
460 if (!options) {
461 options = {};
462 }
463 const domainName = options.domainName || 'local';
464 const timeout = options.timeout || this._cluster.managementTimeout;
465 return utilities_1.PromiseHelper.wrapAsync(async () => {
466 const res = await this._http.request({
467 type: httpexecutor_1.HttpServiceType.Management,
468 method: httpexecutor_1.HttpMethod.Delete,
469 path: `/settings/rbac/users/${domainName}/${username}`,
470 timeout: timeout,
471 });
472 if (res.statusCode !== 200) {
473 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
474 if (res.statusCode === 404) {
475 throw new errors_1.UserNotFoundError(undefined, errCtx);
476 }
477 throw new errors_1.CouchbaseError('failed to drop the user', undefined, errCtx);
478 }
479 }, callback);
480 }
481 /**
482 * Returns a list of roles available on the server.
483 *
484 * @param options Optional parameters for this operation.
485 * @param callback A node-style callback to be invoked after execution.
486 */
487 async getRoles(options, callback) {
488 if (options instanceof Function) {
489 callback = arguments[0];
490 options = undefined;
491 }
492 if (!options) {
493 options = {};
494 }
495 const timeout = options.timeout || this._cluster.managementTimeout;
496 return utilities_1.PromiseHelper.wrapAsync(async () => {
497 const res = await this._http.request({
498 type: httpexecutor_1.HttpServiceType.Management,
499 method: httpexecutor_1.HttpMethod.Get,
500 path: `/settings/rbac/roles`,
501 timeout: timeout,
502 });
503 if (res.statusCode !== 200) {
504 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
505 throw new errors_1.CouchbaseError('failed to get roles', undefined, errCtx);
506 }
507 const rolesData = JSON.parse(res.body.toString());
508 const roles = rolesData.map((roleData) => RoleAndDescription._fromNsData(roleData));
509 return roles;
510 }, callback);
511 }
512 /**
513 * Returns a group by it's name.
514 *
515 * @param groupName The name of the group to retrieve.
516 * @param options Optional parameters for this operation.
517 * @param callback A node-style callback to be invoked after execution.
518 */
519 async getGroup(groupName, options, callback) {
520 if (options instanceof Function) {
521 callback = arguments[1];
522 options = undefined;
523 }
524 if (!options) {
525 options = {};
526 }
527 const timeout = options.timeout || this._cluster.managementTimeout;
528 return utilities_1.PromiseHelper.wrapAsync(async () => {
529 const res = await this._http.request({
530 type: httpexecutor_1.HttpServiceType.Management,
531 method: httpexecutor_1.HttpMethod.Get,
532 path: `/settings/rbac/groups/${groupName}`,
533 timeout: timeout,
534 });
535 if (res.statusCode !== 200) {
536 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
537 if (res.statusCode === 404) {
538 throw new errors_1.GroupNotFoundError(undefined, errCtx);
539 }
540 throw new errors_1.CouchbaseError('failed to get the group', undefined, errCtx);
541 }
542 const groupData = JSON.parse(res.body.toString());
543 return Group._fromNsData(groupData);
544 }, callback);
545 }
546 /**
547 * Returns a list of all existing groups.
548 *
549 * @param options Optional parameters for this operation.
550 * @param callback A node-style callback to be invoked after execution.
551 */
552 async getAllGroups(options, callback) {
553 if (options instanceof Function) {
554 callback = arguments[0];
555 options = undefined;
556 }
557 if (!options) {
558 options = {};
559 }
560 const timeout = options.timeout || this._cluster.managementTimeout;
561 return utilities_1.PromiseHelper.wrapAsync(async () => {
562 const res = await this._http.request({
563 type: httpexecutor_1.HttpServiceType.Management,
564 method: httpexecutor_1.HttpMethod.Get,
565 path: `/settings/rbac/groups`,
566 timeout: timeout,
567 });
568 if (res.statusCode !== 200) {
569 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
570 throw new errors_1.CouchbaseError('failed to get groups', undefined, errCtx);
571 }
572 const groupsData = JSON.parse(res.body.toString());
573 const groups = groupsData.map((groupData) => Group._fromNsData(groupData));
574 return groups;
575 }, callback);
576 }
577 /**
578 * Creates or updates an existing group.
579 *
580 * @param group The group to update.
581 * @param options Optional parameters for this operation.
582 * @param callback A node-style callback to be invoked after execution.
583 */
584 async upsertGroup(group, options, callback) {
585 if (options instanceof Function) {
586 callback = arguments[1];
587 options = undefined;
588 }
589 if (!options) {
590 options = {};
591 }
592 const timeout = options.timeout || this._cluster.managementTimeout;
593 return utilities_1.PromiseHelper.wrapAsync(async () => {
594 const groupData = Group._toNsData(group);
595 const res = await this._http.request({
596 type: httpexecutor_1.HttpServiceType.Management,
597 method: httpexecutor_1.HttpMethod.Put,
598 path: `/settings/rbac/groups/${group.name}`,
599 contentType: 'application/x-www-form-urlencoded',
600 body: (0, utilities_1.cbQsStringify)(groupData),
601 timeout: timeout,
602 });
603 if (res.statusCode !== 200) {
604 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
605 throw new errors_1.CouchbaseError('failed to upsert group', undefined, errCtx);
606 }
607 }, callback);
608 }
609 /**
610 * Drops an existing group.
611 *
612 * @param groupName The name of the group to drop.
613 * @param options Optional parameters for this operation.
614 * @param callback A node-style callback to be invoked after execution.
615 */
616 async dropGroup(groupName, options, callback) {
617 if (options instanceof Function) {
618 callback = arguments[1];
619 options = undefined;
620 }
621 if (!options) {
622 options = {};
623 }
624 const timeout = options.timeout || this._cluster.managementTimeout;
625 return utilities_1.PromiseHelper.wrapAsync(async () => {
626 const res = await this._http.request({
627 type: httpexecutor_1.HttpServiceType.Management,
628 method: httpexecutor_1.HttpMethod.Delete,
629 path: `/settings/rbac/groups/${groupName}`,
630 timeout: timeout,
631 });
632 if (res.statusCode !== 200) {
633 const errCtx = httpexecutor_1.HttpExecutor.errorContextFromResponse(res);
634 if (res.statusCode === 404) {
635 throw new errors_1.GroupNotFoundError(undefined, errCtx);
636 }
637 throw new errors_1.CouchbaseError('failed to drop the group', undefined, errCtx);
638 }
639 }, callback);
640 }
641}
642exports.UserManager = UserManager;