k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
1,142 lines (1,141 loc) • 48.3 kB
JavaScript
"use strict";
/*
* K2HR3 REST API
*
* Copyright 2023 Yahoo Japan Corporation.
*
* K2HR3 is K2hdkc based Resource and Roles and policy Rules, gathers
* common management information for the cloud.
* K2HR3 can dynamically manage information as "who", "what", "operate".
* These are stored as roles, resources, policies in K2hdkc, and the
* client system can dynamically read and modify these information.
*
* For the full copyright and license information, please view
* the license file that was distributed with this source code.
*
* AUTHOR: Takeshi Nakatani
* CREATE: Mon Sep 3 2023
* REVISION:
*
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const k2hr3apiutil_1 = __importDefault(require("../lib/k2hr3apiutil"));
const k2hr3resutil_1 = __importDefault(require("../lib/k2hr3resutil"));
const k2hr3tokens_1 = __importDefault(require("../lib/k2hr3tokens"));
const k2hr3dkc_1 = __importDefault(require("../lib/k2hr3dkc"));
const dbglogging_1 = __importDefault(require("../lib/dbglogging"));
const express_1 = __importDefault(require("express"));
const k2hr3keys_1 = require("../lib/k2hr3keys");
const r3keys = k2hr3keys_1.getK2hr3Keys;
const router = express_1.default.Router();
//=========================================================
// CAUTION
//---------------------------------------------------------
// This note is common to the TENANT API.
//
// TENANT API requires User Unscoped Token or User Scoped
// Token.
// Note that even if a User Scoped Token is specified, that
// scoped Tenant will be ignored.
// To specify the tenant of each API, use URI path or parameter
// instead of Token.
// Specify the tenant only by the tenant name, not by the YRN
// full path.
//
//=========================================================
// Common Utility function
//=========================================================
//
// Utility for parsing common input parameters
//
// This function parse token(user or role or not have this) from HTTP request(req),
// and tenant name, etc.
//
// return {
// result: true/false
// message: null or error message
// status: status code(default 200)
// parameters: {
// token_type: null or 'user' or 'role'
// token_str: token string(if user token or role token)
// token_info: null or object(returned from checkToken)
// user_name: null or user name(if user token)
// tenant_name: null or tenant name in request uri path
// keys: k2hr3keys object
// }
// }
//
const rawParseBaseParamInRequest = (req) => {
const parameters = {
token_type: null,
token_str: null,
token_info: null,
token_tenant: null,
user_name: null,
tenant_name: null,
keys: r3keys() // temporary
};
const result = {
result: true,
message: null,
status: 200,
parameters: parameters
};
//
// check token for API mode
//
if (k2hr3tokens_1.default.hasAuthTokenHeader(req)) {
const token_result = k2hr3tokens_1.default.checkToken(req, false, true); // (un)scoped, user
if (!token_result.result) {
result.result = token_result.result;
result.message = token_result.message;
result.status = token_result.status;
dbglogging_1.default.elog(result.message);
return result;
}
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_result.token_info)) {
result.result = false;
result.message = 'specified wrong token or it is not scoped user token';
result.status = 400; // 400: Bad Request
dbglogging_1.default.elog(result.message);
return result;
}
result.parameters.token_str = token_result.token ?? null;
result.parameters.token_type = token_result.token_type ?? null;
result.parameters.token_info = token_result.token_info;
result.parameters.user_name = k2hr3apiutil_1.default.getSafeString(result.parameters.token_info.user);
}
//
// get tenant name from uri
//
const requestptn = new RegExp('^/v1/tenant/(.*)'); // regex = /^\/v1\/tenant\/(.*)/
const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
if (!k2hr3apiutil_1.default.isStringArray(reqmatchs) || !k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) || reqmatchs.length < 2 || '' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1])) {
result.parameters.tenant_name = null;
}
else {
// check tenant name
if (0 !== reqmatchs[1].indexOf(result.parameters.keys.VALUE_PREFIX_LOCAL_TENANT)) {
// Not have prefix("local@")
const tmp_tenant_name = result.parameters.keys.VALUE_PREFIX_LOCAL_TENANT + reqmatchs[1];
result.parameters.tenant_name = tmp_tenant_name.toLowerCase();
}
else {
result.parameters.tenant_name = reqmatchs[1].toLowerCase();
}
}
// keys
result.parameters.keys = r3keys(result.parameters.user_name, result.parameters.tenant_name);
return result;
};
//
// Utility for Create/Update tenant for POST/PUT
//
// is_create : true/false
// user_name : add main user name for tenant
// tenant_name : tenant name
// tenant_id : tenant id
// tenant_desc : tenant description
// tenant_display : tenant display name
// tenant_users : other tenant user names
//
// result {
// result: true/false
// message: error message
// rescode: 200/201/4xx/5xx
// }
//
const rawCreateUpdateTenant = (is_create, user_name, tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users) => {
let result_status;
if (is_create) {
//
// Create tenant
//
const resobj = k2hr3dkc_1.default.findTenant(tenant_name);
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isBoolean(resobj.result) && true === resobj.result) {
const result = {
result: false,
message: 'failed to create tenant by already tenant(' + tenant_name + ') existed',
status: 400
};
dbglogging_1.default.elog(result.message);
return result;
}
result_status = 201; // 201: Created
}
else {
//
// Update tenant
//
const resobj = k2hr3dkc_1.default.findTenant(tenant_name, user_name, tenant_id);
if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || false === resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isSafeString(resobj.message)) {
const result = {
result: false,
message: 'failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(resobj.message),
status: 400
};
dbglogging_1.default.elog(result.message);
return result;
}
else {
const result = {
result: false,
message: 'failed to update tenant by unknown reason',
status: 400
};
dbglogging_1.default.elog(result.message);
return result;
}
}
result_status = 200; // 200: OK
}
//
// Create/Update tenant
//
const init_resobj = k2hr3dkc_1.default.initTenant(tenant_name, tenant_id, tenant_desc, tenant_display, user_name, tenant_users);
if (!k2hr3apiutil_1.default.isPlainObject(init_resobj) || !k2hr3apiutil_1.default.isBoolean(init_resobj.result) || false === init_resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(init_resobj) && k2hr3apiutil_1.default.isSafeString(init_resobj.message)) {
const result = {
result: false,
message: 'failed to create tenant by ' + k2hr3apiutil_1.default.getSafeString(init_resobj.message),
status: 400
};
dbglogging_1.default.elog(result.message);
return result;
}
else {
const result = {
result: false,
message: 'failed to create tenant by unknown reason',
status: 400
};
dbglogging_1.default.elog(result.message);
return result;
}
}
const resobj = {
result: true,
message: null,
status: result_status
};
return resobj;
};
//=========================================================
// Router POST
//=========================================================
//
// Mountpath : '/v1/tenant'
//
//---------------------------------------------------------
// [POST] No tenant path
//---------------------------------------------------------
// POST '/v1/tenant' : create tenant version 1
// HEADER : X-Auth-Token = <User token>
// body : {
// "tenant": {
// "name": <tenant> => key is "yrn:yahoo:::<tenant>"
// thix value type must be string.
// "desc": <description> => value for "yrn:yahoo:::<tenant>:desc"
// thix value type must be string.
// "display": <display name> => key is "yrn:yahoo:::<tenant>:display"
// thix value type must be string.
// "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>"
// specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name"
// }
// }
//
// response status code : 201 or 4xx/5xx
// response body : {
// result: true/false
// message: messages
// }
//
// Create a tenant as <K2HR3 cluster LOCAL> tenant.
//
// [NOTE]
// If the <K2HR3 cluster LOCAL> tenant already exists, this repsponses an error.
//
// Tenant names must start with "local@"(if not set it, this prefix adds automatically).
// Specify the user by YRN full path or user name.
// If the user indicated by <User Token> does not exist, it will be added.
// New tenant id is set automatically.
//
//---------------------------------------------------------
// [POST] With tenant path
//---------------------------------------------------------
// POST '/v1/tenant/tenant' : update tenant version 1
// HEADER : X-Auth-Token = <User token>
// body : {
// "tenant": {
// "id": <id> => key is "yrn:yahoo:::<tenant>:id"
// this value type must be string.
// "desc": <description> => value for "yrn:yahoo:::<tenant>:desc"
// thix value type must be string.
// "display": <display name> => key is "yrn:yahoo:::<tenant>:display"
// thix value type must be string.
// "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>"
// specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name"
// }
// }
//
// response status code : 200 or 4xx/5xx
// response body : {
// result: true/false
// message: messages
// }
//
// Update existed tenant as <K2HR3 cluster LOCAL> tenant.
//
// [NOTE]
// If the <K2HR3 cluster LOCAL> tenant does not exist, this repsponses an error.
// Tenant names must start with "local@"(if not set it, this prefix adds automatically for search).
// The <User Token> user must be included in the tenant's user list.
//
// Specify the user by YRN full path or user name.
// If the user indicated by <User Token> does not exist, it will be added.
//
router.post('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl) ||
!k2hr3apiutil_1.default.isPlainObject(req.body) ||
!k2hr3apiutil_1.default.isPlainObject(req.body.tenant)) {
const result = {
result: false,
message: 'POST body does not have tenant data'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check common parameters(token, tenant etc)
//------------------------------
const resobj = rawParseBaseParamInRequest(req);
if (!resobj.result) {
const result = {
result: resobj.result,
message: resobj.message
};
dbglogging_1.default.elog(resobj.message);
k2hr3resutil_1.default.errResponse(req, res, resobj.status, result);
return;
}
const comparam = resobj.parameters;
//------------------------------
// check token type
//------------------------------
if ('user' !== k2hr3apiutil_1.default.getSafeString(comparam.token_type)) {
const result = {
result: false,
message: 'POST request tenant must specify <User Token>'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check arguments
//------------------------------
let is_create;
let tenant_name;
let tenant_id;
let tenant_desc;
let tenant_display;
let tenant_users = [];
if (!k2hr3apiutil_1.default.isSafeString(comparam.tenant_name)) {
//
// Create mode
//
is_create = true;
tenant_name = k2hr3apiutil_1.default.getSafeString(req.body.tenant.name).toLowerCase();
tenant_id = k2hr3apiutil_1.default.getStrUuid4(); // Create new id here.
if (!k2hr3apiutil_1.default.isSafeString(tenant_name)) {
const result = {
result: false,
message: 'POST request tenant body does not have tenant.name string object.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
if (0 !== tenant_name.indexOf(comparam.keys.VALUE_PREFIX_LOCAL_TENANT)) {
// Not have prefix("local@")
tenant_name = comparam.keys.VALUE_PREFIX_LOCAL_TENANT + tenant_name;
}
}
else {
//
// Update mode
//
is_create = false;
tenant_name = comparam.tenant_name;
tenant_id = k2hr3apiutil_1.default.getSafeString(req.body.tenant.id);
if (!k2hr3apiutil_1.default.isSafeString(tenant_id)) {
const result = {
result: false,
message: 'POST request tenant(' + tenant_name + ') body does not have tenant.id string object.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
if (k2hr3apiutil_1.default.isSafeString(req.body.tenant.desc)) {
tenant_desc = k2hr3apiutil_1.default.getSafeString(req.body.tenant.desc);
}
else {
tenant_desc = 'K2HR3 Cluster Local tenant';
}
if (k2hr3apiutil_1.default.isSafeString(req.body.tenant.display)) {
tenant_display = k2hr3apiutil_1.default.getSafeString(req.body.tenant.display);
}
else {
tenant_display = tenant_name;
}
//
// Check users
//
if (k2hr3apiutil_1.default.isSafeString(req.body.tenant.users)) {
tenant_users = [req.body.tenant.users.trim()];
}
else if (k2hr3apiutil_1.default.isStringArray(req.body.tenant.users)) {
tenant_users = k2hr3apiutil_1.default.getSafeArray(req.body.tenant.users);
}
if (is_create) {
// add own user
if (k2hr3apiutil_1.default.isSafeString(comparam.user_name)) {
k2hr3apiutil_1.default.tryAddStringToArray(tenant_users, comparam.user_name);
}
}
else {
if (!k2hr3apiutil_1.default.isStringArray(tenant_users) || !k2hr3apiutil_1.default.isNotEmptyArray(tenant_users)) {
const result = {
result: false,
message: 'POST request tenant(' + JSON.stringify(tenant_name) + ') does not have any user list.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const findobj = k2hr3dkc_1.default.findTenant(tenant_name, comparam.user_name, tenant_id);
if (!k2hr3apiutil_1.default.isPlainObject(findobj) ||
!k2hr3apiutil_1.default.isBoolean(findobj.result) ||
false === findobj.result ||
!k2hr3dkc_1.default.isDkcTypeTenantInfo(findobj.tenant) ||
!k2hr3apiutil_1.default.isSafeString(findobj.tenant.name) ||
!k2hr3apiutil_1.default.isStringArray(findobj.tenant.users) ||
!k2hr3apiutil_1.default.findStringInArray(findobj.tenant.users, comparam.user_name)) {
const result = {
result: false,
message: 'POST request tenant(' + tenant_name + ') does not allow user(' + comparam.user_name + ').'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
if (k2hr3apiutil_1.default.isArray(tenant_users)) {
tenant_users.sort();
}
//------------------------------
// Processing
//------------------------------
const create_result = rawCreateUpdateTenant(is_create, (comparam.user_name ?? ''), tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users);
if (!k2hr3apiutil_1.default.isPlainObject(create_result) || !k2hr3apiutil_1.default.isBoolean(create_result.result) || !k2hr3apiutil_1.default.isSafeNumber(create_result.status) || false === create_result.result) {
if (k2hr3apiutil_1.default.isPlainObject(create_result) && k2hr3apiutil_1.default.isSafeString(create_result.message)) {
const result = {
result: false,
message: 'POST request failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(create_result.message)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, (create_result?.status ?? 500), result);
}
else {
const result = {
result: false,
message: 'POST request failed to update tenant by unknown reason'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, (k2hr3apiutil_1.default.isSafeNumber(create_result.status) ? create_result.status : 500), result);
}
return;
}
dbglogging_1.default.dlog('succeed : create/update tenant(' + JSON.stringify(tenant_name) + ') by user(' + JSON.stringify(comparam.user_name) + ')');
const success_result = {
result: true,
message: null
};
res.status(create_result.status ?? 200); // 200 or 201
res.send(JSON.stringify(success_result));
});
//=========================================================
// Router PUT
//=========================================================
//
// Mountpath : '/v1/tenant'
//
//---------------------------------------------------------
// [PUT] No tenant path
//---------------------------------------------------------
// PUT '/v1/tenant' : create tenant version 1
// HEADER : X-Auth-Token = <User token>
// url argument :
// "name": <tenant> => key is "yrn:yahoo:::<tenant>"
// <tenant> must include the prefix "R3CLUSTERLOCAL-".
// "desc": <description> => value for "yrn:yahoo:::<tenant>:desc"
// thix value type must be string.
// "display": <display name> => key is "yrn:yahoo:::<tenant>:display"
// thix value type must be string.
// "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>"
// specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name"
//
// response status code : 201 or 4xx/5xx
// response body : {
// result: true/false
// message: messages
// }
//
// Create a tenant as <K2HR3 cluster LOCAL> tenant.
//
// [NOTE]
// If the <K2HR3 cluster LOCAL> tenant already exists, this repsponses an error.
//
// Tenant names must start with "R3CLUSTERLOCAL-".
// Specify the user by YRN full path or user name.
// If the user indicated by <User Token> does not exist, it will be added.
// New tenant id("R3CLUSTERLOCAL-xxxxxx") is set automatically.
//
//---------------------------------------------------------
// [PUT] With tenant path
//---------------------------------------------------------
// PUT '/v1/tenant/tenant' : update tenant version 1
// HEADER : X-Auth-Token = <User token>
// url argument :
// "id": <id> => key is "yrn:yahoo:::<tenant>:id"
// this value type must be string.
// "desc": <description> => value for "yrn:yahoo:::<tenant>:desc"
// thix value type must be string.
// "display": <display name> => key is "yrn:yahoo:::<tenant>:display"
// thix value type must be string.
// "users": <user> or [user, ...] => key is "yrn:yahoo::::user:<user>"
// specify adding user array which is yrn path as "yrn:yahoo::::user:<user>" or "user name"
//
// response status code : 200 or 4xx/5xx
// response body : {
// result: true/false
// message: messages
// }
//
// Update existed tenant as <K2HR3 cluster LOCAL> tenant.
//
// [NOTE]
// If the <K2HR3 cluster LOCAL> tenant does not exist, this repsponses an error.
// The <User Token> user must be included in the tenant's user list.
//
// Specify the user by YRN full path or user name.
// If the user indicated by <User Token> does not exist, it will be added.
//
router.put('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl) ||
!k2hr3apiutil_1.default.isPlainObject(req.query)) {
const result = {
result: false,
message: 'PUT request is something wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check common parameters(token, tenant etc)
//------------------------------
const resobj = rawParseBaseParamInRequest(req);
if (!resobj.result) {
const result = {
result: resobj.result,
message: resobj.message
};
dbglogging_1.default.elog(resobj.message);
k2hr3resutil_1.default.errResponse(req, res, resobj.status, result);
return;
}
const comparam = resobj.parameters;
//------------------------------
// check token type
//------------------------------
if ('user' !== k2hr3apiutil_1.default.getSafeString(comparam.token_type)) {
const result = {
result: false,
message: 'PUT request tenant must specify <User Token>'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check arguments
//------------------------------
let is_create;
let tenant_name;
let tenant_id;
let tenant_desc;
let tenant_display;
let tenant_users = [];
if (!k2hr3apiutil_1.default.isSafeString(comparam.tenant_name)) {
//
// Create mode
//
is_create = true;
tenant_name = k2hr3apiutil_1.default.getSafeString(req.query.name).toLowerCase();
tenant_id = k2hr3apiutil_1.default.getStrUuid4(); // Create new id here.
if (!k2hr3apiutil_1.default.isSafeString(tenant_name)) {
const result = {
result: false,
message: 'PUT request tenant body does not have tenant.name string object.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
if (0 !== tenant_name.indexOf(comparam.keys.VALUE_PREFIX_LOCAL_TENANT)) {
// Not have prefix("local@")
tenant_name = comparam.keys.VALUE_PREFIX_LOCAL_TENANT + tenant_name;
}
}
else {
//
// Update mode
//
is_create = false;
tenant_name = comparam.tenant_name;
tenant_id = k2hr3apiutil_1.default.getSafeString(req.query.id);
if (!k2hr3apiutil_1.default.isSafeString(tenant_id)) {
const result = {
result: false,
message: 'PUT request tenant(' + tenant_name + ') body does not have tenant.id string object.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
if (k2hr3apiutil_1.default.isSafeString(req.query.desc)) {
tenant_desc = k2hr3apiutil_1.default.getSafeString(req.query.desc);
}
else {
tenant_desc = 'K2HR3 Cluster Local tenant';
}
if (k2hr3apiutil_1.default.isSafeString(req.query.display)) {
tenant_display = k2hr3apiutil_1.default.getSafeString(req.query.display);
}
else {
tenant_display = tenant_name;
}
//
// Check users
//
if (k2hr3apiutil_1.default.checkSimpleJSON(req.query.users)) {
const tenant_users_tmp = k2hr3apiutil_1.default.parseJSON(req.query.users);
if (k2hr3apiutil_1.default.isSafeString(tenant_users_tmp)) {
tenant_users = [tenant_users_tmp];
}
else if (k2hr3apiutil_1.default.isStringArray(tenant_users_tmp)) {
tenant_users = k2hr3apiutil_1.default.getSafeArray(tenant_users_tmp);
}
}
else if (k2hr3apiutil_1.default.isSafeString(req.query.users)) {
tenant_users = [req.query.users];
}
else if (k2hr3apiutil_1.default.isStringArray(req.query.users)) {
tenant_users = k2hr3apiutil_1.default.getSafeArray(req.query.users);
}
if (is_create) {
// add own user
if (k2hr3apiutil_1.default.isSafeString(comparam.user_name)) {
k2hr3apiutil_1.default.tryAddStringToArray(tenant_users, comparam.user_name);
}
}
else {
// check user in current tenant users
if (!k2hr3apiutil_1.default.isStringArray(tenant_users) || !k2hr3apiutil_1.default.isNotEmptyArray(tenant_users)) {
const result = {
result: false,
message: 'PUT request tenant(' + JSON.stringify(tenant_name) + ') does not have any user list.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const findobj = k2hr3dkc_1.default.findTenant(tenant_name, comparam.user_name, tenant_id);
if (!k2hr3apiutil_1.default.isPlainObject(findobj) ||
!k2hr3apiutil_1.default.isBoolean(findobj.result) ||
false === findobj.result ||
!k2hr3dkc_1.default.isDkcTypeTenantInfo(findobj.tenant) ||
!k2hr3apiutil_1.default.isSafeString(findobj.tenant.name) ||
!k2hr3apiutil_1.default.isStringArray(findobj.tenant.users) ||
!k2hr3apiutil_1.default.findStringInArray(findobj.tenant.users, comparam.user_name)) {
const result = {
result: false,
message: 'PUT request tenant(' + tenant_name + ') does not allow user(' + comparam.user_name + ').'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
if (k2hr3apiutil_1.default.isArray(tenant_users)) {
tenant_users.sort();
}
//------------------------------
// Processing
//------------------------------
const create_result = rawCreateUpdateTenant(is_create, (comparam.user_name ?? ''), tenant_name, tenant_id, tenant_desc, tenant_display, tenant_users);
if (!k2hr3apiutil_1.default.isPlainObject(create_result) || !k2hr3apiutil_1.default.isBoolean(create_result.result) || !k2hr3apiutil_1.default.isSafeNumber(create_result.status) || false === create_result.result) {
if (k2hr3apiutil_1.default.isPlainObject(create_result) && k2hr3apiutil_1.default.isSafeString(create_result.message)) {
const result = {
result: false,
message: 'PUT request failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(create_result.message)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, (create_result?.status ?? 500), result);
}
else {
const result = {
result: false,
message: 'PUT request failed to update tenant by unknown reason'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, (k2hr3apiutil_1.default.isSafeNumber(create_result.status) ? create_result.status : 500), result);
}
return;
}
dbglogging_1.default.dlog('succeed : create/update tenant(' + JSON.stringify(tenant_name) + ') by user(' + JSON.stringify(comparam.user_name) + ')');
const success_result = {
result: true,
message: null
};
res.status(create_result.status ?? 200); // 200 or 201
res.send(JSON.stringify(success_result));
});
//=========================================================
// Router GET
//=========================================================
//
// Mountpath : '/v1/tenant{/tenant}'
//
//---------------------------------------------------------
// [GET] No tenant path
//---------------------------------------------------------
// GET '/v1/tenant' : get tenant list version 1
// HEADER : X-Auth-Token = <User token>
// URL arguments : expand = "true"(default) or "false"
// response status code : 200 or 4xx/5xx
// response : nothing
// response body : {
// result: true/false,
// message: null or error message string
// tenants: [
// {
// name: "string",
// id: "string",
// desc: "string",
// display: "string",
// user: array[users...]
// },
// ...
// ]
// }
// or
// {
// result: true/false,
// message: null or error message string
// tenants: [
// "tenant",
// ...
// ]
// }
//
// This mount point retrieves a list of tenants and information about each.
//
//---------------------------------------------------------
// [GET] With tenant path
//---------------------------------------------------------
// GET '/v1/tenant/<tenant>' : get tenant information on version 1
// HEADER : X-Auth-Token = <User token>
// URL arguments : nothing
// response status code : 200 or 4xx/5xx
// response : nothing
// response body : {
// result: true/false,
// message: null or error message string
// tenant: {
// name: "string",
// id: "string",
// desc: "string",
// display: "string",
// user: array[users...]
// }
// }
//
router.get('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
if ('GET' !== req.method) {
// HEAD request comes here, so it should be routed to head function.
next();
return;
}
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
const result = {
result: false,
message: 'GET request is something wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check common parameters(token, tenant etc)
//------------------------------
const resobj = rawParseBaseParamInRequest(req);
if (!resobj.result) {
const result = {
result: resobj.result,
message: resobj.message
};
dbglogging_1.default.elog(resobj.message);
k2hr3resutil_1.default.errResponse(req, res, resobj.status, result);
return;
}
const comparam = resobj.parameters;
//------------------------------
// check token type
//------------------------------
if ('user' !== k2hr3apiutil_1.default.getSafeString(comparam.token_type)) {
const result = {
result: false,
message: 'GET request tenant must specify <User Token>'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// Processing
//------------------------------
let jsonres;
if (!k2hr3apiutil_1.default.isSafeString(comparam.tenant_name)) {
//
// List mode
//
const keys = r3keys(comparam.user_name);
//
// Check expand type
//
let is_expand = true;
if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.expand)) {
if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_TRUE, req.query.expand)) {
is_expand = true;
}
else if (k2hr3apiutil_1.default.compareCaseString(keys.VALUE_FALSE, req.query.expand)) {
is_expand = false;
}
else {
const result = {
result: false,
message: 'GET expand url argument parameter(' + JSON.stringify(req.query.expand) + ') is wrong, it must be ' + keys.VALUE_TRUE + ' or ' + keys.VALUE_FALSE + '.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
//
// Get list
//
const resobj = k2hr3dkc_1.default.listLocalTenant(comparam.user_name, is_expand);
if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || (!is_expand && !k2hr3apiutil_1.default.isStringArray(resobj.tenants)) || (is_expand && !k2hr3dkc_1.default.isDkcTypeTenantInfoList(resobj.tenants)) || false === resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isSafeString(resobj.message)) {
const result = {
result: false,
message: 'GET request failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(resobj.message)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: false,
message: 'GET request failed to update tenant by unknown reason'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
const result = {
result: true,
message: null,
tenants: resobj.tenants
};
jsonres = JSON.stringify(result);
}
else {
//
// One tenant
//
const resobj = k2hr3dkc_1.default.findTenant(comparam.tenant_name);
if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || !k2hr3dkc_1.default.isDkcTypeTenantInfo(resobj.tenant) || false === resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isSafeString(resobj.message)) {
const result = {
result: false,
message: 'GET request failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(resobj.message)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: false,
message: 'GET request failed to update tenant by unknown reason'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
const result = {
result: true,
message: null,
tenant: resobj.tenant
};
jsonres = JSON.stringify(result);
}
dbglogging_1.default.dlog('succeed : get tenant(s) by user(' + JSON.stringify(comparam.user_name) + ')');
res.status(200); // 200: OK
res.send(jsonres);
});
//=========================================================
// Router HEAD
//=========================================================
//
// Mountpath : '/v1/tenant/tenant'
//
// HEAD '/v1/tenant/<tenant>' : head tenant on version 1
// HEADER : X-Auth-Token = <User token>
// response status code : 204 or 4xx/5xx
// response body : nothing
//
// This mount point is an API for checking the existence of a tenant.
// If the tenant is given, this returns a 204 if that tenant exists and is allowed to be seen.
// If no tenant is given, returns 204 if at least one target tenant exists.
//
router.head('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
if ('HEAD' !== req.method) {
// If other method request comes here, so it should be routed another function.
next();
return;
}
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
dbglogging_1.default.elog('HEAD request is something wrong');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check common parameters(token, tenant etc)
//------------------------------
const resobj = rawParseBaseParamInRequest(req);
if (!resobj.result) {
dbglogging_1.default.elog(resobj.message);
k2hr3resutil_1.default.errResponse(req, res, resobj.status);
return;
}
const comparam = resobj.parameters;
//------------------------------
// check token type
//------------------------------
if ('user' !== k2hr3apiutil_1.default.getSafeString(comparam.token_type)) {
dbglogging_1.default.elog('HEAD request tenant must specify <User Token>');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Check uri paths(tenant name)
//------------------------------
if (!k2hr3apiutil_1.default.isSafeString(comparam.tenant_name)) {
dbglogging_1.default.elog('HEAD request tenant must specify <tenant> path');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Processing
//------------------------------
const find_result = k2hr3dkc_1.default.findTenant(comparam.tenant_name);
if (!k2hr3apiutil_1.default.isPlainObject(find_result) || !k2hr3apiutil_1.default.isBoolean(find_result.result) || !k2hr3dkc_1.default.isDkcTypeTenantInfo(find_result.tenant) || false === find_result.result) {
if (k2hr3apiutil_1.default.isPlainObject(find_result) && k2hr3apiutil_1.default.isSafeString(find_result.message)) {
dbglogging_1.default.elog('HEAD request failed to update tenant by ' + k2hr3apiutil_1.default.getSafeString(find_result.message));
}
else {
dbglogging_1.default.elog('HEAD request failed to update tenant by unknown reason');
}
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
dbglogging_1.default.dlog('HEAD request succeed - check tenant(' + JSON.stringify(comparam.tenant_name) + ') exists');
res.status(204); // 204: No Content
res.send();
});
//=========================================================
// Router DELETE
//=========================================================
//
// Mountpath : '/v1/tenant'
//
//---------------------------------------------------------
// [DELETE] No tenant path
//---------------------------------------------------------
// DELETE '/v1/tenant' : delete tenant version 1
// HEADER : X-Auth-Token = <User token>
// url argument : "tenant" = <tenant name>
// url argument : "id" = <id> => key is "yrn:yahoo:::<tenant>:id"
// response status code : 204 or 4xx/5xx
// response body : nothing
//
// This mount point deletes the specified <K2HR3 cluster LOCAL> tenant.
//
//---------------------------------------------------------
// [DELETE] With tenant path
//---------------------------------------------------------
// DELETE '/v1/tenant/tenant' : delete tenant version 1
// HEADER : X-Auth-Token = <User token>
// url argument : "id" = <id> => key is "yrn:yahoo:::<tenant>:id"
// response status code : 204 or 4xx/5xx
// response body : nothing
//
// This mount point deletes the specified <K2HR3 cluster LOCAL> tenant.
//
// [NOTE]
// Only users registered in the tenant to be deleted can delete this tenant.
//
router.delete('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
dbglogging_1.default.elog('DELETE request or url or query is wrong');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check common parameters(token, tenant etc)
//------------------------------
const resobj = rawParseBaseParamInRequest(req);
if (!resobj.result) {
dbglogging_1.default.elog(resobj.message);
k2hr3resutil_1.default.errResponse(req, res, resobj.status);
return;
}
const comparam = resobj.parameters;
//------------------------------
// check token type
//------------------------------
if ('user' !== k2hr3apiutil_1.default.getSafeString(comparam.token_type)) {
dbglogging_1.default.elog('DELETE request tenant must specify <User Token>');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Check uri paths
//------------------------------
if (!k2hr3apiutil_1.default.isSafeString(comparam.tenant_name)) {
//------------------------------
// Check argments(tenant)
//------------------------------
const tenant_name = k2hr3apiutil_1.default.isPlainObject(req.query) ? k2hr3apiutil_1.default.getSafeString(req.query.tenant) : '';
if (!k2hr3apiutil_1.default.isSafeString(tenant_name)) {
dbglogging_1.default.elog('DELETE request tenant must specify in argument');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Check argments(id)
//------------------------------
const tenant_id = k2hr3apiutil_1.default.isPlainObject(req.query) ? k2hr3apiutil_1.default.getSafeString(req.query.id) : '';
if (!k2hr3apiutil_1.default.isSafeString(tenant_id)) {
dbglogging_1.default.elog('DELETE request id must specify in argument');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Processing
//------------------------------
const resobj = k2hr3dkc_1.default.removeLocalTenant(tenant_name, comparam.user_name, tenant_id);
if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || false === resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isSafeString(resobj.message)) {
dbglogging_1.default.elog('DELETE request failed to remove user from tenant by ' + k2hr3apiutil_1.default.getSafeString(resobj.message));
}
else {
dbglogging_1.default.elog('DELETE request failed to remove user from tenant by unknown reason');
}
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
dbglogging_1.default.dlog('DELETE request succeed - remove tenant');
}
else {
//------------------------------
// Check argments(id)
//------------------------------
const tenant_id = k2hr3apiutil_1.default.isPlainObject(req.query) ? k2hr3apiutil_1.default.getSafeString(req.query.id) : '';
if (!k2hr3apiutil_1.default.isSafeString(tenant_id)) {
dbglogging_1.default.elog('DELETE request id must specify in argument');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// Processing
//------------------------------
const resobj = k2hr3dkc_1.default.removeUserFromLocalTenant(comparam.tenant_name, comparam.user_name, tenant_id);
if (!k2hr3apiutil_1.default.isPlainObject(resobj) || !k2hr3apiutil_1.default.isBoolean(resobj.result) || false === resobj.result) {
if (k2hr3apiutil_1.default.isPlainObject(resobj) && k2hr3apiutil_1.default.isSafeString(resobj.message)) {
dbglogging_1.default.elog('DELETE request failed to remove user from tenant by ' + k2hr3apiutil_1.default.getSafeString(resobj.message));
}
else {
dbglogging_1.default.elog('DELETE request failed to remove user from tenant by unknown reason');
}
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
dbglogging_1.default.dlog('DELETE request succeed - remove user from tenant');
}
res.status(204); // 204: No Content
res.send();
});
//---------------------------------------------------------
// Exports
//---------------------------------------------------------
//
// Functions
//
exports.default = router;
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noexpandtab sw=4 ts=4 fdm=marker
* vim<600: noexpandtab sw=4 ts=4
*/