@requestly/requestly-proxy 1.0.4 → 1.1.1
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/components/proxy-middleware/constants.js +1 -0
- package/dist/components/proxy-middleware/helpers/redirectHelper.d.ts +9 -0
- package/dist/components/proxy-middleware/helpers/redirectHelper.js +167 -0
- package/dist/components/proxy-middleware/rule_action_processor/processors/helpers/redirectHelper.d.ts +22 -0
- package/dist/components/proxy-middleware/rule_action_processor/processors/helpers/redirectHelper.js +149 -0
- package/dist/components/proxy-middleware/rule_action_processor/processors/redirect_processor.js +7 -4
- package/package.json +1 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.makeExternalRequest = exports.shouldMakeExternalRequest = void 0;
|
|
39
|
+
const parser = require("ua-parser-js");
|
|
40
|
+
const Sentry = __importStar(require("@sentry/browser"));
|
|
41
|
+
const https_1 = __importDefault(require("https"));
|
|
42
|
+
const http_1 = __importDefault(require("http"));
|
|
43
|
+
const willCreateMixedResponse = (ctx, destinationUrl) => {
|
|
44
|
+
var _a, _b, _c, _d;
|
|
45
|
+
let user_agent_str = null;
|
|
46
|
+
user_agent_str = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.clientToProxyRequest) === null || _a === void 0 ? void 0 : _a.headers["user-agent"];
|
|
47
|
+
console.log("handling mixed response. i got headers", (_b = ctx === null || ctx === void 0 ? void 0 : ctx.clientToProxyRequest) === null || _b === void 0 ? void 0 : _b.headers);
|
|
48
|
+
const user_agent = (_d = (_c = parser(user_agent_str)) === null || _c === void 0 ? void 0 : _c.browser) === null || _d === void 0 ? void 0 : _d.name;
|
|
49
|
+
const LOCAL_DOMAINS = ["localhost", "127.0.0.1"];
|
|
50
|
+
return ctx.isSSL && destinationUrl.includes("http") && (user_agent === "Safari" ||
|
|
51
|
+
!LOCAL_DOMAINS.some((domain) => destinationUrl.includes(domain)));
|
|
52
|
+
};
|
|
53
|
+
const canPreserveCookie = (ctx, destinationUrl) => {
|
|
54
|
+
/* DOES NOT WORK */
|
|
55
|
+
// CAN'T DIFFERENTIATE CALL TO TOP LEVEL DOCUMENT
|
|
56
|
+
// // had to create this because host and referer were sometimes same
|
|
57
|
+
// // but had additional prefixes like `/`
|
|
58
|
+
// // note: neither referer nor host have search params
|
|
59
|
+
// const areUrlsSame = (u1, u2) => {
|
|
60
|
+
// try {
|
|
61
|
+
// let u1obj = new URL(u1)
|
|
62
|
+
// let u2obj = new URL(u2)
|
|
63
|
+
// return u1obj.href === u2obj.href
|
|
64
|
+
// } catch {
|
|
65
|
+
// // when url objects were not properly formed
|
|
66
|
+
// return false
|
|
67
|
+
// }
|
|
68
|
+
// }
|
|
69
|
+
// const requestHeaders = ctx?.clientToProxyRequest?.headers;
|
|
70
|
+
// const referer = requestHeaders["referer"] || requestHeaders["Referer"]
|
|
71
|
+
// const origin = requestHeaders["origin"] || requestHeaders["Origin"]
|
|
72
|
+
// // cannot preserve cookie on request for toplevel document
|
|
73
|
+
// if (
|
|
74
|
+
// // navigating to the domain directly from the search bar
|
|
75
|
+
// !referer ||
|
|
76
|
+
// // when navigating using google search result
|
|
77
|
+
// // referrer is present but origin is not
|
|
78
|
+
// !origin || // bug: origin not passed by firefox in some cases
|
|
79
|
+
// !areUrlsSame(referer, origin)
|
|
80
|
+
// ) return false
|
|
81
|
+
return true;
|
|
82
|
+
};
|
|
83
|
+
const shouldMakeExternalRequest = (ctx, action) => {
|
|
84
|
+
return ((action.preserveCookie && canPreserveCookie(ctx, action.url)) ||
|
|
85
|
+
willCreateMixedResponse(ctx, action.url));
|
|
86
|
+
};
|
|
87
|
+
exports.shouldMakeExternalRequest = shouldMakeExternalRequest;
|
|
88
|
+
function makeRequest(requestOptions) {
|
|
89
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
90
|
+
let requestAgent = http_1.default;
|
|
91
|
+
if (requestOptions.url.includes("https"))
|
|
92
|
+
requestAgent = https_1.default;
|
|
93
|
+
requestOptions.headers["Cache-Control"] = "no-cache";
|
|
94
|
+
try {
|
|
95
|
+
const { data, response } = yield new Promise((resolve, reject) => {
|
|
96
|
+
// `.request` wasn't working well with the provided request options
|
|
97
|
+
// node only provides wrapper for get, hence did not implement other methods
|
|
98
|
+
if (requestOptions.method === "GET") {
|
|
99
|
+
let request = requestAgent.get(requestOptions.url, requestOptions, (res) => {
|
|
100
|
+
const dataBuffers = [];
|
|
101
|
+
res.on('data', (buffer) => {
|
|
102
|
+
dataBuffers.push(buffer);
|
|
103
|
+
});
|
|
104
|
+
res.on('end', () => {
|
|
105
|
+
resolve({ data: Buffer.concat(dataBuffers).toString(), response: res });
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
request.on('error', (error) => {
|
|
109
|
+
console.log("requestError", requestOptions);
|
|
110
|
+
console.error(error);
|
|
111
|
+
reject(error);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// hack: to return an understandable response back to user
|
|
116
|
+
// @nsr fix: implement all other methods using some workaround of http.request bug
|
|
117
|
+
const errMsg = "Can only preserve cookies for get requests";
|
|
118
|
+
const customError = new Error(errMsg);
|
|
119
|
+
customError.response = { data: errMsg };
|
|
120
|
+
throw customError;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return { success: true, response, data };
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
Sentry.captureException(error);
|
|
127
|
+
console.error(error);
|
|
128
|
+
return { success: false, error };
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const makeExternalRequest = (ctx, url) => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
+
const requestOptions = ctx.proxyToServerRequestOptions;
|
|
134
|
+
// can't pass all request options because they o
|
|
135
|
+
// verride some attrubutes of node http request options
|
|
136
|
+
// in the wrong way
|
|
137
|
+
let finalRequestOptions = {
|
|
138
|
+
headers: Object.assign({}, requestOptions.headers),
|
|
139
|
+
url,
|
|
140
|
+
method: requestOptions.method
|
|
141
|
+
};
|
|
142
|
+
if (url.includes("https")) {
|
|
143
|
+
finalRequestOptions = Object.assign(Object.assign({}, finalRequestOptions), { rejectUnauthorized: false, requestCert: true, agent: false, strictSSL: false });
|
|
144
|
+
}
|
|
145
|
+
const { success, error, response, data } = yield makeRequest(finalRequestOptions);
|
|
146
|
+
if (success) {
|
|
147
|
+
return {
|
|
148
|
+
status: true,
|
|
149
|
+
responseData: {
|
|
150
|
+
headers: Object.assign(Object.assign({}, response.headers), { "connection": "close", "Cache-Control": "no-cache" }),
|
|
151
|
+
status_code: response.statuscode,
|
|
152
|
+
body: data,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return {
|
|
158
|
+
status: true,
|
|
159
|
+
responseData: {
|
|
160
|
+
headers: { "Cache-Control": "no-cache" },
|
|
161
|
+
status_code: 502,
|
|
162
|
+
body: error.response ? error.response.data : null,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
exports.makeExternalRequest = makeExternalRequest;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function handleMixedResponse(ctx: any, destinationUrl: any): Promise<{
|
|
2
|
+
status: boolean;
|
|
3
|
+
response_data: {
|
|
4
|
+
headers: any;
|
|
5
|
+
status_code: any;
|
|
6
|
+
body: any;
|
|
7
|
+
};
|
|
8
|
+
} | {
|
|
9
|
+
status: boolean;
|
|
10
|
+
response_data?: undefined;
|
|
11
|
+
}>;
|
|
12
|
+
export function handleServerSideRedirect(ctx: any, destinationUrl: any): Promise<{
|
|
13
|
+
status: boolean;
|
|
14
|
+
response_data: {
|
|
15
|
+
headers: any;
|
|
16
|
+
status_code: any;
|
|
17
|
+
body: any;
|
|
18
|
+
};
|
|
19
|
+
} | {
|
|
20
|
+
status: boolean;
|
|
21
|
+
response_data?: undefined;
|
|
22
|
+
}>;
|
package/dist/components/proxy-middleware/rule_action_processor/processors/helpers/redirectHelper.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.handleServerSideRedirect = exports.handleMixedResponse = void 0;
|
|
39
|
+
const parser = require("ua-parser-js");
|
|
40
|
+
const Sentry = __importStar(require("@sentry/browser"));
|
|
41
|
+
const https_1 = __importDefault(require("https"));
|
|
42
|
+
function makeSameRequestToDifferentUrl(ctx, url) {
|
|
43
|
+
var _a;
|
|
44
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
try {
|
|
46
|
+
const requestOptions = {
|
|
47
|
+
headers: Object.assign(Object.assign({}, (_a = ctx === null || ctx === void 0 ? void 0 : ctx.clientToProxyRequest) === null || _a === void 0 ? void 0 : _a.headers), { "Cache-Control": "no-cache" }),
|
|
48
|
+
rejectUnauthorized: false,
|
|
49
|
+
requestCert: true,
|
|
50
|
+
agent: false,
|
|
51
|
+
strictSSL: false,
|
|
52
|
+
};
|
|
53
|
+
const { data, response } = yield new Promise((resolve, reject) => {
|
|
54
|
+
let request = https_1.default.get(url, requestOptions, (res) => {
|
|
55
|
+
const dataBuffers = [];
|
|
56
|
+
res.on('data', (buffer) => {
|
|
57
|
+
dataBuffers.push(buffer);
|
|
58
|
+
});
|
|
59
|
+
res.on('end', () => {
|
|
60
|
+
resolve({ data: Buffer.concat(dataBuffers).toString(), response: res });
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
request.on('error', (error) => {
|
|
64
|
+
console.error(error);
|
|
65
|
+
reject(error);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
return { success: true, response, data };
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
Sentry.captureException(error);
|
|
72
|
+
console.error(error);
|
|
73
|
+
return { success: false, error };
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const willCreateMixedResponse = (ctx, destinationUrl) => {
|
|
78
|
+
var _a, _b, _c, _d;
|
|
79
|
+
let user_agent_str = null;
|
|
80
|
+
user_agent_str = (_a = ctx === null || ctx === void 0 ? void 0 : ctx.clientToProxyRequest) === null || _a === void 0 ? void 0 : _a.headers["user-agent"];
|
|
81
|
+
console.log("handling mixed response. i got headers", (_b = ctx === null || ctx === void 0 ? void 0 : ctx.clientToProxyRequest) === null || _b === void 0 ? void 0 : _b.headers);
|
|
82
|
+
const user_agent = (_d = (_c = parser(user_agent_str)) === null || _c === void 0 ? void 0 : _c.browser) === null || _d === void 0 ? void 0 : _d.name;
|
|
83
|
+
const LOCAL_DOMAINS = ["localhost", "127.0.0.1"];
|
|
84
|
+
return ctx.isSSL && (user_agent === "Safari" ||
|
|
85
|
+
!LOCAL_DOMAINS.some((domain) => destinationUrl.includes(domain)));
|
|
86
|
+
};
|
|
87
|
+
const handleMixedResponse = (ctx, destinationUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
+
if (willCreateMixedResponse(ctx, destinationUrl)) {
|
|
89
|
+
const { success, error, response, data } = yield makeSameRequestToDifferentUrl(ctx, destinationUrl);
|
|
90
|
+
if (success) {
|
|
91
|
+
return {
|
|
92
|
+
status: true,
|
|
93
|
+
response_data: {
|
|
94
|
+
headers: Object.assign(Object.assign({}, response.headers), { "connection": "close", "Cache-Control": "no-cache" }),
|
|
95
|
+
status_code: response.statuscode,
|
|
96
|
+
body: data,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return {
|
|
102
|
+
status: true,
|
|
103
|
+
response_data: {
|
|
104
|
+
headers: { "Cache-Control": "no-cache" },
|
|
105
|
+
status_code: 502,
|
|
106
|
+
body: error.response ? error.responserror.data : null,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return { status: false };
|
|
112
|
+
});
|
|
113
|
+
exports.handleMixedResponse = handleMixedResponse;
|
|
114
|
+
const canMakeServerSideRedirect = (ctx, destinationUrl) => {
|
|
115
|
+
// todo: no redirects for html documents
|
|
116
|
+
// content-type
|
|
117
|
+
// will be handled by mixed content case
|
|
118
|
+
if (destinationUrl.includes("http"))
|
|
119
|
+
return false;
|
|
120
|
+
return true;
|
|
121
|
+
};
|
|
122
|
+
const handleServerSideRedirect = (ctx, destinationUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
123
|
+
if (canMakeServerSideRedirect(ctx, destinationUrl)) {
|
|
124
|
+
const { success, error, response, data } = yield makeSameRequestToDifferentUrl(ctx, destinationUrl);
|
|
125
|
+
if (success) {
|
|
126
|
+
return {
|
|
127
|
+
status: true,
|
|
128
|
+
response_data: {
|
|
129
|
+
headers: Object.assign(Object.assign({}, response.headers), { "connection": "close", "Cache-Control": "no-cache" }),
|
|
130
|
+
status_code: response.statuscode,
|
|
131
|
+
body: data,
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
return {
|
|
137
|
+
status: true,
|
|
138
|
+
response_data: {
|
|
139
|
+
headers: { "Cache-Control": "no-cache" },
|
|
140
|
+
status_code: 502,
|
|
141
|
+
body: error.response ? error.responserror.data : null,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { status: false };
|
|
147
|
+
});
|
|
148
|
+
exports.handleServerSideRedirect = handleServerSideRedirect;
|
|
149
|
+
// export default handleMixedResponse; // change exports
|
package/dist/components/proxy-middleware/rule_action_processor/processors/redirect_processor.js
CHANGED
|
@@ -15,7 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
const proxy_1 = require("../../../../lib/proxy");
|
|
16
16
|
const proxy_ctx_helper_1 = require("../../helpers/proxy_ctx_helper");
|
|
17
17
|
const modified_requests_pool_1 = __importDefault(require("../modified_requests_pool"));
|
|
18
|
-
const
|
|
18
|
+
const redirectHelper_1 = require("../../helpers/redirectHelper");
|
|
19
19
|
const utils_1 = require("../utils");
|
|
20
20
|
const { URL } = require("url");
|
|
21
21
|
// adding util to get origin header for handling cors
|
|
@@ -41,9 +41,12 @@ const process_redirect_action = (action, ctx) => __awaiter(void 0, void 0, void
|
|
|
41
41
|
else {
|
|
42
42
|
modified_requests_pool_1.default.add(new_url);
|
|
43
43
|
}
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
44
|
+
// handle mixed content and redirect with preserve cookie
|
|
45
|
+
if ((0, redirectHelper_1.shouldMakeExternalRequest)(ctx, action)) {
|
|
46
|
+
const { status: wasExternalRequestSuccessful, responseData } = yield (0, redirectHelper_1.makeExternalRequest)(ctx, new_url);
|
|
47
|
+
if (wasExternalRequestSuccessful) {
|
|
48
|
+
return (0, utils_1.build_action_processor_response)(action, true, (0, utils_1.build_post_process_data)(responseData.status_code, responseData.headers, responseData.body));
|
|
49
|
+
}
|
|
47
50
|
}
|
|
48
51
|
// If this is a pre-flight request, don't redirect it
|
|
49
52
|
if ((0, proxy_ctx_helper_1.is_request_preflight)(ctx))
|