@stuntman/server 0.1.7 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/api.d.ts +25 -0
- package/dist/api/api.d.ts.map +1 -0
- package/dist/api/api.js +212 -0
- package/dist/api/api.js.map +1 -0
- package/dist/api/utils.d.ts +5 -0
- package/dist/api/utils.d.ts.map +1 -0
- package/dist/api/utils.js +61 -0
- package/dist/api/utils.js.map +1 -0
- package/dist/api/validators.d.ts +4 -0
- package/dist/api/validators.d.ts.map +1 -0
- package/dist/api/validators.js +125 -0
- package/dist/api/validators.js.map +1 -0
- package/dist/api/webgui/rules.pug +147 -0
- package/dist/api/webgui/style.css +28 -0
- package/dist/api/webgui/traffic.pug +38 -0
- package/dist/bin/stuntman.d.ts +3 -0
- package/dist/bin/stuntman.d.ts.map +1 -0
- package/dist/bin/stuntman.js +8 -0
- package/dist/bin/stuntman.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/ipUtils.d.ts +18 -0
- package/dist/ipUtils.d.ts.map +1 -0
- package/dist/ipUtils.js +102 -0
- package/dist/ipUtils.js.map +1 -0
- package/dist/mock.d.ts +32 -0
- package/dist/mock.d.ts.map +1 -0
- package/dist/mock.js +306 -0
- package/dist/mock.js.map +1 -0
- package/dist/requestContext.d.ts +10 -0
- package/dist/requestContext.d.ts.map +1 -0
- package/dist/requestContext.js +19 -0
- package/dist/requestContext.js.map +1 -0
- package/dist/ruleExecutor.d.ts +23 -0
- package/dist/ruleExecutor.d.ts.map +1 -0
- package/dist/ruleExecutor.js +189 -0
- package/dist/ruleExecutor.js.map +1 -0
- package/dist/rules/catchAll.d.ts +3 -0
- package/dist/rules/catchAll.d.ts.map +1 -0
- package/dist/rules/catchAll.js +16 -0
- package/dist/rules/catchAll.js.map +1 -0
- package/dist/rules/echo.d.ts +3 -0
- package/dist/rules/echo.d.ts.map +1 -0
- package/dist/rules/echo.js +16 -0
- package/dist/rules/echo.js.map +1 -0
- package/dist/rules/index.d.ts +4 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +71 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/storage.d.ts +5 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +43 -0
- package/dist/storage.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import http from 'http';
|
|
3
|
+
import { NextFunction, Request, Response, Express as ExpressServer } from 'express';
|
|
4
|
+
import type * as Stuntman from '@stuntman/shared';
|
|
5
|
+
import LRUCache from 'lru-cache';
|
|
6
|
+
type ApiOptions = Stuntman.ApiConfig & {
|
|
7
|
+
mockUuid: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class API {
|
|
10
|
+
protected options: Required<ApiOptions>;
|
|
11
|
+
protected webGuiOptions: Stuntman.WebGuiConfig;
|
|
12
|
+
protected apiApp: ExpressServer | null;
|
|
13
|
+
trafficStore: LRUCache<string, Stuntman.LogEntry>;
|
|
14
|
+
server: http.Server | null;
|
|
15
|
+
constructor(options: ApiOptions, webGuiOptions?: Stuntman.WebGuiConfig);
|
|
16
|
+
private auth;
|
|
17
|
+
protected authReadOnly(req: Request, _res: Response, next: NextFunction): void;
|
|
18
|
+
protected authReadWrite(req: Request, _res: Response, next: NextFunction): void;
|
|
19
|
+
private initApi;
|
|
20
|
+
private initWebGui;
|
|
21
|
+
start(): void;
|
|
22
|
+
stop(): void;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api/api.ts"],"names":[],"mappings":";AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAK7F,OAAO,KAAK,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAGlD,OAAO,QAAQ,MAAM,WAAW,CAAC;AAIjC,KAAK,UAAU,GAAG,QAAQ,CAAC,SAAS,GAAG;IACnC,QAAQ,EAAE,MAAM,CAAC;CACpB,CAAC;AAIF,qBAAa,GAAG;IACZ,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxC,SAAS,CAAC,aAAa,EAAE,QAAQ,CAAC,YAAY,CAAC;IAC/C,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAQ;IAC9C,YAAY,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClD,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAQ;gBAEtB,OAAO,EAAE,UAAU,EAAE,aAAa,GAAE,QAAQ,CAAC,YAAkC;IAa3F,OAAO,CAAC,IAAI;IAaZ,SAAS,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IAK9E,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI;IAK/E,OAAO,CAAC,OAAO;IA+Gf,OAAO,CAAC,UAAU;IAwDX,KAAK;IAaL,IAAI;CASd"}
|
package/dist/api/api.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.API = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const uuid_1 = require("uuid");
|
|
9
|
+
const storage_1 = require("../storage");
|
|
10
|
+
const ruleExecutor_1 = require("../ruleExecutor");
|
|
11
|
+
const shared_1 = require("@stuntman/shared");
|
|
12
|
+
const requestContext_1 = __importDefault(require("../requestContext"));
|
|
13
|
+
const serialize_javascript_1 = __importDefault(require("serialize-javascript"));
|
|
14
|
+
const validators_1 = require("./validators");
|
|
15
|
+
const utils_1 = require("./utils");
|
|
16
|
+
const API_KEY_HEADER = 'x-api-key';
|
|
17
|
+
class API {
|
|
18
|
+
constructor(options, webGuiOptions = { disabled: false }) {
|
|
19
|
+
this.apiApp = null;
|
|
20
|
+
this.server = null;
|
|
21
|
+
if (!options.apiKeyReadOnly !== !options.apiKeyReadWrite) {
|
|
22
|
+
throw new Error('apiKeyReadOnly and apiKeyReadWrite options need to be set either both or none');
|
|
23
|
+
}
|
|
24
|
+
this.options = options;
|
|
25
|
+
this.webGuiOptions = webGuiOptions;
|
|
26
|
+
this.trafficStore = (0, storage_1.getTrafficStore)(this.options.mockUuid);
|
|
27
|
+
this.auth = this.auth.bind(this);
|
|
28
|
+
this.authReadOnly = this.authReadOnly.bind(this);
|
|
29
|
+
this.authReadWrite = this.authReadWrite.bind(this);
|
|
30
|
+
}
|
|
31
|
+
auth(req, type) {
|
|
32
|
+
if (!this.options.apiKeyReadOnly && !this.options.apiKeyReadWrite) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const hasValidReadKey = req.header(API_KEY_HEADER) === this.options.apiKeyReadOnly;
|
|
36
|
+
const hasValidWriteKey = req.header(API_KEY_HEADER) === this.options.apiKeyReadWrite;
|
|
37
|
+
const hasValidKey = type === 'read' ? hasValidReadKey || hasValidWriteKey : hasValidWriteKey;
|
|
38
|
+
if (!hasValidKey) {
|
|
39
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.UNAUTHORIZED, message: 'unauthorized' });
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
authReadOnly(req, _res, next) {
|
|
44
|
+
this.auth(req, 'read');
|
|
45
|
+
next();
|
|
46
|
+
}
|
|
47
|
+
authReadWrite(req, _res, next) {
|
|
48
|
+
this.auth(req, 'write');
|
|
49
|
+
next();
|
|
50
|
+
}
|
|
51
|
+
initApi() {
|
|
52
|
+
this.apiApp = (0, express_1.default)();
|
|
53
|
+
this.apiApp.use(express_1.default.json());
|
|
54
|
+
this.apiApp.use(express_1.default.text());
|
|
55
|
+
this.apiApp.use((req, _res, next) => {
|
|
56
|
+
requestContext_1.default.bind(req, this.options.mockUuid);
|
|
57
|
+
next();
|
|
58
|
+
});
|
|
59
|
+
this.apiApp.get('/rule', this.authReadOnly.bind, async (_req, res) => {
|
|
60
|
+
res.send((0, shared_1.stringify)(await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).getRules()));
|
|
61
|
+
});
|
|
62
|
+
this.apiApp.get('/rule/:ruleId', this.authReadOnly, async (req, res) => {
|
|
63
|
+
if (!req.params.ruleId) {
|
|
64
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'missing ruleId' });
|
|
65
|
+
}
|
|
66
|
+
res.send((0, shared_1.stringify)(await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).getRule(req.params.ruleId)));
|
|
67
|
+
});
|
|
68
|
+
this.apiApp.get('/rule/:ruleId/disable', this.authReadWrite, (req, res) => {
|
|
69
|
+
if (!req.params.ruleId) {
|
|
70
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'missing ruleId' });
|
|
71
|
+
}
|
|
72
|
+
(0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).disableRule(req.params.ruleId);
|
|
73
|
+
res.send();
|
|
74
|
+
});
|
|
75
|
+
this.apiApp.get('/rule/:ruleId/enable', this.authReadWrite, (req, res) => {
|
|
76
|
+
if (!req.params.ruleId) {
|
|
77
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'missing ruleId' });
|
|
78
|
+
}
|
|
79
|
+
(0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).enableRule(req.params.ruleId);
|
|
80
|
+
res.send();
|
|
81
|
+
});
|
|
82
|
+
this.apiApp.post('/rule', this.authReadWrite, async (req, res) => {
|
|
83
|
+
const deserializedRule = (0, utils_1.deserializeRule)(req.body);
|
|
84
|
+
(0, validators_1.validateDeserializedRule)(deserializedRule);
|
|
85
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
86
|
+
// @ts-ignore
|
|
87
|
+
const rule = await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).addRule(deserializedRule);
|
|
88
|
+
res.send((0, shared_1.stringify)(rule));
|
|
89
|
+
});
|
|
90
|
+
this.apiApp.get('/rule/:ruleId/remove', this.authReadWrite, async (req, res) => {
|
|
91
|
+
if (!req.params.ruleId) {
|
|
92
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'missing ruleId' });
|
|
93
|
+
}
|
|
94
|
+
await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).removeRule(req.params.ruleId);
|
|
95
|
+
res.send();
|
|
96
|
+
});
|
|
97
|
+
this.apiApp.get('/traffic', this.authReadOnly, (_req, res) => {
|
|
98
|
+
const serializedTraffic = [];
|
|
99
|
+
for (const value of this.trafficStore.values()) {
|
|
100
|
+
serializedTraffic.push(value);
|
|
101
|
+
}
|
|
102
|
+
res.json(serializedTraffic);
|
|
103
|
+
});
|
|
104
|
+
this.apiApp.get('/traffic/:ruleIdOrLabel', this.authReadOnly, (req, res) => {
|
|
105
|
+
if (!req.params.ruleIdOrLabel) {
|
|
106
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'missing ruleIdOrLabel' });
|
|
107
|
+
}
|
|
108
|
+
const serializedTraffic = [];
|
|
109
|
+
for (const value of this.trafficStore.values()) {
|
|
110
|
+
if (value.mockRuleId === req.params.ruleIdOrLabel || (value.labels || []).includes(req.params.ruleIdOrLabel)) {
|
|
111
|
+
serializedTraffic.push(value);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
res.json(serializedTraffic);
|
|
115
|
+
});
|
|
116
|
+
if (!this.webGuiOptions.disabled) {
|
|
117
|
+
this.apiApp.set('views', __dirname + '/webgui');
|
|
118
|
+
this.apiApp.set('view engine', 'pug');
|
|
119
|
+
this.initWebGui();
|
|
120
|
+
}
|
|
121
|
+
this.apiApp.all(/.*/, (_req, res) => res.status(404).send());
|
|
122
|
+
this.apiApp.use((error, req, res) => {
|
|
123
|
+
const ctx = requestContext_1.default.get(req);
|
|
124
|
+
const uuid = (ctx === null || ctx === void 0 ? void 0 : ctx.uuid) || (0, uuid_1.v4)();
|
|
125
|
+
if (error instanceof shared_1.AppError && error.isOperational && res) {
|
|
126
|
+
shared_1.logger.error(error);
|
|
127
|
+
res.status(error.httpCode).json({
|
|
128
|
+
error: { message: error.message, httpCode: error.httpCode, stack: error.stack },
|
|
129
|
+
});
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
shared_1.logger.error({ message: error.message, stack: error.stack, name: error.name, uuid }, 'unexpected error');
|
|
133
|
+
if (res) {
|
|
134
|
+
res.status(shared_1.HttpCode.INTERNAL_SERVER_ERROR).json({
|
|
135
|
+
error: { message: error.message, httpCode: shared_1.HttpCode.INTERNAL_SERVER_ERROR, uuid },
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// eslint-disable-next-line no-console
|
|
140
|
+
console.log('API server encountered a critical error. Exiting');
|
|
141
|
+
process.exit(1);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
initWebGui() {
|
|
145
|
+
if (!this.apiApp) {
|
|
146
|
+
throw new Error('initialization error');
|
|
147
|
+
}
|
|
148
|
+
this.apiApp.get('/webgui/rules', this.authReadOnly, async (_req, res) => {
|
|
149
|
+
const rules = {};
|
|
150
|
+
for (const rule of await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).getRules()) {
|
|
151
|
+
rules[rule.id] = (0, serialize_javascript_1.default)((0, utils_1.liveRuleToRule)(rule), { unsafe: true });
|
|
152
|
+
}
|
|
153
|
+
res.render('rules', { rules: (0, utils_1.escapedSerialize)(rules), INDEX_DTS: shared_1.INDEX_DTS, ruleKeys: Object.keys(rules) });
|
|
154
|
+
});
|
|
155
|
+
this.apiApp.get('/webgui/traffic', this.authReadOnly, async (_req, res) => {
|
|
156
|
+
const serializedTraffic = [];
|
|
157
|
+
for (const value of this.trafficStore.values()) {
|
|
158
|
+
serializedTraffic.push(value);
|
|
159
|
+
}
|
|
160
|
+
res.render('traffic', {
|
|
161
|
+
traffic: JSON.stringify(serializedTraffic.sort((a, b) => b.originalRequest.timestamp - a.originalRequest.timestamp)),
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
// TODO make webui way better and safer, nicer formatting, eslint/prettier, blackjack and hookers
|
|
165
|
+
this.apiApp.post('/webgui/rules/unsafesave', this.authReadWrite, async (req, res) => {
|
|
166
|
+
const rule = new Function(req.body)();
|
|
167
|
+
if (!rule ||
|
|
168
|
+
!rule.id ||
|
|
169
|
+
typeof rule.matches !== 'function' ||
|
|
170
|
+
typeof rule.ttlSeconds !== 'number' ||
|
|
171
|
+
rule.ttlSeconds > shared_1.MAX_RULE_TTL_SECONDS) {
|
|
172
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'Invalid rule' });
|
|
173
|
+
}
|
|
174
|
+
await (0, ruleExecutor_1.getRuleExecutor)(this.options.mockUuid).addRule({
|
|
175
|
+
id: rule.id,
|
|
176
|
+
matches: rule.matches,
|
|
177
|
+
ttlSeconds: rule.ttlSeconds,
|
|
178
|
+
actions: rule.actions,
|
|
179
|
+
...(rule.disableAfterUse !== undefined && { disableAfterUse: rule.disableAfterUse }),
|
|
180
|
+
...(rule.isEnabled !== undefined && { isEnabled: rule.isEnabled }),
|
|
181
|
+
...(rule.labels !== undefined && { labels: rule.labels }),
|
|
182
|
+
...(rule.priority !== undefined && { priority: rule.priority }),
|
|
183
|
+
...(rule.removeAfterUse !== undefined && { removeAfterUse: rule.removeAfterUse }),
|
|
184
|
+
...(rule.storeTraffic !== undefined && { storeTraffic: rule.storeTraffic }),
|
|
185
|
+
}, true);
|
|
186
|
+
res.send();
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
start() {
|
|
190
|
+
if (this.server) {
|
|
191
|
+
throw new Error('mock server already started');
|
|
192
|
+
}
|
|
193
|
+
this.initApi();
|
|
194
|
+
if (!this.apiApp) {
|
|
195
|
+
throw new Error('initialization error');
|
|
196
|
+
}
|
|
197
|
+
this.server = this.apiApp.listen(this.options.port, () => {
|
|
198
|
+
shared_1.logger.info(`API listening on ${this.options.port}`);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
stop() {
|
|
202
|
+
if (!this.server) {
|
|
203
|
+
throw new Error('mock server not started');
|
|
204
|
+
}
|
|
205
|
+
this.server.close((error) => {
|
|
206
|
+
shared_1.logger.warn(error, 'problem closing server');
|
|
207
|
+
this.server = null;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.API = API;
|
|
212
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type * as Stuntman from '@stuntman/shared';
|
|
2
|
+
export declare const deserializeRule: (serializedRule: Stuntman.SerializedRule) => Stuntman.Rule;
|
|
3
|
+
export declare const escapedSerialize: (obj: any) => string;
|
|
4
|
+
export declare const liveRuleToRule: (liveRule: Stuntman.LiveRule) => Stuntman.Rule;
|
|
5
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAKlD,eAAO,MAAM,eAAe,mBAAoB,SAAS,cAAc,KAAG,SAAS,IAgDlF,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAS,GAAG,WAC2D,CAAC;AAErG,eAAO,MAAM,cAAc,aAAc,SAAS,QAAQ,kBASzD,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.liveRuleToRule = exports.escapedSerialize = exports.deserializeRule = void 0;
|
|
7
|
+
const serialize_javascript_1 = __importDefault(require("serialize-javascript"));
|
|
8
|
+
const shared_1 = require("@stuntman/shared");
|
|
9
|
+
const validators_1 = require("./validators");
|
|
10
|
+
// TODO
|
|
11
|
+
const deserializeRule = (serializedRule) => {
|
|
12
|
+
shared_1.logger.debug(serializedRule, 'attempt to deserialize rule');
|
|
13
|
+
(0, validators_1.validateSerializedRuleProperties)(serializedRule);
|
|
14
|
+
const rule = {
|
|
15
|
+
id: serializedRule.id,
|
|
16
|
+
matches: (req) => new Function('____arg0', serializedRule.matches.remoteFn)(req),
|
|
17
|
+
ttlSeconds: serializedRule.ttlSeconds,
|
|
18
|
+
actions: { mockResponse: { status: 200 } },
|
|
19
|
+
...(serializedRule.disableAfterUse !== undefined && { disableAfterUse: serializedRule.disableAfterUse }),
|
|
20
|
+
...(serializedRule.removeAfterUse !== undefined && { removeAfterUse: serializedRule.removeAfterUse }),
|
|
21
|
+
...(serializedRule.labels !== undefined && { labels: serializedRule.labels }),
|
|
22
|
+
...(serializedRule.priority !== undefined && { priority: serializedRule.priority }),
|
|
23
|
+
...(serializedRule.isEnabled !== undefined && { isEnabled: serializedRule.isEnabled }),
|
|
24
|
+
...(serializedRule.storeTraffic !== undefined && { storeTraffic: serializedRule.storeTraffic }),
|
|
25
|
+
};
|
|
26
|
+
// TODO store the original localFn and variables sent from client for web UI editing maybe
|
|
27
|
+
if (serializedRule.actions.mockResponse) {
|
|
28
|
+
rule.actions = {
|
|
29
|
+
mockResponse: 'remoteFn' in serializedRule.actions.mockResponse
|
|
30
|
+
? (req) => new Function('____arg0', serializedRule.actions.mockResponse.remoteFn)(req)
|
|
31
|
+
: serializedRule.actions.mockResponse,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
rule.actions = {
|
|
36
|
+
...(serializedRule.actions.modifyRequest && {
|
|
37
|
+
modifyRequest: ((req) => new Function('____arg0', serializedRule.actions.modifyRequest.remoteFn)(req)),
|
|
38
|
+
}),
|
|
39
|
+
...(serializedRule.actions.modifyResponse && {
|
|
40
|
+
modifyResponse: ((req, res) => new Function('____arg0', '____arg1', serializedRule.actions.modifyResponse.remoteFn)(req, res)),
|
|
41
|
+
}),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
shared_1.logger.debug(rule, 'deserialized rule');
|
|
45
|
+
return rule;
|
|
46
|
+
};
|
|
47
|
+
exports.deserializeRule = deserializeRule;
|
|
48
|
+
const escapedSerialize = (obj) => (0, serialize_javascript_1.default)(obj).replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/\n/g, "\\n'\n+ '");
|
|
49
|
+
exports.escapedSerialize = escapedSerialize;
|
|
50
|
+
const liveRuleToRule = (liveRule) => {
|
|
51
|
+
const ruleClone = { ...liveRule };
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
53
|
+
// @ts-ignore
|
|
54
|
+
delete ruleClone.counter;
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
56
|
+
// @ts-ignore
|
|
57
|
+
delete ruleClone.createdTimestamp;
|
|
58
|
+
return ruleClone;
|
|
59
|
+
};
|
|
60
|
+
exports.liveRuleToRule = liveRuleToRule;
|
|
61
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/api/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type * as Stuntman from '@stuntman/shared';
|
|
2
|
+
export declare const validateSerializedRuleProperties: (rule: Stuntman.SerializedRule) => void;
|
|
3
|
+
export declare const validateDeserializedRule: (deserializedRule: Stuntman.Rule) => void;
|
|
4
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/api/validators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAElD,eAAO,MAAM,gCAAgC,SAAU,SAAS,cAAc,KAAG,IAmGhF,CAAC;AAEF,eAAO,MAAM,wBAAwB,qBAAsB,SAAS,IAAI,SA2BvE,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateDeserializedRule = exports.validateSerializedRuleProperties = void 0;
|
|
4
|
+
const shared_1 = require("@stuntman/shared");
|
|
5
|
+
const validateSerializedRuleProperties = (rule) => {
|
|
6
|
+
if (!rule) {
|
|
7
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid serialized rule' });
|
|
8
|
+
}
|
|
9
|
+
if (typeof rule.id !== 'string') {
|
|
10
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.id' });
|
|
11
|
+
}
|
|
12
|
+
if (typeof rule.matches !== 'object' || !('remoteFn' in rule.matches) || typeof rule.matches.remoteFn !== 'string') {
|
|
13
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.matches' });
|
|
14
|
+
}
|
|
15
|
+
if (rule.priority && typeof rule.priority !== 'number') {
|
|
16
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.priority' });
|
|
17
|
+
}
|
|
18
|
+
if (typeof rule.actions !== 'object') {
|
|
19
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions - not an object' });
|
|
20
|
+
}
|
|
21
|
+
if (rule.actions.proxyPass !== true &&
|
|
22
|
+
typeof rule.actions.mockResponse !== 'object' &&
|
|
23
|
+
typeof rule.actions.modifyRequest !== 'object' &&
|
|
24
|
+
typeof rule.actions.modifyResponse !== 'object') {
|
|
25
|
+
throw new shared_1.AppError({
|
|
26
|
+
httpCode: shared_1.HttpCode.BAD_REQUEST,
|
|
27
|
+
message: 'invalid rule.actions - missing one of: proxyPass, mockResponse, modifyRequest, modifyResponse',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (typeof rule.actions.mockResponse !== 'undefined') {
|
|
31
|
+
if (typeof rule.actions.mockResponse !== 'object') {
|
|
32
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions.mockResponse' });
|
|
33
|
+
}
|
|
34
|
+
if ('remoteFn' in rule.actions.mockResponse && typeof rule.actions.mockResponse.remoteFn !== 'string') {
|
|
35
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions.mockResponse' });
|
|
36
|
+
}
|
|
37
|
+
else if ('status' in rule.actions.mockResponse) {
|
|
38
|
+
if (typeof rule.actions.mockResponse.status !== 'number') {
|
|
39
|
+
throw new shared_1.AppError({
|
|
40
|
+
httpCode: shared_1.HttpCode.BAD_REQUEST,
|
|
41
|
+
message: 'invalid rule.actions.mockResponse.status',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (typeof rule.actions.mockResponse.rawHeaders !== 'undefined' &&
|
|
45
|
+
(!Array.isArray(rule.actions.mockResponse.rawHeaders) ||
|
|
46
|
+
rule.actions.mockResponse.rawHeaders.some((header) => typeof header !== 'string'))) {
|
|
47
|
+
throw new shared_1.AppError({
|
|
48
|
+
httpCode: shared_1.HttpCode.BAD_REQUEST,
|
|
49
|
+
message: 'invalid rule.actions.mockResponse.rawHeaders',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (typeof rule.actions.mockResponse.body !== 'undefined' && typeof rule.actions.mockResponse.body !== 'string') {
|
|
53
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions.mockResponse.body' });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (typeof rule.actions.modifyRequest !== 'undefined' && typeof rule.actions.modifyRequest.remoteFn !== 'string') {
|
|
58
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions.modifyRequest' });
|
|
59
|
+
}
|
|
60
|
+
if (typeof rule.actions.modifyResponse !== 'undefined' && typeof rule.actions.modifyResponse.remoteFn !== 'string') {
|
|
61
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.actions.modifyResponse' });
|
|
62
|
+
}
|
|
63
|
+
if (typeof rule.disableAfterUse !== 'undefined' &&
|
|
64
|
+
typeof rule.disableAfterUse !== 'boolean' &&
|
|
65
|
+
(typeof rule.disableAfterUse !== 'number' || rule.disableAfterUse < 0)) {
|
|
66
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.disableAfterUse' });
|
|
67
|
+
}
|
|
68
|
+
if (typeof rule.removeAfterUse !== 'undefined' &&
|
|
69
|
+
typeof rule.removeAfterUse !== 'boolean' &&
|
|
70
|
+
(typeof rule.removeAfterUse !== 'number' || rule.removeAfterUse < 0)) {
|
|
71
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.removeAfterUse' });
|
|
72
|
+
}
|
|
73
|
+
if (typeof rule.labels !== 'undefined' &&
|
|
74
|
+
(!Array.isArray(rule.labels) || rule.labels.some((label) => typeof label !== 'string'))) {
|
|
75
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.labels' });
|
|
76
|
+
}
|
|
77
|
+
if (rule.actions.mockResponse && rule.actions.modifyResponse) {
|
|
78
|
+
throw new shared_1.AppError({
|
|
79
|
+
httpCode: shared_1.HttpCode.BAD_REQUEST,
|
|
80
|
+
message: 'rule.actions.mockResponse and rule.actions.modifyResponse are mutually exclusive',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
if (!rule.ttlSeconds || rule.ttlSeconds < shared_1.MIN_RULE_TTL_SECONDS || rule.ttlSeconds > shared_1.MAX_RULE_TTL_SECONDS) {
|
|
84
|
+
throw new shared_1.AppError({
|
|
85
|
+
httpCode: shared_1.HttpCode.BAD_REQUEST,
|
|
86
|
+
message: `rule.ttlSeconds should be within ${shared_1.MIN_RULE_TTL_SECONDS} and ${shared_1.MAX_RULE_TTL_SECONDS}`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (typeof rule.isEnabled !== 'undefined' && typeof rule.isEnabled !== 'boolean') {
|
|
90
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.isEnabled' });
|
|
91
|
+
}
|
|
92
|
+
if (typeof rule.storeTraffic !== 'undefined' && typeof rule.storeTraffic !== 'boolean') {
|
|
93
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.BAD_REQUEST, message: 'invalid rule.storeTraffic' });
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
exports.validateSerializedRuleProperties = validateSerializedRuleProperties;
|
|
97
|
+
const validateDeserializedRule = (deserializedRule) => {
|
|
98
|
+
// TODO validate other functions ?
|
|
99
|
+
let matchValidationResult;
|
|
100
|
+
try {
|
|
101
|
+
matchValidationResult = deserializedRule.matches({
|
|
102
|
+
id: 'validation',
|
|
103
|
+
method: 'GET',
|
|
104
|
+
rawHeaders: new shared_1.RawHeaders(),
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
url: 'http://dummy.invalid/',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
shared_1.logger.error({ ruleId: deserializedRule.id }, error);
|
|
111
|
+
throw new shared_1.AppError({
|
|
112
|
+
httpCode: shared_1.HttpCode.UNPROCESSABLE_ENTITY,
|
|
113
|
+
message: 'match function threw an error',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (matchValidationResult !== true &&
|
|
117
|
+
matchValidationResult !== false &&
|
|
118
|
+
matchValidationResult.result !== true &&
|
|
119
|
+
matchValidationResult.result !== false) {
|
|
120
|
+
shared_1.logger.error({ ruleId: deserializedRule.id, matchValidationResult }, 'match function retruned invalid value');
|
|
121
|
+
throw new shared_1.AppError({ httpCode: shared_1.HttpCode.UNPROCESSABLE_ENTITY, message: 'match function returned invalid value' });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
exports.validateDeserializedRule = validateDeserializedRule;
|
|
125
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../src/api/validators.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
doctype html
|
|
2
|
+
html
|
|
3
|
+
head
|
|
4
|
+
title Stuntman - rule editor
|
|
5
|
+
script(src='https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.35.0/min/vs/loader.min.js')
|
|
6
|
+
style
|
|
7
|
+
include style.css
|
|
8
|
+
body(style='color: rgb(204, 204, 204); background-color: rgb(50, 50, 50)')
|
|
9
|
+
button#newRule(type='button', onclick='window.newRule()') New rule
|
|
10
|
+
button#saveRule(type='button', onclick='window.saveRule()', disabled) Save rule
|
|
11
|
+
div(style='width: 100%; overflow: hidden')
|
|
12
|
+
div(style='width: 230px; float: left')
|
|
13
|
+
h3 Rules
|
|
14
|
+
ul#ruleKeys.no-bullets
|
|
15
|
+
each ruleId in ruleKeys
|
|
16
|
+
li
|
|
17
|
+
button.rule(
|
|
18
|
+
type='button',
|
|
19
|
+
onclick='window.setRuleModel(this.getAttribute("data-rule-id"))',
|
|
20
|
+
data-rule-id=ruleId
|
|
21
|
+
)= ruleId
|
|
22
|
+
div(style='margin-left: 240px')
|
|
23
|
+
#container(style='height: 400px')
|
|
24
|
+
script.
|
|
25
|
+
/* eslint no-undef: 0 */
|
|
26
|
+
const uuidv4 = () => {
|
|
27
|
+
function getRandomSymbol(symbol) {
|
|
28
|
+
var array;
|
|
29
|
+
|
|
30
|
+
if (symbol === 'y') {
|
|
31
|
+
array = ['8', '9', 'a', 'b'];
|
|
32
|
+
return array[Math.floor(Math.random() * array.length)];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
array = new Uint8Array(1);
|
|
36
|
+
window.crypto.getRandomValues(array);
|
|
37
|
+
return (array[0] % 16).toString(16);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, getRandomSymbol);
|
|
41
|
+
};
|
|
42
|
+
require.config({
|
|
43
|
+
paths: {
|
|
44
|
+
vs: 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.35.0/min/vs',
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
require(['vs/editor/editor.main'], function () {
|
|
48
|
+
monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true);
|
|
49
|
+
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({
|
|
50
|
+
noSemanticValidation: false,
|
|
51
|
+
noSyntaxValidation: false,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// compiler options
|
|
55
|
+
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
|
56
|
+
target: monaco.languages.typescript.ScriptTarget.ES6,
|
|
57
|
+
allowNonTsExtensions: true,
|
|
58
|
+
noLib: true,
|
|
59
|
+
moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
|
|
60
|
+
module: monaco.languages.typescript.ModuleKind.CommonJS,
|
|
61
|
+
noEmit: true,
|
|
62
|
+
checkJs: true,
|
|
63
|
+
allowJs: true,
|
|
64
|
+
isolatedModules: true,
|
|
65
|
+
typeRoots: ['node_modules/@types'],
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
monaco.languages.typescript.typescriptDefaults.addExtraLib(`!{INDEX_DTS}`, 'file:///node_modules/@types/stuntman/index.d.ts');
|
|
69
|
+
const models = {};
|
|
70
|
+
const rules = eval('(!{rules})');
|
|
71
|
+
for (const ruleId of Object.keys(rules)) {
|
|
72
|
+
models[ruleId] = monaco.editor.createModel("import type * as Stuntman from 'stuntman';\n\nvar STUNTMAN_RULE: Stuntman.Rule = " + rules[ruleId] + ';', 'typescript', `file:///${ruleId}.ts`);
|
|
73
|
+
}
|
|
74
|
+
const editor = monaco.editor.create(document.getElementById('container'), {
|
|
75
|
+
theme: 'vs-dark',
|
|
76
|
+
formatOnPaste: true,
|
|
77
|
+
formatOnType: true,
|
|
78
|
+
automaticLayout: true,
|
|
79
|
+
autoIndent: true,
|
|
80
|
+
tabSize: 2,
|
|
81
|
+
});
|
|
82
|
+
editor.onDidChangeModel((event) => {
|
|
83
|
+
const isInternal = /^file:\/\/\/internal\/.+/.test(event.newModelUrl);
|
|
84
|
+
if (isInternal) {
|
|
85
|
+
document.getElementById('saveRule').setAttribute('disabled', 'true');
|
|
86
|
+
} else {
|
|
87
|
+
document.getElementById('saveRule').removeAttribute('disabled');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setTimeout(() => {
|
|
91
|
+
editor.getAction('editor.action.formatDocument').run();
|
|
92
|
+
}, 100);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
window.setRuleModel = (ruleId) => {
|
|
96
|
+
if (history.pushState) {
|
|
97
|
+
const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}?ruleId=${encodeURIComponent(ruleId)}`;
|
|
98
|
+
window.history.pushState({ path: newUrl }, '', newUrl);
|
|
99
|
+
}
|
|
100
|
+
editor.setModel(models[ruleId]);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
104
|
+
if (urlSearchParams.has('ruleId') && urlSearchParams.get('ruleId') in models) {
|
|
105
|
+
editor.setModel(models[urlSearchParams.get('ruleId')]);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
window.saveRule = () => {
|
|
109
|
+
document.getElementById('saveRule').setAttribute('disabled', 'true');
|
|
110
|
+
const modelUri = editor.getModel().uri;
|
|
111
|
+
const result = monaco.languages.typescript.getTypeScriptWorker();
|
|
112
|
+
result.then((worker) => {
|
|
113
|
+
worker(modelUri).then(function (client) {
|
|
114
|
+
client.getEmitOutput(modelUri.toString()).then((output) => {
|
|
115
|
+
const ruleFunctionText = output.outputFiles[0].text.replace(/^export .+$/im, '');
|
|
116
|
+
const newId = new Function(ruleFunctionText + '\n return STUNTMAN_RULE;')().id;
|
|
117
|
+
fetch('/webgui/rules/unsafesave', {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: { 'content-type': 'text/plain' },
|
|
120
|
+
body: ruleFunctionText + '\n return STUNTMAN_RULE;',
|
|
121
|
+
}).then((response) => {
|
|
122
|
+
if (response.ok) {
|
|
123
|
+
const newUrl = `${window.location.protocol}//${window.location.host}${window.location.pathname}?ruleId=${encodeURIComponent(newId)}`;
|
|
124
|
+
window.history.pushState({ path: newUrl }, '', newUrl);
|
|
125
|
+
window.location.reload();
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
alert('Error when saving rule');
|
|
129
|
+
document.getElementById('saveRule').removeAttribute('disabled');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
window.newRule = () => {
|
|
137
|
+
const ruleId = uuidv4();
|
|
138
|
+
const emptyRule = `import type * as Stuntman from 'stuntman';\n\nvar STUNTMAN_RULE: Stuntman.Rule = { id: '${ruleId}', matches: (req: Stuntman.Request) => true, ttlSeconds: 600, actions: { mockResponse: { status: '200', body: '${ruleId}' }} };`;
|
|
139
|
+
models[ruleId] = monaco.editor.createModel(emptyRule, 'typescript', `file:///${ruleId}.ts`);
|
|
140
|
+
const ruleKeyNode = document.getElementById('ruleKeys').firstChild;
|
|
141
|
+
const ruleKeyNodeClone = ruleKeyNode.cloneNode(true);
|
|
142
|
+
ruleKeyNodeClone.getElementsByTagName('button')[0].setAttribute('data-rule-id', ruleId);
|
|
143
|
+
ruleKeyNodeClone.getElementsByTagName('button')[0].innerText = ruleId;
|
|
144
|
+
document.getElementById('ruleKeys').appendChild(ruleKeyNodeClone);
|
|
145
|
+
window.setRuleModel(ruleId);
|
|
146
|
+
};
|
|
147
|
+
});
|