@kenote/api-proxy
Version:
403 lines (402 loc) • 24 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseProps = exports.getEntrance = exports.getProxyResponse = void 0;
var config_1 = require("@kenote/config");
var rule_judgment_1 = __importDefault(require("rule-judgment"));
var lodash_1 = require("lodash");
var http_errors_1 = __importDefault(require("http-errors"));
var parse_string_1 = require("parse-string");
var http_1 = require("./http");
var socket_1 = require("./socket");
var utils_1 = require("./utils");
var js_yaml_1 = __importDefault(require("js-yaml"));
var path_1 = __importDefault(require("path"));
function getProxyResponse(entrance, payload) {
var _this = this;
return function (options) { return __awaiter(_this, void 0, void 0, function () {
var setting, serviceModules, logger, ctx, result, type, _a, name_1, args, httpProxy, ret, _b, code, _c, msgtype, requestType, serverTag, tag, tcpSocket, server;
var _d, _e, _f, _g, _h;
return __generator(this, function (_j) {
switch (_j.label) {
case 0:
setting = options.setting, serviceModules = options.serviceModules, logger = options.logger, ctx = options.ctx;
result = null;
type = 'application/octet-stream';
if (!(entrance === null || entrance === void 0 ? void 0 : entrance.service)) return [3, 2];
_a = entrance.service, name_1 = _a.name, args = _a.args;
ctx.payload = payload;
return [4, (0, utils_1.runService)(name_1, args)(serviceModules, ctx)];
case 1:
result = _j.sent();
return [3, 6];
case 2:
if (!(entrance === null || entrance === void 0 ? void 0 : entrance.httpProxy)) return [3, 4];
httpProxy = entrance.httpProxy;
if (httpProxy.method.toUpperCase() === 'GET') {
httpProxy.params = (0, lodash_1.merge)(httpProxy.params, payload);
}
else {
httpProxy.body = (0, lodash_1.merge)(httpProxy.body, payload);
}
if (payload.__TAG) {
httpProxy.url = "".concat(httpProxy.url, "/").concat(payload.__TAG);
}
return [4, (0, http_1.shellAsCurl)(httpProxy)];
case 3:
ret = _j.sent();
_b = __read((_e = (_d = ret.status) === null || _d === void 0 ? void 0 : _d.split(/\s+/)) !== null && _e !== void 0 ? _e : [], 2), code = _b[1];
if (code != '200') {
throw (0, http_errors_1.default)(500, ['HttpProxy:', (_f = ret.status) === null || _f === void 0 ? void 0 : _f.replace('404 OK', '404 Not Found')].join(''), { code: 1000 });
}
result = ret.body;
type = (0, utils_1.getHeader)('content-type')((_g = ret.headers) !== null && _g !== void 0 ? _g : []);
if ((0, config_1.isJson)(result.toString())) {
result = JSON.stringify(JSON.parse(result.toString()), null, 2);
}
if ((0, config_1.isYaml)(result.toString()) && entrance.native === 'json') {
result = JSON.stringify(js_yaml_1.default.load(result.toString()), null, 2);
}
return [3, 6];
case 4:
if (!(entrance === null || entrance === void 0 ? void 0 : entrance.socketProxy)) return [3, 6];
_c = entrance.socketProxy, msgtype = _c.msgtype, requestType = _c.requestType, serverTag = _c.serverTag;
tag = void 0;
tcpSocket = { port: 8080 };
server = [];
if ((0, lodash_1.isPlainObject)(serverTag)) {
tcpSocket = serverTag;
}
else if ((0, lodash_1.isString)(serverTag)) {
tag = serverTag;
}
if (setting) {
tcpSocket = (0, lodash_1.merge)(tcpSocket, setting === null || setting === void 0 ? void 0 : setting.tcpSocket);
server = (_h = setting.server) !== null && _h !== void 0 ? _h : [];
}
tcpSocket.logger = logger;
return [4, (0, socket_1.socketRequest)(msgtype, payload, requestType)({ tcpSocket: tcpSocket, server: server, tag: tag })];
case 5:
result = _j.sent();
_j.label = 6;
case 6:
result = (0, utils_1.parsePlainObject)(result, entrance === null || entrance === void 0 ? void 0 : entrance.parse)((0, lodash_1.get)(serviceModules, 'service.customize'));
if (entrance === null || entrance === void 0 ? void 0 : entrance.native) {
if ((0, lodash_1.isPlainObject)(result)) {
result = JSON.stringify(result, null, 2);
}
if ((0, lodash_1.isString)(result)) {
result = Buffer.from(result);
}
}
if ((0, lodash_1.isString)(result)) {
result = js_yaml_1.default.load(result);
}
return [2, [type, result]];
}
});
}); };
}
exports.getProxyResponse = getProxyResponse;
function getEntrance(options) {
var _this = this;
return function (ctx, pathname) { return __awaiter(_this, void 0, void 0, function () {
var channel, pathLabel, getUser, sandbox, channelPath, allEntrance, method, body, entrance, setting, serviceModules, whitelist, signuserOpts, __TAG, signuser, openapi, authentication, _a, _b, _c, key, val, original, target, _d, authenticationState, isUser, payload, sign, timestamp, tokenOpts, valid, valid;
var e_1, _e;
var _f, _g, _h, _j, _k, _l;
return __generator(this, function (_m) {
switch (_m.label) {
case 0:
channel = options.channel, pathLabel = options.pathLabel, getUser = options.getUser, sandbox = options.sandbox;
channelPath = path_1.default.resolve(process.cwd(), pathname, channel);
allEntrance = (0, config_1.loadConfig)([pathname, channel, 'api'].join('/'), { type: 'array' });
method = ctx.method;
body = method === 'GET' ? ctx.query : ctx.body;
entrance = allEntrance === null || allEntrance === void 0 ? void 0 : allEntrance.find(function (v) { return v.router.find((0, rule_judgment_1.default)({ method: method, path: pathLabel })); });
if (!entrance)
return [2, { notFound: true }];
setting = (0, config_1.loadConfig)([pathname, channel, 'setting'].join('/'), { mode: 'merge' });
return [4, (0, utils_1.getServiceModules)({
cwd: path_1.default.resolve(channelPath, 'js'),
sandbox: sandbox,
alias: setting === null || setting === void 0 ? void 0 : setting.jsAlias
})];
case 1:
serviceModules = _m.sent();
whitelist = (0, lodash_1.uniq)((0, lodash_1.compact)((0, lodash_1.concat)(setting === null || setting === void 0 ? void 0 : setting.whitelist, entrance === null || entrance === void 0 ? void 0 : entrance.whitelist)));
if (whitelist.length > 0 && !whitelist.find(function (v) { return new RegExp(v).test(clientIP(ctx)); })) {
throw (0, http_errors_1.default)(500, '没有访问该页面的权限', { code: 1000 });
}
signuserOpts = setting.signuserOpts;
__TAG = (0, lodash_1.get)(ctx.params, 'tag');
signuser = signuserOpts === null || signuserOpts === void 0 ? void 0 : signuserOpts.user.find(function (v) { var _a; return v.id == __TAG && ((_a = v.openapi) === null || _a === void 0 ? void 0 : _a.includes(entrance === null || entrance === void 0 ? void 0 : entrance.name)); });
if (signuser && !((_f = entrance === null || entrance === void 0 ? void 0 : entrance.authentication) === null || _f === void 0 ? void 0 : _f.find(function (v) { return v.type == 'sign'; }))) {
openapi = signuserOpts === null || signuserOpts === void 0 ? void 0 : signuserOpts.openapi.find(function (v) { return v.name == (entrance === null || entrance === void 0 ? void 0 : entrance.name); });
authentication = {
type: 'sign',
sign: {
field: 'sign',
md5: openapi === null || openapi === void 0 ? void 0 : openapi.valid,
token: [
{
key: signuser.token,
name: signuser.name,
tags: [String(signuser.id)]
}
]
}
};
if (!entrance.authentication)
entrance.authentication = [];
entrance.authentication.push(authentication);
if (openapi === null || openapi === void 0 ? void 0 : openapi.props) {
try {
for (_a = __values(Object.entries(openapi === null || openapi === void 0 ? void 0 : openapi.props)), _b = _a.next(); !_b.done; _b = _a.next()) {
_c = __read(_b.value, 2), key = _c[0], val = _c[1];
original = (0, lodash_1.isArray)((0, lodash_1.get)(body, key)) ? (0, lodash_1.get)(body, key) : String((0, lodash_1.get)(body, key)).split(',');
if (!(0, lodash_1.get)(signuser.optional, val))
continue;
target = (0, lodash_1.intersection)((0, lodash_1.get)(signuser.optional, val), original);
if (!(0, lodash_1.isArray)((0, lodash_1.get)(body, key))) {
target = target.join(',');
}
(0, lodash_1.set)(body, key, target);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
}
finally { if (e_1) throw e_1.error; }
}
}
if (openapi === null || openapi === void 0 ? void 0 : openapi.fields) {
(0, lodash_1.set)(entrance, 'payload', (0, lodash_1.concat)(entrance.payload, openapi.fields));
}
}
return [4, useAuthentication(entrance, getUser)];
case 2:
_d = _m.sent(), authenticationState = _d.authenticationState, isUser = _d.isUser;
payload = entrance.payload ? (0, parse_string_1.filterData)(entrance.payload, serviceModules)(body) : body;
if (__TAG) {
(0, lodash_1.set)(payload, '__TAG', __TAG);
}
if ((authenticationState === null || authenticationState === void 0 ? void 0 : authenticationState.type) === 'sign' && !((_g = authenticationState.sign) === null || _g === void 0 ? void 0 : _g.debug)) {
sign = authenticationState.sign;
if (signuserOpts === null || signuserOpts === void 0 ? void 0 : signuserOpts.timestamp) {
timestamp = Number((0, lodash_1.get)(payload, signuserOpts.timestamp.field));
if (Number.isNaN(timestamp)) {
timestamp = 0;
}
if (Date.now() < timestamp) {
throw (0, http_errors_1.default)(500, 'MD5验签失败', { code: 1000 });
}
if (Date.now() - timestamp > ((_h = signuserOpts.timestamp.timeout) !== null && _h !== void 0 ? _h : 1000)) {
throw (0, http_errors_1.default)(500, 'MD5验签失败', { code: 1000 });
}
}
if ((0, lodash_1.isArray)(sign === null || sign === void 0 ? void 0 : sign.token)) {
tokenOpts = __TAG ? sign === null || sign === void 0 ? void 0 : sign.token.find((0, rule_judgment_1.default)({ tags: { $_in: __TAG } })) : (0, lodash_1.get)(sign === null || sign === void 0 ? void 0 : sign.token, 0);
valid = tokenOpts && (0, parse_string_1.validSign)(sign === null || sign === void 0 ? void 0 : sign.md5, sign === null || sign === void 0 ? void 0 : sign.field)((0, lodash_1.merge)(payload, { key: tokenOpts === null || tokenOpts === void 0 ? void 0 : tokenOpts.key }));
if (!valid) {
throw (0, http_errors_1.default)(500, 'MD5验签失败', { code: 1000 });
}
}
else {
valid = (0, parse_string_1.validSign)(sign === null || sign === void 0 ? void 0 : sign.md5, sign === null || sign === void 0 ? void 0 : sign.field)((0, lodash_1.merge)(payload, { key: sign === null || sign === void 0 ? void 0 : sign.token }));
if (!valid) {
throw (0, http_errors_1.default)(500, 'MD5验签失败', { code: 1000 });
}
}
}
if ((authenticationState === null || authenticationState === void 0 ? void 0 : authenticationState.type) === 'jwt') {
if (isUser === false) {
throw (0, http_errors_1.default)(500, '没有访问该页面的权限', { code: 1000 });
}
}
payload = (0, lodash_1.omit)(parseProps(entrance.props)(payload), (authenticationState === null || authenticationState === void 0 ? void 0 : authenticationState.type) === 'sign'
? [(_k = (_j = authenticationState === null || authenticationState === void 0 ? void 0 : authenticationState.sign) === null || _j === void 0 ? void 0 : _j.field) !== null && _k !== void 0 ? _k : 'sign']
: []);
serviceModules.payload = payload;
if (entrance.httpProxy) {
entrance.native = (_l = entrance.native) !== null && _l !== void 0 ? _l : true;
}
return [2, { isUser: isUser, payload: payload, entrance: entrance, setting: setting, authenticationState: authenticationState, channelPath: channelPath, serviceModules: serviceModules }];
}
});
}); };
}
exports.getEntrance = getEntrance;
function useAuthentication(entrance, getUser) {
var _a, _b, _c, _d;
return __awaiter(this, void 0, void 0, function () {
var authenticationState, isUser, _e, _f, authentication, user, e_2_1;
var e_2, _g;
return __generator(this, function (_h) {
switch (_h.label) {
case 0:
authenticationState = null;
isUser = false;
if (!entrance.authentication) return [3, 9];
_h.label = 1;
case 1:
_h.trys.push([1, 7, 8, 9]);
_e = __values(entrance.authentication), _f = _e.next();
_h.label = 2;
case 2:
if (!!_f.done) return [3, 6];
authentication = _f.value;
authenticationState = authentication;
if (!(authentication.type === 'jwt')) return [3, 4];
return [4, getUser()];
case 3:
user = _h.sent();
if (user) {
isUser = (0, rule_judgment_1.default)(__assign({}, authentication.jwt))(user);
if (isUser)
return [3, 6];
}
else {
isUser = 'Unauthorized';
}
_h.label = 4;
case 4:
if (authentication.type === 'sign') {
(_a = entrance.payload) === null || _a === void 0 ? void 0 : _a.push({
key: (_c = (_b = authentication.sign) === null || _b === void 0 ? void 0 : _b.field) !== null && _c !== void 0 ? _c : 'sign',
type: 'string',
rules: ((_d = authentication.sign) === null || _d === void 0 ? void 0 : _d.debug) ? undefined : [
{ required: true, message: '缺少验签', code: 1000 }
],
});
}
_h.label = 5;
case 5:
_f = _e.next();
return [3, 2];
case 6: return [3, 9];
case 7:
e_2_1 = _h.sent();
e_2 = { error: e_2_1 };
return [3, 9];
case 8:
try {
if (_f && !_f.done && (_g = _e.return)) _g.call(_e);
}
finally { if (e_2) throw e_2.error; }
return [7];
case 9: return [2, { authenticationState: authenticationState, isUser: isUser }];
}
});
});
}
function parseProps(props) {
return function (data, tag) {
var e_3, _a, _b;
if (tag === void 0) { tag = 'payload'; }
if (!props)
return data;
var result = data;
var keys = [];
try {
for (var _c = __values(Object.entries(props)), _d = _c.next(); !_d.done; _d = _c.next()) {
var _e = __read(_d.value, 2), key = _e[0], val = _e[1];
var value = (0, lodash_1.get)((_b = {}, _b[tag] = data, _b), val);
if (value !== undefined)
result[key] = value;
if (key !== val)
keys.push(val);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_3) throw e_3.error; }
}
return (0, lodash_1.pick)(result, Object.keys(props));
};
}
exports.parseProps = parseProps;
function clientIP(ctx) {
var _a, _b, _c, _d;
return (_d = (_c = (_b = (_a = (0, lodash_1.get)(ctx.headers, 'x-forwarded-for')) !== null && _a !== void 0 ? _a : (0, lodash_1.get)(ctx.headers, 'x-real-ip')) !== null && _b !== void 0 ? _b : ctx.connection.remoteAddress) !== null && _c !== void 0 ? _c : ctx.req.socket.remoteAddress) !== null && _d !== void 0 ? _d : ctx.ip;
}