k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
909 lines (908 loc) • 38.9 kB
JavaScript
"use strict";
/*
* K2HR3 REST API
*
* Copyright 2017 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: Wed Nov 1 2017
* 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();
//
// Common utility function
//
// Convert tenant yrn path to tenant name
//
const rawGetTenantNameFromYrn = (tenant) => {
if (!k2hr3apiutil_1.default.isSafeString(tenant)) {
return null;
}
const keys = r3keys();
const yrnptn = new RegExp('^' + keys.MATCH_ANY_TENANT_MAIN); // regex = /^yrn:yahoo:(.*)::(.*)/
const matches = tenant.match(yrnptn);
if (!k2hr3apiutil_1.default.isStringArray(matches) || !k2hr3apiutil_1.default.isNotEmptyArray(matches) || matches.length < 3) {
// not match tenant yrn, then return original tenant
return tenant;
}
tenant = matches[2]; // tenant name
if (!k2hr3apiutil_1.default.isSafeString(tenant)) {
return null;
}
return tenant;
};
//
// Common utility function
//
// Create or update service
//
// Result null(succeed) or error message(failed)
//
const rawUpdateService = (owner, servicename, verify, tenants, is_clear, is_create) => {
if (!k2hr3apiutil_1.default.isSafeString(owner) || !k2hr3apiutil_1.default.isSafeString(servicename)) {
const error = new Error('Internal error: rawUpdateService');
return error;
}
if (!k2hr3apiutil_1.default.isValTypeAll(verify)) {
verify = null;
}
if (!k2hr3apiutil_1.default.isStringArray(tenants) || !k2hr3apiutil_1.default.isNotEmptyArray(tenants)) {
tenants = null;
}
let processed = false;
//------------------------------
// set(update) all field / update verify field
//------------------------------
if (is_create || null !== verify) {
//
// [NOTE]
// initService() === updateServiceVerify()
//
const ini_result = k2hr3dkc_1.default.initService(owner, servicename, verify);
if (!k2hr3apiutil_1.default.isPlainObject(ini_result) || !k2hr3apiutil_1.default.isBoolean(ini_result.result) || false === ini_result.result) {
let error = null;
if (!k2hr3apiutil_1.default.isPlainObject(ini_result)) {
error = new Error('Could not get response from initService');
}
else {
if (!k2hr3apiutil_1.default.isString(ini_result.message)) {
error = new Error('Could not get error message in response from initService');
}
}
return error;
}
processed = true;
}
//------------------------------
// add tenants
//------------------------------
const allowtenants = (k2hr3apiutil_1.default.isStringArray(tenants) && k2hr3apiutil_1.default.isNotEmptyArray(tenants)) ? tenants : [];
const denytenants = [];
if (is_clear || k2hr3apiutil_1.default.isNotEmptyArray(allowtenants)) {
// get all service data
const allres = k2hr3dkc_1.default.getService(owner, servicename);
if (!k2hr3apiutil_1.default.isPlainObject(allres) || !k2hr3apiutil_1.default.isBoolean(allres.result) || false === allres.result) {
let error;
if (!k2hr3apiutil_1.default.isPlainObject(allres)) {
error = new Error('Could not get response from getService');
}
else {
if (!k2hr3apiutil_1.default.isString(allres.message)) {
error = new Error('Could not get error message in response from getService');
}
else {
error = new Error(k2hr3apiutil_1.default.getSafeString(allres.message));
}
}
return error;
}
// check
if (allres.service && k2hr3dkc_1.default.isDkcTypeServiceRawValue(allres.service) && k2hr3apiutil_1.default.isStringArray(allres.service.tenant)) {
const keys = r3keys(null, owner, null);
for (let cnt = 0; cnt < allres.service.tenant.length; ++cnt) {
let found = false;
for (let cnt2 = 0; cnt2 < allowtenants.length; ++cnt2) {
if (k2hr3apiutil_1.default.compareCaseString(allres.service.tenant[cnt], allowtenants[cnt2])) {
// cut already existing tenant
allowtenants.splice(cnt2, 1);
found = true;
break;
}
}
if (!found) {
// does not remove owner tenant
if (!k2hr3apiutil_1.default.compareCaseString(allres.service.tenant[cnt], keys.MASTER_TENANT_TOP_KEY)) {
// add new deny tenant
denytenants.push(allres.service.tenant[cnt]);
}
}
}
}
}
// add new allow tenants
for (let cnt = 0; cnt < allowtenants.length; ++cnt) {
const addtenant = rawGetTenantNameFromYrn(allowtenants[cnt]);
if (!k2hr3apiutil_1.default.isSafeString(addtenant)) {
const error = new Error('To allow Tenant name(' + allowtenants[cnt] + ') is something wrong.');
return error;
}
const allow_result = k2hr3dkc_1.default.allowTenantToService(owner, servicename, addtenant);
if (!k2hr3apiutil_1.default.isPlainObject(allow_result) || !k2hr3apiutil_1.default.isBoolean(allow_result.result) || false === allow_result.result) {
let error;
if (!k2hr3apiutil_1.default.isPlainObject(allow_result)) {
error = new Error('Could not get response from allowTenantToService');
}
else {
error = new Error('Could not get error message in response from allowTenantToService');
}
return error;
}
processed = true;
}
// remove new deny tenants
if (is_clear && k2hr3apiutil_1.default.isNotEmptyArray(denytenants)) {
for (let cnt = 0; cnt < denytenants.length; ++cnt) {
const denytenant = rawGetTenantNameFromYrn(denytenants[cnt]);
if (!k2hr3apiutil_1.default.isSafeString(denytenant)) {
const error = new Error('To allow Tenant name(' + denytenants[cnt] + ') is something wrong.');
return error;
}
const deny_result = k2hr3dkc_1.default.denyTenantFromService(owner, servicename, denytenant);
if (!k2hr3apiutil_1.default.isPlainObject(deny_result) || !k2hr3apiutil_1.default.isBoolean(deny_result.result) || false === deny_result.result) {
let error;
if (!k2hr3apiutil_1.default.isPlainObject(deny_result)) {
error = new Error('Could not get response from denyTenantToService');
}
else {
error = new Error('Could not get error message in response from denyTenantToService');
}
return error;
}
processed = true;
}
}
if (!processed) {
const error = new Error('Internal error: rawUpdateService');
return error;
}
dbglogging_1.default.dlog('succeed');
return null;
};
//
// Mountpath : '/v1/service'
//
// POST '/v1/service' : post service on version 1
// HEADER : X-Auth-Token => Scoped User token
// response body : result => true/false
// message => messages
// body :
// {
// "name": <service name> => key is "yrn:yahoo::::service:<service>"
// "verify": <verify url> => key is "yrn:yahoo::::service:<service>:verify"
// when the value is URL, it is save as URL string.
// the value is allowed null or undefined, then verify url value is null.
// the value is allowed string(not URL), it is saved and converted by JSON.
// }
//
// POST '/v1/service/<service>' : post tenant or verify for service on version 1
// HEADER : X-Auth-Token => Scoped User token
// response body : result => true/false
// message => messages
// body :
// {
// "tenant": <tenant name> or array => key is "yrn:yahoo::::service:<service>:tenant"
// if this key is specified, adding tenants to service
// the value is string for tenant name, or array of tenant name list
// "clear_tenant": true/false => true means clear existing tenant without "tenant".
// default false
// "verify": <verify url> => key is "yrn:yahoo::::service:<service>:verify"
// if this key is specified, updating verify url.
// when the value is URL, it is save as URL string.
// the value is allowed string(not URL), it is saved and converted by JSON.
// }
// }
//
// [NOTE]
// Verify URL is used as following formatted:
//
// GET http://<verify host[:port]>{/<path>}?service=<service name>&tenant=<tenant name>&tenantid=<tenant id>&user=<user name>&userid=<user id>
//
// service : service name
// tenant : tenant name
// tenantid : tenant id
// user : user name
// userid : user id
//
// And it's response is following:
// response body = [ => undefined/null or resource array(if one element, allows only it not array)
// {
// name => resource name which is key name(path) for resource
// expire => undefined/null or integer
// type => resource data type(string or object), if date is null or '', this value must be string.
// data => resource data which must be string or object or null/undefined.
// keys = { => resource has keys(associative array), or null/undefined.
// 'foo': bar, => any value is allowed
// ...
// }
// },
// ...
// ]
//
router.post('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
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)) {
const result = {
result: false,
message: 'POST body does not exist'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check service path in url
//------------------------------
let is_create;
let name = null;
const requestptn = new RegExp('^/v1/service/(.*)'); // regex = /^\/v1\/service\/(.*)/
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])) {
is_create = true;
}
else {
name = reqmatchs[1].toLowerCase();
is_create = false;
}
//------------------------------
// check arguments
//------------------------------
let verify = null;
let tenant = null;
let is_clear = false;
if (is_create) {
if (!k2hr3apiutil_1.default.isSafeString(req.body.name)) {
const result = {
result: false,
message: 'service:name field is wrong : ' + JSON.stringify(req.body.name)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
name = req.body.name.toLowerCase();
if (k2hr3apiutil_1.default.isValTypeAll(req.body.verify)) {
verify = req.body.verify;
}
}
else {
if (k2hr3apiutil_1.default.isSafeString(req.body.tenant)) {
const tenant_tmp = req.body.tenant;
if (k2hr3apiutil_1.default.checkSimpleJSON(tenant_tmp)) {
const tenant_raw = JSON.parse(tenant_tmp);
if (k2hr3apiutil_1.default.isStringArray(tenant_raw)) {
tenant = [];
for (let cnt = 0; cnt < tenant_raw.length; ++cnt) {
tenant.push(tenant_raw[cnt].toLowerCase());
}
}
else if (k2hr3apiutil_1.default.isSafeString(tenant_raw)) {
tenant = [tenant_raw.toLowerCase()];
}
else {
tenant = null;
}
}
else {
tenant = [tenant_tmp.toLowerCase()];
}
if (!k2hr3apiutil_1.default.isNotEmptyArray(tenant)) {
tenant = null;
}
}
if (k2hr3apiutil_1.default.isBoolean(req.body.clear_tenant) && true === req.body.clear_tenant) {
is_clear = true;
}
if (k2hr3apiutil_1.default.isValTypeAll(req.body.verify)) {
verify = req.body.verify;
}
if (null === tenant && null === verify) {
const result = {
result: false,
message: 'both tenant and verify are not specified.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
//------------------------------
// create/update service
//------------------------------
const error = rawUpdateService((token_info.tenant ?? null), name, verify, tenant, is_clear, is_create);
if (null !== error) {
const result = {
result: false,
message: error.message
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403, result); // 403: Forbidden(is this status OK?)
return;
}
const success_result = { result: true, message: null };
res.status(201); // 201: Created
res.send(JSON.stringify(success_result));
});
//
// Mountpath : '/v1/service/*'
//
// PUT '/v1/service' : post service on version 1
// HEADER : X-Auth-Token => Scoped User token
// response body : result => true/false
// message => messages
// URL argument
// "name" : <service name> => key is "yrn:yahoo::::service:<service>"
// "verify" : <verify url> => key is "yrn:yahoo::::service:<service>:verify"
// when the value is URL, it is save as URL string.
// the value is allowed null or undefined, then verify url value is null.
// the value is allowed string(not URL), it is saved and converted by JSON.
//
// PUT '/v1/service/<service>' : post tenant or verify for service on version 1
// HEADER : X-Auth-Token => Scoped User token
// response body : result => true/false
// message => messages
// URL argument
// "tenant" : <tenant name> => key is "yrn:yahoo::::service:<service>:tenant"
// if this key is specified, adding tenants to service
// the value is string for tenant name of tenant name list
// "clear_tenant" : true/false => true means clear existing tenant without "tenant".
// default false
// "verify" : <verify url> => key is "yrn:yahoo::::service:<service>:verify"
// when the value is URL, it is save as URL string.
// the value is allowed string(not URL), it is saved and converted by JSON.
//
// [NOTE] see POST
//
router.put('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
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 argument does not have any data'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check service path in url
//------------------------------
let is_create;
let name = null;
const requestptn = new RegExp('^/v1/service/(.*)'); // regex = /^\/v1\/service\/(.*)/
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])) {
is_create = true;
}
else {
name = reqmatchs[1].toLowerCase();
is_create = false;
}
//------------------------------
// check arguments
//------------------------------
let verify = null;
let tenant = null;
let is_clear = false;
if (is_create) {
if (!k2hr3apiutil_1.default.isSafeString(req.query.name)) {
const result = {
result: false,
message: 'name argument is wrong : ' + JSON.stringify(req.query.name)
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
name = req.query.name.toLowerCase();
if (k2hr3apiutil_1.default.isValTypeAll(req.query.verify)) {
if (k2hr3apiutil_1.default.isString(req.query.verify) && k2hr3apiutil_1.default.checkSimpleJSON(req.query.verify)) {
const tmp_verify = JSON.parse(req.query.verify);
if (k2hr3apiutil_1.default.isValTypeAll(tmp_verify)) {
verify = tmp_verify;
}
}
else {
verify = req.query.verify;
}
}
}
else {
if (k2hr3apiutil_1.default.isSafeString(req.query.tenant)) {
const tenant_tmp = req.query.tenant;
if (k2hr3apiutil_1.default.checkSimpleJSON(tenant_tmp)) {
const tenant_raw = JSON.parse(tenant_tmp);
if (k2hr3apiutil_1.default.isStringArray(tenant_raw)) {
tenant = [];
for (let cnt = 0; cnt < tenant_raw.length; ++cnt) {
tenant.push(tenant_raw[cnt].toLowerCase());
}
}
else if (k2hr3apiutil_1.default.isSafeString(tenant_raw)) {
tenant = [tenant_raw.toLowerCase()];
}
else {
tenant = null;
}
}
else {
tenant = [tenant_tmp.toLowerCase()];
}
if (!k2hr3apiutil_1.default.isNotEmptyArray(tenant)) {
tenant = null;
}
}
if ((k2hr3apiutil_1.default.isBoolean(req.query.clear_tenant) && true === req.query.clear_tenant) ||
(k2hr3apiutil_1.default.isSafeString(req.query.clear_tenant) && (k2hr3apiutil_1.default.compareCaseString('true', req.query.clear_tenant) || k2hr3apiutil_1.default.compareCaseString('1', req.query.clear_tenant)))) {
is_clear = true;
}
if (k2hr3apiutil_1.default.isValTypeAll(req.query.verify)) {
if (k2hr3apiutil_1.default.isString(req.query.verify) && k2hr3apiutil_1.default.checkSimpleJSON(req.query.verify)) {
const tmp_verify = JSON.parse(req.query.verify);
if (k2hr3apiutil_1.default.isValTypeAll(tmp_verify)) {
verify = tmp_verify;
}
}
else {
verify = req.query.verify;
}
}
if (null === tenant && null === verify) {
const result = {
result: false,
message: 'both tenant and verify are not specified.'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
}
//------------------------------
// create/update service
//------------------------------
const error = rawUpdateService((token_info.tenant ?? null), name, verify, tenant, is_clear, is_create);
if (null !== error) {
const result = {
result: false,
message: error.message
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403, result); // 403: Forbidden(is this status OK?)
return;
}
const success_result = { result: true, message: null };
res.status(201); // 201: Created
res.send(JSON.stringify(success_result));
});
//
// Mountpath : '/v1/service/*'
//
// GET '/v1/service/<service>' : get service on version 1
// HEADER : X-Auth-Token => Scoped User token
// response body : result => true/false
// message => error message
// service => object
// service object
// {
// "verify": <verify url> or <verify object>
// "tenant": [
// <tenant yrn full path>,
// ...
// ]
// }
//
router.get('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
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 or url is wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check service path in url
//------------------------------
const requestptn = new RegExp('^/v1/service/(.*)'); // regex = /^\/v1\/service\/(.*)/
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])) {
const result = {
result: false,
message: 'GET request url does not have service name'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const servicename = reqmatchs[1].toLowerCase();
//------------------------------
// get all service
//------------------------------
const allres = k2hr3dkc_1.default.getService(token_info.tenant, servicename);
if (!k2hr3apiutil_1.default.isPlainObject(allres) || !k2hr3dkc_1.default.isDkcTypeServiceRawValue(allres.service) || !k2hr3apiutil_1.default.isBoolean(allres.result) || false === allres.result) {
if (!k2hr3apiutil_1.default.isPlainObject(allres)) {
const result = {
result: false,
message: 'Could not get service data from getService'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403, result); // 403: Forbidden(is this status OK?)
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(allres.result) ? allres.result : false,
message: k2hr3apiutil_1.default.isString(allres.message) ? allres.message : 'Could not get error message in response from getService'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403, result); // 403: Forbidden(is this status OK?)
}
return;
}
//
// Remove owner/name from result
//
dbglogging_1.default.dlog('succeed : ' + allres.message);
const service_info = {
verify: allres.service.verify,
tenant: allres.service.tenant
};
const success_result = {
result: true,
message: null,
service: service_info
};
res.status(200); // 200: OK
res.send(JSON.stringify(success_result));
});
//
// Mountpath : '/v1/service/*'
//
// HEAD '/v1/service/<service>' : head service on version 1
// HEADER : X-Auth-Token => Scoped User token
//
// HEAD '/v1/service/<service>' : head tenant is allowed in service's tenant list on version 1
// HEADER : X-Auth-Token => Scoped User token
// URL argument :
// "tenant" : <tenant name> => key is "yrn:yahoo::::service:<service>:tenant"
// if this key is specified, check tenant is allowed.
//
router.head('/', (req, res, next) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
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)) {
const result = {
result: false,
message: 'HEAD request or url or query is wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check service path in url
//------------------------------
const requestptn = new RegExp('^/v1/service/(.*)'); // regex = /^\/v1\/service\/(.*)/
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])) {
const result = {
result: false,
message: 'GET request url does not have service name'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const servicename = reqmatchs[1].toLowerCase();
//------------------------------
// check arguments
//------------------------------
let tenantyrn = null;
if (k2hr3apiutil_1.default.isSafeString(req.query.tenant)) {
const keys = r3keys(null, req.query.tenant.toLowerCase(), null);
tenantyrn = keys.MASTER_TENANT_TOP_KEY; // tenant full yrn : "yrn:yahoo:::<tenant>"
}
//------------------------------
// get all service
//------------------------------
const allres = k2hr3dkc_1.default.getService(token_info.tenant, servicename);
if (!k2hr3apiutil_1.default.isPlainObject(allres) || !k2hr3apiutil_1.default.isBoolean(allres.result) || false === allres.result) {
if (!k2hr3apiutil_1.default.isSafeEntity(allres)) {
const result = {
result: false,
message: 'Could not get service data from getService'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(allres.result) ? allres.result : false,
message: k2hr3apiutil_1.default.isString(allres.message) ? allres.message : 'Could not get error message in response from getService'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
}
return;
}
if (k2hr3apiutil_1.default.isSafeString(tenantyrn)) {
// tenant check
if (!k2hr3dkc_1.default.isDkcTypeServiceRawValue(allres.service) || !k2hr3apiutil_1.default.isStringArray(allres.service.tenant) || !k2hr3apiutil_1.default.findStringInArray(allres.service.tenant, tenantyrn)) {
const result = {
result: false,
message: 'Deny tenant(' + k2hr3apiutil_1.default.getSafeString(req.query.tenant).toLowerCase() + ') for service(' + servicename + ')'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
return;
}
}
dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(allres.message));
res.status(204); // 204: No Content
res.send();
});
//
// Mountpath : '/v1/service/*'
//
// DELETE '/v1/service/<service>' : delete service on version 1
// remove service and all related to service.
// HEADER : X-Auth-Token => Scoped User token
//
// DELETE '/v1/service/<service>' : delete tenant from service's tenant list on version 1
// HEADER : X-Auth-Token => Scoped User token
// URL argument :
// "tenant" : <tenant name> => key is "yrn:yahoo::::service:<service>:tenant"
// if this key is specified, removing tenant from service
//
router.delete('/', (req, res, _) => {
dbglogging_1.default.dlog('CALL:', req.method, req.url, req.baseUrl);
res.type('application/json; charset=utf-8');
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl)) {
const result = {
result: false,
message: 'DELETE request or url or query is wrong'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_result.message),
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, token_result.status, result);
return;
}
const token_info = token_result.token_info;
if (!k2hr3tokens_1.default.isResTypeCheckRoleToken(token_info)) {
const result = {
result: false,
message: 'specified wrong token or it is not scoped user token'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// check service path in url
//------------------------------
const requestptn = new RegExp('^/v1/service/(.*)'); // regex = /^\/v1\/service\/(.*)/
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])) {
const result = {
result: false,
message: 'DELETE request url does not have service name'
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const servicename = reqmatchs[1].toLowerCase();
//------------------------------
// check arguments
//------------------------------
let tenantname = null;
if (k2hr3apiutil_1.default.isPlainObject(req.query) && k2hr3apiutil_1.default.isSafeString(req.query.tenant)) {
tenantname = req.query.tenant.toLowerCase();
}
const strRemoveType = k2hr3apiutil_1.default.isSafeString(tenantname) ? 'denyTenantFromService' : 'removeService';
//------------------------------
// Do remove
//------------------------------
let rm_result;
if (null === tenantname) {
// remove service and all
rm_result = k2hr3dkc_1.default.removeService(token_info.tenant, servicename);
}
else {
// remove tenant from service's tenant list
rm_result = k2hr3dkc_1.default.removeServiceTenant(token_info.user, tenantname, servicename);
}
if (!k2hr3apiutil_1.default.isPlainObject(rm_result) || !k2hr3apiutil_1.default.isBoolean(rm_result.result) || false === rm_result.result) {
if (!k2hr3apiutil_1.default.isPlainObject(rm_result)) {
const result = {
result: false,
message: 'Could not remove service data from ' + strRemoveType
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
}
else {
const result = {
result: k2hr3apiutil_1.default.isBoolean(rm_result.result) ? rm_result.result : false,
message: k2hr3apiutil_1.default.isString(rm_result.message) ? rm_result.message : 'Could not get error message in response from ' + strRemoveType
};
dbglogging_1.default.elog(result.message);
k2hr3resutil_1.default.errResponse(req, res, 403); // 403: Forbidden(is this status OK?)
}
return;
}
dbglogging_1.default.dlog('succeed : ' + k2hr3apiutil_1.default.getSafeString(rm_result.message));
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
*/