k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
220 lines (219 loc) • 9.22 kB
JavaScript
"use strict";
/*
* K2HR3 REST API
*
* Copyright 2018 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: Tue May 13 2020
* 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 dbglogging_1 = __importDefault(require("../lib/dbglogging"));
const k2hr3extdata_1 = __importDefault(require("../lib/k2hr3extdata"));
const express_1 = __importDefault(require("express"));
const router = express_1.default.Router();
//---------------------------------------------------------
// Router GET
//---------------------------------------------------------
//
// Mountpath : '/v1/extdata/*'
//
// GET '/v1/extdata/<exturi>/<encrypted data>' : get extra(user-defined) data on version 1
// response : compressed(gzip) extdata(binary)
//
// This mount point is for getting compressed user defined extra data.
// The user can define this extra data as a template in the configuration.
// The variables can be used in templates, and those are replaced real values
// as like userdata entry point.
// The returned data is encrypted and compressed with the specified algorithm.
//
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(not defined) function.
next();
return;
}
if (!k2hr3apiutil_1.default.isPlainObject(req) ||
!k2hr3apiutil_1.default.isSafeString(req.baseUrl) ||
!k2hr3apiutil_1.default.isSafeEntity(req.headers)) // Must User-Agent in header
{
const result = {
result: false,
message: 'GET request or url is wrong'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
//------------------------------
// Check headers
//------------------------------
if (!k2hr3apiutil_1.default.isSafeEntity(req.headers['user-agent'])) {
// 'User-Agent' Must be existed
const result = {
result: false,
message: 'GET request does not have User-Agent header'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const userAgent = k2hr3apiutil_1.default.getSafeString(req.headers['user-agent']).toLowerCase();
const typeEncode = req.headers['accept-encoding'];
const typeContent = req.headers['content-type'];
let isGzip = false;
if (k2hr3apiutil_1.default.isSafeEntity(typeEncode)) {
if (k2hr3apiutil_1.default.hasPartString(typeEncode, ',', ['gzip', 'deflate'], true)) {
isGzip = true;
}
else if (!isGzip) {
// Accept-Encoding should have 'gzip' or 'deflate', but all type is allowed
dbglogging_1.default.dlog('Get request Accept-Encoding does not have gzip nor deflate, but continue...');
}
}
else {
//r3logger.dlog('GET request doe not have Accept-Encoding, but continue...');
}
if (k2hr3apiutil_1.default.isSafeEntity(typeContent)) {
if (!k2hr3apiutil_1.default.hasPartString(typeContent, ';', 'application/octet-stream', true)) {
// should be 'application/octet-stream', but all type is allowed
dbglogging_1.default.dlog('GET request Content-Type is not application/octet-stream, but continue...');
}
}
else {
//r3logger.dlog('GET request doe not have Content-Type, but continue...');
}
//------------------------------
// get url paths and decode
//------------------------------
// check path matching
const requestptn = new RegExp('^/v1/extdata/(.*)/(.*)'); // regex = /^\/v1\/extdata\/(.*)\/(.*)/
const reqmatchs = decodeURI(req.baseUrl).match(requestptn);
if (!k2hr3apiutil_1.default.isArray(reqmatchs) ||
!k2hr3apiutil_1.default.isNotEmptyArray(reqmatchs) ||
reqmatchs.length < 3 ||
'' === k2hr3apiutil_1.default.getSafeString(reqmatchs[1]) ||
'' === k2hr3apiutil_1.default.getSafeString(reqmatchs[2])) {
const result = {
result: false,
message: 'GET request url does not have extdata path parameter'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
// decode and check extdata parameter
const extdataproc = new k2hr3extdata_1.default;
const suburi = k2hr3apiutil_1.default.getSafeString(reqmatchs[1]);
const roleinfo = extdataproc.decryptRoleInfo(reqmatchs[2]);
if (!k2hr3apiutil_1.default.isSafeString(suburi) || !extdataproc.checkSuburi(suburi)) {
const result = {
result: false,
message: 'GET request URL path(' + k2hr3apiutil_1.default.getSafeString(suburi) + ') does not exist'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
if (!extdataproc.checkUserAgent(userAgent, suburi)) {
const result = {
result: false,
message: 'GET request is not allowed from your client'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
if (!k2hr3apiutil_1.default.isValTypeRoleInfo(roleinfo)) {
const result = {
result: false,
message: 'GET /extdata/' + suburi + '/<path> is invalid'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
const contype = extdataproc.getContentType(suburi);
//------------------------------
// Make response
//------------------------------
if (isGzip) {
// Gzip
const responsebody = extdataproc.getGzipExtdata(roleinfo, suburi);
if (null == responsebody) {
const result = {
result: false,
message: 'Could not make gzip response'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
res.type('application/zip');
res.setHeader('Content-Encoding', 'gzip');
res.setHeader('Content-Transfer-Encoding', 'binary');
res.setHeader('Content-Disposition', 'attachment; filename=k2hr3-extdata.gz');
res.setHeader('Content-Length', responsebody.length);
dbglogging_1.default.dlog('succeed : (response body is gzip compressed)');
res.status(200); // 200: OK
res.send(responsebody.data);
}
else {
// Text
const responsebody = extdataproc.getExtdata(roleinfo, suburi);
if (null == responsebody) {
const result = {
result: false,
message: 'Could not make response'
};
dbglogging_1.default.elog(result.message);
res.type('application/json; charset=utf-8');
k2hr3resutil_1.default.errResponse(req, res, 400, result); // 400: Bad Request
return;
}
res.type((null === contype || !k2hr3apiutil_1.default.isSafeString(contype)) ? 'text/plain' : contype);
res.setHeader('Content-Length', responsebody.length);
dbglogging_1.default.dlog('succeed : (response body is not gzip compressed)');
res.status(200); // 200: OK
res.send(responsebody);
}
});
//---------------------------------------------------------
// 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
*/