k2hr3-api
Version:
K2HR3 REST API is K2hdkc based Resource and Roles and policy Rules
1,495 lines (1,360 loc) • 35.5 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: Wed Jun 8 2017
* REVISION:
*
*/
'use strict';
var dns = require('dns');
var url = require('url');
var fs = require('fs');
var crypto = require('crypto');
//---------------------------------------------------------
// Utilities for variables
//---------------------------------------------------------
function rawIsSafeString(str)
{
if(undefined === str || null === str || 'string' !== typeof str || '' === str){
return false;
}
return true;
}
function rawIsSafeEntity(data)
{
return (undefined !== data && null !== data);
}
function rawCompareCaseString(str1, str2)
{
if(rawIsSafeString(str1) && rawIsSafeString(str2) && str1.toLowerCase() === str2.toLowerCase()){
return true;
}
return false;
}
function rawHasPartString(strbase, sep, values, iscase)
{
if(!rawIsSafeString(strbase) || !rawIsSafeString(sep)){
return false;
}
var valarray = values;
if(!rawIsArray(values)){
if(!rawIsSafeString(values)){
return false;
}
valarray = new Array();
valarray.push(values);
}
var basearray = strbase.split(sep);
for(var cnt1 = 0; cnt1 < basearray.length; ++cnt1){
var strtmp1 = basearray[cnt1].trim();
if(!rawIsSafeString(strtmp1)){
continue;
}
for(var cnt2 = 0; cnt2 < valarray.length; ++cnt2){
var strtmp2 = valarray[cnt2].trim();
if(!rawIsSafeString(strtmp2)){
continue;
}
if(iscase){
if(rawCompareCaseString(strtmp1, strtmp2)){
return true;
}
}else{
if(strtmp1 === strtmp2){
return true;
}
}
}
}
return false;
}
function rawGetSafeString(str)
{
if(rawIsSafeString(str)){
return str;
}
return '';
}
function rawCheckSimpleJSON(str)
{
if(undefined === str || null === str || !isNaN(str) || 'string' !== typeof str){
return false;
}
try{
var tmp = JSON.parse(str); // eslint-disable-line no-unused-vars
}catch(exception){ // eslint-disable-line no-unused-vars
return false;
}
return true;
}
function rawParseJSON(str)
{
if(undefined === str || null === str || !isNaN(str) || 'string' !== typeof str){
return null;
}
try{
return JSON.parse(str);
}catch(exception){ // eslint-disable-line no-unused-vars
return null;
}
}
function rawIsArray(arr)
{
if(arr instanceof Array){
return true;
}
return false;
}
function rawIsEmptyArray(arr)
{
if(!(arr instanceof Array) || 0 === arr.length){
return true;
}
return false;
}
function rawGetSafeArray(arr)
{
var result_array;
if(!(arr instanceof Array)){
result_array = new Array(0);
}else{
result_array = arr;
}
return result_array;
}
function rawFindStringInArray(arr, str)
{
if(arr instanceof Array && undefined !== str && null !== str){
for(var cnt = 0; cnt < arr.length; ++cnt){
if(str == arr[cnt]){
return true;
}
}
}
return false;
}
function rawAddStringToArray(arr, str)
{
var result_array;
if(!(arr instanceof Array)){
result_array = new Array(0);
}else{
result_array = arr;
}
result_array.push(str);
return result_array;
}
function rawTryAddStringToArray(arr, str)
{
if(!(arr instanceof Array)){
return false;
}
if(rawFindStringInArray(arr, str)){
return false;
}
// arr is array and it does not have str.
// so add str to arr.
arr.push(str);
return true;
}
function rawRemoveStringFromArray(arr, str)
{
if(!(arr instanceof Array) || undefined === str || null === str){
return false;
}
for(var cnt = 0; cnt < arr.length; ++cnt){
if(str == arr[cnt]){
arr.splice(cnt, 1);
return true;
}
}
return false;
}
function rawCompareArray(arr1, arr2, strict)
{
if(!(arr1 instanceof Array) || !(arr2 instanceof Array) || arr1.length !== arr2.length){
return false;
}
if(!rawIsSafeEntity(strict) || 'boolean' !== typeof strict || false === strict){
var is_found;
for(var cnt1 = 0; cnt1 < arr1.length; ++cnt1){
is_found = false;
for(var cnt2 = 0; cnt2 < arr2.length; ++cnt2){
if(arr1[cnt1] === arr2[cnt2]){
is_found = true;
break;
}
}
if(!is_found){
return false;
}
}
}else{
if(JSON.stringify(arr1) !== JSON.stringify(arr2)){
return false;
}
}
return true;
}
function rawMergeArray(arr1, arr2)
{
if(!(arr1 instanceof Array) && !(arr2 instanceof Array)){
return [];
}
if(!(arr2 instanceof Array)){
return arr1;
}
if(!(arr1 instanceof Array)){
return arr2;
}
for(var cnt2 = 0; cnt2 < arr2.length; ++cnt2){
var is_found = false;
for(var cnt1 = 0; cnt1 < arr1.length; ++cnt1){
if(arr1[cnt1] === arr2[cnt2]){
is_found = true;
break;
}
}
if(!is_found){
arr1.push(arr2[cnt2]);
}
}
return arr1;
}
//
// Get difference from base to new array elements.
// If is_deleted_element is true, returns result difference elements for deleting from base.
// If is_deleted_element is false, returns result difference elements for adding from base.
//
function rawGetDiffArray(basearr, newarr, is_deleted_element)
{
if(!(basearr instanceof Array) && !(newarr instanceof Array)){
return [];
}else if(!(basearr instanceof Array) && (newarr instanceof Array)){
if(is_deleted_element){
return [];
}else{
return newarr;
}
}else if((basearr instanceof Array) && !(newarr instanceof Array)){
if(is_deleted_element){
return basearr;
}else{
return [];
}
}
var cnt;
var result = new Array(0);
if(is_deleted_element){
for(cnt = 0; cnt < basearr.length; ++cnt){
if(!rawFindStringInArray(newarr, basearr[cnt])){
result.push(basearr[cnt]);
}
}
}else{
for(cnt = 0; cnt < newarr.length; ++cnt){
if(!rawFindStringInArray(basearr, newarr[cnt])){
result.push(newarr[cnt]);
}
}
}
return result;
}
function rawMergeObjects(obj1, obj2)
{
if(!rawIsSafeEntity(obj1)){
obj1 = {};
}
if(!rawIsSafeEntity(obj2)){
obj2 = {};
}
var resobj = {};
for(var key1 in obj1){
resobj[key1] = obj1[key1];
}
for(var key2 in obj2){
resobj[key2] = obj2[key2];
}
return resobj;
}
//---------------------------------------------------------
// Utilities for time
//---------------------------------------------------------
//
// base is UTC
//
function convertUnixtime(base)
{
var unixtime_ms;
if(undefined === base || null === base || '' === base){
var now = new Date();
unixtime_ms = now.getTime();
}else{
unixtime_ms = Date.parse(base);
}
return Math.floor(unixtime_ms / 1000);
}
function rawConvertISOStringToUnixtime(iso)
{
if(!rawIsSafeString(iso)){
return 0;
}
var isoTime = new Date(iso);
var utime = isoTime.getTime() / 1000;
return utime;
}
function rawGetExpireUnixtime(starttime, expiretime)
{
return (expiretime - starttime);
}
function rawGetExpireUnixtimeFromISOStrings(startiso, expireiso)
{
var starttime = rawConvertISOStringToUnixtime(startiso);
var expiretime = rawConvertISOStringToUnixtime(expireiso);
return rawGetExpireUnixtime(starttime, expiretime);
}
//---------------------------------------------------------
// Utilities for Key and Hierarchy
//---------------------------------------------------------
//
// Convert string to Hierarchy Array by separator
// ex) "parent-", "a/b/c" => ["parent-", "parent-a", "parent-a/b", "parent-a/b/c"]
// null, "a/b/c" => ["a", "a/b", "a/b/c"]
//
function rawExpandHierarchyArray(parent, str, separator, allow_empty)
{
if(!rawIsSafeString(str)){
return null;
}
var sep = '/';
if(rawIsSafeString(separator)){
sep = separator;
}
if(!rawIsSafeEntity(allow_empty)){
allow_empty = false;
}else if('boolean' !== typeof allow_empty){
return null;
}
var result = new Array(0);
if(rawIsSafeString(parent)){
result.push(parent);
}else{
parent = '';
}
var parts = str.split(sep);
var tmp = parent;
for(var cnt = 0; cnt < parts.length; ++cnt){
if(0 !== cnt){
tmp += sep;
}
var tmpstr = rawGetSafeString(parts[cnt]);
tmp += tmpstr;
if(allow_empty || '' !== str){
result.push(tmp);
}
}
return result;
}
//
// Convert parent and terminal children(string or array) to Hierarchy object
// The result is the object which is configured "key=parent", "value=parent's children".
//
// ex) parent = "parent-" ===> result = { "parent": ["parent-a"],
// children = "a/b/c" "parent-a": ["parent-a/b"],
// "parent-a/b": ["parent-a/b/c"],
// "parent-a/b/c": []
// };
//
// ex) parent = "parent-" ===> result = { "parent": ["parent-a", "parent-1"],
// children = [ "a/b/c", "parent-a": ["parent-a/b"],
// "1/2/3"] "parent-a/b": ["parent-a/b/c"],
// "parent-a/b/c": [],
// "parent-1": ["parent-1/2"],
// "parent-1/2": ["parent-1/2/3"],
// "parent-1/2/3": []
// };
//
// ex) parent = "" ===> result = { "a": ["a/b"],
// children = ["a/b/c"] "a/b": ["a/b/c"],
// "a/b/c": []
// };
//
// ex) parent = "" ===> result = null(because this case does not have hierarchy)
// children = "a"
//
function rawExpandHierarchy(parent, children, separator, allow_empty)
{
if(!rawIsSafeString(parent)){
parent = '';
}
if(!(children instanceof Array)){
if(!rawIsSafeString(children)){
return null;
}
var tmp = children;
children= [tmp];
}
var is_set = false;
var result = {};
var parent_in_array;
for(var cnt = 0; cnt < children.length; ++cnt){
// parent + children[x] ---> ["parent", "parent child1", "parent child1 sep child2", ...]
var child_hierarchy_arr = rawExpandHierarchyArray(parent, children[cnt], separator, allow_empty);
if(null === child_hierarchy_arr || !(child_hierarchy_arr instanceof Array) || 0 === child_hierarchy_arr.length){
continue;
}
parent_in_array = '';
for(var cnt2 = 0; cnt2 < child_hierarchy_arr.length; ++cnt2){
if('' !== parent_in_array){
// parent ---> [child, child, ...]
if(!rawFindStringInArray(result[parent_in_array], child_hierarchy_arr[cnt2])){
result[parent_in_array].push(child_hierarchy_arr[cnt2]);
is_set = true;
}
}
parent_in_array = child_hierarchy_arr[cnt2];
if(!rawIsSafeEntity(result[parent_in_array]) || !(result[parent_in_array] instanceof Array)){
result[parent_in_array] = new Array(0);
}
}
}
if(!is_set){
return null;
}
return result;
}
//
// Get direct parent path for key
// ex) parent: "parent", childkey: ":a/b/c" => parent:a/b
// parent: null, childkey: ":a/b/c" => :a/b
// parent: "parent", childkey: ":a" => parent
// parent: "parent", childkey: "" => null
//
function rawGetParentKey(parent, childkey, separator, allow_empty)
{
if(!rawIsSafeString(childkey)){
return null;
}
var child_hierarchy_arr = rawExpandHierarchyArray(parent, childkey, separator, allow_empty);
if(null === child_hierarchy_arr || !(child_hierarchy_arr instanceof Array) || 0 === child_hierarchy_arr.length){
return null;
}
if(1 === child_hierarchy_arr.length){
// there is no parent, the array is only childkey(or parent)
return null;
}
return child_hierarchy_arr[child_hierarchy_arr.length - 2];
}
//
// Get parent path from string
//
// ex) "a/b/c" => "a/b"
// "a" => null
// "a/b/c/" => "a/b" : if allow_empty is false
// "a/b/c/" => "a/b/c" : if allow_empty is true
// "a//b/c" => "a//b"
// "a/b/c//" => "a/b" : if allow_empty is false
// "a/b/c//" => "a/b/c/" : if allow_empty is true
// "a/" => null : if allow_empty is false
// "a/" => "a" : if allow_empty is true
// "/a/b" => "/a"
// "/a" => null
// "a//b" => "a" : if allow_empty is false
// "a//b" => "a/" : if allow_empty is true
// "a/b///" => "a" : if allow_empty is false
// "a/b///" => "a/b//" : if allow_empty is true
//
function rawGetParentPath(str, separator, allow_empty)
{
if(!rawIsSafeString(str)){
return '';
}
if(!rawIsSafeEntity(allow_empty)){
allow_empty = false;
}else if('boolean' !== typeof allow_empty){
return '';
}
if(!rawIsSafeString(separator)){
separator = '/';
}
var tmp;
var cnt;
// escape if allow empty
if(allow_empty){
// escape '\' --> '\\'
str = str.replace(/\\/g, '\\\\');
// last word is '/' --> add '\'
if('/' === str[str.length - 1]){
str += '\\';
}
// if '//' --> '/\/'
tmp = '';
for(cnt = 0; cnt < str.length; ++cnt){
tmp += str[cnt];
if('/' === str[cnt] && (cnt + 1) < str.length && '/' === str[cnt + 1]){
tmp += '\\';
}
}
str = tmp;
}
// parse by separator
var parts = str.split(separator);
// remove last elements until it is not empty
while(0 < parts.length && !rawIsSafeString(parts[parts.length - 1])){
parts.pop();
}
// remove last element
if(0 < parts.length){
parts.pop();
}
// remove last elements until it is not empty
while(0 < parts.length && !rawIsSafeString(parts[parts.length - 1])){
parts.pop();
}
// join with separator
var parent = parts.join(separator);
// unescape if allow empty
if(allow_empty && rawIsSafeString(parent)){
// '\' --> '' or '\\' --> '\'
tmp = '';
for(cnt = 0; cnt < parent.length; ++cnt){
if('\\' === parent[cnt]){
++cnt;
if(cnt < parent.length && '\\' === parent[cnt]){
tmp += parent[cnt]; // = '\'
}
}else{
tmp += parent[cnt];
}
}
parent = tmp;
}
return parent;
}
//
// Compare string by regex or string patterns(array)
//
function rawCompareStringByFormats(str, regex_ptn, pattern_array)
{
if(!rawIsSafeString(str)){
return null;
}
var tmpstr = str.toLowerCase();
if(rawIsSafeEntity(regex_ptn)){
var matches = tmpstr.match(regex_ptn);
if(!rawIsEmptyArray(matches) && 2 <= matches.length){
return tmpstr;
}
}
if(!rawIsArray(pattern_array) && rawIsSafeString(pattern_array)){
var tmpptn = pattern_array;
pattern_array = [tmpptn];
}
if(rawIsArray(pattern_array)){
for(var cnt = 0; cnt < pattern_array.length; ++cnt){
if(rawCompareCaseString(tmpstr, pattern_array[cnt])){
return tmpstr;
}
}
}
return null;
}
//---------------------------------------------------------
// Utilities for regex
//---------------------------------------------------------
//
// return object = {
// result: true/false
// parameter: object(array) or null or '' or undefined
// }
//
function rawGetNormalizeParameter(parameter, regex_ptn, pattern)
{
var resobj = { result: false };
var resstr;
var cnt;
if(rawIsSafeEntity(parameter) && rawCheckSimpleJSON(parameter)){
parameter = JSON.parse(parameter);
}
if(!rawIsSafeEntity(parameter)){
resobj.result = true;
resobj.parameter= null; // = not update type
}else if(rawIsArray(parameter)){
if(rawIsEmptyArray(parameter)){
resobj.result = true;
resobj.parameter= ''; // = clean up type
}else{
resobj.result = true;
resobj.parameter= new Array(0);
for(cnt = 0; cnt < parameter.length; ++cnt){
resstr = rawCompareStringByFormats(parameter[cnt], regex_ptn, pattern);
if(null === resstr){
resobj.result = false;
resobj.parameter= null;
break;
}
resobj.parameter.push(resstr);
}
}
}else if('' === parameter){
resobj.result = true;
resobj.parameter= ''; // = clean up type
}else if(rawIsSafeString(parameter)){
var tmparr = parameter.split(',');
if(rawIsArray(tmparr) && !rawIsEmptyArray(tmparr)){
resobj.result = true;
resobj.parameter= new Array(0);
for(cnt = 0; cnt < tmparr.length; ++cnt){
resstr = rawCompareStringByFormats(tmparr[cnt], regex_ptn, pattern);
if(null === resstr){
resobj.result = false;
resobj.parameter= null;
break;
}
resobj.parameter.push(resstr);
}
}else{
resobj.result = true;
resobj.parameter= ''; // = clean up type
}
}else{
resobj.result = false;
}
return resobj;
}
//---------------------------------------------------------
// Utilities for UUID4
//---------------------------------------------------------
// RFC4122
// https://www.ietf.org/rfc/rfc4122.txt
//
// UUID4 = xxxxxxxx-xxxx-Nxxx-Mxxx-xxxxxxxxxxxx
// N: 0x4X
// M: 0x{8,9,A,B}X
//
function rawGetBinUuid4()
{
var binUuid4= crypto.randomBytes(16);
binUuid4[6] = (binUuid4[6] & 0x0f) | 0x40; // UUID4 must be 0x4X for pos 6 in buffer
binUuid4[8] = (binUuid4[8] & 0x3f) | 0x80; // UUID4 must be 0x{8,9,A,B}X for pos 8 in buffer
return binUuid4;
}
// [NOTE]
// If binary data is given, this is only a conversion to UUID format,
// not a method that enforces UUID4 format.
//
function rawGetStrUuid4(binUuid4)
{
if(!rawIsSafeEntity(binUuid4) || !(binUuid4 instanceof Buffer)){
binUuid4 = rawGetBinUuid4();
}
var parsed = binUuid4.toString('hex').match(/(.{8})(.{4})(.{4})(.{4})(.{12})/);
parsed.shift(); // first element is all, then skip it.
var strUuid = parsed.join('-');
return strUuid;
}
function rawIsSafeStrUuid4(strUuid4)
{
if(!rawIsSafeString(strUuid4)){
return false;
}
// split '-' separator
var strArray = strUuid4.split('-');
if(5 != strArray.length){
return false;
}
// check length
if( 0 == strArray[0].length || 8 < strArray[0].length ||
0 == strArray[1].length || 4 < strArray[1].length ||
0 == strArray[2].length || 4 < strArray[2].length ||
0 == strArray[3].length || 4 < strArray[3].length ||
0 == strArray[4].length || 12 < strArray[4].length )
{
return false;
}
return true;
}
function rawCvtStrToBinUuid4(strUuid4)
{
if(!rawIsSafeString(strUuid4)){
return null;
}
// split '-' separator
var strArray = strUuid4.split('-');
if(5 != strArray.length){
return null;
}
// check length and fill '0' for short part
strArray[0] = rawFillZeroString(strArray[0], 8);
strArray[1] = rawFillZeroString(strArray[1], 4);
strArray[2] = rawFillZeroString(strArray[2], 4);
strArray[3] = rawFillZeroString(strArray[3], 4);
strArray[4] = rawFillZeroString(strArray[4], 12);
if(null == strArray[0] || null == strArray[1] || null == strArray[2] || null == strArray[3] || null == strArray[4]){
return null;
}
// uuid full hex string
var fullString = strArray.join('');
// convert to binary array
var binUuid4 = new Uint8Array(fullString.match(/.{1,2}/g).map(function(val){ return parseInt(val, 16); }));
return Buffer.from(binUuid4);
}
function rawFillZeroString(str, size)
{
if(!rawIsSafeString(str)){
return null;
}
if(size < str.length){
return null;
}else if(str.length < size){
var fillstr = '';
for(var fillcnt = size - str.length; 0 < fillcnt; --fillcnt){
fillstr += '0';
}
str = fillstr + str;
}
return str;
}
//
// Return result
// {
// hi_id: Buffer[16] for hi uuid
// low_id: Buffer[16] for low uuid
// base: Buffer[32] for base
// str_token: hex[32] string for token
// token: Buffer[32] for token
// }
//
function rawMakeToken256(hiUuid4, lowUuid4, base)
{
// hiUuid4[128] / lowUuid4[128]
if( !rawIsSafeEntity(hiUuid4) || !(hiUuid4 instanceof Buffer) || 16 != hiUuid4.length ||
!rawIsSafeEntity(lowUuid4) || !(lowUuid4 instanceof Buffer) || 16 != lowUuid4.length ||
!rawIsSafeEntity(base) || !(base instanceof Buffer) || 32 != base.length )
{
return null;
}
var result = {};
result.hi_id = hiUuid4;
result.low_id = lowUuid4;
result.base = base;
// raw not crypted token[256]
var token = Buffer.alloc(32);
for(var cnt = 0; cnt < 32; ++cnt){
if(cnt < 16){
token[cnt] = result.base[cnt] ^ hiUuid4[cnt];
}else{
token[cnt] = result.base[cnt] ^ lowUuid4[cnt - 16];
}
}
// sha256 token[256]
var cryptSha256 = crypto.createHash('sha256');
cryptSha256.update(token);
result.str_token = cryptSha256.digest('hex');
// sha256 binary token[256]
result.token = rawCvtNumberStringToBinBuffer(result.str_token, 16, 32);
return result;
}
//
// Return result
// {
// str_hi_id: hi uuid string
// hi_id: Buffer[16] for hi uuid
// str_low_id: low uuid string
// low_id: Buffer[16] for low uuid
// str_base: base string
// base: Buffer[32] for base
// str_token: hex[32] string for token
// token: Buffer[32] for token
// }
//
function rawMakeStringToken256(strHiUuid4, strLowUuid4, strBase)
{
var hiUuid4 = rawCvtStrToBinUuid4(strHiUuid4);
var lowUuid4 = rawCvtStrToBinUuid4(strLowUuid4);
var base;
if(rawIsSafeString(strBase)){
// string base is specified, then convert to buffer[32]
base = rawCvtNumberStringToBinBuffer(strBase, 16, 32);
}else{
// base is not specified, then it is made at here.
base = crypto.randomBytes(32); // base data is random value in buffer[32]
}
var result = rawMakeToken256(hiUuid4, lowUuid4, base);
if(null == result){
return null;
}
result.str_hi_id = strHiUuid4;
result.str_low_id = strLowUuid4;
result.str_base = base.toString('hex');
return result;
}
//
// Converts a decimal or hexadecimal character string into a Buffer array(hexadecimal)
// with a specified number of bytes.
//
// strNumber: string for decimal or hexadecimal number
// base: radix(10 or 16)
// size: output Buffer array size
//
// result: Buffer array
//
function rawCvtNumberStringToBinBuffer(strNumber, base, size)
{
if(!rawIsSafeString(strNumber)){
return null;
}
if(16 != base && 10 != base){
return null;
}
if(10 == base){
// convert dec string to hex string
var tmpNumber = parseInt(strNumber, 10);
strNumber = tmpNumber.toString(16);
}
var uintarr = new Uint8Array(strNumber.match(/.{1,2}/g).map(function(val){ return parseInt(val, 16); }));
var binbuff = Buffer.alloc(size);
binbuff.fill(0);
var diff_length;
var cnt;
if(size < uintarr.length){
// If input number array length is larger than required length, fill bottom.
diff_length = uintarr.length - size;
for(cnt = uintarr.length; diff_length < cnt; --cnt){
binbuff[cnt - 1 - diff_length] = uintarr[cnt - 1];
}
}else{
// If required length is larger than input length, fill zero to top.
diff_length = size - uintarr.length;
for(cnt = size; 0 < cnt; --cnt){
if((cnt -1) < diff_length){
break;
}
binbuff[cnt - 1] = uintarr[cnt - 1 - diff_length];
}
}
return binbuff;
}
function rawCvtNumberStringToUuid4(strNumber, base)
{
var bin_uuid4 = rawCvtNumberStringToBinBuffer(strNumber, base, 16); // UUID4 is 16bytes
if(null == bin_uuid4){
return null;
}
return rawGetStrUuid4(bin_uuid4);
}
//---------------------------------------------------------
// Utilities for Host/IP address
//---------------------------------------------------------
//
// Get client ip address
//
// [NOTE]
// If the server is behind of proxy, you have to set "trust proxy" to express app.
// Then we get client ip address in X-Forwarded-for header from req.ip.
//
// If you do not use "trust proxy", you can get client ip by following:
//
// ip = (rawIsSafeEntity(req.headers) && rawIsSafeEntity(req.headers['x-forwarded-for'])) ? req.headers['x-forwarded-for'].split(',')[0] :
// (rawIsSafeEntity(req.connection) && rawIsSafeString(req.connection.remoteAddress)) ? req.connection.remoteAddress :
// (rawIsSafeEntity(req.connection) && rawIsSafeEntity(req.connection.socket) && rawIsSafeString(req.connection.socket.remoteAddress)) ? req.connection.socket.remoteAddress :
// (rawIsSafeEntity(req.socket) && rawIsSafeString(req.socket.remoteAddress)) ? req.socket.remoteAddress :
// '0.0.0.0';
// ip = ip.split(':').slice(-1); //in case the ip returned in a format: "::ffff:xxx.xxx.xxx.xxx"
//
function rawGetClientIpAddress(req)
{
// If "trust proxy" is set, set client ip address to req.ip.
var ip = (rawIsSafeEntity(req) && rawIsSafeString(req.ip)) ? req.ip : null;
if(!rawIsSafeString(ip)){
ip = null;
}else{
// check format "::ffff:" for ipv4 on ipv6
if('::ffff:' === ip.substr(0,7)) {
ip = ip.substr(7);
}
}
return ip;
}
function rawCompareRequestIpAddress(req, ip)
{
var req_ip = rawGetClientIpAddress(req);
return (req_ip === ip);
}
//
// Get hostname from ip address
//
// ip : ip address
// callback : function(err message, result<string[]>)
//
function rawGetHostnameFromIpAddress(ip, callback)
{
if(!rawIsSafeString(ip)){
callback('ip address parameter is wrong', null);
return;
}
var _ip = ip;
dns.reverse(_ip, function(err, hosts)
{
if(rawIsSafeEntity(err)){
callback('ip address(' + _ip + ') is not convert hostname: ' + err.message, null);
return;
}
if(rawIsEmptyArray(hosts)){
callback('ip address(' + _ip + ') is not convert hostname', null);
return;
}
callback(null, hosts);
});
}
//
// Get ip address from hostname
//
// hostname : host name
// callback : function(err message, result<string[]>)
//
function rawGetIpAddressFromHostname(hostname, callback)
{
if(!rawIsSafeString(hostname)){
callback('hostname parameter is wrong', null);
return;
}
// try ipv4
var _hostname4 = hostname;
dns.resolve4(_hostname4, function(err, ip4)
{
if(rawIsSafeEntity(err) || rawIsEmptyArray(ip4)){
// try ipv6
var _hostname6 = _hostname4;
dns.resolve6(_hostname6, function(err, ip6)
{
if(rawIsSafeEntity(err) || rawIsEmptyArray(ip6)){
callback('hostname(' + _hostname4 + ') is not convert ipv6 address' + ((rawIsSafeEntity(err) && rawIsSafeString(err.message)) ? err.message : ''), null);
return;
}
callback(null, ip6);
});
}
callback(null, ip4);
});
}
//
// Complement ip address and hostname
//
// hostname : host name
// ip : ip address
// callback : function(err message, ip array[ip,...], hostname array[name,...])
//
function rawComplementHostnameIpAddress(hostname, ip, callback)
{
if(!rawIsSafeString(hostname) && !rawIsSafeString(ip)){
callback('hostname and ip parameter is wrong', null, null);
return;
}
if(rawIsSafeString(hostname) && rawIsSafeString(ip)){
var ips = [ip];
var hosts = [hostname];
callback('hostname and ip parameter is wrong', ips, hosts);
return;
}
if(rawIsSafeString(hostname)){
var _hostname = [hostname];
rawGetIpAddressFromHostname(ip, function(err, result)
{
if(rawIsSafeEntity(err)){
callback(err, null, null);
return;
}
callback(null, result, _hostname);
});
}else{ // rawIsSafeString(ip)
var _ips = [ip];
rawGetHostnameFromIpAddress(ip, function(err, result)
{
if(rawIsSafeEntity(err)){
callback(err, null, null);
return;
}
callback(null, _ips, result);
});
}
}
//
// url parser with default port
//
function rawUrlParse(strurl)
{
var ep = url.parse(strurl);
if(rawIsSafeEntity(ep) && (null === ep.port || !rawIsSafeEntity(ep.port) || isNaN(ep.port))){
// set default port
if(rawIsSafeString(ep.protocol) && 'https:' === ep.protocol){
ep.port = 443;
}else{
ep.port = 80;
}
}
return ep;
}
//
// Check hostname/ip address
//
// host : hostname or ip address string
//
const simple_reg_ipv4 = /^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
const simple_reg_ipv6 = /^(([0-9]|[a-f]|[A-F])*:)*([0-9]|[a-f]|[A-F])$/;
function rawIsIpAddressString(host)
{
if(!rawIsSafeString(host)){
return false;
}
if(host.match(simple_reg_ipv4) || host.match(simple_reg_ipv6)){
return true;
}
return false;
}
//
// Check URL
//
// Allow formatted as "http(s)://<host{:port}>{/{<path>}...}"
//
// Result matches by regex
// matches.length 7
// matches[0] input string(url)
// matches[1] method string(http or https)
// matches[2] FQDN string(domain name)
// matches[3] port number starting with ':'(':xxxx'). if url does not have port, this value is ''(empty string)
// matches[4] port number starting with ':'(':xxxx'). if url does not have port, this value is undefined
// matches[5] url path and arguments string(string after port number). if url end of character is port number, this value is ''(empty string)
// matches[6] url path and arguments string(string after port number). if url end of character is port number, this value is undefined
//
// Ex.)
// Input url : 'https://abc.co.jp:8080/path?arg=value'
// matches : [ 'https://abc.co.jp:8080/path?arg=value',
// 'https',
// 'abc.co.jp',
// ':8080',
// ':8080',
// '/path?arg=value',
// '/path?arg=value',
// index: 0,
// input: 'https://abc.co.jp:8080/path?arg=value'
// ]
//
// Input url : 'https://abc.co.jp/'
// matches : [ 'https://abc.co.jp/',
// 'https',
// 'abc.co.jp',
// '',
// undefined,
// '',
// undefined,
// index: 0,
// input: 'https://abc.co.jp/'
// ]
//
const reg_url = /^(https?):\/\/([a-z|A-Z|0-9|$|%|&|(|)|-|=|~|^|||@|+|.|_]+)((:[1-9]\d*)?)((\/.*)*)$/;
function rawIsSafeUrl(strurl)
{
if(!rawIsSafeString(strurl)){
return false;
}
if(null === strurl.match(reg_url)){
return false;
}
return true;
}
function rawParseUrl(strurl)
{
if(!rawIsSafeString(strurl)){
return null;
}
var matches = strurl.match(reg_url);
if(null === matches || rawIsEmptyArray(matches) || matches < 7){
return null;
}
var resobj = {};
resobj.https = rawCompareCaseString(matches[1], 'https');
resobj.host = matches[2];
resobj.path = matches[5];
if(rawIsSafeString(matches[3]) && !isNaN(matches[3].substr(1))){
resobj.port = parseInt(matches[3].substr(1));
}else{
resobj.port = resobj.https ? 443 : 80;
}
return resobj;
}
function rawCheckFileExist(file)
{
if(!rawIsSafeString(file)){
return false;
}
try{
fs.statSync(file);
}catch(err){ // eslint-disable-line no-unused-vars
return false;
}
return true;
}
function rawReadFileContents(file)
{
var contents = null;
if(!rawCheckFileExist(file)){
return contents;
}
try{
contents = fs.readFileSync(file).toString();
}catch(err){ // eslint-disable-line no-unused-vars
return contents;
}
return contents;
}
function rawCheckDir(path)
{
if(!rawIsSafeString(path)){
return false;
}
return fs.existsSync(path);
}
function rawCheckMakeDir(path)
{
if(rawCheckDir(path)){
return true;
}
if(!rawIsSafeString(path)){
return false;
}
try{
fs.mkdirSync(path);
}catch(err){ // eslint-disable-line no-unused-vars
return false;
}
return true;
}
//---------------------------------------------------------
// Exports
//---------------------------------------------------------
exports.isSafeEntity = function(data)
{
return rawIsSafeEntity(data);
};
exports.isSafeString = function(str)
{
return rawIsSafeString(str);
};
exports.isSafeStrings = function()
{
for(var cnt = 0; cnt < arguments.length; ++cnt){
if(!rawIsSafeString(arguments[cnt])){
return false;
}
}
return true;
};
exports.compareCaseString = function(str1, str2)
{
return rawCompareCaseString(str1, str2);
};
exports.hasPartString = function(strbase, sep, values, iscase)
{
return rawHasPartString(strbase, sep, values, iscase);
};
exports.getSafeString = function(str)
{
return rawGetSafeString(str);
};
exports.checkSimpleJSON = function(str)
{
return rawCheckSimpleJSON(str);
};
exports.parseJSON = function(str)
{
return rawParseJSON(str);
};
exports.isArray = function(arr)
{
return rawIsArray(arr);
};
exports.isEmptyArray = function(arr)
{
return rawIsEmptyArray(arr);
};
exports.getSafeArray = function(arr)
{
return rawGetSafeArray(arr);
};
exports.findStringInArray = function(arr, str)
{
return rawFindStringInArray(arr, str);
};
exports.addStringToArray = function(arr, str)
{
return rawAddStringToArray(arr, str);
};
exports.tryAddStringToArray = function(arr, str)
{
return rawTryAddStringToArray(arr, str);
};
exports.removeStringFromArray = function(arr, str)
{
return rawRemoveStringFromArray(arr, str);
};
exports.compareArray = function(arr1, arr2, strict)
{
return rawCompareArray(arr1, arr2, strict);
};
exports.mergeArray = function(arr1, arr2)
{
return rawMergeArray(arr1, arr2);
};
exports.getDeletingDifferenceArray = function(basearr, newarr)
{
return rawGetDiffArray(basearr, newarr, true);
};
exports.getAddingDifferenceArray = function(basearr, newarr)
{
return rawGetDiffArray(basearr, newarr, false);
};
exports.mergeObjects = function(obj1, obj2)
{
return rawMergeObjects(obj1, obj2);
};
exports.getUnixtime = function(base)
{
return convertUnixtime(base);
};
exports.calcExpire = function(expiredate)
{
var expire = convertUnixtime(expiredate) - convertUnixtime();
if(expire < 0){
expire = 0;
}
return expire;
};
exports.isExpired = function(base)
{
return (convertUnixtime(base) < convertUnixtime()); // base(UTC ISO 8601) < now
};
exports.convertISOStringToUnixtime = function(iso)
{
return rawConvertISOStringToUnixtime(iso);
};
exports.getExpireUnixtime = function(starttime, expiretime)
{
return rawGetExpireUnixtime(starttime, expiretime);
};
exports.getExpireUnixtimeFromISOStrings = function(startiso, expireiso)
{
return rawGetExpireUnixtimeFromISOStrings(startiso, expireiso);
};
exports.expandHierarchy = function(parent, children, separator)
{
return rawExpandHierarchy(parent, children, separator);
};
exports.getParentKey = function(parent, childkey, separator, allow_empty)
{
return rawGetParentKey(parent, childkey, separator, allow_empty);
};
exports.getParentPath = function(str, separator, allow_empty)
{
return rawGetParentPath(str, separator, allow_empty);
};
exports.getNormalizeParameter = function(parameter, regex_ptn, pattern)
{
return rawGetNormalizeParameter(parameter, regex_ptn, pattern);
};
exports.getBinUuid4 = function()
{
return rawGetBinUuid4();
};
exports.getStrUuid4 = function(binUuid4)
{
return rawGetStrUuid4(binUuid4);
};
exports.isSafeStrUuid4 = function(strUuid4)
{
return rawIsSafeStrUuid4(strUuid4);
};
exports.cvtStrToBinUuid4 = function(strUuid4)
{
return rawCvtStrToBinUuid4(strUuid4);
};
exports.makeToken256 = function(hiUuid4, lowUuid4, base)
{
return rawMakeToken256(hiUuid4, lowUuid4, base);
};
exports.makeStringToken256 = function(strHiUuid4, strLowUuid4, strBase)
{
return rawMakeStringToken256(strHiUuid4, strLowUuid4, strBase);
};
exports.cvtNumberStringToBinBuffer = function(strNumber, base, size)
{
return rawCvtNumberStringToBinBuffer(strNumber, base, size);
};
exports.cvtNumberStringToUuid4 = function(strNumber, base)
{
return rawCvtNumberStringToUuid4(strNumber, base);
};
exports.getClientIpAddress = function(req)
{
return rawGetClientIpAddress(req);
};
exports.compareRequestIpAddress = function(req, ip)
{
return rawCompareRequestIpAddress(req, ip);
};
exports.complementHostnameIpAddress = function(hostname, ip, callback)
{
return rawComplementHostnameIpAddress(hostname, ip, callback);
};
exports.isIpAddressString = function(host)
{
return rawIsIpAddressString(host);
};
exports.urlParse = function(strurl)
{
return rawUrlParse(strurl);
};
exports.isSafeUrl = function(strurl)
{
return rawIsSafeUrl(strurl);
};
exports.parseUrl = function(strurl)
{
return rawParseUrl(strurl);
};
exports.checkFileExist = function(file)
{
return rawCheckFileExist(file);
};
exports.readFileContents = function(file)
{
return rawReadFileContents(file);
};
exports.checkDir = function(path)
{
return rawCheckDir(path);
};
exports.checkMakeDir = function(path)
{
return rawCheckMakeDir(path);
};
/*
* 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
*/