k2hr3-api 1.0.42 → 2.0.1

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 (149) hide show
  1. package/config/k2hr3-init.sh.templ +4 -4
  2. package/dist/.gitkeep +0 -0
  3. package/dist/src/app.js +262 -0
  4. package/{bin → dist/src/bin}/run.sh +1 -1
  5. package/dist/src/bin/watcher.js +113 -0
  6. package/dist/src/bin/www.js +217 -0
  7. package/dist/src/lib/basicipcheck.js +392 -0
  8. package/dist/src/lib/cacerts.js +106 -0
  9. package/dist/src/lib/dbglogging.js +190 -0
  10. package/dist/src/lib/dummyuserapi.js +719 -0
  11. package/dist/src/lib/ipwatch.js +354 -0
  12. package/dist/src/lib/k2hr3acrutil.js +532 -0
  13. package/dist/src/lib/k2hr3apiutil.js +1444 -0
  14. package/dist/src/lib/k2hr3cliutil.js +183 -0
  15. package/dist/src/lib/k2hr3config.js +832 -0
  16. package/dist/src/lib/k2hr3cryptutil.js +258 -0
  17. package/dist/src/lib/k2hr3dkc.js +12121 -0
  18. package/dist/src/lib/k2hr3extdata.js +198 -0
  19. package/dist/src/lib/k2hr3keys.js +207 -0
  20. package/dist/src/lib/k2hr3resutil.js +111 -0
  21. package/dist/src/lib/k2hr3template.js +6546 -0
  22. package/dist/src/lib/k2hr3tokens.js +2643 -0
  23. package/dist/src/lib/k2hr3userdata.js +296 -0
  24. package/dist/src/lib/k8soidc.js +1000 -0
  25. package/dist/src/lib/openstackapiv2.js +695 -0
  26. package/dist/src/lib/openstackapiv3.js +932 -0
  27. package/dist/src/lib/openstackep.js +667 -0
  28. package/{tests/auto_common.js → dist/src/lib/types.js} +4 -38
  29. package/dist/src/routes/acr.js +704 -0
  30. package/dist/src/routes/debugVerify.js +294 -0
  31. package/dist/src/routes/extdata.js +219 -0
  32. package/dist/src/routes/list.js +264 -0
  33. package/dist/src/routes/policy.js +840 -0
  34. package/dist/src/routes/resource.js +1489 -0
  35. package/dist/src/routes/role.js +2627 -0
  36. package/dist/src/routes/service.js +908 -0
  37. package/dist/src/routes/tenant.js +1141 -0
  38. package/dist/src/routes/userTokens.js +482 -0
  39. package/dist/src/routes/userdata.js +212 -0
  40. package/dist/src/routes/version.js +103 -0
  41. package/package.json +152 -121
  42. package/ChangeLog +0 -378
  43. package/app.js +0 -292
  44. package/bin/watcher +0 -122
  45. package/bin/www +0 -180
  46. package/eslint.config.mjs +0 -68
  47. package/lib/basicipcheck.js +0 -376
  48. package/lib/cacerts.js +0 -71
  49. package/lib/dbglogging.js +0 -151
  50. package/lib/dummyuserapi.js +0 -766
  51. package/lib/ipwatch.js +0 -379
  52. package/lib/k2hr3acrutil.js +0 -516
  53. package/lib/k2hr3apiutil.js +0 -1494
  54. package/lib/k2hr3cliutil.js +0 -191
  55. package/lib/k2hr3config.js +0 -826
  56. package/lib/k2hr3cryptutil.js +0 -254
  57. package/lib/k2hr3dkc.js +0 -12632
  58. package/lib/k2hr3extdata.js +0 -198
  59. package/lib/k2hr3keys.js +0 -234
  60. package/lib/k2hr3resutil.js +0 -100
  61. package/lib/k2hr3template.js +0 -6925
  62. package/lib/k2hr3tokens.js +0 -2799
  63. package/lib/k2hr3userdata.js +0 -312
  64. package/lib/k8soidc.js +0 -1012
  65. package/lib/openstackapiv2.js +0 -764
  66. package/lib/openstackapiv3.js +0 -1032
  67. package/lib/openstackep.js +0 -553
  68. package/routes/acr.js +0 -738
  69. package/routes/debugVerify.js +0 -263
  70. package/routes/extdata.js +0 -232
  71. package/routes/list.js +0 -270
  72. package/routes/policy.js +0 -869
  73. package/routes/resource.js +0 -1441
  74. package/routes/role.js +0 -2664
  75. package/routes/service.js +0 -894
  76. package/routes/tenant.js +0 -1095
  77. package/routes/userTokens.js +0 -511
  78. package/routes/userdata.js +0 -218
  79. package/routes/version.js +0 -108
  80. package/templ/Dockerfile.templ +0 -71
  81. package/tests/auto_acr.js +0 -1101
  82. package/tests/auto_acr_spec.js +0 -79
  83. package/tests/auto_all_spec.js +0 -142
  84. package/tests/auto_control_subprocess.sh +0 -243
  85. package/tests/auto_extdata.js +0 -220
  86. package/tests/auto_extdata_spec.js +0 -79
  87. package/tests/auto_init_config_json.sh +0 -275
  88. package/tests/auto_k2hdkc_server.ini +0 -109
  89. package/tests/auto_k2hdkc_slave.ini +0 -83
  90. package/tests/auto_list.js +0 -439
  91. package/tests/auto_list_spec.js +0 -79
  92. package/tests/auto_policy.js +0 -1579
  93. package/tests/auto_policy_spec.js +0 -79
  94. package/tests/auto_resource.js +0 -10956
  95. package/tests/auto_resource_spec.js +0 -79
  96. package/tests/auto_role.js +0 -6150
  97. package/tests/auto_role_spec.js +0 -79
  98. package/tests/auto_service.js +0 -770
  99. package/tests/auto_service_spec.js +0 -79
  100. package/tests/auto_subprocesses.js +0 -114
  101. package/tests/auto_template.sh +0 -126
  102. package/tests/auto_tenant.js +0 -1100
  103. package/tests/auto_tenant_spec.js +0 -79
  104. package/tests/auto_token_util.js +0 -219
  105. package/tests/auto_userdata.js +0 -292
  106. package/tests/auto_userdata_spec.js +0 -79
  107. package/tests/auto_usertokens.js +0 -565
  108. package/tests/auto_usertokens_spec.js +0 -79
  109. package/tests/auto_version.js +0 -127
  110. package/tests/auto_version_spec.js +0 -79
  111. package/tests/auto_watcher.js +0 -157
  112. package/tests/auto_watcher_spec.js +0 -79
  113. package/tests/k2hdkc_test.data +0 -986
  114. package/tests/k2hdkc_test_load.sh +0 -255
  115. package/tests/k2hr3template_test.js +0 -187
  116. package/tests/k2hr3template_test.sh +0 -339
  117. package/tests/k2hr3template_test_async.js +0 -216
  118. package/tests/k2hr3template_test_template.result +0 -7117
  119. package/tests/k2hr3template_test_template.txt +0 -3608
  120. package/tests/k2hr3template_test_vars.js +0 -194
  121. package/tests/manual_acr_delete.js +0 -143
  122. package/tests/manual_acr_get.js +0 -297
  123. package/tests/manual_acr_postput.js +0 -215
  124. package/tests/manual_allusertenant_get.js +0 -113
  125. package/tests/manual_extdata_get.js +0 -191
  126. package/tests/manual_k2hr3keys_get.js +0 -84
  127. package/tests/manual_list_gethead.js +0 -230
  128. package/tests/manual_policy_delete.js +0 -132
  129. package/tests/manual_policy_gethead.js +0 -275
  130. package/tests/manual_policy_postput.js +0 -297
  131. package/tests/manual_resource_delete.js +0 -433
  132. package/tests/manual_resource_gethead.js +0 -423
  133. package/tests/manual_resource_postput.js +0 -487
  134. package/tests/manual_role_delete.js +0 -404
  135. package/tests/manual_role_gethead.js +0 -547
  136. package/tests/manual_role_postput.js +0 -544
  137. package/tests/manual_service_delete.js +0 -153
  138. package/tests/manual_service_gethead.js +0 -178
  139. package/tests/manual_service_postput.js +0 -348
  140. package/tests/manual_tenant_delete.js +0 -186
  141. package/tests/manual_tenant_gethead.js +0 -268
  142. package/tests/manual_tenant_postput.js +0 -293
  143. package/tests/manual_test.sh +0 -352
  144. package/tests/manual_userdata_get.js +0 -173
  145. package/tests/manual_usertoken_gethead.js +0 -136
  146. package/tests/manual_usertoken_postput.js +0 -310
  147. package/tests/manual_version_get.js +0 -127
  148. package/tests/run_local_test_k2hdkc.sh +0 -174
  149. package/tests/test.sh +0 -333
@@ -0,0 +1,2627 @@
1
+ "use strict";
2
+ /*
3
+ * K2HR3 REST API
4
+ *
5
+ * Copyright 2017 Yahoo Japan Corporation.
6
+ *
7
+ * K2HR3 is K2hdkc based Resource and Roles and policy Rules, gathers
8
+ * common management information for the cloud.
9
+ * K2HR3 can dynamically manage information as "who", "what", "operate".
10
+ * These are stored as roles, resources, policies in K2hdkc, and the
11
+ * client system can dynamically read and modify these information.
12
+ *
13
+ * For the full copyright and license information, please view
14
+ * the license file that was distributed with this source code.
15
+ *
16
+ * AUTHOR: Takeshi Nakatani
17
+ * CREATE: Wed Jun 8 2017
18
+ * REVISION:
19
+ *
20
+ */
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ const k2hr3apiutil_1 = __importDefault(require("../lib/k2hr3apiutil"));
26
+ const k2hr3resutil_1 = __importDefault(require("../lib/k2hr3resutil"));
27
+ const k2hr3tokens_1 = __importDefault(require("../lib/k2hr3tokens"));
28
+ const k2hr3userdata_1 = __importDefault(require("../lib/k2hr3userdata"));
29
+ const k2hr3dkc_1 = __importDefault(require("../lib/k2hr3dkc"));
30
+ const dbglogging_1 = __importDefault(require("../lib/dbglogging"));
31
+ const express_1 = __importDefault(require("express"));
32
+ const k2hr3config_1 = require("../lib/k2hr3config");
33
+ const k2hr3keys_1 = require("../lib/k2hr3keys");
34
+ const apiConf = new k2hr3config_1.r3ApiConfig();
35
+ const r3keys = k2hr3keys_1.getK2hr3Keys;
36
+ const router = express_1.default.Router();
37
+ //
38
+ // check typs
39
+ //
40
+ const rawIsValTypeQueryRoleHostBaseValue = (val) => {
41
+ if (!k2hr3apiutil_1.default.isPlainObject(val)) {
42
+ return false;
43
+ }
44
+ const _obj = val;
45
+ const _isStringOrNull = (key) => (null === _obj[key] || k2hr3apiutil_1.default.isString(_obj[key]));
46
+ const _isStringOrNullOrUndef = (key) => (undefined === _obj[key] || null === _obj[key] || k2hr3apiutil_1.default.isString(_obj[key]));
47
+ const _isStrNumOrNullOrUndef = (key) => (undefined === _obj[key] || null === _obj[key] || k2hr3apiutil_1.default.isString(_obj[key]) || k2hr3apiutil_1.default.isSafeNumber(_obj[key]));
48
+ return (_isStringOrNull('host') &&
49
+ _isStrNumOrNullOrUndef('port') &&
50
+ _isStringOrNullOrUndef('cuk') &&
51
+ _isStringOrNullOrUndef('extra') &&
52
+ _isStringOrNullOrUndef('tag') &&
53
+ _isStringOrNullOrUndef('inboundip') &&
54
+ _isStringOrNullOrUndef('outboundip'));
55
+ };
56
+ const rawIsValTypeQueryRoleHostBaseValueArray = (arr) => {
57
+ return (Array.isArray(arr) && arr.every((element) => rawIsValTypeQueryRoleHostBaseValue(element)));
58
+ };
59
+ //---------------------------------------------------------
60
+ // Configuration
61
+ // * Get role full path which is allowed to remove ip address
62
+ // * Get expiration for role tokens
63
+ //---------------------------------------------------------
64
+ let delhost_role_yrn = null;
65
+ let expire_rtoken = 0;
66
+ let expire_reg_rtoken = 0;
67
+ (() => {
68
+ const admincfgobj = apiConf.getK2hr3AdminConfig();
69
+ if (k2hr3apiutil_1.default.isPlainObject(admincfgobj) && k2hr3apiutil_1.default.isSafeString(admincfgobj.tenant) && k2hr3apiutil_1.default.isSafeString(admincfgobj.delhostrole)) {
70
+ const keys = r3keys(null, admincfgobj.tenant.trim());
71
+ delhost_role_yrn = keys.ROLE_TOP_KEY + ':' + admincfgobj.delhostrole.trim();
72
+ }
73
+ else {
74
+ dbglogging_1.default.elog('Could not find tenant/role in configuration for deleting host by cuk.');
75
+ delhost_role_yrn = null;
76
+ }
77
+ expire_rtoken = apiConf.getExpireTimeRoleToken();
78
+ expire_reg_rtoken = apiConf.getExpireTimeRegRoleToken();
79
+ })();
80
+ //---------------------------------------------------------
81
+ // Router POST
82
+ //---------------------------------------------------------
83
+ //
84
+ // Mountpath : '/v1/role'
85
+ // POST '/v1/role{/<role{/...}>}' : post role on version 1
86
+ // HEADER : X-Auth-Token => User token or Role token
87
+ // response body : result => true/false
88
+ // message => messages
89
+ //
90
+ // This mount point is for creating(update) role or creating(update) host in role.
91
+ //
92
+ router.post('/', (req, res, next) => {
93
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
94
+ res.type('application/json; charset=utf-8');
95
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
96
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
97
+ const result = {
98
+ result: false,
99
+ message: 'POST request or url or query is wrong'
100
+ };
101
+ dbglogging_1.default.elog(result.message);
102
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
103
+ return;
104
+ }
105
+ // check api type
106
+ if ('/v1/role' === decodeURI(req.baseUrl)) {
107
+ //------------------------------
108
+ // create role type
109
+ //------------------------------
110
+ postRole(req, res, next);
111
+ }
112
+ else {
113
+ // check host api
114
+ const keys = r3keys();
115
+ const requestptn = new RegExp(keys.MATCH_URI_GET_ROLE_DATA); // regex = /^\/v1\/role\/(.*)/
116
+ const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
117
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
118
+ const result = {
119
+ result: false,
120
+ message: 'POST request url does not have role name'
121
+ };
122
+ dbglogging_1.default.elog(result.message);
123
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
124
+ return;
125
+ }
126
+ // role name
127
+ const name = reqmatchs[1].toLowerCase();
128
+ //------------------------------
129
+ // create host type
130
+ //------------------------------
131
+ postRoleHost(name, req, res, next);
132
+ }
133
+ });
134
+ //---------------------------------------------------------
135
+ // Router PUT
136
+ //---------------------------------------------------------
137
+ // Mountpath : '/v1/role'
138
+ // PUT '/v1/role{/<role{/...}>}': put role on version 1
139
+ // HEADER : X-Auth-Token => User token or Role token
140
+ // response body : result => true/false
141
+ // message => messages
142
+ //
143
+ // This mount point is for creating(update) role and creating(update) host in role.
144
+ //
145
+ router.put('/', (req, res, next) => {
146
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
147
+ res.type('application/json; charset=utf-8');
148
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
149
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
150
+ const result = {
151
+ result: false,
152
+ message: 'PUT request or url or query is wrong'
153
+ };
154
+ dbglogging_1.default.elog(result.message);
155
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
156
+ return;
157
+ }
158
+ // check api type
159
+ if ('/v1/role' === decodeURI(req.baseUrl)) {
160
+ //------------------------------
161
+ // create role type
162
+ //------------------------------
163
+ putRole(req, res, next);
164
+ }
165
+ else {
166
+ // check host api
167
+ const keys = r3keys();
168
+ const requestptn = new RegExp(keys.MATCH_URI_GET_ROLE_DATA); // regex = /^\/v1\/role\/(.*)/
169
+ const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
170
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
171
+ const result = {
172
+ result: false,
173
+ message: 'POST request url does not have role name'
174
+ };
175
+ dbglogging_1.default.elog(result.message);
176
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
177
+ return;
178
+ }
179
+ // role name
180
+ const name = reqmatchs[1].toLowerCase();
181
+ //------------------------------
182
+ // create host type
183
+ //------------------------------
184
+ putRoleHost(name, req, res, next);
185
+ }
186
+ });
187
+ //
188
+ // Sub router function for POST CREATE ROLE
189
+ //
190
+ // Mountpath : '/v1/role'
191
+ // POST '/v1/role' : post role on version 1
192
+ // HEADER : X-Auth-Token => User token
193
+ // response body : result => true/false
194
+ // message => messages
195
+ // body :
196
+ // {
197
+ // "role": {
198
+ // "name": <role name> => key is "yrn:yahoo:<service>::<tenant>:role:<role>"
199
+ // <role> can include '/' for hierarchical path
200
+ // "policies": [<policy yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:role:<role>/policies"
201
+ // specify policy as "yrn:yahoo:<service>::<tenant>:policy:<policy>"
202
+ // if null or undefined is specified, not update this member in role when this role exists.
203
+ // if '' or zero array, this member in role is set empty array.
204
+ // "alias": [<role yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:role:<role>/@"
205
+ // specify another role as "yrn:yahoo:<service>::<tenant>:role:<role>"
206
+ // if null or undefined is specified, not update this member in role when this role exists.
207
+ // if '' or zero array, this member in role is set empty array.
208
+ // }
209
+ // }
210
+ //
211
+ // [NOTE]
212
+ // This API does not set host into roles as initial. You can add host to role
213
+ // by another API which is an API dedicated to adding host.
214
+ //
215
+ const postRole = (req, res, _) => {
216
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
217
+ !k2hr3apiutil_1.default.isPlainObject(req.body) ||
218
+ !k2hr3apiutil_1.default.isPlainObject(req.body.role)) {
219
+ const result = {
220
+ result: false,
221
+ message: 'POST body does not have role data'
222
+ };
223
+ dbglogging_1.default.elog(result.message);
224
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
225
+ return;
226
+ }
227
+ //------------------------------
228
+ // check token
229
+ //------------------------------
230
+ const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
231
+ if (!token_result.result) {
232
+ const result = {
233
+ result: token_result.result,
234
+ message: k2hr3apiutil_1.default.getSafeString(token_result.message),
235
+ };
236
+ dbglogging_1.default.elog(result.message);
237
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
238
+ return;
239
+ }
240
+ const token_info = token_result.token_info;
241
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
242
+ const result = {
243
+ result: false,
244
+ message: 'specified wrong token or it is not scoped user token'
245
+ };
246
+ dbglogging_1.default.elog(result.message);
247
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
248
+ return;
249
+ }
250
+ //------------------------------
251
+ // check arguments
252
+ //------------------------------
253
+ // name
254
+ if (!k2hr3apiutil_1.default.isSafeString(req.body.role.name)) {
255
+ const result = {
256
+ result: false,
257
+ message: 'role:name field is wrong : ' + JSON.stringify(req.body.role.name)
258
+ };
259
+ dbglogging_1.default.elog(result.message);
260
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
261
+ return;
262
+ }
263
+ const keys = r3keys(token_info.user, token_info.tenant);
264
+ let name = k2hr3apiutil_1.default.getSafeString(req.body.role.name).toLowerCase();
265
+ // role name is only name or full yrn path
266
+ let nameptn = new RegExp('^' + keys.ROLE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:role:(.*)/
267
+ const namematchs = name.match(nameptn);
268
+ if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
269
+ name = namematchs[1];
270
+ }
271
+ // check name which is not full yrn
272
+ nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
273
+ if (name.match(nameptn)) {
274
+ const result = {
275
+ result: false,
276
+ message: 'POST request query has wrong yrn full path to role'
277
+ };
278
+ dbglogging_1.default.elog(result.message);
279
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
280
+ return;
281
+ }
282
+ // policies
283
+ const policiesptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
284
+ const policiespram = k2hr3apiutil_1.default.getNormalizeParameter(req.body.role.policies, policiesptn, null);
285
+ if (false === policiespram.result) {
286
+ const result = {
287
+ result: false,
288
+ message: 'role:policies field is wrong : ' + JSON.stringify(req.body.role.policies)
289
+ };
290
+ dbglogging_1.default.elog(result.message);
291
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
292
+ return;
293
+ }
294
+ const policies = policiespram.parameter;
295
+ // alias
296
+ const aliasptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
297
+ const aliaspram = k2hr3apiutil_1.default.getNormalizeParameter(req.body.role.alias, aliasptn, null);
298
+ if (false === aliaspram.result) {
299
+ const result = {
300
+ result: false,
301
+ message: 'role:alias field is wrong : ' + JSON.stringify(req.body.role.alias)
302
+ };
303
+ dbglogging_1.default.elog(result.message);
304
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
305
+ return;
306
+ }
307
+ const aliases = aliaspram.parameter;
308
+ //------------------------------
309
+ // set all field to role
310
+ //------------------------------
311
+ const role_result = k2hr3dkc_1.default.setRoleAll(token_info.user, token_info.tenant, name, policies, aliases, null, false, null, false);
312
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
313
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result)) {
314
+ const result = {
315
+ result: false,
316
+ message: 'Could not get response from setRoleAll'
317
+ };
318
+ dbglogging_1.default.elog(result.message);
319
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
320
+ }
321
+ else {
322
+ const result = {
323
+ result: k2hr3apiutil_1.default.isBoolean(role_result.result) ? role_result.result : false,
324
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : 'Could not get error message in response from setRoleAll'
325
+ };
326
+ dbglogging_1.default.elog(result.message);
327
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
328
+ }
329
+ return;
330
+ }
331
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
332
+ res.status(201); // 201: Created
333
+ res.send(JSON.stringify(role_result));
334
+ };
335
+ //
336
+ // Sub router function for PUT CREATE ROLE
337
+ //
338
+ // Mountpath : '/v1/role'
339
+ // PUT '/v1/role{/<role{/...}>}' : put role on version 1
340
+ // HEADER : X-Auth-Token => User token
341
+ // response body : result => true/false
342
+ // message => messages
343
+ // url argument
344
+ // "name": <role name> => key is "yrn:yahoo:<service>::<tenant>:role:<role>"
345
+ // <role> can include '/' for hierarchical path
346
+ // "policies": [<policy yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:role:<role>/policies"
347
+ // specify policy as "yrn:yahoo:<service>::<tenant>:policy:<policy>", it is formatted by JSON.
348
+ // if null or undefined is specified, not update this member in role when this role exists.
349
+ // if '' or zero array, this member in role is set empty array.
350
+ // "alias": [<role yrn full path>, ...] => key is "yrn:yahoo:<service>::<tenant>:role:<role>/@"
351
+ // specify another role as "yrn:yahoo:<service>::<tenant>:role:<role>", it is formatted by JSON.
352
+ // if null or undefined is specified, not update this member in role when this role exists.
353
+ // if '' or zero array, this member in role is set empty array.
354
+ //
355
+ // [NOTE]
356
+ // This API does not set host into roles as initial. You can add host to role
357
+ // by another API which is an API dedicated to adding host.
358
+ //
359
+ const putRole = (req, res, _) => {
360
+ dbglogging_1.default.dlog('CALL:', req.method, req.url);
361
+ res.type('application/json; charset=utf-8');
362
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
363
+ !k2hr3apiutil_1.default.isPlainObject(req.query)) {
364
+ const result = {
365
+ result: false,
366
+ message: 'PUT argument does not have any data'
367
+ };
368
+ dbglogging_1.default.elog(result.message);
369
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
370
+ return;
371
+ }
372
+ //------------------------------
373
+ // check token
374
+ //------------------------------
375
+ const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
376
+ if (!token_result.result) {
377
+ const result = {
378
+ result: token_result.result,
379
+ message: k2hr3apiutil_1.default.getSafeString(token_result.message),
380
+ };
381
+ dbglogging_1.default.elog(result.message);
382
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
383
+ return;
384
+ }
385
+ const token_info = token_result.token_info;
386
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
387
+ const result = {
388
+ result: false,
389
+ message: 'specified wrong token or it is not scoped user token'
390
+ };
391
+ dbglogging_1.default.elog(result.message);
392
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
393
+ return;
394
+ }
395
+ //------------------------------
396
+ // check arguments
397
+ //------------------------------
398
+ // name
399
+ if (!k2hr3apiutil_1.default.isSafeString(req.query.name)) {
400
+ const result = {
401
+ result: false,
402
+ message: 'role:name field is wrong : ' + JSON.stringify(req.query.name)
403
+ };
404
+ dbglogging_1.default.elog(result.message);
405
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
406
+ return;
407
+ }
408
+ const keys = r3keys(token_info.user, token_info.tenant);
409
+ let name = k2hr3apiutil_1.default.getSafeString(req.query.name).toLowerCase();
410
+ // role name is only name or full yrn path
411
+ let nameptn = new RegExp('^' + keys.ROLE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:role:(.*)/
412
+ const namematchs = name.match(nameptn);
413
+ if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
414
+ name = namematchs[1];
415
+ }
416
+ // check name which is not full yrn
417
+ nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
418
+ if (name.match(nameptn)) {
419
+ const result = {
420
+ result: false,
421
+ message: 'PUT request query has wrong yrn full path to role'
422
+ };
423
+ dbglogging_1.default.elog(result.message);
424
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
425
+ return;
426
+ }
427
+ // policies
428
+ let policies = null;
429
+ if (!k2hr3apiutil_1.default.isString(req.query.policies)) {
430
+ policies = null;
431
+ }
432
+ else if ('' === req.query.policies) {
433
+ policies = '';
434
+ }
435
+ else if (k2hr3apiutil_1.default.isSafeString(req.query.policies)) {
436
+ // policies is encoded by JSON, this value is array.
437
+ //
438
+ let tmp_pol = k2hr3apiutil_1.default.getSafeString(req.query.policies);
439
+ if (k2hr3apiutil_1.default.checkSimpleJSON(tmp_pol)) {
440
+ tmp_pol = JSON.parse(tmp_pol);
441
+ }
442
+ const policiesptn = new RegExp('^' + keys.POLICY_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:policy:(.*)/
443
+ const policiespram = k2hr3apiutil_1.default.getNormalizeParameter(tmp_pol, policiesptn, null);
444
+ if (false === policiespram.result) {
445
+ const result = {
446
+ result: false,
447
+ message: 'role:policies field is wrong : ' + req.query.policies
448
+ };
449
+ dbglogging_1.default.elog(result.message);
450
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
451
+ return;
452
+ }
453
+ policies = policiespram.parameter ?? null;
454
+ }
455
+ // alias
456
+ let aliases = null;
457
+ if (!k2hr3apiutil_1.default.isString(req.query.alias)) {
458
+ aliases = null;
459
+ }
460
+ else if ('' === req.query.alias) {
461
+ aliases = '';
462
+ }
463
+ else if (k2hr3apiutil_1.default.isSafeString(req.query.alias)) {
464
+ // alias is encoded by JSON, this value is array.
465
+ //
466
+ let tmp_aliases = k2hr3apiutil_1.default.getSafeString(req.query.alias);
467
+ if (k2hr3apiutil_1.default.checkSimpleJSON(tmp_aliases)) {
468
+ tmp_aliases = JSON.parse(tmp_aliases);
469
+ }
470
+ const aliasptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
471
+ const aliaspram = k2hr3apiutil_1.default.getNormalizeParameter(tmp_aliases, aliasptn, null);
472
+ if (false === aliaspram.result) {
473
+ const result = {
474
+ result: false,
475
+ message: 'role:alias field is wrong : ' + req.query.alias
476
+ };
477
+ dbglogging_1.default.elog(result.message);
478
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
479
+ return;
480
+ }
481
+ aliases = aliaspram.parameter ?? null;
482
+ }
483
+ //------------------------------
484
+ // set all field to role
485
+ //------------------------------
486
+ const role_result = k2hr3dkc_1.default.setRoleAll(token_info.user, token_info.tenant, name, policies, aliases, null, false, null, false);
487
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
488
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result)) {
489
+ const result = {
490
+ result: false,
491
+ message: 'Could not get response from setRoleAll'
492
+ };
493
+ dbglogging_1.default.elog(result.message);
494
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
495
+ }
496
+ else {
497
+ const result = {
498
+ result: k2hr3apiutil_1.default.isBoolean(role_result.result) ? role_result.result : false,
499
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : 'Could not get error message in response from setRoleAll'
500
+ };
501
+ dbglogging_1.default.elog(result.message);
502
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
503
+ }
504
+ return;
505
+ }
506
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
507
+ res.status(201); // 201: Created
508
+ res.send(JSON.stringify(role_result));
509
+ };
510
+ //
511
+ // Sub router function for POST CREATE HOST
512
+ //
513
+ // Mountpath : '/v1/role'
514
+ // POST '/v1/role/<role{/...}>' : post role on version 1
515
+ // HEADER : X-Auth-Token => User token or Role token
516
+ // response body : result => true/false
517
+ // message => messages
518
+ //
519
+ // [UserToken] body :
520
+ // {
521
+ // "host": { => specified single host
522
+ // "host": <hostname / ip address> => key is for "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/{name, ip}/<hostname port cuk>"
523
+ // "port": <port number> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
524
+ // this value is number string(0-), allowed null and '' for this value.
525
+ // if this value is '0', it means any port.
526
+ // "cuk": <container unique key> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
527
+ // this value is string. if this value is undefined/null/empty string, it means any.
528
+ // "extra": <extra string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
529
+ // extra is any string including Control code, allowed null and '' for this value.
530
+ // "tag": <string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
531
+ // tag is any string including Control code, allowed null and '' for this value.
532
+ // "inboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
533
+ // inboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
534
+ // "outboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
535
+ // outboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
536
+ // }
537
+ // "clear_hostname": <true/false>
538
+ // "clear_ips": <true/false>
539
+ // }
540
+ // or
541
+ // {
542
+ // "host": [ => specified host as Array(only POST request has this type)
543
+ // {
544
+ // "host": <hostname / ip address>
545
+ // "port": <port number>
546
+ // "cuk": <container unique key>
547
+ // "extra": <extra string data>
548
+ // "tag": <string data>
549
+ // "inboundip": <ip address>
550
+ // "outboundip": <ip address>
551
+ // }
552
+ // ...
553
+ // ]
554
+ // "clear_hostname": <true/false>
555
+ // "clear_ips": <true/false>
556
+ // }
557
+ //
558
+ // [RoleToken] body :
559
+ // {
560
+ // "host": {
561
+ // "port": <port number> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/ip/<ip port cuk>"
562
+ // this value is number string(0-), allowed null and '' for this value.
563
+ // if this value is '0', it means any port.
564
+ // "cuk": <container unique key> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
565
+ // this value is string. if this value is undefined/null/empty string, it means any.
566
+ // "extra": <extra string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
567
+ // extra is any string including Control code, allowed null and '' for this value.
568
+ // "tag": <string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
569
+ // tag is any string including Control code, allowed null and '' for this value.
570
+ // "inboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
571
+ // inboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
572
+ // "outboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
573
+ // outboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
574
+ // }
575
+ // }
576
+ //
577
+ // [NOTE]
578
+ // This API only set(add/create) host into role. The host is specified hostname.
579
+ // The hostname is any string as like hostname.(ex. "x.yahoo.co.jp", "x[0-9].yahoo.co.jp", "*.yahoo.co.jp", "*", "(.*)", etc)
580
+ // If port number is 0, it means any port.
581
+ // If cuk is undefined/null/empty string, it means any.
582
+ // Extra data can include control-code(CR, etc).
583
+ //
584
+ const postRoleHost = (role, req, res, _) => {
585
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
586
+ !k2hr3apiutil_1.default.isPlainObject(req.body) ||
587
+ (!k2hr3apiutil_1.default.isArray(req.body.host) && !k2hr3apiutil_1.default.isPlainObject(req.body.host))) {
588
+ const result = {
589
+ result: false,
590
+ message: 'POST body does not have host data'
591
+ };
592
+ dbglogging_1.default.elog(result.message);
593
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
594
+ return;
595
+ }
596
+ //------------------------------
597
+ // check token
598
+ //------------------------------
599
+ const token_result = k2hr3tokens_1.default.checkToken(req, true); // scoped, both token
600
+ if (!token_result.result) {
601
+ const result = {
602
+ result: token_result.result,
603
+ message: k2hr3apiutil_1.default.getSafeString(token_result.message),
604
+ };
605
+ dbglogging_1.default.elog(result.message);
606
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
607
+ return;
608
+ }
609
+ const token_info = token_result.token_info;
610
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
611
+ const result = {
612
+ result: false,
613
+ message: 'specified wrong token or it is not scoped user token'
614
+ };
615
+ dbglogging_1.default.elog(result.message);
616
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
617
+ return;
618
+ }
619
+ const is_host_req = (!k2hr3apiutil_1.default.isArray(req.body.host) && (!k2hr3apiutil_1.default.isPlainObject(req.body.host) || !k2hr3apiutil_1.default.isSafeString(req.body.host.host)));
620
+ const keys = r3keys(token_info.user, token_info.tenant);
621
+ //------------------------------
622
+ // check arguments
623
+ //------------------------------
624
+ // role name check
625
+ let name = k2hr3apiutil_1.default.getSafeString(role).toLowerCase();
626
+ let nameptn = new RegExp('^' + keys.ROLE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:role:(.*)/
627
+ const namematchs = name.match(nameptn);
628
+ if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
629
+ // name is full yrn, then reset only name.
630
+ name = namematchs[1];
631
+ }
632
+ else {
633
+ // role name is not full yrn, then check other yrn path
634
+ nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
635
+ if (name.match(nameptn)) {
636
+ const result = {
637
+ result: false,
638
+ message: 'POST request url has wrong yrn full path to role'
639
+ };
640
+ dbglogging_1.default.elog(result.message);
641
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
642
+ return;
643
+ }
644
+ }
645
+ //------------------------------
646
+ // build parameters
647
+ //------------------------------
648
+ let role_result;
649
+ if (!is_host_req) {
650
+ //
651
+ // request from user token
652
+ //
653
+ let hostArray = [];
654
+ if (rawIsValTypeQueryRoleHostBaseValueArray(req.body.host)) {
655
+ hostArray = req.body.host;
656
+ }
657
+ else if (rawIsValTypeQueryRoleHostBaseValue(req.body.host)) {
658
+ hostArray = [req.body.host];
659
+ }
660
+ // check array and make ip array
661
+ let hostnameArray = [];
662
+ let ipArray = [];
663
+ for (let cnt = 0; cnt < hostArray.length; ++cnt) {
664
+ if (!k2hr3apiutil_1.default.isSafeString(hostArray[cnt].host)) {
665
+ const result = {
666
+ result: false,
667
+ message: 'host is not specified.'
668
+ };
669
+ dbglogging_1.default.elog(result.message);
670
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
671
+ return;
672
+ }
673
+ // hostname or ip address
674
+ const tmp_host = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].host);
675
+ let tg_host = null;
676
+ let tg_ip = null;
677
+ if (k2hr3apiutil_1.default.isIpAddressString(tmp_host)) {
678
+ tg_ip = tmp_host.toLowerCase();
679
+ tg_host = null;
680
+ }
681
+ else if (k2hr3apiutil_1.default.isSafeString(tmp_host)) {
682
+ tg_host = tmp_host.toLowerCase();
683
+ tg_ip = null;
684
+ }
685
+ // port
686
+ let port = 0;
687
+ if (k2hr3apiutil_1.default.isSafeNumeric(hostArray[cnt].port)) {
688
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(hostArray[cnt].port);
689
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
690
+ const result = {
691
+ result: false,
692
+ message: 'POST request has port which is not number: ' + JSON.stringify(hostArray[cnt].port)
693
+ };
694
+ dbglogging_1.default.elog(result.message);
695
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
696
+ return;
697
+ }
698
+ port = port_tmp;
699
+ }
700
+ // cuk
701
+ const tmp_cuk = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].cuk).trim();
702
+ let cuk = null;
703
+ if (k2hr3apiutil_1.default.isSafeString(tmp_cuk)) {
704
+ cuk = tmp_cuk;
705
+ }
706
+ // extra
707
+ const tmp_extra = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].extra);
708
+ let extra = null;
709
+ if (k2hr3apiutil_1.default.isSafeString(tmp_extra)) {
710
+ extra = tmp_extra;
711
+ }
712
+ // tag
713
+ const tmp_tag = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].tag);
714
+ let tag = null;
715
+ if (k2hr3apiutil_1.default.isSafeString(tmp_tag)) {
716
+ tag = tmp_tag;
717
+ }
718
+ // set base host information
719
+ const host_info = {
720
+ hostname: tg_host,
721
+ ip: tg_ip,
722
+ port: port,
723
+ cuk: cuk,
724
+ extra: extra,
725
+ tag: tag,
726
+ inboundip: null,
727
+ outboundip: null
728
+ };
729
+ // set optional keys
730
+ if (k2hr3apiutil_1.default.isSafeString(hostArray[cnt].inboundip)) {
731
+ if (!k2hr3apiutil_1.default.isIpAddressString(hostArray[cnt].inboundip)) {
732
+ const result = {
733
+ result: false,
734
+ message: 'POST request has inbound ip address which is not ignore ip address string: ' + JSON.stringify(hostArray[cnt].inboundip)
735
+ };
736
+ dbglogging_1.default.elog(result.message);
737
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
738
+ return;
739
+ }
740
+ host_info.inboundip = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].inboundip);
741
+ }
742
+ if (k2hr3apiutil_1.default.isSafeString(hostArray[cnt].outboundip)) {
743
+ if (!k2hr3apiutil_1.default.isIpAddressString(hostArray[cnt].outboundip)) {
744
+ const result = {
745
+ result: false,
746
+ message: 'POST request has outbound ip address which is not ignore ip address string: ' + JSON.stringify(hostArray[cnt].outboundip)
747
+ };
748
+ dbglogging_1.default.elog(result.message);
749
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
750
+ return;
751
+ }
752
+ host_info.outboundip = k2hr3apiutil_1.default.getSafeString(hostArray[cnt].outboundip);
753
+ }
754
+ // push array
755
+ if (null !== tg_host) {
756
+ hostnameArray.push(host_info);
757
+ }
758
+ if (null !== tg_ip) {
759
+ ipArray.push(host_info);
760
+ }
761
+ }
762
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(hostnameArray)) {
763
+ hostnameArray = null;
764
+ }
765
+ if (!k2hr3apiutil_1.default.isNotEmptyArray(ipArray)) {
766
+ ipArray = null;
767
+ }
768
+ // flags
769
+ let clear_hostname = false;
770
+ let clear_ips = false;
771
+ if (k2hr3apiutil_1.default.isBoolean(req.body.clear_hostname)) {
772
+ clear_hostname = req.body.clear_hostname;
773
+ }
774
+ if (k2hr3apiutil_1.default.isBoolean(req.body.clear_ips)) {
775
+ clear_ips = req.body.clear_ips;
776
+ }
777
+ //
778
+ // Add hostnames and ips ---> Need User Token
779
+ //
780
+ role_result = k2hr3dkc_1.default.updateRoleHosts(token_info.user, token_info.tenant, name, hostnameArray, clear_hostname, ipArray, clear_ips);
781
+ }
782
+ else {
783
+ //
784
+ // request from host(token)
785
+ //
786
+ // get ip address
787
+ const ip = k2hr3apiutil_1.default.getClientIpAddress(req);
788
+ if (!k2hr3apiutil_1.default.isSafeString(ip)) {
789
+ const result = {
790
+ result: false,
791
+ message: 'Could not get ip address from request.'
792
+ };
793
+ dbglogging_1.default.elog(result.message);
794
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
795
+ return;
796
+ }
797
+ // port
798
+ let port = 0;
799
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeNumeric(req.body.host.port)) {
800
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.body.host.port);
801
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
802
+ const result = {
803
+ result: false,
804
+ message: 'POST request has port which is not number: ' + JSON.stringify(req.body.host.port)
805
+ };
806
+ dbglogging_1.default.elog(result.message);
807
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
808
+ return;
809
+ }
810
+ port = port_tmp;
811
+ }
812
+ // cuk
813
+ let cuk = null;
814
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeString(req.body.host.cuk) && k2hr3apiutil_1.default.isSafeString(req.body.host.cuk.trim())) {
815
+ cuk = k2hr3apiutil_1.default.getSafeString(req.body.host.cuk).trim();
816
+ }
817
+ // extra
818
+ let extra = null;
819
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeString(req.body.host.extra)) {
820
+ const extra_tmp = k2hr3apiutil_1.default.getSafeString(req.body.host.extra);
821
+ if (k2hr3apiutil_1.default.checkSimpleJSON(extra_tmp)) {
822
+ const extra_parsed_tmp = JSON.parse(extra_tmp);
823
+ if (!k2hr3apiutil_1.default.isSafeString(extra_parsed_tmp)) {
824
+ const result = {
825
+ result: false,
826
+ message: 'POST request has extra which is not string: ' + JSON.stringify(req.body.host.extra)
827
+ };
828
+ dbglogging_1.default.elog(result.message);
829
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
830
+ return;
831
+ }
832
+ extra = extra_parsed_tmp;
833
+ }
834
+ else {
835
+ extra = extra_tmp;
836
+ }
837
+ }
838
+ // tag
839
+ let tag = null;
840
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeString(req.body.host.tag)) {
841
+ const tag_tmp = k2hr3apiutil_1.default.getSafeString(req.body.host.tag);
842
+ if (k2hr3apiutil_1.default.checkSimpleJSON(tag_tmp)) {
843
+ const tag_parsed_tmp = JSON.parse(tag_tmp);
844
+ if (!k2hr3apiutil_1.default.isSafeString(tag_parsed_tmp)) {
845
+ const result = {
846
+ result: false,
847
+ message: 'POST request has tag which is not string: ' + JSON.stringify(req.body.host.tag)
848
+ };
849
+ dbglogging_1.default.elog(result.message);
850
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
851
+ return;
852
+ }
853
+ tag = tag_parsed_tmp;
854
+ }
855
+ else {
856
+ tag = tag_tmp;
857
+ }
858
+ }
859
+ // inboundip(optional)
860
+ let inboundip = null;
861
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeString(req.body.host.inboundip)) {
862
+ if (!k2hr3apiutil_1.default.isIpAddressString(req.body.host.inboundip)) {
863
+ const result = {
864
+ result: false,
865
+ message: 'POST request has inbound ip address which is not ignore ip address string: ' + JSON.stringify(req.body.host.inboundip)
866
+ };
867
+ dbglogging_1.default.elog(result.message);
868
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
869
+ return;
870
+ }
871
+ inboundip = k2hr3apiutil_1.default.getSafeString(req.body.host.inboundip);
872
+ }
873
+ // outboundip(optional)
874
+ let outboundip = null;
875
+ if (k2hr3apiutil_1.default.isPlainObject(req.body.host) && k2hr3apiutil_1.default.isSafeString(req.body.host.outboundip)) {
876
+ if (!k2hr3apiutil_1.default.isIpAddressString(req.body.host.outboundip)) {
877
+ const result = {
878
+ result: false,
879
+ message: 'POST request has outbound ip address which is not ignore ip address string: ' + JSON.stringify(req.body.host.outboundip)
880
+ };
881
+ dbglogging_1.default.elog(result.message);
882
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
883
+ return;
884
+ }
885
+ outboundip = k2hr3apiutil_1.default.getSafeString(req.body.host.outboundip);
886
+ }
887
+ //
888
+ // Add ip address ---> Role Token or User Token
889
+ //
890
+ role_result = k2hr3dkc_1.default.addHost(token_info.tenant, name, null, ip, port, cuk, extra, tag, inboundip, outboundip);
891
+ }
892
+ //------------------------------
893
+ // check result
894
+ //------------------------------
895
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
896
+ const mode_type = (is_host_req ? 'addHost' : 'updateRoleHosts');
897
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result)) {
898
+ const result = {
899
+ result: false,
900
+ message: ('Could not get response from ' + mode_type)
901
+ };
902
+ dbglogging_1.default.elog(result.message);
903
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
904
+ }
905
+ else {
906
+ const result = {
907
+ result: false,
908
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : ('Could not get error message in response from ' + mode_type)
909
+ };
910
+ dbglogging_1.default.elog(result.message);
911
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
912
+ }
913
+ return;
914
+ }
915
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
916
+ res.status(201); // 201: Created
917
+ res.send(JSON.stringify(role_result));
918
+ };
919
+ //
920
+ // Sub router function for PUT CREATE HOST
921
+ //
922
+ // Mountpath : '/v1/role'
923
+ // PUT '/v1/role/<role{/...}>' : put role on version 1
924
+ // HEADER : X-Auth-Token => User token or Role token
925
+ // response body : result => true/false
926
+ // message => messages
927
+ //
928
+ // [UserToken] url argument
929
+ // "host": <hostname or ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/{name, ip}/<hostname port cuk>"
930
+ // "port": <port number> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
931
+ // this value is number string(0-), allowed null and '' for this value.
932
+ // if this value is '0', it means any port.
933
+ // "cuk": <container unique key> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
934
+ // this value is string. if this value is undefined/null/empty string, it means any.
935
+ // "extra": <extra string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
936
+ // This value must be encoded by JSON.
937
+ // extra is any string including Control code, allowed null and '' for this value.
938
+ // "tag": <string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
939
+ // This value must be encoded by JSON.
940
+ // tag is any string including Control code, allowed null and '' for this value.
941
+ // "inboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
942
+ // inboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
943
+ // "outboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
944
+ // outboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
945
+ //
946
+ // [RoleToken] url argument
947
+ // "port": <port number> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/ip/<ip port cuk>"
948
+ // this value is number string(0-), allowed null and '' for this value.
949
+ // if this value is '0', it means any port.
950
+ // "cuk": <container unique key> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/name/<hostname port cuk>"
951
+ // this value is string. if this value is undefined/null/empty string, it means any.
952
+ // "extra": <extra string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
953
+ // This value must be encoded by JSON.
954
+ // extra is any string including Control code, allowed null and '' for this value.
955
+ // "tag": <string data> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
956
+ // This value must be encoded by JSON.
957
+ // tag is any string including Control code, allowed null and '' for this value.
958
+ // "inboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
959
+ // inboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
960
+ // "outboundip": <ip address> => key is "yrn:yahoo:<service>::<tenant>:role:<role>/hosts/..."
961
+ // outboundip is set ip address string. if you do not use proxy/gateway/bridge/etc, you do not need to set this key.
962
+ //
963
+ // [NOTE]
964
+ // This API only set(add/create) host into role. Ether hostname or ip address must be specified.
965
+ // If port number is 0, it means any port.
966
+ // If cuk is undefined/null/empty string, it means any.
967
+ // Extra data can include control-code(CR, etc).
968
+ //
969
+ const putRoleHost = (role, req, res, _) => {
970
+ dbglogging_1.default.dlog('CALL:', req.method, req.url);
971
+ res.type('application/json; charset=utf-8');
972
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
973
+ !k2hr3apiutil_1.default.isPlainObject(req.query)) {
974
+ const result = {
975
+ result: false,
976
+ message: 'PUT argument does not have any data'
977
+ };
978
+ dbglogging_1.default.elog(result.message);
979
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
980
+ return;
981
+ }
982
+ //------------------------------
983
+ // check token
984
+ //------------------------------
985
+ const token_result = k2hr3tokens_1.default.checkToken(req, true); // scoped, both token
986
+ if (!token_result.result) {
987
+ const result = {
988
+ result: token_result.result,
989
+ message: k2hr3apiutil_1.default.getSafeString(token_result.message),
990
+ };
991
+ dbglogging_1.default.elog(result.message);
992
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
993
+ return;
994
+ }
995
+ const token_info = token_result.token_info;
996
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
997
+ const result = {
998
+ result: false,
999
+ message: 'specified wrong token or it is not scoped user token'
1000
+ };
1001
+ dbglogging_1.default.elog(result.message);
1002
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1003
+ return;
1004
+ }
1005
+ const is_host_req = !k2hr3apiutil_1.default.isSafeString(req.query.host);
1006
+ const keys = r3keys(token_info.user, token_info.tenant);
1007
+ //------------------------------
1008
+ // check arguments
1009
+ //------------------------------
1010
+ // role name check
1011
+ let name = k2hr3apiutil_1.default.getSafeString(role).toLowerCase();
1012
+ let nameptn = new RegExp('^' + keys.ROLE_TOP_KEY + ':(.*)'); // regex = /^yrn:yahoo:<service>::<tenant>:role:(.*)/
1013
+ const namematchs = name.match(nameptn);
1014
+ if (k2hr3apiutil_1.default.isStringArray(namematchs) && k2hr3apiutil_1.default.isNotEmptyArray(namematchs) && 2 <= namematchs.length) {
1015
+ // name is full yrn, then reset only name.
1016
+ name = namematchs[1];
1017
+ }
1018
+ else {
1019
+ // role name is not full yrn, then check other yrn path
1020
+ nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
1021
+ if (name.match(nameptn)) {
1022
+ const result = {
1023
+ result: false,
1024
+ message: 'POST request url has wrong yrn full path to role'
1025
+ };
1026
+ dbglogging_1.default.elog(result.message);
1027
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1028
+ return;
1029
+ }
1030
+ }
1031
+ // hostname
1032
+ let hostname = null;
1033
+ let ip = null;
1034
+ if (!is_host_req) {
1035
+ if (!k2hr3apiutil_1.default.isSafeString(req.query.host)) {
1036
+ const result = {
1037
+ result: false,
1038
+ message: 'host is not specified.'
1039
+ };
1040
+ dbglogging_1.default.elog(result.message);
1041
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1042
+ return;
1043
+ }
1044
+ const tg_host = k2hr3apiutil_1.default.getSafeString(req.query.host);
1045
+ if (k2hr3apiutil_1.default.isIpAddressString(tg_host)) {
1046
+ ip = tg_host.toLowerCase();
1047
+ }
1048
+ else {
1049
+ hostname = tg_host.toLowerCase();
1050
+ }
1051
+ }
1052
+ else {
1053
+ // get ip address
1054
+ ip = k2hr3apiutil_1.default.getClientIpAddress(req);
1055
+ if (!k2hr3apiutil_1.default.isSafeString(ip)) {
1056
+ const result = {
1057
+ result: false,
1058
+ message: 'Could not get ip address from request.'
1059
+ };
1060
+ dbglogging_1.default.elog(result.message);
1061
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1062
+ return;
1063
+ }
1064
+ }
1065
+ // port
1066
+ let port;
1067
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
1068
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
1069
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
1070
+ const result = {
1071
+ result: false,
1072
+ message: 'PUT request has port which is not number: ' + JSON.stringify(req.query.port)
1073
+ };
1074
+ dbglogging_1.default.elog(result.message);
1075
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1076
+ return;
1077
+ }
1078
+ port = port_tmp;
1079
+ }
1080
+ else {
1081
+ port = 0; // default any
1082
+ }
1083
+ // cuk
1084
+ let cuk = null;
1085
+ if (k2hr3apiutil_1.default.isSafeString(req.query.cuk) && k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
1086
+ cuk = k2hr3apiutil_1.default.getSafeString(req.query.cuk).trim();
1087
+ }
1088
+ // extra
1089
+ let extra = null;
1090
+ if (k2hr3apiutil_1.default.isSafeString(req.query.extra)) {
1091
+ const extra_tmp = k2hr3apiutil_1.default.getSafeString(req.query.extra);
1092
+ if (k2hr3apiutil_1.default.checkSimpleJSON(extra_tmp)) {
1093
+ const extra_parsed_tmp = JSON.parse(extra_tmp); // extra encoded JSON
1094
+ if (!k2hr3apiutil_1.default.isSafeString(extra_parsed_tmp)) {
1095
+ const result = {
1096
+ result: false,
1097
+ message: 'PUT request has extra which is not string: ' + JSON.stringify(req.query.extra)
1098
+ };
1099
+ dbglogging_1.default.elog(result.message);
1100
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1101
+ return;
1102
+ }
1103
+ extra = extra_parsed_tmp;
1104
+ }
1105
+ else {
1106
+ extra = extra_tmp;
1107
+ }
1108
+ }
1109
+ // tag
1110
+ let tag = null;
1111
+ if (k2hr3apiutil_1.default.isSafeString(req.query.tag)) {
1112
+ const tag_tmp = k2hr3apiutil_1.default.getSafeString(req.query.tag);
1113
+ if (k2hr3apiutil_1.default.checkSimpleJSON(tag_tmp)) {
1114
+ const tag_parsed_tmp = JSON.parse(tag_tmp); // tag encoded JSON
1115
+ if (!k2hr3apiutil_1.default.isSafeString(tag_parsed_tmp)) {
1116
+ const result = {
1117
+ result: false,
1118
+ message: 'PUT request has tag which is not string: ' + JSON.stringify(req.body.host.tag)
1119
+ };
1120
+ dbglogging_1.default.elog(result.message);
1121
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1122
+ return;
1123
+ }
1124
+ tag = tag_parsed_tmp;
1125
+ }
1126
+ else {
1127
+ tag = tag_tmp;
1128
+ }
1129
+ }
1130
+ // make base host information
1131
+ const host_info = {
1132
+ hostname: hostname,
1133
+ ip: ip,
1134
+ port: port,
1135
+ cuk: cuk,
1136
+ extra: extra,
1137
+ tag: tag,
1138
+ inboundip: null,
1139
+ outboundip: null
1140
+ };
1141
+ // set inboundip(optional)
1142
+ let inboundip = null;
1143
+ if (k2hr3apiutil_1.default.isSafeString(req.query.inboundip)) {
1144
+ if (!k2hr3apiutil_1.default.isIpAddressString(req.query.inboundip)) {
1145
+ const result = {
1146
+ result: false,
1147
+ message: 'PUT request has inbound ip address which is not ignore ip address string: ' + JSON.stringify(req.query.inboundip)
1148
+ };
1149
+ dbglogging_1.default.elog(result.message);
1150
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1151
+ return;
1152
+ }
1153
+ inboundip = k2hr3apiutil_1.default.getSafeString(req.query.inboundip);
1154
+ host_info.inboundip = inboundip;
1155
+ }
1156
+ // set outboundip(optional)
1157
+ let outboundip = null;
1158
+ if (k2hr3apiutil_1.default.isSafeString(req.query.outboundip)) {
1159
+ if (!k2hr3apiutil_1.default.isIpAddressString(req.query.outboundip)) {
1160
+ const result = {
1161
+ result: false,
1162
+ message: 'PUT request has outbound ip address which is not ignore ip address string: ' + JSON.stringify(req.query.outboundip)
1163
+ };
1164
+ dbglogging_1.default.elog(result.message);
1165
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1166
+ return;
1167
+ }
1168
+ outboundip = k2hr3apiutil_1.default.getSafeString(req.query.outboundip);
1169
+ host_info.outboundip = outboundip;
1170
+ }
1171
+ //------------------------------
1172
+ // add host to role
1173
+ //------------------------------
1174
+ let role_result;
1175
+ if (!is_host_req) {
1176
+ // Add hostname ---> Need User Token
1177
+ if (null === ip) {
1178
+ role_result = k2hr3dkc_1.default.updateRoleHosts(token_info.user, token_info.tenant, name, host_info);
1179
+ }
1180
+ else {
1181
+ role_result = k2hr3dkc_1.default.updateRoleHosts(token_info.user, token_info.tenant, name, null, false, host_info);
1182
+ }
1183
+ }
1184
+ else {
1185
+ // Add ip address ---> Role Token or User Token
1186
+ role_result = k2hr3dkc_1.default.addHost(token_info.tenant, name, null, ip, port, cuk, extra, tag, inboundip, outboundip);
1187
+ }
1188
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
1189
+ const mode_type = (is_host_req ? 'addHost' : 'updateRoleHosts');
1190
+ if (!k2hr3apiutil_1.default.isSafeEntity(role_result)) {
1191
+ const result = {
1192
+ result: false,
1193
+ message: ('Could not get response from ' + mode_type)
1194
+ };
1195
+ dbglogging_1.default.elog(result.message);
1196
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1197
+ }
1198
+ else {
1199
+ const result = {
1200
+ result: false,
1201
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : ('Could not get error message in response from ' + mode_type)
1202
+ };
1203
+ dbglogging_1.default.elog(result.message);
1204
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1205
+ }
1206
+ return;
1207
+ }
1208
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
1209
+ res.status(201); // 201: Created
1210
+ res.send(JSON.stringify(role_result));
1211
+ };
1212
+ //---------------------------------------------------------
1213
+ // Router GET
1214
+ //---------------------------------------------------------
1215
+ //
1216
+ // Mountpath : '/v1/role/<role{/...}>'
1217
+ //
1218
+ // GET '/v1/role/<role{/...}>' : get role on version 1
1219
+ // HEADER : X-Auth-Token => User token
1220
+ // URL arguments : expand => "true"(default) or "false"
1221
+ // response : {
1222
+ // "result": true or false
1223
+ // "message": error message
1224
+ // "role": {
1225
+ // policies: array,
1226
+ // aliases: array <--- only not expand
1227
+ // hosts: { <--- only not expand
1228
+ // 'hostnames': [ hostname array or empty array
1229
+ // <hostname> <port> <cuk> <extra> <tag>, (if any port, port is *)
1230
+ // ...
1231
+ // ],
1232
+ // 'ips': [ ip address array or empty array
1233
+ // <ip address> <port> <cuk> <extra> <tag>,(if any port, port is *)
1234
+ // ...
1235
+ // ]
1236
+ // }
1237
+ // }
1238
+ // }
1239
+ //
1240
+ // GET '/v1/role/token/<role{/...}>' : get role token on version 1
1241
+ // HEADER : X-Auth-Token => User token or Role token
1242
+ // URL arguments : expire => "expire time(unix time value)" or undefined(default 24H)
1243
+ // response : {
1244
+ // "result": true or false
1245
+ // "message": error message
1246
+ // "token": "role token"
1247
+ // "registerpath": "path for registering"
1248
+ // }
1249
+ //
1250
+ // GET '/v1/role/token/list/<role{/...}>': get list of role tokens on version 1
1251
+ // HEADER : X-Auth-Token => User token
1252
+ // URL arguments : expand => "true"(default) or "false"
1253
+ // response : {
1254
+ // result: true/false
1255
+ // message: null or error message string
1256
+ // tokens: {
1257
+ // "token": {
1258
+ // date: create date(UTC ISO 8601)
1259
+ // expire: expire date(UTC ISO 8601)
1260
+ // user: user name if user created this token
1261
+ // hostname: hostname if this token was created by host(name)
1262
+ // ip: ip address if this token was created by ip
1263
+ // port: port number, if specified port when created token
1264
+ // cuk: cuk, if specified cuk when created token
1265
+ // },
1266
+ // ...
1267
+ // }
1268
+ // }
1269
+ // or
1270
+ // {
1271
+ // result: true/false
1272
+ // message: null or error message string
1273
+ // tokens: [
1274
+ // "role token",
1275
+ // ....
1276
+ // ]
1277
+ // }
1278
+ //
1279
+ // This mount point is for creating(update) role or creating(update) host in role.
1280
+ // And get role token by host(ip address) or user(user token), update role token by
1281
+ // role token.
1282
+ //
1283
+ router.get('/', (req, res, next) => {
1284
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
1285
+ if ('GET' !== req.method) {
1286
+ // HEAD request comes here, so it should be routed to head function.
1287
+ next();
1288
+ return;
1289
+ }
1290
+ res.type('application/json; charset=utf-8');
1291
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
1292
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
1293
+ const result = {
1294
+ result: false,
1295
+ message: 'GET request or url is wrong'
1296
+ };
1297
+ dbglogging_1.default.elog(result.message);
1298
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1299
+ return;
1300
+ }
1301
+ //------------------------------
1302
+ // check token for API mode
1303
+ //------------------------------
1304
+ let token_str = null;
1305
+ let token_type = null;
1306
+ let token_info = null;
1307
+ let keys = r3keys();
1308
+ if (k2hr3tokens_1.default.hasAuthTokenHeader(req)) {
1309
+ const token_result = k2hr3tokens_1.default.checkToken(req, true); // scoped, both token
1310
+ if (!token_result.result) {
1311
+ const result = {
1312
+ result: token_result.result,
1313
+ message: k2hr3apiutil_1.default.getSafeString(token_result.message),
1314
+ };
1315
+ dbglogging_1.default.elog(result.message);
1316
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
1317
+ return;
1318
+ }
1319
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_result.token_info)) {
1320
+ const result = {
1321
+ result: false,
1322
+ message: 'specified wrong token or it is not scoped user token'
1323
+ };
1324
+ dbglogging_1.default.elog(result.message);
1325
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1326
+ return;
1327
+ }
1328
+ token_info = token_result.token_info;
1329
+ token_str = token_result.token ?? null;
1330
+ token_type = token_result.token_type ?? null;
1331
+ keys = r3keys(token_info.user, token_info.tenant);
1332
+ }
1333
+ //------------------------------
1334
+ // get role name
1335
+ //------------------------------
1336
+ // check get token type and parse role name
1337
+ let is_get_token = false;
1338
+ let is_get_list = false;
1339
+ let requestptn = new RegExp(keys.MATCH_URI_GET_RTOKEN_LIST); // regex = /^\/v1\/role\/token\/list\/(.*)/
1340
+ let reqmatchs = decodeURI(req.baseUrl).match(requestptn);
1341
+ if (k2hr3apiutil_1.default.isStringArray(reqmatchs) && k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) && 2 <= reqmatchs.length && '' !== k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
1342
+ // get list of tokens
1343
+ is_get_list = true;
1344
+ }
1345
+ else {
1346
+ // recheck
1347
+ requestptn = new RegExp(keys.MATCH_URI_GET_RTOKEN); // regex = /^\/v1\/role\/token\/(.*)/
1348
+ reqmatchs = decodeURI(req.baseUrl).match(requestptn);
1349
+ if (k2hr3apiutil_1.default.isStringArray(reqmatchs) && k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) && 2 <= reqmatchs.length && '' !== k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
1350
+ // get token
1351
+ is_get_token = true;
1352
+ }
1353
+ else {
1354
+ // retry parse role name
1355
+ requestptn = new RegExp(keys.MATCH_URI_GET_ROLE_DATA); // regex = /^\/v1\/role\/(.*)/
1356
+ reqmatchs = decodeURI(req.baseUrl).match(requestptn);
1357
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
1358
+ const result = {
1359
+ result: false,
1360
+ message: 'GET request url does not have role name'
1361
+ };
1362
+ dbglogging_1.default.elog(result.message);
1363
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1364
+ return;
1365
+ }
1366
+ }
1367
+ }
1368
+ // check role name is only name or full yrn path
1369
+ let name = reqmatchs[1].toLowerCase();
1370
+ let nameptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1371
+ const namematchs = name.match(nameptn);
1372
+ if (!k2hr3apiutil_1.default.isStringArray(namematchs) || !k2hr3apiutil_1.default.isNotEmptyArray(namematchs) || namematchs.length < 4) {
1373
+ //
1374
+ // name is not full yrn to role, then check wrong role name
1375
+ //
1376
+ nameptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
1377
+ if (name.match(nameptn)) {
1378
+ const result = {
1379
+ result: false,
1380
+ message: 'GET request query has wrong yrn full path to role'
1381
+ };
1382
+ dbglogging_1.default.elog(result.message);
1383
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1384
+ return;
1385
+ }
1386
+ // role name is not full yrn, we need tenant name
1387
+ if (!k2hr3apiutil_1.default.isSafeString(keys.ROLE_TOP_KEY)) {
1388
+ const result = {
1389
+ result: false,
1390
+ message: 'GET request role name which is not full yrn, and not token. role name must be full yrn, if token is not specified.'
1391
+ };
1392
+ dbglogging_1.default.elog(result.message);
1393
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1394
+ return;
1395
+ }
1396
+ // make full yrn for role name
1397
+ name = keys.ROLE_TOP_KEY + ':' + name;
1398
+ }
1399
+ else {
1400
+ //
1401
+ // name is full yrn to role.
1402
+ // need to check tenant name when token is specified.
1403
+ //
1404
+ if (k2hr3apiutil_1.default.isSafeString(token_type) && (!k2hr3apiutil_1.default.isPlainObject(token_info) || !k2hr3apiutil_1.default.isSafeString(token_info.tenant) || !k2hr3apiutil_1.default.compareCaseString(namematchs[2], token_info.tenant))) {
1405
+ const result = {
1406
+ result: false,
1407
+ message: 'GET request query has wrong tenant yrn full path(tenant=' + namematchs[2] + ') or not specify tenant.'
1408
+ };
1409
+ dbglogging_1.default.elog(result.message);
1410
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1411
+ return;
1412
+ }
1413
+ }
1414
+ // Run
1415
+ if (is_get_token) {
1416
+ //------------------------------
1417
+ // GET ROLE TOKEN
1418
+ //------------------------------
1419
+ // token_info: null(undefined) => not specify token, put token by host ip address
1420
+ // user token => put token by user
1421
+ // role token => update token by role
1422
+ //
1423
+ getRoleToken(name, token_info, token_type, token_str, req, res);
1424
+ }
1425
+ else if (is_get_list) {
1426
+ //------------------------------
1427
+ // GET LIST OF ROLE TOKENS
1428
+ //------------------------------
1429
+ if ('user' === k2hr3apiutil_1.default.getSafeString(token_type)) {
1430
+ getListRoleTokens(name, token_info, req, res);
1431
+ }
1432
+ else {
1433
+ const result = {
1434
+ result: false,
1435
+ message: 'GET request without UserToken for getting list of role(' + name + ') tokens, need User Token.'
1436
+ };
1437
+ dbglogging_1.default.elog(result.message);
1438
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1439
+ return;
1440
+ }
1441
+ }
1442
+ else {
1443
+ //------------------------------
1444
+ // GET ROLE DATA
1445
+ //------------------------------
1446
+ if ('user' === k2hr3apiutil_1.default.getSafeString(token_type) && k2hr3apiutil_1.default.isPlainObject(token_info)) {
1447
+ getRole(name, token_info, req, res);
1448
+ }
1449
+ else {
1450
+ const result = {
1451
+ result: false,
1452
+ message: 'GET request without UserToken for getting role(' + name + '), need User Token.'
1453
+ };
1454
+ dbglogging_1.default.elog(result.message);
1455
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1456
+ return;
1457
+ }
1458
+ }
1459
+ });
1460
+ //
1461
+ // Sub router function for GET ROLE DATA
1462
+ //
1463
+ // Mountpath : '/v1/role/<role{/...}>'
1464
+ //
1465
+ // GET '/v1/role/<role{/...}>' : get role on version 1
1466
+ // HEADER : X-Auth-Token => User token
1467
+ // URL arguments : expand => "true"(default) or "false"
1468
+ // response : {
1469
+ // "result": true or false
1470
+ // "message": error message
1471
+ // "role": {
1472
+ // policies: array,
1473
+ // aliases: array <--- only not expand
1474
+ // hosts: { <--- only not expand
1475
+ // 'hostnames': [ hostname array or empty array
1476
+ // <hostname> <port> <cuk> <extra> <tag>, (if any port, port is *)
1477
+ // ...
1478
+ // ],
1479
+ // 'ips': [ ip address array or empty array
1480
+ // <ip address> <port> <cuk> <extra> <tag>,(if any port, port is *)
1481
+ // ...
1482
+ // ]
1483
+ // }
1484
+ // }
1485
+ // }
1486
+ //
1487
+ // This mount point is for creating(update) role or creating(update) host in role.
1488
+ //
1489
+ const getRole = (role, token_info, req, res) => {
1490
+ dbglogging_1.default.dlog('CALL:', req.method, req.url);
1491
+ res.type('application/json; charset=utf-8');
1492
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
1493
+ !k2hr3apiutil_1.default.isPlainObject(req.query)) {
1494
+ const result = {
1495
+ result: false,
1496
+ message: 'GET request query is wrong'
1497
+ };
1498
+ dbglogging_1.default.elog(result.message);
1499
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1500
+ return;
1501
+ }
1502
+ if (!k2hr3apiutil_1.default.isSafeString(role) ||
1503
+ !k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info) ||
1504
+ !k2hr3apiutil_1.default.isSafeString(token_info.user) ||
1505
+ !k2hr3apiutil_1.default.isSafeString(token_info.tenant)) {
1506
+ const result = {
1507
+ result: false,
1508
+ message: 'GET request is failure by internal error.'
1509
+ };
1510
+ dbglogging_1.default.elog(result.message);
1511
+ k2hr3resutil_1.default.errResponse(req, res, 500, result); // 500: Internal Error
1512
+ return;
1513
+ }
1514
+ //------------------------------
1515
+ // check arguments
1516
+ //------------------------------
1517
+ const keys = r3keys(token_info.user, token_info.tenant);
1518
+ // expand type
1519
+ let is_expand = true;
1520
+ if (k2hr3apiutil_1.default.isSafeString(req.query.expand)) {
1521
+ if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_TRUE, req.query.expand)) {
1522
+ is_expand = true;
1523
+ }
1524
+ else if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_FALSE, req.query.expand)) {
1525
+ is_expand = false;
1526
+ }
1527
+ else {
1528
+ const result = {
1529
+ result: false,
1530
+ message: 'GET expand url argument parameter(' + JSON.stringify(req.query.expand) + ') is wrong, it must be ' + keys.VALUE_TRUE + ' or ' + keys.VALUE_FALSE + '.'
1531
+ };
1532
+ dbglogging_1.default.elog(result.message);
1533
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1534
+ return;
1535
+ }
1536
+ }
1537
+ //------------------------------
1538
+ // get role
1539
+ //------------------------------
1540
+ const role_result = k2hr3dkc_1.default.getRole(role, is_expand);
1541
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
1542
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result)) {
1543
+ const result = {
1544
+ result: false,
1545
+ message: 'Could not get response from getRole'
1546
+ };
1547
+ dbglogging_1.default.elog(result.message);
1548
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1549
+ }
1550
+ else {
1551
+ const result = {
1552
+ result: false,
1553
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : 'Could not get error message in response from getRole'
1554
+ };
1555
+ dbglogging_1.default.elog(result.message);
1556
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1557
+ }
1558
+ return;
1559
+ }
1560
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
1561
+ res.status(200); // 200: OK
1562
+ res.send(JSON.stringify(role_result));
1563
+ };
1564
+ //
1565
+ // Sub router function for GET ROLE TOKEN
1566
+ //
1567
+ // Mountpath : '/v1/role/<role{/...}>'
1568
+ //
1569
+ // GET '/v1/role/token/<role{/...}>' : get role on version 1
1570
+ // HEADER : X-Auth-Token => undefined User token or Role token
1571
+ // URL arguments : expire => "expire time(unix time value)" or undefined(default 24H)
1572
+ // if 0 is specified, no expire.
1573
+ // response : {
1574
+ // "result": true or false
1575
+ // "message": error message
1576
+ // "token": "role token"
1577
+ // "registerpath": "path for registering"
1578
+ // }
1579
+ //
1580
+ // This mount point is for creating(update) role or creating(update) host in role.
1581
+ //
1582
+ const getRoleToken = (role, token_info, token_type, token_str, req, res) => {
1583
+ dbglogging_1.default.dlog('CALL:', req.method, req.url);
1584
+ res.type('application/json; charset=utf-8');
1585
+ if (!k2hr3apiutil_1.default.isSafeString(role)) {
1586
+ const result = {
1587
+ result: false,
1588
+ message: 'GET request is failure by internal error.'
1589
+ };
1590
+ dbglogging_1.default.elog(result.message);
1591
+ k2hr3resutil_1.default.errResponse(req, res, 500, result); // 500: Internal Error
1592
+ return;
1593
+ }
1594
+ //------------------------------
1595
+ // tenant/role name/client ip
1596
+ //------------------------------
1597
+ let tenant;
1598
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info) || !k2hr3apiutil_1.default.isSafeString(token_info.tenant)) {
1599
+ // parse role yrn path to tenant and role name
1600
+ const keys = r3keys();
1601
+ const nameptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1602
+ const namematchs = role.match(nameptn);
1603
+ if (!k2hr3apiutil_1.default.isStringArray(namematchs) || !k2hr3apiutil_1.default.isNotEmptyArray(namematchs) || namematchs.length < 4) {
1604
+ // role is not full yrn
1605
+ const result = {
1606
+ result: false,
1607
+ message: 'GET request is failure by internal error(role yrn path is broken).'
1608
+ };
1609
+ dbglogging_1.default.elog(result.message);
1610
+ k2hr3resutil_1.default.errResponse(req, res, 500, result); // 500: Internal Error
1611
+ return;
1612
+ }
1613
+ tenant = namematchs[2];
1614
+ }
1615
+ else {
1616
+ tenant = token_info.tenant;
1617
+ }
1618
+ // client ip
1619
+ const clientip = k2hr3apiutil_1.default.getClientIpAddress(req);
1620
+ if (!k2hr3apiutil_1.default.isSafeString(clientip)) {
1621
+ const result = {
1622
+ result: false,
1623
+ message: 'GET request does not have ip address for client.'
1624
+ };
1625
+ dbglogging_1.default.elog(result.message);
1626
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1627
+ return;
1628
+ }
1629
+ // date/expire
1630
+ let token_date = '';
1631
+ if (k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info) && k2hr3apiutil_1.default.isSafeString(token_info.date)) {
1632
+ token_date = token_info.date;
1633
+ }
1634
+ let token_expire = '';
1635
+ if (k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info) && k2hr3apiutil_1.default.isSafeString(token_info.expire)) {
1636
+ token_expire = token_info.expire;
1637
+ }
1638
+ //------------------------------
1639
+ // get role token
1640
+ //------------------------------
1641
+ let rtoken_result;
1642
+ if (!k2hr3apiutil_1.default.isSafeString(token_type)) {
1643
+ // no token
1644
+ let port = 0;
1645
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
1646
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
1647
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
1648
+ const result = {
1649
+ result: false,
1650
+ message: 'GET request has port which is not number: ' + JSON.stringify(req.query.port)
1651
+ };
1652
+ dbglogging_1.default.elog(result.message);
1653
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1654
+ return;
1655
+ }
1656
+ port = port_tmp;
1657
+ }
1658
+ // check cuk parameter
1659
+ let cuk = null;
1660
+ if (k2hr3apiutil_1.default.isSafeString(req.query.cuk) && k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
1661
+ cuk = k2hr3apiutil_1.default.getSafeString(req.query.cuk).trim();
1662
+ }
1663
+ rtoken_result = k2hr3tokens_1.default.getRoleTokenByIP(clientip, port, cuk, tenant, role, expire_rtoken); // strict checking port/cuk
1664
+ }
1665
+ else if ('role' === k2hr3apiutil_1.default.getSafeString(token_type)) {
1666
+ // role token
1667
+ if (!k2hr3apiutil_1.default.compareRequestIpAddress(req, (null !== token_info ? k2hr3apiutil_1.default.getSafeString(token_info.ip) : ''))) {
1668
+ // wrong ip address in token
1669
+ const result = {
1670
+ result: false,
1671
+ message: 'GET request ip address and role token are not same.'
1672
+ };
1673
+ dbglogging_1.default.elog(result.message);
1674
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1675
+ return;
1676
+ }
1677
+ // set expire time as same as old token
1678
+ let expire = k2hr3apiutil_1.default.getExpireUnixtimeFromISOStrings(token_date, token_expire);
1679
+ if (0 >= expire) {
1680
+ expire = expire_rtoken;
1681
+ }
1682
+ // using port/cuk from token inforamtion
1683
+ rtoken_result = k2hr3tokens_1.default.getRoleTokenByIP(clientip, (null !== token_info ? token_info.port : null), (null !== token_info ? token_info.cuk : null), tenant, role, expire); // strict checking port/cuk
1684
+ // if succeed to get new role token, remove old token
1685
+ if (k2hr3apiutil_1.default.isPlainObject(rtoken_result) && k2hr3apiutil_1.default.isBoolean(rtoken_result.result) && rtoken_result.result) {
1686
+ const rm_result = k2hr3tokens_1.default.removeRoleTokenByIP(token_str, clientip, (null !== token_info ? token_info.port : null), (null !== token_info ? token_info.cuk : null));
1687
+ if (!k2hr3apiutil_1.default.isPlainObject(rm_result) || !k2hr3apiutil_1.default.isBoolean(rm_result.result) || false === rm_result.result) {
1688
+ dbglogging_1.default.wlog('could not remove old role token(' + token_str + '), but continue...');
1689
+ }
1690
+ }
1691
+ }
1692
+ else if ('user' === k2hr3apiutil_1.default.getSafeString(token_type)) {
1693
+ // user token
1694
+ // expire
1695
+ let expire = expire_rtoken; // expire default is 24H
1696
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.expire)) {
1697
+ const tmpExp = k2hr3apiutil_1.default.cvtToNumber(req.query.expire);
1698
+ if (!k2hr3apiutil_1.default.isSafeNumber(tmpExp)) {
1699
+ const result = {
1700
+ result: false,
1701
+ message: 'GET request has expire which is not number: ' + JSON.stringify(req.query.expire)
1702
+ };
1703
+ dbglogging_1.default.elog(result.message);
1704
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1705
+ return;
1706
+ }
1707
+ if (0 == tmpExp) {
1708
+ expire = expire_reg_rtoken; // If 0 is specified, it means no expire
1709
+ }
1710
+ else {
1711
+ expire = tmpExp;
1712
+ }
1713
+ }
1714
+ rtoken_result = k2hr3tokens_1.default.getRoleTokenByUser((null !== token_info ? token_info.user : null), tenant, role, expire);
1715
+ }
1716
+ else {
1717
+ // broken token
1718
+ const result = {
1719
+ result: false,
1720
+ message: 'GET request is failure by internal error(token data broken).'
1721
+ };
1722
+ dbglogging_1.default.elog(result.message);
1723
+ k2hr3resutil_1.default.errResponse(req, res, 500, result); // 500: Internal Error
1724
+ return;
1725
+ }
1726
+ // check result
1727
+ if (!k2hr3apiutil_1.default.isPlainObject(rtoken_result) || !k2hr3apiutil_1.default.isBoolean(rtoken_result.result) || false === rtoken_result.result) {
1728
+ if (!k2hr3apiutil_1.default.isPlainObject(rtoken_result)) {
1729
+ const result = {
1730
+ result: false,
1731
+ message: 'Could not get role token.'
1732
+ };
1733
+ dbglogging_1.default.elog(result.message);
1734
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1735
+ }
1736
+ else {
1737
+ const result = {
1738
+ result: false,
1739
+ message: k2hr3apiutil_1.default.isString(rtoken_result.message) ? rtoken_result.message : 'Could not get error message in response from get role token'
1740
+ };
1741
+ dbglogging_1.default.elog(result.message);
1742
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1743
+ }
1744
+ return;
1745
+ }
1746
+ // create url parameter(path) for registering role member
1747
+ //
1748
+ const regparamobj = {
1749
+ role: role,
1750
+ token: rtoken_result.token
1751
+ };
1752
+ const udproc = new k2hr3userdata_1.default();
1753
+ const regparamstr = udproc.encryptRoleInfo(regparamobj);
1754
+ if (!k2hr3apiutil_1.default.isSafeString(regparamstr)) {
1755
+ const result = {
1756
+ result: false,
1757
+ message: 'Could not create register url parameter with role token.'
1758
+ };
1759
+ dbglogging_1.default.elog(result.message);
1760
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1761
+ return;
1762
+ }
1763
+ const res_result = {
1764
+ result: rtoken_result.result,
1765
+ message: rtoken_result.message,
1766
+ token: rtoken_result.token,
1767
+ registerpath: regparamstr
1768
+ };
1769
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(res_result.message));
1770
+ res.status(200); // 200: OK
1771
+ res.send(JSON.stringify(res_result));
1772
+ };
1773
+ //
1774
+ // Sub router function for GET LIST OF ROLE TOKENS
1775
+ //
1776
+ // Mountpath : '/v1/role/list/token/<role{/...}>'
1777
+ //
1778
+ // GET '/v1/role/token/list/<role{/...}>' : get list of role tokens on version 1
1779
+ // HEADER : X-Auth-Token => User token
1780
+ // URL arguments : expand => "true"(default) or "false"
1781
+ //
1782
+ // response : {
1783
+ // result: true/false
1784
+ // message: null or error message string
1785
+ // tokens: {
1786
+ // "token": {
1787
+ // date: create date(UTC ISO 8601)
1788
+ // expire: expire date(UTC ISO 8601)
1789
+ // user: user name if user created this token
1790
+ // hostname: hostname if this token was created by host(name)
1791
+ // ip: ip address if this token was created by ip
1792
+ // port: port number, if specified port when created token
1793
+ // cuk: cuk, if specified cuk when created token
1794
+ // registerpath: register path in user data script
1795
+ // },
1796
+ // ...
1797
+ // }
1798
+ // }
1799
+ // or
1800
+ // {
1801
+ // result: true/false
1802
+ // message: null or error message string
1803
+ // tokens: [
1804
+ // "role token",
1805
+ // ....
1806
+ // ]
1807
+ // }
1808
+ //
1809
+ // This mount point is for listing of all role tokens in role.
1810
+ //
1811
+ const getListRoleTokens = (role, token_info, req, res) => {
1812
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
1813
+ res.type('application/json; charset=utf-8');
1814
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
1815
+ !k2hr3apiutil_1.default.isPlainObject(req.query)) {
1816
+ const result = {
1817
+ result: false,
1818
+ message: 'GET request query is wrong'
1819
+ };
1820
+ dbglogging_1.default.elog(result.message);
1821
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1822
+ return;
1823
+ }
1824
+ //------------------------------
1825
+ // check arguments
1826
+ //------------------------------
1827
+ const keys = r3keys();
1828
+ let expand = true;
1829
+ if (k2hr3apiutil_1.default.isSafeString(req.query.expand)) {
1830
+ if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_TRUE, req.query.expand)) {
1831
+ expand = true;
1832
+ }
1833
+ else if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_FALSE, req.query.expand)) {
1834
+ expand = false;
1835
+ }
1836
+ else {
1837
+ const result = {
1838
+ result: false,
1839
+ message: 'GET expand url argument parameter(' + JSON.stringify(req.query.expand) + ') is wrong, it must be ' + keys.VALUE_TRUE + ' or ' + keys.VALUE_FALSE + '.'
1840
+ };
1841
+ dbglogging_1.default.elog(result.message);
1842
+ k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
1843
+ return;
1844
+ }
1845
+ }
1846
+ // check token
1847
+ if (!k2hr3apiutil_1.default.isSafeString(role) ||
1848
+ !k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info) ||
1849
+ !k2hr3apiutil_1.default.isSafeString(token_info.user) ||
1850
+ !k2hr3apiutil_1.default.isSafeString(token_info.tenant)) {
1851
+ const result = {
1852
+ result: false,
1853
+ message: 'GET request is failure by internal error.'
1854
+ };
1855
+ dbglogging_1.default.elog(result.message);
1856
+ k2hr3resutil_1.default.errResponse(req, res, 500, result); // 500: Internal Error
1857
+ return;
1858
+ }
1859
+ //------------------------------
1860
+ // get list of role tokens
1861
+ //------------------------------
1862
+ const role_result = k2hr3tokens_1.default.getListRoleTokens(role, token_info.tenant, expand);
1863
+ // check result
1864
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result) || !k2hr3apiutil_1.default.isBoolean(role_result.result) || false === role_result.result) {
1865
+ if (!k2hr3apiutil_1.default.isPlainObject(role_result)) {
1866
+ const result = {
1867
+ result: false,
1868
+ message: 'Could not get role token list.'
1869
+ };
1870
+ dbglogging_1.default.elog(result.message);
1871
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1872
+ }
1873
+ else {
1874
+ const result = {
1875
+ result: false,
1876
+ message: k2hr3apiutil_1.default.isString(role_result.message) ? role_result.message : 'Could not get error message in response from get role token list'
1877
+ };
1878
+ dbglogging_1.default.elog(result.message);
1879
+ k2hr3resutil_1.default.errResponse(req, res, 404, result); // 404: Not Found
1880
+ }
1881
+ return;
1882
+ }
1883
+ // add register path into each role token elements
1884
+ if (expand && k2hr3tokens_1.default.isResTypeObjRoleTokens(role_result.tokens)) {
1885
+ Object.keys(role_result.tokens).forEach((oneToken) => {
1886
+ const regparamobj = {
1887
+ role: role,
1888
+ token: oneToken
1889
+ };
1890
+ const udproc = new k2hr3userdata_1.default();
1891
+ const regparamstr = udproc.encryptRoleInfo(regparamobj);
1892
+ if (!k2hr3apiutil_1.default.isSafeString(regparamstr) || !k2hr3tokens_1.default.isResTypeObjRoleTokens(role_result.tokens)) { // need to check type again(because scope is not same)
1893
+ dbglogging_1.default.elog('Could not create register url parameter with role token(' + JSON.stringify(oneToken) + '), but continue...');
1894
+ }
1895
+ else {
1896
+ role_result.tokens[oneToken].registerpath = regparamstr;
1897
+ }
1898
+ });
1899
+ }
1900
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(role_result.message));
1901
+ res.status(200); // 200: OK
1902
+ res.send(JSON.stringify(role_result));
1903
+ };
1904
+ //---------------------------------------------------------
1905
+ // Router HEAD
1906
+ //---------------------------------------------------------
1907
+ //
1908
+ // Mountpath : '/v1/role/<role{/...}>'
1909
+ //
1910
+ // HEAD '/v1/role/<role{/...}>' : head role on version 1
1911
+ // HEADER : X-Auth-Token => User token or Role token or undefined
1912
+ // response : nothing
1913
+ // response status code : 204 or 4xx/5xx
1914
+ //
1915
+ // This mount point is for checking role existing or validation for role token/host ip address in role.
1916
+ //
1917
+ router.head('/', (req, res, next) => {
1918
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
1919
+ if ('HEAD' !== req.method) {
1920
+ // If other method request comes here, so it should be routed another function.
1921
+ next();
1922
+ return;
1923
+ }
1924
+ res.type('application/json; charset=utf-8');
1925
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
1926
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
1927
+ dbglogging_1.default.elog('HEAD request or url or query is wrong');
1928
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
1929
+ return;
1930
+ }
1931
+ //------------------------------
1932
+ // check token for API mode
1933
+ //------------------------------
1934
+ let token_str = null;
1935
+ let token_type = null;
1936
+ let token_info = null;
1937
+ let keys = r3keys();
1938
+ if (k2hr3tokens_1.default.hasAuthTokenHeader(req)) {
1939
+ const token_result = k2hr3tokens_1.default.checkToken(req, true); // scoped, both token
1940
+ if (!token_result.result) {
1941
+ dbglogging_1.default.elog(token_result.message);
1942
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status);
1943
+ return;
1944
+ }
1945
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_result.token_info)) {
1946
+ dbglogging_1.default.elog('specified wrong token or it is not scoped user token');
1947
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
1948
+ return;
1949
+ }
1950
+ token_info = token_result.token_info;
1951
+ token_str = token_result.token ?? null;
1952
+ token_type = token_result.token_type ?? null;
1953
+ keys = r3keys(token_info.user, token_info.tenant);
1954
+ }
1955
+ //------------------------------
1956
+ // get role name
1957
+ //------------------------------
1958
+ // check get token type and parse role name
1959
+ const requestptn = new RegExp(keys.MATCH_URI_GET_ROLE_DATA); // regex = /^\/v1\/role\/(.*)/
1960
+ const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
1961
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
1962
+ dbglogging_1.default.elog('HEAD request url does not have role name');
1963
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
1964
+ return;
1965
+ }
1966
+ // check role name is only name or full yrn path and tenant name
1967
+ let tenantname;
1968
+ let rolename;
1969
+ let roleyrn = reqmatchs[1].toLowerCase();
1970
+ let roleyrnptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
1971
+ const roleyrnmatchs = roleyrn.match(roleyrnptn);
1972
+ if (!k2hr3apiutil_1.default.isStringArray(roleyrnmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(roleyrnmatchs) || roleyrnmatchs.length < 4) {
1973
+ //
1974
+ // roleyrn is not full yrn to role, then check wrong role name
1975
+ //
1976
+ roleyrnptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
1977
+ if (roleyrn.match(roleyrnptn)) {
1978
+ dbglogging_1.default.elog('HEAD request query has wrong yrn full path to role');
1979
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
1980
+ return;
1981
+ }
1982
+ // roleyrn is not full yrn, we need tenant name
1983
+ if (!k2hr3apiutil_1.default.isSafeString(keys.ROLE_TOP_KEY)) {
1984
+ dbglogging_1.default.elog('HEAD request role name which is not full yrn, and not token. role name must be full yrn, if token is not specified.');
1985
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
1986
+ return;
1987
+ }
1988
+ // make full yrn for role, and set tenant name/role name.
1989
+ tenantname = (k2hr3apiutil_1.default.isPlainObject(token_info) && k2hr3apiutil_1.default.isSafeString(token_info.tenant)) ? token_info.tenant : null;
1990
+ rolename = roleyrn;
1991
+ roleyrn = keys.ROLE_TOP_KEY + ':' + roleyrn;
1992
+ }
1993
+ else {
1994
+ //
1995
+ // roleyrn is full yrn to role.
1996
+ // need to check tenant name when token is specified.
1997
+ //
1998
+ if (null !== token_type && (!k2hr3apiutil_1.default.isPlainObject(token_info) || !k2hr3apiutil_1.default.isSafeString(token_info.tenant) || !k2hr3apiutil_1.default.compareCaseString(roleyrnmatchs[2], token_info.tenant))) {
1999
+ dbglogging_1.default.elog('HEAD request query has wrong tenant yrn full path(tenant=' + roleyrnmatchs[2] + ') or not specify tenant.');
2000
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2001
+ return;
2002
+ }
2003
+ // set tenant name/role name.
2004
+ tenantname = roleyrnmatchs[2];
2005
+ rolename = roleyrnmatchs[3];
2006
+ }
2007
+ //------------------------------
2008
+ // Run
2009
+ //------------------------------
2010
+ if (!k2hr3apiutil_1.default.isSafeString(token_type)) {
2011
+ // check host ip address in role
2012
+ const clientip = k2hr3apiutil_1.default.getClientIpAddress(req);
2013
+ if (!k2hr3apiutil_1.default.isSafeString(clientip)) {
2014
+ dbglogging_1.default.elog('HEAD request does not have ip address for client.');
2015
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2016
+ return;
2017
+ }
2018
+ // port
2019
+ let tg_port = 0;
2020
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
2021
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
2022
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
2023
+ dbglogging_1.default.elog('HEAD request has port which is not number: ' + JSON.stringify(req.query.port));
2024
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2025
+ return;
2026
+ }
2027
+ tg_port = port_tmp;
2028
+ }
2029
+ // cuk
2030
+ let tg_cuk = null;
2031
+ if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.cuk) && k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
2032
+ tg_cuk = req.query.cuk.trim();
2033
+ }
2034
+ // find host
2035
+ const find_result = k2hr3dkc_1.default.findHost(tenantname, rolename, null, clientip, tg_port, tg_cuk, false); // not strictly checking
2036
+ // result
2037
+ if (!find_result.result) {
2038
+ dbglogging_1.default.elog('HEAD request failure - check host ip(' + clientip + ') address in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2039
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2040
+ return;
2041
+ }
2042
+ else {
2043
+ dbglogging_1.default.dlog('HEAD request succeed - check host ip(' + clientip + ') address in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2044
+ res.status(204); // 204: No Content
2045
+ }
2046
+ }
2047
+ else if ('role' === k2hr3apiutil_1.default.getSafeString(token_type)) {
2048
+ // check role token
2049
+ const check_result = k2hr3tokens_1.default.checkToken(req, true, false); // recheck - scoped, both token
2050
+ // result
2051
+ if (!check_result.result) {
2052
+ dbglogging_1.default.elog('HEAD request failure - check role token(' + JSON.stringify(token_str) + ') : ' + k2hr3apiutil_1.default.getSafeString(check_result.message));
2053
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2054
+ return;
2055
+ }
2056
+ else {
2057
+ dbglogging_1.default.dlog('HEAD request succeed - check role token(' + JSON.stringify(token_str) + ')');
2058
+ res.status(204); // 204: No Content
2059
+ }
2060
+ }
2061
+ else if ('user' === k2hr3apiutil_1.default.getSafeString(token_type)) {
2062
+ // check role exist
2063
+ const role_result = k2hr3dkc_1.default.getRole(roleyrn, true);
2064
+ // result
2065
+ if (!role_result.result) {
2066
+ dbglogging_1.default.elog('HEAD request failure - check role(' + roleyrn + ') exist');
2067
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2068
+ return;
2069
+ }
2070
+ else {
2071
+ dbglogging_1.default.dlog('HEAD request succeed - check role(' + roleyrn + ') exists');
2072
+ res.status(204); // 204: No Content
2073
+ }
2074
+ }
2075
+ else {
2076
+ // broken token
2077
+ dbglogging_1.default.elog('HEAD request is failure by internal error(token data broken).');
2078
+ k2hr3resutil_1.default.errResponse(req, res, 500); // 500: Internal Error
2079
+ return;
2080
+ }
2081
+ res.send();
2082
+ });
2083
+ //---------------------------------------------------------
2084
+ // Router DELETE
2085
+ //---------------------------------------------------------
2086
+ //
2087
+ // Mountpath : '/v1/role/<role{/...}>'
2088
+ //
2089
+ // DELETE '/v1/role/<role{/...}>' : delete role member host on version 1
2090
+ // HEADER : X-Auth-Token => undefined
2091
+ // URL arguments
2092
+ // "port": <port number> : this value is number string(0-), allowed null and '' for this value.
2093
+ // "cuk": <container unique key> : this value is string. if this value is undefined/null/empty string, it means any.
2094
+ // response : nothing
2095
+ // response status code : 204 or 4xx/5xx
2096
+ //
2097
+ // The role's host member removes itself from the role without any token.
2098
+ // Whether a role member is a host is automatically determined by client ip, port, and cuk.
2099
+ //
2100
+ //
2101
+ // DELETE '/v1/role/<role{/...}>' : delete role token on version 1
2102
+ // HEADER : X-Auth-Token => Role token
2103
+ // URL arguments : n/a
2104
+ // response : nothing
2105
+ // response status code : 204 or 4xx/5xx
2106
+ //
2107
+ // Delete the role token by role token.
2108
+ //
2109
+ //
2110
+ // DELETE '/v1/role/<role{/...}>' : delete role member hosts or ip addresses on version 1
2111
+ // HEADER : X-Auth-Token => User Scoped token
2112
+ // URL arguments
2113
+ // "host": <string, JSON string array> : this value is string for one IP address, or string array encoded JSON string
2114
+ // for IP addresses.
2115
+ // "port": <port number> : this value is number string(0-), allowed null and '' for this value.
2116
+ // "cuk": <container unique key> : this value is string. if this value is undefined/null/empty string, it means any.
2117
+ // response : nothing
2118
+ // response status code : 204 or 4xx/5xx
2119
+ //
2120
+ // Delete the role host(ip address)s member.
2121
+ //
2122
+ //
2123
+ // DELETE '/v1/role/<role{/...}>' : delete role member hosts or ip addresses on version 1
2124
+ // HEADER : X-Auth-Token => User Scoped token
2125
+ // URL arguments : n/a
2126
+ // response : nothing
2127
+ // response status code : 204 or 4xx/5xx
2128
+ //
2129
+ // Delete the role.
2130
+ //
2131
+ //---------------------------------------------------------
2132
+ //
2133
+ // Mountpath : '/v1/role/token/<role token>'
2134
+ //
2135
+ // DELETE '/v1/role/token/<role token>' : delete role token on version 1
2136
+ // HEADER : X-Auth-Token => User Scoped token
2137
+ // URL arguments : undefined
2138
+ // response : nothing
2139
+ // response status code : 204 or 4xx/5xx
2140
+ //
2141
+ // Delete the role token by user.
2142
+ //
2143
+ //---------------------------------------------------------
2144
+ //
2145
+ // Mountpath : '/v1/role'
2146
+ //
2147
+ // DELETE '/v1/role' : delete role member by cuk on version 1
2148
+ // URL arguments
2149
+ // "cuk": <container unique key> : this value is string.
2150
+ // Specify the Container Unique Id to be deleted.
2151
+ // Role members associated with this Id will be deleted.
2152
+ // "host": <string, JSON string array> : this value is string for one IP address, or string array encoded JSON string
2153
+ // for IP addresses.
2154
+ // response : nothing
2155
+ // response status code : 204 or 4xx/5xx
2156
+ //
2157
+ //
2158
+ // This mount point is for deleting ip addresses from roles by container unique key which includes ip addresses.
2159
+ // The requester must be role member which is allowed to access this mount point for removing IP address by cuk.
2160
+ //
2161
+ router.delete('/', (req, res, _) => {
2162
+ dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
2163
+ res.type('application/json; charset=utf-8');
2164
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
2165
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
2166
+ dbglogging_1.default.elog('DELETE request or url or query is wrong');
2167
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2168
+ return;
2169
+ }
2170
+ //
2171
+ // Check Path type and branch
2172
+ //
2173
+ const keys = r3keys();
2174
+ let is_delete_token = false;
2175
+ let is_delete_ip = false;
2176
+ const urlpath = decodeURI(req.baseUrl);
2177
+ const requestptn = new RegExp(keys.MATCH_URI_GET_RTOKEN); // regex = /^\/v1\/role\/token\/(.*)/
2178
+ const reqmatchs = urlpath.match(requestptn);
2179
+ if (k2hr3apiutil_1.default.isStringArray(reqmatchs) && k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) && 2 <= reqmatchs.length && '' !== k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
2180
+ // get token
2181
+ is_delete_token = true;
2182
+ }
2183
+ else {
2184
+ // recheck simply
2185
+ if (k2hr3apiutil_1.default.isSafeString(urlpath) && (urlpath == '/v1/role' || urlpath == '/v1/role/')) {
2186
+ // urlpath is /v1/role, this is to delete ip address by cuk
2187
+ is_delete_ip = true;
2188
+ }
2189
+ else {
2190
+ // urlpath is not /v1/role, expected /v1/role/<role>, this is to delete role.
2191
+ }
2192
+ }
2193
+ // Run
2194
+ if (is_delete_token) {
2195
+ // delete role token.
2196
+ if (!rawDeleteRoleToken(req, res)) {
2197
+ dbglogging_1.default.elog('failed to delete role token.');
2198
+ }
2199
+ }
2200
+ else if (is_delete_ip) {
2201
+ // delete ip address by cuk
2202
+ if (!rawDeleteIpsByCuk(req, res)) {
2203
+ dbglogging_1.default.elog('failed to delete ip address by cuk.');
2204
+ }
2205
+ }
2206
+ else {
2207
+ // delete role / role token.
2208
+ if (!rawDeleteRoleByPath(req, res)) {
2209
+ dbglogging_1.default.elog('failed to delete role.');
2210
+ }
2211
+ }
2212
+ res.send();
2213
+ });
2214
+ //
2215
+ // Utility for deleting role / role token
2216
+ //
2217
+ const rawDeleteRoleByPath = (req, res) => {
2218
+ //------------------------------
2219
+ // check token for API mode
2220
+ //------------------------------
2221
+ let token_str = null;
2222
+ let token_type = null;
2223
+ let token_info = null;
2224
+ let keys = r3keys();
2225
+ if (k2hr3tokens_1.default.hasAuthTokenHeader(req)) {
2226
+ const token_result = k2hr3tokens_1.default.checkToken(req, true); // scoped, both token
2227
+ if (!token_result.result) {
2228
+ dbglogging_1.default.elog(token_result.message);
2229
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status);
2230
+ return false;
2231
+ }
2232
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_result.token_info)) {
2233
+ dbglogging_1.default.elog('specified wrong token or it is not scoped user token');
2234
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2235
+ return false;
2236
+ }
2237
+ token_info = token_result.token_info;
2238
+ token_str = token_result.token ?? null;
2239
+ token_type = token_result.token_type ?? null;
2240
+ keys = r3keys(token_info.user, token_info.tenant);
2241
+ }
2242
+ //------------------------------
2243
+ // get role name
2244
+ //------------------------------
2245
+ // check get token type and parse role name
2246
+ const requestptn = new RegExp(keys.MATCH_URI_GET_ROLE_DATA); // regex = /^\/v1\/role\/(.*)/
2247
+ const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
2248
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
2249
+ dbglogging_1.default.elog('DELETE request url does not have role name');
2250
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2251
+ return false;
2252
+ }
2253
+ // check role name is only name or full yrn path and tenant name
2254
+ let tenantname;
2255
+ let rolename;
2256
+ let roleyrn = reqmatchs[1].toLowerCase();
2257
+ let roleyrnptn = new RegExp('^' + keys.MATCH_ANY_TENANT_ROLE); // regex = /^yrn:yahoo:(.*)::(.*):role:(.*)/
2258
+ const roleyrnmatchs = roleyrn.match(roleyrnptn);
2259
+ if (!k2hr3apiutil_1.default.isStringArray(roleyrnmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(roleyrnmatchs) || roleyrnmatchs.length < 4) {
2260
+ //
2261
+ // roleyrn is not full yrn to role, then check wrong role name
2262
+ //
2263
+ roleyrnptn = new RegExp('^' + keys.NO_TENANT_KEY); // regex = /^yrn:yahoo:/
2264
+ if (roleyrn.match(roleyrnptn)) {
2265
+ dbglogging_1.default.elog('DELETE request query has wrong yrn full path to role');
2266
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2267
+ return false;
2268
+ }
2269
+ // roleyrn is not full yrn, we need tenant name
2270
+ if (!k2hr3apiutil_1.default.isSafeString(keys.ROLE_TOP_KEY)) {
2271
+ dbglogging_1.default.elog('DELETE request role name which is not full yrn, and not token. role name must be full yrn, if token is not specified.');
2272
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2273
+ return false;
2274
+ }
2275
+ // make full yrn for role, and set tenant name/role name.
2276
+ tenantname = (k2hr3apiutil_1.default.isPlainObject(token_info) && k2hr3apiutil_1.default.isSafeString(token_info.tenant)) ? token_info.tenant : null;
2277
+ rolename = roleyrn;
2278
+ roleyrn = keys.ROLE_TOP_KEY + ':' + roleyrn;
2279
+ }
2280
+ else {
2281
+ //
2282
+ // roleyrn is full yrn to role.
2283
+ // need to check tenant name when token is specified.
2284
+ //
2285
+ if (null !== token_type && (!k2hr3apiutil_1.default.isPlainObject(token_info) || !k2hr3apiutil_1.default.isSafeString(token_info.tenant) || !k2hr3apiutil_1.default.compareCaseString(roleyrnmatchs[2], token_info.tenant))) {
2286
+ dbglogging_1.default.elog('DELETE request query has wrong tenant yrn full path(tenant=' + roleyrnmatchs[2] + ') or not specify tenant.');
2287
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2288
+ return false;
2289
+ }
2290
+ // set tenant name/role name.
2291
+ tenantname = roleyrnmatchs[2];
2292
+ rolename = roleyrnmatchs[3];
2293
+ }
2294
+ //------------------------------
2295
+ // Run
2296
+ //------------------------------
2297
+ if (!k2hr3apiutil_1.default.isSafeString(token_type)) {
2298
+ // remove host ip address in role
2299
+ const clientip = k2hr3apiutil_1.default.getClientIpAddress(req);
2300
+ if (!k2hr3apiutil_1.default.isSafeString(clientip)) {
2301
+ dbglogging_1.default.elog('DELETE request does not have ip address for client.');
2302
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2303
+ return false;
2304
+ }
2305
+ // check port
2306
+ let port = 0;
2307
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
2308
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
2309
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
2310
+ dbglogging_1.default.elog('DELETE request has port which is not number: ' + JSON.stringify(req.query.port));
2311
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2312
+ return false;
2313
+ }
2314
+ port = port_tmp;
2315
+ }
2316
+ // check cuk parameter
2317
+ let cuk = null;
2318
+ if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.cuk) && k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
2319
+ cuk = k2hr3apiutil_1.default.getSafeString(req.query.cuk).trim();
2320
+ }
2321
+ // remove host(check requester and requester is target)
2322
+ const rm_result = k2hr3dkc_1.default.removeHost(tenantname, rolename, clientip, port, cuk, clientip, port, cuk);
2323
+ // result
2324
+ if (!rm_result.result) {
2325
+ dbglogging_1.default.elog('DELETE request failure - remove host by ip(' + clientip + ':' + String(port) + ') address, cuk(' + JSON.stringify(cuk) + ') in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2326
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2327
+ return false;
2328
+ }
2329
+ else {
2330
+ dbglogging_1.default.dlog('DELETE request succeed - remove host by ip(' + clientip + ':' + String(port) + ') address, cuk(' + JSON.stringify(cuk) + ') in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2331
+ res.status(204); // 204: No Content
2332
+ }
2333
+ }
2334
+ else if ('role' === k2hr3apiutil_1.default.getSafeString(token_type) && k2hr3apiutil_1.default.isPlainObject(token_info)) {
2335
+ // remove role token
2336
+ const clientip = k2hr3apiutil_1.default.getClientIpAddress(req);
2337
+ if (!k2hr3apiutil_1.default.isSafeString(clientip)) {
2338
+ dbglogging_1.default.elog('DELETE request does not have ip address for client.');
2339
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2340
+ return false;
2341
+ }
2342
+ // check full role yrn path in token and path
2343
+ if (!k2hr3apiutil_1.default.isSafeString(token_info.role) || token_info.role != roleyrn) {
2344
+ dbglogging_1.default.elog('DELETE request is something wrong, the role token(' + JSON.stringify(token_info.role) + ') and role path(' + JSON.stringify(roleyrn) + ') do not match.');
2345
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2346
+ return false;
2347
+ }
2348
+ // check for k8s cuk/port
2349
+ let port = 0;
2350
+ let cuk;
2351
+ if (k2hr3apiutil_1.default.isSafeString(token_info.extra) && token_info.extra === keys.VALUE_K8S_V1) {
2352
+ // cuk
2353
+ if (!k2hr3apiutil_1.default.isPlainObject(req.query) || !k2hr3apiutil_1.default.isSafeString(req.query.cuk) || !k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
2354
+ dbglogging_1.default.elog('DELETE request need cuk parameter for deleting role token which is made for k8s.');
2355
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2356
+ return false;
2357
+ }
2358
+ cuk = k2hr3apiutil_1.default.getSafeString(req.query.cuk).trim();
2359
+ if (!k2hr3apiutil_1.default.isSafeString(token_info.cuk) || token_info.cuk != cuk) {
2360
+ dbglogging_1.default.elog('DELETE request cuk(' + JSON.stringify(cuk) + ') parameter is invalid.');
2361
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2362
+ return false;
2363
+ }
2364
+ // port
2365
+ if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
2366
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
2367
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
2368
+ dbglogging_1.default.elog('DELETE request has port which is not number: ' + JSON.stringify(req.query.port));
2369
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2370
+ return false;
2371
+ }
2372
+ port = port_tmp;
2373
+ }
2374
+ if (!k2hr3apiutil_1.default.isSafeNumber(token_info.port) || token_info.port != port) {
2375
+ dbglogging_1.default.elog('DELETE request port(' + JSON.stringify(port) + ') parameter is invalid.');
2376
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2377
+ return false;
2378
+ }
2379
+ }
2380
+ // remove role token
2381
+ const rm_result = k2hr3tokens_1.default.removeRoleTokenByIP(token_str, clientip, token_info.port, token_info.cuk);
2382
+ // result
2383
+ if (!rm_result.result) {
2384
+ dbglogging_1.default.elog('DELETE request failure - remove role token(' + JSON.stringify(token_str) + ')');
2385
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2386
+ return false;
2387
+ }
2388
+ else {
2389
+ dbglogging_1.default.dlog('DELETE request succeed - remove role token(' + JSON.stringify(token_str) + ')');
2390
+ res.status(204); // 204: No Content
2391
+ }
2392
+ }
2393
+ else if ('user' === k2hr3apiutil_1.default.getSafeString(token_type) && k2hr3apiutil_1.default.isPlainObject(token_info)) {
2394
+ if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.host)) {
2395
+ // remove host(hostname or ip address) in role
2396
+ let tg_host;
2397
+ const tmp_str_host = k2hr3apiutil_1.default.getSafeString(req.query.host);
2398
+ const tmp_arr_host = k2hr3apiutil_1.default.parseJSON(req.query.host);
2399
+ if (k2hr3apiutil_1.default.isStringArray(tmp_arr_host) && k2hr3apiutil_1.default.isNotEmptyArray(tmp_arr_host)) {
2400
+ tg_host = tmp_arr_host;
2401
+ }
2402
+ else {
2403
+ tg_host = [tmp_str_host];
2404
+ }
2405
+ // check port
2406
+ let port = 0;
2407
+ if (k2hr3apiutil_1.default.isSafeNumeric(req.query.port)) {
2408
+ const port_tmp = k2hr3apiutil_1.default.cvtToNumber(req.query.port);
2409
+ if (!k2hr3apiutil_1.default.isSafeNumber(port_tmp)) {
2410
+ dbglogging_1.default.elog('GET request has port which is not number: ' + JSON.stringify(req.query.port));
2411
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2412
+ return false;
2413
+ }
2414
+ port = port_tmp;
2415
+ }
2416
+ // check cuk parameter
2417
+ let cuk = null;
2418
+ if (k2hr3apiutil_1.default.isSafeString(req.query.cuk) && k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
2419
+ cuk = k2hr3apiutil_1.default.getSafeString(req.query.cuk).trim();
2420
+ }
2421
+ // remove host(not check requester)
2422
+ const rm_result = k2hr3dkc_1.default.removeHost(tenantname, rolename, tg_host, port, cuk);
2423
+ // result
2424
+ if (!rm_result.result) {
2425
+ dbglogging_1.default.elog('DELETE request failure - remove host(' + k2hr3apiutil_1.default.getSafeString(tg_host) + ':' + String(port) + ') address, cuk(' + JSON.stringify(cuk) + ') in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2426
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2427
+ return false;
2428
+ }
2429
+ else {
2430
+ dbglogging_1.default.dlog('DELETE request succeed - remove host(' + k2hr3apiutil_1.default.getSafeString(tg_host) + ':' + String(port) + ') address, cuk(' + JSON.stringify(cuk) + ') in role(tenant=' + tenantname + ', role=' + rolename + ') host');
2431
+ res.status(204); // 204: No Content
2432
+ }
2433
+ }
2434
+ else {
2435
+ // remove role
2436
+ const rm_result = k2hr3dkc_1.default.removeRole(token_info.user, tenantname, rolename);
2437
+ // result
2438
+ if (!rm_result.result) {
2439
+ dbglogging_1.default.elog('DELETE request failure - remove role(' + rolename + ') exist');
2440
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2441
+ return false;
2442
+ }
2443
+ else {
2444
+ dbglogging_1.default.dlog('DELETE request succeed - remove role(' + rolename + ') exists');
2445
+ res.status(204); // 204: No Content
2446
+ }
2447
+ }
2448
+ }
2449
+ else {
2450
+ // broken token
2451
+ dbglogging_1.default.elog('DELETE request is failure by internal error(token data broken).');
2452
+ k2hr3resutil_1.default.errResponse(req, res, 500); // 500: Internal Error
2453
+ return false;
2454
+ }
2455
+ return true;
2456
+ };
2457
+ //
2458
+ // Utility for deleting ip address by cuk
2459
+ //
2460
+ const rawDeleteIpsByCuk = (req, res) => {
2461
+ const keys = r3keys();
2462
+ const clientip = k2hr3apiutil_1.default.getClientIpAddress(req);
2463
+ if (!k2hr3apiutil_1.default.isSafeString(clientip)) {
2464
+ dbglogging_1.default.elog('DELETE request does not have ip address for client');
2465
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2466
+ return false;
2467
+ }
2468
+ //------------------------------
2469
+ // check arguments
2470
+ //------------------------------
2471
+ if (!k2hr3apiutil_1.default.isPlainObject(req.query)) {
2472
+ dbglogging_1.default.elog('DELETE request has no query parameter');
2473
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2474
+ return false;
2475
+ }
2476
+ let tg_host = [];
2477
+ if (k2hr3apiutil_1.default.isSafeEntity(req.query.host)) {
2478
+ const tmp_str_host = k2hr3apiutil_1.default.getSafeString(req.query.host).trim();
2479
+ const tmp_arr_host = k2hr3apiutil_1.default.parseJSON(tmp_str_host);
2480
+ if (k2hr3apiutil_1.default.isStringArray(tmp_arr_host) && k2hr3apiutil_1.default.isNotEmptyArray(tmp_arr_host)) {
2481
+ tg_host = tmp_arr_host.slice(0, tmp_arr_host.length);
2482
+ }
2483
+ else if (k2hr3apiutil_1.default.isSafeString(tmp_str_host)) {
2484
+ tg_host.push(tmp_str_host);
2485
+ }
2486
+ else {
2487
+ dbglogging_1.default.dlog('DELETE request has no host parameter, it means removing all host in cuk: ' + JSON.stringify(req.query.cuk));
2488
+ }
2489
+ }
2490
+ // cuk parameter
2491
+ if (!k2hr3apiutil_1.default.isSafeString(req.query.cuk) || !k2hr3apiutil_1.default.isSafeString(req.query.cuk.trim())) {
2492
+ dbglogging_1.default.elog('DELETE request has invalid cuk parameter: ' + JSON.stringify(req.query.cuk));
2493
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2494
+ return false;
2495
+ }
2496
+ const tg_cuk = req.query.cuk.trim();
2497
+ const tg_extra = k2hr3dkc_1.default.getExtraFromCuk(tg_cuk);
2498
+ // Check client ip address
2499
+ if (tg_extra == keys.VALUE_K8S_V1) {
2500
+ // for kubernetes
2501
+ // check client ip address is the host itself to be removed
2502
+ //
2503
+ // [NOTE]
2504
+ // if result is true, it means client ip address is cuk's node ip address.
2505
+ // after that, the comparison between the cuk object data contents and the cuk data
2506
+ // in k2hdkc linked to the this ip address is done in removeIpsByCuk() function.
2507
+ //
2508
+ if (!k2hr3dkc_1.default.compareIpAndKubernetesCuk(clientip, tg_cuk)) {
2509
+ // client ip is not as same as cuk's node ip address,
2510
+ // then retry to compare delhost ip in config and it.
2511
+ const adminips = k2hr3dkc_1.default.findRoleHost(null, delhost_role_yrn, null, clientip, 0, null); // not strict checking for admin delhost host
2512
+ if (!k2hr3apiutil_1.default.isArray(adminips)) {
2513
+ dbglogging_1.default.elog('DELETE request from ip address(' + JSON.stringify(clientip) + ') is not role(' + JSON.stringify(delhost_role_yrn) + ') member.');
2514
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2515
+ return false;
2516
+ }
2517
+ }
2518
+ }
2519
+ else if (tg_extra == keys.VALUE_OPENSTACK_V1) {
2520
+ // for openstack
2521
+ // In case of openstack, when deleting without token, it can be deleted only from
2522
+ // the IP address registered as delhost ip in config.
2523
+ //
2524
+ // Check client ip address is in role admin member ip address.
2525
+ const adminips = k2hr3dkc_1.default.findRoleHost(null, delhost_role_yrn, null, clientip, 0, null); // not strict checking for admin delhost host
2526
+ if (!k2hr3apiutil_1.default.isArray(adminips)) {
2527
+ dbglogging_1.default.elog('DELETE request from ip address(' + JSON.stringify(clientip) + ') is not role(' + JSON.stringify(delhost_role_yrn) + ') member.');
2528
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2529
+ return false;
2530
+ }
2531
+ }
2532
+ else {
2533
+ // Currently supports only openstack and kubernetes
2534
+ dbglogging_1.default.elog('DELETE request has unknown extra type in cuk parameter: ' + JSON.stringify(req.query.cuk));
2535
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2536
+ return false;
2537
+ }
2538
+ //------------------------------
2539
+ // Run
2540
+ //------------------------------
2541
+ const resobj = k2hr3dkc_1.default.removeIpsByCuk(tg_cuk, tg_host, true);
2542
+ if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || false === resobj.result) {
2543
+ if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isString(resobj.message)) {
2544
+ dbglogging_1.default.elog('DELETE request failed by ' + resobj.message);
2545
+ }
2546
+ else {
2547
+ dbglogging_1.default.elog('DELETE request failed by unknown reason.');
2548
+ }
2549
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
2550
+ return false;
2551
+ }
2552
+ dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(resobj.message));
2553
+ res.status(204); // 204: No Content
2554
+ return true;
2555
+ };
2556
+ //
2557
+ // Utility for deleting role token
2558
+ //
2559
+ const rawDeleteRoleToken = (req, res) => {
2560
+ if (!k2hr3apiutil_1.default.isPlainObject(req) ||
2561
+ !k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
2562
+ dbglogging_1.default.elog('DELETE request or url or query is wrong');
2563
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2564
+ return false;
2565
+ }
2566
+ //------------------------------
2567
+ // check token
2568
+ //------------------------------
2569
+ if (!k2hr3tokens_1.default.hasAuthTokenHeader(req)) {
2570
+ dbglogging_1.default.elog('DELETE request does not have any auth token.');
2571
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2572
+ return false;
2573
+ }
2574
+ const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
2575
+ if (!token_result.result) {
2576
+ dbglogging_1.default.elog(token_result.message);
2577
+ k2hr3resutil_1.default.errResponse(req, res, token_result.status);
2578
+ return false;
2579
+ }
2580
+ const token_info = token_result.token_info;
2581
+ if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
2582
+ dbglogging_1.default.elog('specified wrong token or it is not scoped user token');
2583
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2584
+ return false;
2585
+ }
2586
+ const keys = r3keys(token_info.user, token_info.tenant);
2587
+ //------------------------------
2588
+ // get role token from uri
2589
+ //------------------------------
2590
+ // check get token type and parse role name
2591
+ const requestptn = new RegExp(keys.MATCH_URI_GET_RTOKEN); // regex = /^\/v1\/role\/token\/(.*)/
2592
+ const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
2593
+ if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
2594
+ dbglogging_1.default.elog('DELETE request url does not have token string nor yrn path');
2595
+ k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
2596
+ return false;
2597
+ }
2598
+ const token_string = k2hr3apiutil_1.default.getSafeString(reqmatchs[1]);
2599
+ //------------------------------
2600
+ // Run
2601
+ //------------------------------
2602
+ if (!k2hr3tokens_1.default.removeRoleTokenByPath(token_string, (k2hr3apiutil_1.default.isSafeString(token_info.tenant) ? token_info.tenant : null))) {
2603
+ dbglogging_1.default.elog('DELETE request failure - remove role token(' + token_string + ')');
2604
+ k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden
2605
+ return false;
2606
+ }
2607
+ else {
2608
+ dbglogging_1.default.dlog('DELETE request succeed - remove role token(' + token_string + ')');
2609
+ res.status(204); // 204: No Content
2610
+ }
2611
+ return true;
2612
+ };
2613
+ //---------------------------------------------------------
2614
+ // Exports
2615
+ //---------------------------------------------------------
2616
+ //
2617
+ // Functions
2618
+ //
2619
+ exports.default = router;
2620
+ /*
2621
+ * Local variables:
2622
+ * tab-width: 4
2623
+ * c-basic-offset: 4
2624
+ * End:
2625
+ * vim600: noexpandtab sw=4 ts=4 fdm=marker
2626
+ * vim<600: noexpandtab sw=4 ts=4
2627
+ */