-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.js
109 lines (99 loc) · 2.79 KB
/
utils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import fetch from "node-fetch";
import fs from "fs";
import { load } from "cheerio";
const ENABLE_LOGS = true;
/**
* Fetchs text response for a url
*
* @param {String} url Url to be fetched
* @returns {Promise<String>} Text Response
*/
export async function fetchResponseAsText(url) {
const response = await fetch(url);
const text = await response.text();
ENABLE_LOGS &&
fs.writeFileSync("./logs/markup.txt", text, { encoding: "utf-8" });
return text;
}
/**
* Gets an array of all static script urls
*
* @param {String} markup MarkupString
* @returns {Array<string>} Array of static script urls
*/
export function getStaticScriptsUrl(markup, url) {
const $ = load(markup);
const bundleUrls = $("script")
.map((_, el) => {
if (!el.attribs.src) return undefined;
const _url = url.endsWith("/") ? url.slice(0, url.length - 1) : url;
const _src = el.attribs.src.startsWith(".")
? el.attribs.src.slice(1)
: el.attribs.src;
return _src.startsWith("http") ? _src : _url + _src;
})
.filter(Boolean)
.toArray();
ENABLE_LOGS &&
fs.writeFileSync(
"./logs/bundles.txt",
String(bundleUrls).replaceAll(",", "\n"),
{
encoding: "utf-8",
}
);
return bundleUrls;
}
/**
* Searches for React environment variables and
* returns array of env. objects
*
* @param {Array<string>} urls Script Urls
* @returns {Promise<Array<Record<string, string>>>} Array of founded enviroment objects
*/
export async function getEnvFromBundles(urls) {
const results = await Promise.all(
urls.map(async (url) => {
const jsText = await fetchResponseAsText(url);
const codeUrls = [];
const urlWordMatchers = ["sentry", "mixpanel", "clevertap"];
for (const word of urlWordMatchers) {
const urlWordMatch = jsText.match(
new RegExp(`https?:\/\/[^"\\s]*${word}[^"\\s]*`)
);
if (word === "sentry") {
const sentryDsnRegex = /dsn:\s*"(https:\/\/[^"]+)"/;
const sentryDsnMatch = jsText.match(sentryDsnRegex);
codeUrls.push({
[word]: sentryDsnMatch,
url,
});
}
if (urlWordMatch) {
codeUrls.push({
[word]: urlWordMatch,
url,
});
}
}
const envs = []
.concat(jsText.match(/REACT_APP[\w]+:[\S]+?('|"|$)/g))
.filter(Boolean);
let envsData = {};
if (envs) {
envsData = Object.fromEntries(
envs
.map((envStr) => envStr.split(/:(.*)/s).slice(0, 2))
.map(([k, v]) => [k, v.replace(/"/g, "")])
);
}
if (Object.keys(envsData).length || codeUrls.length) {
return {
envsData,
codeUrls,
};
}
})
);
return results.filter(Boolean);
}