chemicaljs 1.0.4 → 1.2.0
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/README.md +28 -6
- package/client/chemical.js +245 -0
- package/client/chemical.sw.js +35 -0
- package/config/scramjet/scramjet.config.js +9 -0
- package/{public → config}/uv/uv.config.js +1 -1
- package/example/public/index.html +2 -2
- package/index.js +115 -4
- package/package.json +4 -2
- package/rammerhead.tgz +0 -0
- package/public/chemical.js +0 -41
- package/public/chemical.sw.js +0 -19
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Chemical
|
|
2
|
-
|
|
2
|
+
Easily create your own web proxy with no experience required.
|
|
3
3
|
|
|
4
4
|
## Setup
|
|
5
5
|
|
|
@@ -19,6 +19,17 @@ import { ChemicalServer } from "chemicaljs";
|
|
|
19
19
|
const chemical = new ChemicalServer();
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
You can pass options to disable proxy services and set the default service.
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
const chemical = new ChemicalServer({
|
|
26
|
+
default: "rammerhead",
|
|
27
|
+
uv: true,
|
|
28
|
+
scramjet: false,
|
|
29
|
+
rammerhead: true
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
22
33
|
3. Use `chemical.app` which is an express app. You may need to import express for certain APIs.
|
|
23
34
|
|
|
24
35
|
```js
|
|
@@ -62,10 +73,22 @@ In your project create a folder to store your static assets. Create an index.htm
|
|
|
62
73
|
<script src="/chemical.js"></script>
|
|
63
74
|
```
|
|
64
75
|
|
|
65
|
-
|
|
76
|
+
If you want to set the wisp server to an external server just change the `wisp` attribute.
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<script wisp="wss://wisp.mercurywork.shop" src="/chemical.js"></script>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. In a inline script or javascript file, encode a URL with Chemical using the async function `window.chemicalEncode`.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
await window.chemicalEncode("https://example.com")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Optional: Change service to `ultraviolet`, `scramjet`, or `rammerhead`. Defaults to `uv` or server option.
|
|
66
89
|
|
|
67
90
|
```js
|
|
68
|
-
window.chemicalEncode("https://example.com")
|
|
91
|
+
await window.chemicalEncode("https://example.com", "rammerhead")
|
|
69
92
|
```
|
|
70
93
|
|
|
71
94
|
3. You may want to check if Chemical has loaded before encoding a URL.
|
|
@@ -92,9 +115,9 @@ Below is a simple example of a simple input that redirects to the encoded URL wh
|
|
|
92
115
|
<script>
|
|
93
116
|
const search = document.getElementById("search");
|
|
94
117
|
|
|
95
|
-
search.addEventListener("keydown", function (e) {
|
|
118
|
+
search.addEventListener("keydown", async function (e) {
|
|
96
119
|
if (e.key == "Enter" && window.chemicalLoaded && e.target.value) {
|
|
97
|
-
window.location = window.chemicalEncode(e.target.value)
|
|
120
|
+
window.location = await window.chemicalEncode(e.target.value)
|
|
98
121
|
}
|
|
99
122
|
})
|
|
100
123
|
</script>
|
|
@@ -104,7 +127,6 @@ Below is a simple example of a simple input that redirects to the encoded URL wh
|
|
|
104
127
|
|
|
105
128
|
Some features that may come in the future are:
|
|
106
129
|
|
|
107
|
-
- More proxy services.
|
|
108
130
|
- Easy client components.
|
|
109
131
|
- Easy tab cloaking components.
|
|
110
132
|
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
window.chemicalLoaded = false;
|
|
2
|
+
|
|
3
|
+
function rammerheadEncode(baseUrl) {
|
|
4
|
+
const mod = (n, m) => ((n % m) + m) % m
|
|
5
|
+
const baseDictionary =
|
|
6
|
+
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~-"
|
|
7
|
+
const shuffledIndicator = "_rhs"
|
|
8
|
+
const generateDictionary = function () {
|
|
9
|
+
let str = ""
|
|
10
|
+
const split = baseDictionary.split("")
|
|
11
|
+
while (split.length > 0) {
|
|
12
|
+
str += split.splice(Math.floor(Math.random() * split.length), 1)[0]
|
|
13
|
+
}
|
|
14
|
+
return str
|
|
15
|
+
}
|
|
16
|
+
class StrShuffler {
|
|
17
|
+
constructor(dictionary = generateDictionary()) {
|
|
18
|
+
this.dictionary = dictionary
|
|
19
|
+
}
|
|
20
|
+
shuffle(str) {
|
|
21
|
+
if (str.startsWith(shuffledIndicator)) {
|
|
22
|
+
return str
|
|
23
|
+
}
|
|
24
|
+
let shuffledStr = ""
|
|
25
|
+
for (let i = 0; i < str.length; i++) {
|
|
26
|
+
const char = str.charAt(i)
|
|
27
|
+
const idx = baseDictionary.indexOf(char)
|
|
28
|
+
if (char === "%" && str.length - i >= 3) {
|
|
29
|
+
shuffledStr += char
|
|
30
|
+
shuffledStr += str.charAt(++i)
|
|
31
|
+
shuffledStr += str.charAt(++i)
|
|
32
|
+
} else if (idx === -1) {
|
|
33
|
+
shuffledStr += char
|
|
34
|
+
} else {
|
|
35
|
+
shuffledStr += this.dictionary.charAt(
|
|
36
|
+
mod(idx + i, baseDictionary.length)
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return shuffledIndicator + shuffledStr
|
|
41
|
+
}
|
|
42
|
+
unshuffle(str) {
|
|
43
|
+
if (!str.startsWith(shuffledIndicator)) {
|
|
44
|
+
return str
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
str = str.slice(shuffledIndicator.length)
|
|
48
|
+
|
|
49
|
+
let unshuffledStr = ""
|
|
50
|
+
for (let i = 0; i < str.length; i++) {
|
|
51
|
+
const char = str.charAt(i)
|
|
52
|
+
const idx = this.dictionary.indexOf(char)
|
|
53
|
+
if (char === "%" && str.length - i >= 3) {
|
|
54
|
+
unshuffledStr += char
|
|
55
|
+
unshuffledStr += str.charAt(++i)
|
|
56
|
+
unshuffledStr += str.charAt(++i)
|
|
57
|
+
} else if (idx === -1) {
|
|
58
|
+
unshuffledStr += char
|
|
59
|
+
} else {
|
|
60
|
+
unshuffledStr += baseDictionary.charAt(
|
|
61
|
+
mod(idx - i, baseDictionary.length)
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return unshuffledStr
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function get(url, callback, shush = false) {
|
|
69
|
+
var request = new XMLHttpRequest()
|
|
70
|
+
request.open("GET", url, true)
|
|
71
|
+
request.send()
|
|
72
|
+
|
|
73
|
+
request.onerror = function () {
|
|
74
|
+
if (!shush) console.log("Cannot communicate with the server")
|
|
75
|
+
}
|
|
76
|
+
request.onload = function () {
|
|
77
|
+
if (request.status === 200) {
|
|
78
|
+
callback(request.responseText)
|
|
79
|
+
} else {
|
|
80
|
+
if (!shush)
|
|
81
|
+
console.log(
|
|
82
|
+
'unexpected server response to not match "200". Server says "' +
|
|
83
|
+
request.responseText +
|
|
84
|
+
'"'
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
var api = {
|
|
90
|
+
newsession(callback) {
|
|
91
|
+
get("/newsession", callback)
|
|
92
|
+
},
|
|
93
|
+
sessionexists(id, callback) {
|
|
94
|
+
get("/sessionexists?id=" + encodeURIComponent(id), function (res) {
|
|
95
|
+
if (res === "exists") return callback(true)
|
|
96
|
+
if (res === "not found") return callback(false)
|
|
97
|
+
console.log("unexpected response from server. received" + res)
|
|
98
|
+
})
|
|
99
|
+
},
|
|
100
|
+
shuffleDict(id, callback) {
|
|
101
|
+
console.log("Shuffling", id)
|
|
102
|
+
get("/api/shuffleDict?id=" + encodeURIComponent(id), function (res) {
|
|
103
|
+
callback(JSON.parse(res))
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
var localStorageKey = "rammerhead_sessionids"
|
|
108
|
+
var localStorageKeyDefault = "rammerhead_default_sessionid"
|
|
109
|
+
var sessionIdsStore = {
|
|
110
|
+
get() {
|
|
111
|
+
var rawData = localStorage.getItem(localStorageKey)
|
|
112
|
+
if (!rawData) return []
|
|
113
|
+
try {
|
|
114
|
+
var data = JSON.parse(rawData)
|
|
115
|
+
if (!Array.isArray(data)) throw "getout"
|
|
116
|
+
return data
|
|
117
|
+
} catch (e) {
|
|
118
|
+
return []
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
set(data) {
|
|
122
|
+
if (!data || !Array.isArray(data)) throw new TypeError("must be array")
|
|
123
|
+
localStorage.setItem(localStorageKey, JSON.stringify(data))
|
|
124
|
+
},
|
|
125
|
+
getDefault() {
|
|
126
|
+
var sessionId = localStorage.getItem(localStorageKeyDefault)
|
|
127
|
+
if (sessionId) {
|
|
128
|
+
var data = sessionIdsStore.get()
|
|
129
|
+
data.filter(function (e) {
|
|
130
|
+
return e.id === sessionId
|
|
131
|
+
})
|
|
132
|
+
if (data.length) return data[0]
|
|
133
|
+
}
|
|
134
|
+
return null
|
|
135
|
+
},
|
|
136
|
+
setDefault(id) {
|
|
137
|
+
localStorage.setItem(localStorageKeyDefault, id)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function addSession(id) {
|
|
141
|
+
var data = sessionIdsStore.get()
|
|
142
|
+
data.unshift({ id: id, createdOn: new Date().toLocaleString() })
|
|
143
|
+
sessionIdsStore.set(data)
|
|
144
|
+
}
|
|
145
|
+
function getSessionId() {
|
|
146
|
+
return new Promise(resolve => {
|
|
147
|
+
var id = localStorage.getItem("session-string")
|
|
148
|
+
api.sessionexists(id, function (value) {
|
|
149
|
+
if (!value) {
|
|
150
|
+
console.log("Session validation failed")
|
|
151
|
+
api.newsession(function (id) {
|
|
152
|
+
addSession(id)
|
|
153
|
+
localStorage.setItem("session-string", id)
|
|
154
|
+
console.log(id)
|
|
155
|
+
console.log("^ new id")
|
|
156
|
+
resolve(id)
|
|
157
|
+
})
|
|
158
|
+
} else {
|
|
159
|
+
resolve(id)
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
var ProxyHref
|
|
165
|
+
|
|
166
|
+
return getSessionId().then(id => {
|
|
167
|
+
return new Promise(resolve => {
|
|
168
|
+
api.shuffleDict(id, function (shuffleDict) {
|
|
169
|
+
var shuffler = new StrShuffler(shuffleDict)
|
|
170
|
+
ProxyHref = "/" + id + "/" + shuffler.shuffle(baseUrl)
|
|
171
|
+
resolve(ProxyHref)
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function chemicalEncode(url, service = defaultService) {
|
|
178
|
+
switch (service) {
|
|
179
|
+
case "uv":
|
|
180
|
+
if (uvEnabled) {
|
|
181
|
+
return (
|
|
182
|
+
window.location.origin +
|
|
183
|
+
window.__uv$config.prefix +
|
|
184
|
+
window.__uv$config.encodeUrl(url)
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
break;
|
|
188
|
+
case "rammerhead":
|
|
189
|
+
if (rammerheadEnabled) {
|
|
190
|
+
return window.location.origin + (await rammerheadEncode(url));
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
case "scramjet":
|
|
194
|
+
if (scramjetEnabled) {
|
|
195
|
+
return (
|
|
196
|
+
window.location.origin +
|
|
197
|
+
window.__scramjet$config.prefix +
|
|
198
|
+
window.__scramjet$config.codec.encode(url)
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
let wispURL = document.currentScript.getAttribute("wisp");
|
|
206
|
+
|
|
207
|
+
async function registerSW() {
|
|
208
|
+
const connection = new window.BareMux.BareMuxConnection("/baremux/worker.js");
|
|
209
|
+
await connection.setTransport("/epoxy/module.js", [{ wisp: wispURL || (location.protocol === "https:" ? "wss" : "ws") + "://" + location.host + "/wisp/" }]);
|
|
210
|
+
|
|
211
|
+
if ("serviceWorker" in navigator) {
|
|
212
|
+
await navigator.serviceWorker.register("/chemical.sw.js");
|
|
213
|
+
} else {
|
|
214
|
+
console.error("Service worker failed to register.")
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function loadScript(src) {
|
|
219
|
+
await new Promise((resolve, reject) => {
|
|
220
|
+
const script = document.createElement("script");
|
|
221
|
+
script.src = src;
|
|
222
|
+
script.onload = () => {
|
|
223
|
+
resolve();
|
|
224
|
+
};
|
|
225
|
+
script.onerror = () => {
|
|
226
|
+
reject();
|
|
227
|
+
};
|
|
228
|
+
document.head.appendChild(script);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
(async () => {
|
|
233
|
+
await loadScript("/baremux/index.js");
|
|
234
|
+
if (uvEnabled) {
|
|
235
|
+
await loadScript("/uv/uv.bundle.js");
|
|
236
|
+
await loadScript("/uv/uv.config.js");
|
|
237
|
+
}
|
|
238
|
+
if (scramjetEnabled) {
|
|
239
|
+
await loadScript("/scramjet/scramjet.codecs.js");
|
|
240
|
+
await loadScript("/scramjet/scramjet.config.js");
|
|
241
|
+
}
|
|
242
|
+
await registerSW();
|
|
243
|
+
chemicalLoaded = true;
|
|
244
|
+
window.dispatchEvent(new Event("chemicalLoaded"));
|
|
245
|
+
})();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
if (uvEnabled) {
|
|
2
|
+
importScripts("/uv/uv.bundle.js");
|
|
3
|
+
importScripts("/uv/uv.config.js");
|
|
4
|
+
importScripts(__uv$config.sw || "/uv/uv.sw.js");
|
|
5
|
+
}
|
|
6
|
+
if (scramjetEnabled) {
|
|
7
|
+
importScripts("/scramjet/scramjet.codecs.js");
|
|
8
|
+
importScripts("/scramjet/scramjet.config.js");
|
|
9
|
+
importScripts(__scramjet$config.bundle || "/scramjet/scramjet.bundle.js");
|
|
10
|
+
importScripts(__scramjet$config.worker || "/scramjet/scramjet.worker.js");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(self, "crossOriginIsolated", { value: true }); // Firefox fix
|
|
14
|
+
|
|
15
|
+
let uv, scramjet;
|
|
16
|
+
|
|
17
|
+
if (uvEnabled) {
|
|
18
|
+
uv = new UVServiceWorker();
|
|
19
|
+
}
|
|
20
|
+
if (scramjetEnabled) {
|
|
21
|
+
scramjet = new ScramjetServiceWorker();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
self.addEventListener("fetch", (event) => {
|
|
25
|
+
event.respondWith(
|
|
26
|
+
(async () => {
|
|
27
|
+
if (uvEnabled && uv.route(event)) {
|
|
28
|
+
return await uv.fetch(event);
|
|
29
|
+
} else if (scramjetEnabled && scramjet.route(event)) {
|
|
30
|
+
return await scramjet.fetch(event);
|
|
31
|
+
}
|
|
32
|
+
return await fetch(event.request);
|
|
33
|
+
})(),
|
|
34
|
+
);
|
|
35
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
self.__scramjet$config = {
|
|
2
|
+
prefix: "/~/sj/",
|
|
3
|
+
codec: self.__scramjet$codecs.plain,
|
|
4
|
+
config: "/scramjet/scramjet.config.js",
|
|
5
|
+
bundle: "/scramjet/scramjet.bundle.js",
|
|
6
|
+
worker: "/scramjet/scramjet.worker.js",
|
|
7
|
+
client: "/scramjet/scramjet.client.js",
|
|
8
|
+
codecs: "/scramjet/scramjet.codecs.js",
|
|
9
|
+
};
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
<script>
|
|
6
6
|
const search = document.getElementById("search");
|
|
7
7
|
|
|
8
|
-
search.addEventListener("keydown", function (e) {
|
|
8
|
+
search.addEventListener("keydown", async function (e) {
|
|
9
9
|
if (e.key == "Enter" && window.chemicalLoaded && e.target.value) {
|
|
10
|
-
window.location = window.chemicalEncode(e.target.value)
|
|
10
|
+
window.location = await window.chemicalEncode(e.target.value, "rammerhead")
|
|
11
11
|
}
|
|
12
12
|
})
|
|
13
13
|
</script>
|
package/index.js
CHANGED
|
@@ -1,25 +1,136 @@
|
|
|
1
1
|
import { resolve } from "node:path";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { createServer } from "node:http";
|
|
3
4
|
import express from "express";
|
|
4
5
|
import wisp from "wisp-server-node";
|
|
5
6
|
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
|
6
7
|
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
|
7
8
|
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
|
9
|
+
import { scramjetPath } from "@mercuryworkshop/scramjet";
|
|
10
|
+
import createRammerhead from "rammerhead/src/server/index.js";
|
|
8
11
|
|
|
9
12
|
class ChemicalServer {
|
|
10
|
-
constructor() {
|
|
13
|
+
constructor(options) {
|
|
14
|
+
if (typeof options !== "object" || Array.isArray(options)) {
|
|
15
|
+
options = {}
|
|
16
|
+
console.error("Error: ChemicalServer options invalid.")
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const rh = createRammerhead()
|
|
20
|
+
|
|
21
|
+
const rammerheadScopes = [
|
|
22
|
+
"/rammerhead.js",
|
|
23
|
+
"/hammerhead.js",
|
|
24
|
+
"/transport-worker.js",
|
|
25
|
+
"/task.js",
|
|
26
|
+
"/iframe-task.js",
|
|
27
|
+
"/worker-hammerhead.js",
|
|
28
|
+
"/messaging",
|
|
29
|
+
"/sessionexists",
|
|
30
|
+
"/deletesession",
|
|
31
|
+
"/newsession",
|
|
32
|
+
"/editsession",
|
|
33
|
+
"/needpassword",
|
|
34
|
+
"/syncLocalStorage",
|
|
35
|
+
"/api/shuffleDict"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
const rammerheadSession = /^\/[a-z0-9]{32}/
|
|
39
|
+
|
|
40
|
+
const shouldRouteRh = req => {
|
|
41
|
+
const url = new URL(req.url, "http://0.0.0.0")
|
|
42
|
+
return (
|
|
43
|
+
rammerheadScopes.includes(url.pathname) ||
|
|
44
|
+
rammerheadSession.test(url.pathname)
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const routeRhRequest = (req, res) => {
|
|
49
|
+
rh.emit("request", req, res)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const routeRhUpgrade = (req, socket, head) => {
|
|
53
|
+
rh.emit("upgrade", req, socket, head)
|
|
54
|
+
}
|
|
55
|
+
|
|
11
56
|
this.server = createServer();
|
|
12
57
|
this.app = express();
|
|
13
|
-
this.app.
|
|
58
|
+
this.app.get("/chemical.js", async function (req, res) {
|
|
59
|
+
let chemicalMain = await readFileSync(resolve(import.meta.dirname, "client/chemical.js"), "utf8");
|
|
60
|
+
|
|
61
|
+
if (options.default) {
|
|
62
|
+
if (["uv", "rammerhead", "scramjet"].includes(options.default)) {
|
|
63
|
+
chemicalMain = `const defaultService = "${options.default}";\n\n` + chemicalMain
|
|
64
|
+
} else {
|
|
65
|
+
chemicalMain = `const defaultService = "uv";\n\n` + chemicalMain
|
|
66
|
+
console.error("Error: Chemical default option invalid.")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (options.uv == false) {
|
|
71
|
+
chemicalMain = "const uvEnabled = false;\n" + chemicalMain
|
|
72
|
+
} else {
|
|
73
|
+
chemicalMain = "const uvEnabled = true;\n" + chemicalMain
|
|
74
|
+
}
|
|
75
|
+
if (options.scramjet == false) {
|
|
76
|
+
chemicalMain = "const scramjetEnabled = false;\n" + chemicalMain
|
|
77
|
+
} else {
|
|
78
|
+
chemicalMain = "const scramjetEnabled = true;\n" + chemicalMain
|
|
79
|
+
}
|
|
80
|
+
if (options.rammerhead == false) {
|
|
81
|
+
chemicalMain = "const rammerheadEnabled = false;\n" + chemicalMain
|
|
82
|
+
} else {
|
|
83
|
+
chemicalMain = "const rammerheadEnabled = true;\n" + chemicalMain
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
res.type("application/javascript");
|
|
87
|
+
return res.send(chemicalMain);
|
|
88
|
+
});
|
|
89
|
+
this.app.get("/chemical.sw.js", async function (req, res) {
|
|
90
|
+
let chemicalSW = await readFileSync(resolve(import.meta.dirname, "client/chemical.sw.js"), "utf8");
|
|
91
|
+
|
|
92
|
+
if (options.uv == false) {
|
|
93
|
+
chemicalSW = "const uvEnabled = false;\n\n" + chemicalSW
|
|
94
|
+
} else {
|
|
95
|
+
chemicalSW = "const uvEnabled = true;\n\n" + chemicalSW
|
|
96
|
+
}
|
|
97
|
+
if (options.scramjet == false) {
|
|
98
|
+
chemicalSW = "const scramjetEnabled = false;\n" + chemicalSW
|
|
99
|
+
} else {
|
|
100
|
+
chemicalSW = "const scramjetEnabled = true;\n" + chemicalSW
|
|
101
|
+
}
|
|
102
|
+
if (options.rammerhead == false) {
|
|
103
|
+
chemicalSW = "const rammerheadEnabled = false;\n" + chemicalSW
|
|
104
|
+
} else {
|
|
105
|
+
chemicalSW = "const rammerheadEnabled = true;\n" + chemicalSW
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
res.type("application/javascript");
|
|
109
|
+
return res.send(chemicalSW);
|
|
110
|
+
});
|
|
111
|
+
this.app.use(express.static(resolve(import.meta.dirname, "client")));
|
|
14
112
|
this.app.use("/baremux/", express.static(baremuxPath));
|
|
15
113
|
this.app.use("/epoxy/", express.static(epoxyPath));
|
|
16
|
-
|
|
114
|
+
if (options.uv !== false) {
|
|
115
|
+
this.app.use("/uv/", express.static(resolve(import.meta.dirname, "config/uv")));
|
|
116
|
+
this.app.use("/uv/", express.static(uvPath));
|
|
117
|
+
}
|
|
118
|
+
if (options.scramjet !== false) {
|
|
119
|
+
this.app.use("/scramjet/", express.static(resolve(import.meta.dirname, "config/scramjet")));
|
|
120
|
+
this.app.use("/scramjet/", express.static(scramjetPath));
|
|
121
|
+
}
|
|
17
122
|
this.server.on("request", (req, res) => {
|
|
18
|
-
|
|
123
|
+
if (options.rammerhead !== false && shouldRouteRh(req)) {
|
|
124
|
+
routeRhRequest(req, res);
|
|
125
|
+
} else {
|
|
126
|
+
this.app(req, res);
|
|
127
|
+
}
|
|
19
128
|
});
|
|
20
129
|
this.server.on("upgrade", (req, socket, head) => {
|
|
21
130
|
if (req.url && req.url.endsWith("/wisp/")) {
|
|
22
131
|
wisp.routeRequest(req, socket, head);
|
|
132
|
+
} else if (options.rammerhead !== false && shouldRouteRh(req)) {
|
|
133
|
+
routeRhUpgrade(req, socket, head);
|
|
23
134
|
} else {
|
|
24
135
|
socket.end();
|
|
25
136
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chemicaljs",
|
|
3
|
-
"version": "1.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Easily create your own web proxy with no experience required.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/chemicaljs/chemical.git"
|
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@mercuryworkshop/bare-mux": "^2.0.0",
|
|
15
15
|
"@mercuryworkshop/epoxy-transport": "^2.1.0",
|
|
16
|
+
"@mercuryworkshop/scramjet": "^1.0.2",
|
|
16
17
|
"@titaniumnetwork-dev/ultraviolet": "^3.2.0",
|
|
17
18
|
"express": "^4.19.2",
|
|
19
|
+
"rammerhead": "file:rammerhead.tgz",
|
|
18
20
|
"wisp-server-node": "^1.1.0"
|
|
19
21
|
}
|
|
20
22
|
}
|
package/rammerhead.tgz
ADDED
|
Binary file
|
package/public/chemical.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
window.chemicalLoaded = false;
|
|
2
|
-
|
|
3
|
-
function chemicalEncode(url) {
|
|
4
|
-
return window.location.origin + window.__uv$config.prefix + window.__uv$config.encodeUrl(url)
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
let wispURL = document.currentScript.getAttribute("wisp");
|
|
8
|
-
|
|
9
|
-
async function registerSW() {
|
|
10
|
-
const connection = new window.BareMux.BareMuxConnection("/baremux/worker.js");
|
|
11
|
-
await connection.setTransport("/epoxy/module.js", [{ wisp: wispURL || (location.protocol === "https:" ? "wss" : "ws") + "://" + location.host + "/wisp/" }]);
|
|
12
|
-
|
|
13
|
-
if ("serviceWorker" in navigator) {
|
|
14
|
-
await navigator.serviceWorker.register("/chemical.sw.js");
|
|
15
|
-
} else {
|
|
16
|
-
console.error("Service worker failed to register.")
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function loadScript(src) {
|
|
21
|
-
await new Promise((resolve, reject) => {
|
|
22
|
-
const script = document.createElement("script");
|
|
23
|
-
script.src = src;
|
|
24
|
-
script.onload = () => {
|
|
25
|
-
resolve();
|
|
26
|
-
};
|
|
27
|
-
script.onerror = () => {
|
|
28
|
-
reject();
|
|
29
|
-
};
|
|
30
|
-
document.head.appendChild(script);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
(async () => {
|
|
35
|
-
await loadScript("/baremux/index.js");
|
|
36
|
-
await loadScript("/uv/uv.bundle.js");
|
|
37
|
-
await loadScript("/uv/uv.config.js");
|
|
38
|
-
await registerSW();
|
|
39
|
-
chemicalLoaded = true;
|
|
40
|
-
window.dispatchEvent(new Event("chemicalLoaded"));
|
|
41
|
-
})();
|
package/public/chemical.sw.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
importScripts("/libcurl/index.js");
|
|
2
|
-
importScripts("/uv/uv.bundle.js");
|
|
3
|
-
importScripts("/uv/uv.config.js");
|
|
4
|
-
importScripts(__uv$config.sw || "/uv/uv.sw.js");
|
|
5
|
-
|
|
6
|
-
Object.defineProperty(self, "crossOriginIsolated", { value: true }); // Firefox fix
|
|
7
|
-
|
|
8
|
-
const uv = new UVServiceWorker();
|
|
9
|
-
|
|
10
|
-
self.addEventListener("fetch", (event) => {
|
|
11
|
-
event.respondWith(
|
|
12
|
-
(async () => {
|
|
13
|
-
if (uv.route(event)) {
|
|
14
|
-
return await uv.fetch(event);
|
|
15
|
-
}
|
|
16
|
-
return await fetch(event.request);
|
|
17
|
-
})(),
|
|
18
|
-
);
|
|
19
|
-
});
|