k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
295 lines (294 loc) • 12.8 kB
JavaScript
;
/*
* 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: Mon Nov 6 2017
* REVISION:
*
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
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 dbglogging_1 = __importDefault(require("../lib/dbglogging"));
const https = __importStar(require("https"));
const http = __importStar(require("http"));
const express_1 = __importDefault(require("express"));
const cacerts_1 = require("../lib/cacerts");
const router = express_1.default.Router();
//
// Debug Verify URL
//
// This router is for debugging verify url for dummy service.
// This is called only on development environment.
//
// Mountpath : '/v1/debug/verify'
//
// GET '/v1/debug/verify' : get verify for debug on version 1
// URL argument
// service : service name(default testservice)
// HEADER : X-Auth-Token => Scoped User token(without 'U=' prefix)
// 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.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');
//
// Check request
//
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl) ||
!k2hr3apiutil_1.default.isSafeString(req.method) ||
!k2hr3apiutil_1.default.isSafeString(req.protocol) ||
!k2hr3apiutil_1.default.isPlainObject(req.query) ||
(!k2hr3apiutil_1.default.isSafeString(req.host) && !k2hr3apiutil_1.default.isSafeString(req.hostname)) ||
!k2hr3apiutil_1.default.isPlainObject(req.headers) ||
!k2hr3apiutil_1.default.isSafeEntity(req.headers.host)) {
dbglogging_1.default.elog('GET request or url or token is wrong');
k2hr3resutil_1.default.errResponse(req, res, 400); // 400: Bad Request
return;
}
const _req = req;
const _res = res;
//------------------------------
// check token
//------------------------------
const token_result = k2hr3tokens_1.default.checkToken(req, true, true); // scoped, user token
if (!token_result.result) {
dbglogging_1.default.elog(k2hr3apiutil_1.default.getSafeString(token_result.message));
const result = {
result: token_result.result,
message: k2hr3apiutil_1.default.getSafeString(token_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 arguments
//
let _service_name = 'testservice'; // [NOTE] default service name
if (k2hr3apiutil_1.default.isSafeString(req.query.service) && k2hr3apiutil_1.default.isSafeString(req.query.service.trim())) {
_service_name = req.query.service.trim();
}
//
// Check localhost information for ACR API
//
const urlobj = k2hr3apiutil_1.default.parseUrl(_req.protocol + '://' + _req.headers.host);
if (null === urlobj || !urlobj.https) {
if (!k2hr3apiutil_1.default.compareCaseString(_req.protocol, 'http')) {
dbglogging_1.default.elog('Original request url method is not as same as request method');
k2hr3resutil_1.default.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
}
else {
if (!k2hr3apiutil_1.default.compareCaseString(_req.protocol, 'https')) {
dbglogging_1.default.elog('Original request url method is not as same as request method');
k2hr3resutil_1.default.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
}
if (null === urlobj || (urlobj.host !== k2hr3apiutil_1.default.getSafeString(_req.host) && urlobj.host !== k2hr3apiutil_1.default.getSafeString(_req.hostname))) {
dbglogging_1.default.elog('Original request url host is not as same as request host');
k2hr3resutil_1.default.errResponse(_req, _res, 400); // 400: Bad Request
return;
}
//
// Make request data
//
const agent = k2hr3apiutil_1.default.compareCaseString('https:', _req.protocol) ? https : http;
const headers = {
'Content-Type': 'application/json',
'Content-Length': 0,
'X-Auth-Token': k2hr3apiutil_1.default.getSafeString(_req.headers['x-auth-token']) // Transfer
};
const options = {
'host': urlobj.host,
'port': urlobj.port,
'path': '/v1/acr/' + _service_name,
'method': 'GET',
'headers': headers,
'ca': (k2hr3apiutil_1.default.compareCaseString('https:', _req.protocol) && null !== cacerts_1.ca) ? ((0, cacerts_1.ca)() ?? undefined) : undefined
};
dbglogging_1.default.dlog('request options = ' + JSON.stringify({ ...options, ca: options.ca ? '[Buffer]' : undefined }));
dbglogging_1.default.dlog('request headers = ' + JSON.stringify(headers));
//
// Send request to localhost
//
const subreq = agent.request(options, (subres) => {
let _body = '';
const _status = subres.statusCode;
const _headers = subres.headers;
dbglogging_1.default.dlog('/v1/acr/testservice response status: ' + _status);
dbglogging_1.default.dlog('/v1/acr/testservice response header: ' + JSON.stringify(_headers));
subres.setEncoding('utf8');
res.on('data', (chunk) => {
//r3logger.dlog('/v1/acr/testservice response chunk: ' + chunk);
_body += chunk;
});
res.on('end', () => {
if (300 <= (_status ?? 500)) {
const _error = new Error('got error response for verify request by status=' + String(_status ?? 500));
dbglogging_1.default.elog(_error.message);
k2hr3resutil_1.default.errResponse(_req, _res, _status, _error.message); // 4xx, 5xx
return;
}
//r3logger.dlog('/v1/acr/testservice response body: ' + _body);
//
// Check response body
//
let res_body = _body;
if (k2hr3apiutil_1.default.checkSimpleJSON(_body)) {
res_body = JSON.parse(_body);
}
if (!k2hr3apiutil_1.default.isPlainObject(res_body) ||
!k2hr3apiutil_1.default.isPlainObject(res_body.tokeninfo) ||
!k2hr3apiutil_1.default.isSafeString(res_body.tokeninfo.service) ||
!k2hr3apiutil_1.default.compareCaseString(res_body.tokeninfo.service, _service_name) ||
!k2hr3apiutil_1.default.isSafeString(res_body.tokeninfo.user) ||
!k2hr3apiutil_1.default.isSafeString(res_body.tokeninfo.tenant)) {
const _error = new Error('/v1/acr/testservice response is something wrong(' + JSON.stringify(res_body) + ').');
dbglogging_1.default.elog(_error.message);
k2hr3resutil_1.default.errResponse(_req, _res, 400, _error.message); // 400: Bad Request
return;
}
dbglogging_1.default.dlog('Call Verify URL: verified user(' + k2hr3apiutil_1.default.getSafeString(res_body.user) + ') and tenant(' + k2hr3apiutil_1.default.getSafeString(res_body.tenant) + ')');
//
// Make response body for debug
//
const resobj = [
{
name: _service_name + '_resource', // resource name
expire: null, // no expire
type: 'string', // resource is string type
data: _service_name + ' resource data for debug', // resource data(string)
keys: {
'creator': k2hr3apiutil_1.default.getSafeString(_token_info.user),
'owner_tenant': k2hr3apiutil_1.default.getSafeString(_token_info.tenant),
'service_name': _service_name,
'token': 'sample_token_value',
'accesskey': 'sample_accesskey_value',
'secretkey': 'sample_secretkey_value',
'anykey': 'sample_value'
}
}
];
//
// Return response
//
dbglogging_1.default.dlog('succeed : ' + JSON.stringify(resobj));
_res.status(200); // 200: OK
_res.send(JSON.stringify(resobj));
});
});
subreq.on('error', (exception) => {
dbglogging_1.default.elog(exception.message);
const maybeErrno = exception.errno;
const maybeCode = exception.code;
let status_code = 500;
if (k2hr3apiutil_1.default.isSafeNumber(maybeErrno)) {
status_code = maybeErrno;
}
else {
let tmpSatus = k2hr3apiutil_1.default.cvtToNumber(maybeErrno);
if (!k2hr3apiutil_1.default.isSafeNumber(tmpSatus)) {
tmpSatus = k2hr3apiutil_1.default.cvtToNumber(maybeCode);
}
if (k2hr3apiutil_1.default.isSafeNumber(tmpSatus)) {
status_code = tmpSatus;
}
}
k2hr3resutil_1.default.errResponse(_req, _res, status_code, exception.message);
return;
});
subreq.end();
});
//---------------------------------------------------------
// 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
*/