dbgate-api-premium 6.6.1 → 6.6.3

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.
@@ -10,7 +10,7 @@ const processArgs = require('./processArgs');
10
10
  const logger = getLogger('authProxy');
11
11
 
12
12
  const AUTH_PROXY_URL = process.env.LOCAL_AUTH_PROXY
13
- ? 'http://localhost:3109'
13
+ ? 'http://localhost:3110'
14
14
  : process.env.DEVWEB || process.env.DEVMODE
15
15
  ? 'https://auth-proxy.dbgate.udolni.net'
16
16
  : 'https://auth.dbgate.eu';
@@ -1,96 +1,303 @@
1
- const { compilePermissions, testPermission } = require('dbgate-tools');
1
+ const { compilePermissions, testPermission, getPermissionsCacheKey } = require('dbgate-tools');
2
2
  const _ = require('lodash');
3
3
  const { getAuthProviderFromReq } = require('../auth/authProvider');
4
4
 
5
5
  const cachedPermissions = {};
6
6
 
7
- function hasPermission(tested, req) {
7
+ async function loadPermissionsFromRequest(req) {
8
+ const authProvider = getAuthProviderFromReq(req);
8
9
  if (!req) {
9
- // request object not available, allow all
10
- return true;
10
+ return null;
11
11
  }
12
12
 
13
- const permissions = getAuthProviderFromReq(req).getCurrentPermissions(req);
13
+ const loadedPermissions = await authProvider.getCurrentPermissions(req);
14
+ return loadedPermissions;
15
+ }
14
16
 
15
- if (!cachedPermissions[permissions]) {
16
- cachedPermissions[permissions] = compilePermissions(permissions);
17
+ function hasPermission(tested, loadedPermissions) {
18
+ if (!loadedPermissions) {
19
+ // not available, allow all
20
+ return true;
17
21
  }
18
22
 
19
- return testPermission(tested, cachedPermissions[permissions]);
20
-
21
- // const { user } = (req && req.auth) || {};
22
- // const { login } = (process.env.OAUTH_PERMISSIONS && req && req.user) || {};
23
- // const key = user || login || '';
24
- // const logins = getLogins();
23
+ const permissionsKey = getPermissionsCacheKey(loadedPermissions);
24
+ if (!cachedPermissions[permissionsKey]) {
25
+ cachedPermissions[permissionsKey] = compilePermissions(loadedPermissions);
26
+ }
25
27
 
26
- // if (!userPermissions[key]) {
27
- // if (logins) {
28
- // const login = logins.find(x => x.login == user);
29
- // userPermissions[key] = compilePermissions(login ? login.permissions : null);
30
- // } else {
31
- // userPermissions[key] = compilePermissions(process.env.PERMISSIONS);
32
- // }
33
- // }
34
- // return testPermission(tested, userPermissions[key]);
28
+ return testPermission(tested, cachedPermissions[permissionsKey]);
35
29
  }
36
30
 
37
- // let loginsCache = null;
38
- // let loginsLoaded = false;
39
-
40
- // function getLogins() {
41
- // if (loginsLoaded) {
42
- // return loginsCache;
43
- // }
44
-
45
- // const res = [];
46
- // if (process.env.LOGIN && process.env.PASSWORD) {
47
- // res.push({
48
- // login: process.env.LOGIN,
49
- // password: process.env.PASSWORD,
50
- // permissions: process.env.PERMISSIONS,
51
- // });
52
- // }
53
- // if (process.env.LOGINS) {
54
- // const logins = _.compact(process.env.LOGINS.split(',').map(x => x.trim()));
55
- // for (const login of logins) {
56
- // const password = process.env[`LOGIN_PASSWORD_${login}`];
57
- // const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
58
- // if (password) {
59
- // res.push({
60
- // login,
61
- // password,
62
- // permissions,
63
- // });
64
- // }
65
- // }
66
- // } else if (process.env.OAUTH_PERMISSIONS) {
67
- // const login_permission_keys = Object.keys(process.env).filter(key => _.startsWith(key, 'LOGIN_PERMISSIONS_'));
68
- // for (const permissions_key of login_permission_keys) {
69
- // const login = permissions_key.replace('LOGIN_PERMISSIONS_', '');
70
- // const permissions = process.env[permissions_key];
71
- // userPermissions[login] = compilePermissions(permissions);
72
- // }
73
- // }
74
-
75
- // loginsCache = res.length > 0 ? res : null;
76
- // loginsLoaded = true;
77
- // return loginsCache;
78
- // }
79
-
80
- function connectionHasPermission(connection, req) {
31
+ function connectionHasPermission(connection, loadedPermissions) {
81
32
  if (!connection) {
82
33
  return true;
83
34
  }
84
35
  if (_.isString(connection)) {
85
- return hasPermission(`connections/${connection}`, req);
36
+ return hasPermission(`connections/${connection}`, loadedPermissions);
86
37
  } else {
87
- return hasPermission(`connections/${connection._id}`, req);
38
+ return hasPermission(`connections/${connection._id}`, loadedPermissions);
39
+ }
40
+ }
41
+
42
+ async function testConnectionPermission(connection, req, loadedPermissions) {
43
+ if (!loadedPermissions) {
44
+ loadedPermissions = await loadPermissionsFromRequest(req);
45
+ }
46
+ if (process.env.STORAGE_DATABASE) {
47
+ if (hasPermission(`all-connections`, loadedPermissions)) {
48
+ return;
49
+ }
50
+ const conid = _.isString(connection) ? connection : connection?._id;
51
+ if (hasPermission('internal-storage', loadedPermissions) && conid == '__storage') {
52
+ return;
53
+ }
54
+ const authProvider = getAuthProviderFromReq(req);
55
+ if (!req) {
56
+ return;
57
+ }
58
+ if (!(await authProvider.checkCurrentConnectionPermission(req, conid))) {
59
+ throw new Error('DBGM-00263 Connection permission not granted');
60
+ }
61
+ } else {
62
+ if (!connectionHasPermission(connection, loadedPermissions)) {
63
+ throw new Error('DBGM-00264 Connection permission not granted');
64
+ }
65
+ }
66
+ }
67
+
68
+ async function loadDatabasePermissionsFromRequest(req) {
69
+ const authProvider = getAuthProviderFromReq(req);
70
+ if (!req) {
71
+ return null;
72
+ }
73
+
74
+ const databasePermissions = await authProvider.getCurrentDatabasePermissions(req);
75
+ return databasePermissions;
76
+ }
77
+
78
+ async function loadTablePermissionsFromRequest(req) {
79
+ const authProvider = getAuthProviderFromReq(req);
80
+ if (!req) {
81
+ return null;
82
+ }
83
+
84
+ const tablePermissions = await authProvider.getCurrentTablePermissions(req);
85
+ return tablePermissions;
86
+ }
87
+
88
+ function matchDatabasePermissionRow(conid, database, permissionRow) {
89
+ if (permissionRow.connection_id) {
90
+ if (conid != permissionRow.connection_id) {
91
+ return false;
92
+ }
93
+ }
94
+ if (permissionRow.database_names_list) {
95
+ const items = permissionRow.database_names_list.split('\n');
96
+ if (!items.find(item => item.trim()?.toLowerCase() === database?.toLowerCase())) {
97
+ return false;
98
+ }
99
+ }
100
+ if (permissionRow.database_names_regex) {
101
+ const regex = new RegExp(permissionRow.database_names_regex, 'i');
102
+ if (!regex.test(database)) {
103
+ return false;
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+
109
+ function matchTablePermissionRow(objectTypeField, schemaName, pureName, permissionRow) {
110
+ if (permissionRow.table_names_list) {
111
+ const items = permissionRow.table_names_list.split('\n');
112
+ if (!items.find(item => item.trim()?.toLowerCase() === pureName?.toLowerCase())) {
113
+ return false;
114
+ }
115
+ }
116
+ if (permissionRow.table_names_regex) {
117
+ const regex = new RegExp(permissionRow.table_names_regex, 'i');
118
+ if (!regex.test(pureName)) {
119
+ return false;
120
+ }
121
+ }
122
+ if (permissionRow.schema_names_list) {
123
+ const items = permissionRow.schema_names_list.split('\n');
124
+ if (!items.find(item => item.trim()?.toLowerCase() === schemaName?.toLowerCase())) {
125
+ return false;
126
+ }
127
+ }
128
+ if (permissionRow.schema_names_regex) {
129
+ const regex = new RegExp(permissionRow.schema_names_regex, 'i');
130
+ if (!regex.test(schemaName)) {
131
+ return false;
132
+ }
133
+ }
134
+
135
+ return true;
136
+ }
137
+
138
+ const DATABASE_ROLE_ID_NAMES = {
139
+ '-1': 'view',
140
+ '-2': 'read_content',
141
+ '-3': 'write_data',
142
+ '-4': 'run_script',
143
+ '-5': 'deny',
144
+ };
145
+
146
+ function getDatabaseRoleLevelIndex(roleName) {
147
+ if (!roleName) {
148
+ return 6;
149
+ }
150
+ if (roleName == 'run_script') {
151
+ return 5;
152
+ }
153
+ if (roleName == 'write_data') {
154
+ return 4;
155
+ }
156
+ if (roleName == 'read_content') {
157
+ return 3;
158
+ }
159
+ if (roleName == 'view') {
160
+ return 2;
161
+ }
162
+ if (roleName == 'deny') {
163
+ return 1;
164
+ }
165
+ return 6;
166
+ }
167
+
168
+ function getTablePermissionRoleLevelIndex(roleName) {
169
+ if (!roleName) {
170
+ return 6;
171
+ }
172
+ if (roleName == 'run_script') {
173
+ return 5;
174
+ }
175
+ if (roleName == 'create_update_delete') {
176
+ return 4;
177
+ }
178
+ if (roleName == 'update_only') {
179
+ return 3;
180
+ }
181
+ if (roleName == 'read') {
182
+ return 2;
183
+ }
184
+ if (roleName == 'deny') {
185
+ return 1;
88
186
  }
187
+ return 6;
89
188
  }
90
189
 
91
- function testConnectionPermission(connection, req) {
92
- if (!connectionHasPermission(connection, req)) {
93
- throw new Error('Connection permission not granted');
190
+ function getDatabasePermissionRole(conid, database, loadedDatabasePermissions) {
191
+ let res = 'deny';
192
+ for (const permissionRow of loadedDatabasePermissions) {
193
+ if (!matchDatabasePermissionRow(conid, database, permissionRow)) {
194
+ continue;
195
+ }
196
+ res = DATABASE_ROLE_ID_NAMES[permissionRow.database_permission_role_id];
197
+ }
198
+ return res;
199
+ }
200
+
201
+ const TABLE_ROLE_ID_NAMES = {
202
+ '-1': 'read',
203
+ '-2': 'update_only',
204
+ '-3': 'create_update_delete',
205
+ '-4': 'run_script',
206
+ '-5': 'deny',
207
+ };
208
+
209
+ const TABLE_SCOPE_ID_NAMES = {
210
+ '-1': 'all_objects',
211
+ '-2': 'tables',
212
+ '-3': 'views',
213
+ '-4': 'tables_views_collections',
214
+ '-5': 'procedures',
215
+ '-6': 'functions',
216
+ '-7': 'triggers',
217
+ '-8': 'sql_objects',
218
+ '-9': 'collections',
219
+ };
220
+
221
+ function getTablePermissionRole(
222
+ conid,
223
+ database,
224
+ objectTypeField,
225
+ schemaName,
226
+ pureName,
227
+ loadedTablePermissions,
228
+ databasePermissionRole
229
+ ) {
230
+ let res =
231
+ databasePermissionRole == 'read_content'
232
+ ? 'read'
233
+ : databasePermissionRole == 'write_data'
234
+ ? 'create_update_delete'
235
+ : databasePermissionRole == 'run_script'
236
+ ? 'run_script'
237
+ : 'deny';
238
+ for (const permissionRow of loadedTablePermissions) {
239
+ if (!matchDatabasePermissionRow(conid, database, permissionRow)) {
240
+ continue;
241
+ }
242
+ if (!matchTablePermissionRow(objectTypeField, schemaName, pureName, permissionRow)) {
243
+ continue;
244
+ }
245
+ const scope = TABLE_SCOPE_ID_NAMES[permissionRow.table_permission_scope_id];
246
+ switch (scope) {
247
+ case 'tables':
248
+ if (objectTypeField != 'tables') continue;
249
+ break;
250
+ case 'views':
251
+ if (objectTypeField != 'views') continue;
252
+ break;
253
+ case 'tables_views_collections':
254
+ if (objectTypeField != 'tables' && objectTypeField != 'views' && objectTypeField != 'collections') continue;
255
+ break;
256
+ case 'procedures':
257
+ if (objectTypeField != 'procedures') continue;
258
+ break;
259
+ case 'functions':
260
+ if (objectTypeField != 'functions') continue;
261
+ break;
262
+ case 'triggers':
263
+ if (objectTypeField != 'triggers') continue;
264
+ break;
265
+ case 'sql_objects':
266
+ if (objectTypeField != 'procedures' && objectTypeField != 'functions' && objectTypeField != 'triggers')
267
+ continue;
268
+ break;
269
+ case 'collections':
270
+ if (objectTypeField != 'collections') continue;
271
+ break;
272
+ }
273
+ res = TABLE_ROLE_ID_NAMES[permissionRow.table_permission_role_id];
274
+ }
275
+ return res;
276
+ }
277
+
278
+ async function testStandardPermission(permission, req, loadedPermissions) {
279
+ if (!loadedPermissions) {
280
+ loadedPermissions = await loadPermissionsFromRequest(req);
281
+ }
282
+ if (!hasPermission(permission, loadedPermissions)) {
283
+ throw new Error('DBGM-00265 Permission not granted');
284
+ }
285
+ }
286
+
287
+ async function testDatabaseRolePermission(conid, database, requiredRole, req) {
288
+ if (!process.env.STORAGE_DATABASE) {
289
+ return;
290
+ }
291
+ const loadedPermissions = await loadPermissionsFromRequest(req);
292
+ if (hasPermission(`all-databases`, loadedPermissions)) {
293
+ return;
294
+ }
295
+ const databasePermissions = await loadDatabasePermissionsFromRequest(req);
296
+ const role = getDatabasePermissionRole(conid, database, databasePermissions);
297
+ const requiredIndex = getDatabaseRoleLevelIndex(requiredRole);
298
+ const roleIndex = getDatabaseRoleLevelIndex(role);
299
+ if (roleIndex < requiredIndex) {
300
+ throw new Error('DBGM-00266 Permission not granted');
94
301
  }
95
302
  }
96
303
 
@@ -98,4 +305,12 @@ module.exports = {
98
305
  hasPermission,
99
306
  connectionHasPermission,
100
307
  testConnectionPermission,
308
+ loadPermissionsFromRequest,
309
+ loadDatabasePermissionsFromRequest,
310
+ loadTablePermissionsFromRequest,
311
+ getDatabasePermissionRole,
312
+ getTablePermissionRole,
313
+ testStandardPermission,
314
+ testDatabaseRolePermission,
315
+ getTablePermissionRoleLevelIndex,
101
316
  };