Skip to content

Commit 3cdebc8

Browse files
committed
review access-control
1 parent 02da6c8 commit 3cdebc8

File tree

5 files changed

+222
-30
lines changed

5 files changed

+222
-30
lines changed

lib/accessControl.js

Lines changed: 189 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ function AccessControl(cloudAPIUrl, params) {
4343
this.setJwtToken(params.jwt);
4444
} else if (params.token) {
4545
this.setApiToken(params.token);
46+
} else if (params.key) {
47+
this.setApiKey(params.key);
48+
this.user = params.user;
4649
}
47-
4850
this.defaultOrganization = this.getDefaultOrganization(params);
4951
}
5052

@@ -68,7 +70,7 @@ AccessControl.prototype.setJwtToken = function (jwt) {
6870
throw new Error('TerminusX Access token required');
6971
}
7072

71-
this.apiJwtToken = jwt;
73+
this.apiKey = jwt;
7274
this.apiType = 'jwt';
7375
};
7476

@@ -81,10 +83,23 @@ AccessControl.prototype.setApiToken = function (token) {
8183
throw new Error('TerminusX Access token required');
8284
}
8385

84-
this.apiToken = token;
86+
this.apiKey = token;
8587
this.apiType = 'apikey';
8688
};
8789

90+
/**
91+
* Sets the API token for the object, to request a token create an account in https://terminusdb.com/
92+
* @param {string} atokenpi - The API token to use to connect with TerminusX
93+
*/
94+
AccessControl.prototype.setApiKey = function (key) {
95+
if (!key) {
96+
throw new Error('TerminusDB bacis authentication key required');
97+
}
98+
99+
this.apiKey = key;
100+
this.apiType = 'basic';
101+
};
102+
88103
/**
89104
* Get a API url from cloudAPIUrl
90105
* @param {string} cloudAPIUrl - The base url for cloud
@@ -112,14 +127,11 @@ AccessControl.prototype.dispatch = function (requestUrl, action, payload) {
112127
),
113128
);
114129
}
115-
116-
const apiToken = this.apiJwtToken || this.apiToken;
117-
118130
return DispatchRequest(
119131
requestUrl,
120132
action,
121133
payload,
122-
{ type: this.apiType, key: apiToken },
134+
{ type: this.apiType, key: this.apiKey, user: this.user },
123135
);
124136
};
125137

@@ -132,8 +144,19 @@ AccessControl.prototype.getAccessRoles = function () {
132144
};
133145

134146
/**
135-
* Any user can create their own organization.
136-
* IMPORTANT This does not work with the API-TOKEN.
147+
* This end point works only in basic authentication admin user
148+
* Get all the system organizations list
149+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
150+
*/
151+
152+
AccessControl.prototype.getAllOrganizations = function () {
153+
return this.dispatch(`${this.baseURL}/organizations`, CONST.GET);
154+
};
155+
156+
/**
157+
* This works only in the local database
158+
* TerminusX - Any user can create their own organization. -
159+
* TerminusX - IMPORTANT This does not work with the API-TOKEN.
137160
* @param {string} orgName - The organization name to create
138161
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
139162
* @example
@@ -142,20 +165,21 @@ AccessControl.prototype.getAccessRoles = function () {
142165
* })
143166
*/
144167
AccessControl.prototype.createOrganization = function (orgName) {
145-
if (!orgName) {
146-
return Promise.reject(
147-
new Error(
148-
ErrorMessage.getInvalidParameterMessage(
149-
'POST',
150-
'Please provide a organization name',
151-
),
152-
),
153-
);
154-
}
168+
// maybe we have to review this
169+
return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(orgName)}`, CONST.POST, {});
170+
};
155171

156-
return this.dispatch(`${this.baseURL}/private/organizations`, CONST.POST, {
157-
organization: orgName,
158-
});
172+
/**
173+
* This api works only in the local installation
174+
* @param {string} orgName - The organization name to create
175+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
176+
* @example
177+
* accessControl.createOrganization("my_org_name").then(result=>{
178+
* console.log(result)
179+
* })
180+
*/
181+
AccessControl.prototype.deleteOrganization = function (orgName) {
182+
return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(orgName)}`, CONST.DELETE);
159183
};
160184

161185
/**
@@ -433,6 +457,53 @@ AccessControl.prototype.getTeamUserRole = function (orgName) {
433457
return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/role`, CONST.GET);
434458
};
435459

460+
/**
461+
* Get the user role for a given organization or the default organization,
462+
* @param {string} [userName] - The organization name.
463+
* @param {string} [orgName] - The organization name.
464+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
465+
* @example
466+
* accessControl.getTeamUserRole("myUser").then(result=>{
467+
* console.log(result)
468+
* })
469+
*
470+
* //response object example
471+
* {
472+
* "@id": "User/myUser",
473+
* "capability": [
474+
* {
475+
* "@id":"Capability/server_access",
476+
* "@type":"Capability",
477+
* "role": [{
478+
* "@id":"Role/reader",
479+
* "@type":"Role",
480+
* "action": [
481+
* "instance_read_access",
482+
* ],
483+
* "name":"reader"
484+
* }],
485+
* "scope":"Organization/myteam"
486+
* }
487+
* ],
488+
* "name": "myUser"
489+
*}
490+
*/
491+
492+
AccessControl.prototype.getTeamUserRoles = function (userName, orgName) {
493+
if (!orgName && !this.defaultOrganization) {
494+
return Promise.reject(
495+
new Error(
496+
ErrorMessage.getInvalidParameterMessage(
497+
'GET',
498+
'Please provide a organization name',
499+
),
500+
),
501+
);
502+
}
503+
const org = orgName || this.defaultOrganization;
504+
return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/users/${UTILS.encodeURISegment(userName)}`, CONST.GET);
505+
};
506+
436507
/**
437508
* Remove an user from an organization, only an admin user can remove an user from an organization
438509
* @param {string} userId - The id of the user to be removed. (this is the document user's @id)
@@ -693,4 +764,100 @@ AccessControl.prototype.deleteAccessRequest = function (acceId, orgName) {
693764
return this.dispatch(`${this.baseURL}/organizations/${UTILS.encodeURISegment(org)}/access_requests/${acceId}`, CONST.DELETE);
694765
};
695766

767+
/**
768+
* Create a new role in the system database, (this api is enabled only in the local installation)
769+
* @param {string} [name] - The role name.
770+
* @param {array} [actions] - A list of actions
771+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
772+
* @example
773+
* accessControl.createRole("Reader",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{
774+
* console.log(result)
775+
* })
776+
*
777+
*/
778+
AccessControl.prototype.createRole = function (name, actions) {
779+
const payload = { name, action: actions };
780+
return this.dispatch(`${this.baseURL}/roles`, CONST.POST, payload);
781+
};
782+
783+
/**
784+
* Delete role in the system database, (this api is enabled only in the local installation)
785+
* @param {string} [name] - The role name.
786+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
787+
* @example
788+
* accessControl.deleteRole("Reader").then(result=>{
789+
* console.log(result)
790+
* })
791+
*
792+
*/
793+
AccessControl.prototype.deleteRole = function (name) {
794+
return this.dispatch(`${this.baseURL}/roles/${UTILS.encodeURISegment(name)}`, CONST.DELETE);
795+
};
796+
797+
/**
798+
* Return the list of all the users (this api is enabled only in the local installation)
799+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
800+
* @example
801+
* accessControl.getAllUsers().then(result=>{
802+
* console.log(result)
803+
* })
804+
*
805+
*/
806+
807+
AccessControl.prototype.getAllUsers = function () {
808+
return this.dispatch(`${this.baseURL}/users`, CONST.GET);
809+
};
810+
811+
/**
812+
* Remove the user from the system database (this api is enabled only in the local installation)
813+
* @param {string} userId - the document user id
814+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
815+
* @example
816+
* accessControl.deleteUser(userId).then(result=>{
817+
* console.log(result)
818+
* })
819+
*
820+
*/
821+
822+
AccessControl.prototype.deleteUser = function (userId) {
823+
return this.dispatch(`${this.baseURL}/users/${UTILS.encodeURISegment(userId)}`, CONST.DELETE);
824+
};
825+
826+
/**
827+
* Add the user into the system database (this api is enabled only in the local installation)
828+
* @param {string} name - the user name
829+
* @param {string} [password] - you need the password for basic authentication
830+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
831+
* @example
832+
* accessControl.deleteUser(userId).then(result=>{
833+
* console.log(result)
834+
* })
835+
*
836+
*/
837+
838+
AccessControl.prototype.createUser = function (name, password) {
839+
const payload = { name, password };
840+
return this.dispatch(`${this.baseURL}/users`, CONST.POST, payload);
841+
};
842+
843+
/**
844+
* Grant/Revoke Capability (this api is enabled only in the local installation)
845+
* @param {string} userId - the document user id
846+
* @param {string} resourceId - the resource id (database or team)
847+
* @param {array} rolesArr - the roles list
848+
* @param {string} operation - grant/revoke operation
849+
* @return {Promise} A promise that returns the call response object, or an Error if rejected.
850+
* @example
851+
{ "operation" : "grant",
852+
"scope" : "Organization/myteam",
853+
"user" : "User/myUser",
854+
"roles" : ["Role/reader"] }
855+
*/
856+
AccessControl.prototype.manageCapability = function (userId, resourceId, rolesArr, operation) {
857+
const payload = {
858+
operation, user: userId, roles: rolesArr, scope: resourceId,
859+
};
860+
return this.dispatch(`${this.baseURL}/capabilities`, CONST.POST, payload);
861+
};
862+
696863
module.exports = AccessControl;

lib/dispatchRequest.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ function DispatchRequest(url, action, payload, local_auth, remote_auth = null, c
114114
.delete(url, options)
115115
.then((response) => (getDataVersion ? getResultWithDataVersion(response) : response.data))
116116
.catch((err) => {
117-
const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err));
118-
if (err.response && err.response.data) e.data = err.response.data;
119-
throw e;
117+
// const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err));
118+
// if (err.response && err.response.data) e.data = err.response.data;
119+
throw ErrorMessage.apiErrorFormatted(url, options, err);
120120
});
121121
}
122122
case CONST.HEAD: {
@@ -141,11 +141,7 @@ function DispatchRequest(url, action, payload, local_auth, remote_auth = null, c
141141
.get(url, options)
142142
.then((response) => (getDataVersion ? getResultWithDataVersion(response) : response.data))
143143
.catch((err) => {
144-
const e = new Error(ErrorMessage.getAPIErrorMessage(url, options, err));
145-
if (err.response && err.response.data) {
146-
e.data = err.response.data;
147-
}
148-
throw e;
144+
throw ErrorMessage.apiErrorFormatted(url, options, err);
149145
});
150146
}
151147
case CONST.ADD_CSV:

lib/errorMessage.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,15 @@ function parseAPIError(response) {
9191
return err;
9292
}
9393

94+
function apiErrorFormatted(url, options, err) {
95+
const e = new Error(getAPIErrorMessage(url, options, err));
96+
if (err.response && err.response.data) e.data = err.response.data;
97+
if (err.response && err.response.status) e.status = err.response.status;
98+
return e;
99+
}
100+
94101
module.exports = {
102+
apiErrorFormatted,
95103
getErrorAsMessage,
96104
getAPIErrorMessage,
97105
getAccessDeniedMessage,

lib/utils.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,26 @@
1212
*/
1313
const Utils = {};
1414

15+
Utils.ACTIONS = {
16+
CREATE_DATABASE: 'create_database',
17+
DELETE_DATABASE: 'delete_database',
18+
SCHEMA_READ_ACCESS: 'schema_read_access',
19+
SCHEMA_WRITE_ACCESS: 'schema_write_access',
20+
INSTANCE_READ_ACCESS: 'instance_read_access',
21+
INSTANCE_WRITE_ACCESS: 'instance_write_access',
22+
COMMIT_READ_ACCESS: 'commit_read_access',
23+
COMMIT_WRITE_ACCESS: 'commit_write_access',
24+
META_READ_ACCESS: 'meta_read_access',
25+
META_WRITE_ACCESS: 'meta_write_access',
26+
CLASS_FRAME: 'class_frame',
27+
BRANCH: 'branch',
28+
CLONE: 'clone',
29+
FETCH: 'fetch',
30+
PUSH: 'push',
31+
REBASE: 'rebase',
32+
/* MANAGE_CAPABILITIES: 'manage_capabilities', */
33+
};
34+
1535
// ˆˆˆˆˆ&&**(((()*(*#&#&&#$*#*(#(#(#)#)#)_
1636
// 'Doc%2F%3D%26test'
1737
//

lib/woqlClient.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,7 @@ WOQLClient.prototype.getPrefixes = function (dbId) {
14391439
*/
14401440
WOQLClient.prototype.getUserOrganizations = function () {
14411441
// this will be change to give back only the organizations list
1442+
console.log('this.connectionConfig.userOrganizationsURL()', this.connectionConfig.userOrganizationsURL());
14421443
return this.dispatch(
14431444
CONST.GET,
14441445
this.connectionConfig.userOrganizationsURL(),

0 commit comments

Comments
 (0)