Skip to content
This repository was archived by the owner on May 28, 2023. It is now read-only.

Commit 544355d

Browse files
Start to add aero
1 parent cd0bbde commit 544355d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+3705
-1
lines changed

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pnpm-debug.log*
2121
/public/dip/
2222
/public/osana/
2323
/public/js/lib/
24+
/public/aero/
2425
.vscode/
2526
.github/
2627
/public/assets/fontawesome/
@@ -29,4 +30,4 @@ docker-compose.yml
2930

3031
*.htpasswd
3132

32-
/public/ruby-assets/
33+
/public/ruby-assets/

public/aero/.editorconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[*]
2+
charset = utf-8
3+
insert_final_newline = false
4+
end_of_line = lf
5+
indent_style = tabs
6+
indent_size = 4

public/aero/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
config.js

public/aero/.prettierrc.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"useTabs": true,
3+
"arrowParens": "avoid"
4+
}

public/aero/LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

public/aero/README.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# aero
2+
3+
Aero is a safe, developer friendly, and innovative interception proxy. Aero provides a good balance of excellent site support speed, while also having a clean and organized codebase. A deployable version can be found [here](https://github.com/ProxyHaven/aero-deploy)
4+
5+
# How to use aero
6+
7+
1. Make sure your backend serves an [aero](https://github.com/ProxyHaven/aero-backends) _recommended_ or a [TompHTTP Compatible Backend](https://github.com/tomphttp)
8+
> If you are using bare, run bare.sh
9+
2. Make sure you included aero into your site
10+
3. Create a service worker like this in the topmost directory
11+
12+
```js
13+
import handle from "./aero/handle.js";
14+
import "./aero/init.js";
15+
16+
self.addEventListener("install", () => self.skipWaiting());
17+
18+
self.addEventListener("fetch", async event =>
19+
event.respondWith(
20+
handle(event).catch(err => new Response(err.stack, { status: 500 }))
21+
)
22+
);
23+
```
24+
25+
4. Register the service worker in a script on your main page like this
26+
_This example uses our [sdk](https://github.com/ProxyHaven/aero-sdk); allowing you to safely manage deployments of multiple proxies, and supports dynamic config updates_
27+
28+
```js
29+
import { proxyApi } from "./aero/config.js";
30+
31+
import ProxyManager from "./sdk/ProxyManager.js";
32+
33+
const proxyManager = new ProxyManager();
34+
35+
proxyManager.add("/sw.js", proxyApi);
36+
```
37+
38+
# How aero works
39+
40+
## Precedence
41+
42+
Previously, proxies could barely handle more than one person, this was due to all the site's code being rewritten on the backend. Because the code was being rewritten on the backend, it required having to share backend rewrite code with frontend code. This was not only slow, but also allowed the possibility of Slowloris attacks against the proxies.
43+
44+
## Interception
45+
46+
aero takes a different approach by not only completely avoiding rewrites, but also by doing all the rewrites on the frontend with no parsers! This allows aero to avoid speed delays. It does this by intercepting requests through a service worker, where the request is routed to the while also injecting important scripts. This prevents the need to hook into code that previously needed to be rewritten to redirect requests saving time and resources. All of its conceptual methods are optimal.
47+
48+
## Extensibility
49+
50+
One of our strengths is Extensibility. This is done by making aero readable and customizable by anyone. Every aspect of it is documented. Even if you are not a programmer, you can understand how aero works. There are configs to control functionality - in order to have no compromises and allow those who can't write code to easily customize it. If you are a programmer, you will appreciate all the hooks and guiding variables we have to easily modify the code. We are working on an even better way of making extensions: event-driven middleware that takes advantage of its internals.
51+
52+
## HTML Interception
53+
54+
HTML is intercepted and rewritten through a Mutation Observer where important elements are rewritten. Script elements with inline code and elements with integrity values set need to be cloned due to the browser's security restrictions.
55+
56+
## Deep Scope Property Checking DSPC
57+
58+
Location objects are replaced with a fake Location api, and also in the case of the site trying to escape the location scoping bracket property accessors for certain objects are checked using our scope function that evaluates the expression in hopes of intercepting the attempted location or window call. Additionaly, this scoping is integrated into Eval, Function Class, and Reflect interceptors. _Support for this feature is enabled in flags_
59+
60+
## Cache Emulation
61+
62+
### HTTP Caches
63+
64+
HTTP caches are removed and replaced by a system using aero's own cache stores. This allows us to have caches stored for a specific origin. This is important for support since Clear-Site-Data deletes every origin's cache making aero otherwise detectable.
65+
66+
### Cache Manifests
67+
68+
aero rewrites the paths in the cache manfiests files
69+
70+
### Clear Site Data
71+
72+
Whenever this header is present a script is injected to aero that handles clearing the data since it can't be done in the SW itself
73+
74+
## Cors Emulation
75+
76+
Unlike other proxies that simply delete the cors policy and ignore it, aero abides by the intended security features by keeping them in place. Without Cors Emulation, sites can infer either the browser doesn't support modern security standards or that a proxy is being used. This means that the site would've been lacking support; no longer with aero! _Support for this feature is enabled in flags_
77+
78+
### SW Interception
79+
80+
aero has interceptors in other SWs to adhere to cache emulation and hide the fact real http caches aren't being used.
81+
82+
### Cors Testing
83+
84+
Aero sends an request to the site without the proxy in order to check if they would allow it
85+
86+
### Trusted Types
87+
88+
We support trusted types through interceptors. Aero simply do nothing because it already knows the is origin secure.

public/aero/bare.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
cd this/misc
2+
3+
if [ ! -d bare ]
4+
then
5+
git clone https://github.com/tomphttp/bare-client bare
6+
fi
7+
8+
cd bare
9+
10+
git pull
11+
12+
npm install
13+
npm run build
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Interceptors for StyleSheet
2+
3+
function getSheet(sheet) {
4+
if (sheet.href) sheet.href = $aero.afterPrefix(sheet.href);
5+
if (sheet.parentStyleSheet)
6+
sheet.parentStyleSheet = getSheet(sheet.parentStyleSheet);
7+
8+
return sheet;
9+
}
10+
11+
let bak = document.styleSheets;
12+
Object.defineProperty(document, "styleSheets", {
13+
get: () => {
14+
// StyleSheetList is read-only so the getter itself needs to be proxified
15+
ret.item = new Proxy(ret.item, {
16+
apply() {
17+
return getSheet(Reflect.apply(...arguments));
18+
},
19+
});
20+
21+
return ret;
22+
},
23+
});
24+
25+
// TODO: Support XML ProcessingInstruction.sheet
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
{
2+
// TODO: Only perform the escapes on the correct element
3+
const escapeAttrs = ["href", "integrity"];
4+
5+
const escape = {
6+
get: attr => {
7+
return attr
8+
.replace($aero.escape(escapeAttrs[0]), "_$&")
9+
.replace($aero.escape(escapeAttrs[1]), "_$&");
10+
},
11+
};
12+
13+
const attr = {
14+
apply(_target, _that, args) {
15+
const [, name] = args;
16+
17+
args[0] = escape.get(name);
18+
19+
return Reflect.apply(...arguments);
20+
},
21+
};
22+
const attrNS = {
23+
apply(_target, _that, args) {
24+
const [, name] = args;
25+
26+
args[1] = escape.get(name);
27+
28+
return Reflect.apply(...arguments);
29+
},
30+
};
31+
const removeAttr = {
32+
apply(_target, _that, args) {
33+
// Remove
34+
Reflect.apply(...arguments);
35+
36+
// Remove the backup too
37+
const [name] = args;
38+
if (name.includes(escapeAttrs)) args[0] = `_${name}`;
39+
40+
Reflect.apply(...arguments);
41+
},
42+
};
43+
const removeAttrNS = {
44+
apply(_target, _that, args) {
45+
// Remove
46+
Reflect.apply(...arguments);
47+
48+
// Remove the backup too
49+
const [, name] = args;
50+
if (name.includes(escapeAttrs)) args[1] = `_${name}`;
51+
52+
Reflect.apply(...arguments);
53+
},
54+
};
55+
56+
window.Element.hasAttribute = new Proxy(
57+
Element.prototype.hasAttribute,
58+
attr
59+
);
60+
window.Element.hasAttribute = new Proxy(
61+
Element.prototype.hasAttribute,
62+
attr
63+
);
64+
window.Element.hasAttributeNS = new Proxy(
65+
Element.prototype.hasAttribute,
66+
attrNS
67+
);
68+
window.Element.getAttribute = new Proxy(
69+
Element.prototype.getAttribute,
70+
attr
71+
);
72+
window.Element.getAttributeNode = new Proxy(
73+
Element.prototype.getAttributeNode,
74+
attr
75+
);
76+
window.Element.getAttributeNS = new Proxy(
77+
Element.prototype.getAttribute,
78+
attrNS
79+
);
80+
window.Element.getAttributeNodeNS = new Proxy(
81+
Element.prototype.getAttribute,
82+
attrNS
83+
);
84+
window.Element.getAttributeNames = new Proxy(
85+
Element.prototype.getAttributeNames,
86+
{
87+
apply(target) {
88+
return Reflect.apply(...arguments)
89+
.filter(attr => attr === "_href")
90+
.map(attr =>
91+
(target instanceof HTMLAnchorElement &&
92+
$aero.escape("href").test(attr)) ||
93+
(target instanceof HTMLScriptElement &&
94+
$aero.escape("integrity").test(attr))
95+
? attr.slice(1)
96+
: attr
97+
);
98+
},
99+
}
100+
);
101+
// Element.toggleAttribute
102+
window.Element.prototype.toggleAttribute = new Proxy(
103+
window.Element.prototype.toggleAttribute,
104+
removeAttr
105+
);
106+
window.Element.prototype.removeAttribute = new Proxy(
107+
window.Element.prototype.removeAttribute,
108+
removeAttr
109+
);
110+
window.Element.prototype.removeAttributeNS = new Proxy(
111+
window.Element.prototype.removeAttribute,
112+
removeAttrNS
113+
);
114+
115+
function conceal(attr) {
116+
Object.defineProperty(window.Element, attr, {
117+
get: () => undefined,
118+
});
119+
}
120+
conceal("_href");
121+
conceal("_xlink:href");
122+
conceal("_integrity");
123+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
Error emulation
3+
These properties are not standard, so functionality is different in browsers
4+
These interceptors will probably change a lot over time
5+
*/
6+
if ($aero.config.flags.nonstandard) {
7+
Error = new Proxy(Error, {
8+
construct() {
9+
const ret = Reflect.construct(...arguments);
10+
11+
// Firefox exclusives
12+
// Error location
13+
if (typeof ret.columnNumber !== "undefined")
14+
// TODO: Get the column number of the unscoped file
15+
// Possibly, add a data attribute with the og script
16+
ret.columnNumber = "";
17+
if (typeof ret.fileName !== "undefined")
18+
ret.fileName = $aero.afterPrefix(ret.fileName);
19+
20+
// Implemented in most major browsers
21+
if (typeof ret.stack !== "undefined")
22+
if (navigator.userAgent.includes("Firefox")) {
23+
const match = /Firefox\/([\d\.]+)/g.exec(
24+
navigator.userAgent
25+
);
26+
27+
if (match.length === 2) {
28+
ver = parseFloat(match[1]);
29+
30+
ret.stack = res.stack.replace(
31+
new RegExp(
32+
`^(@)(.+)(\\d+${ver >= 30 ? ":\\d+" : ""})$`,
33+
"g"
34+
),
35+
(_match, g1, g2, g3) =>
36+
g1 + $aero.afterPrefix(g2) + g3
37+
);
38+
}
39+
} else if (navigator.userAgent.includes("Chrome"))
40+
ret.stack = ret.stack
41+
.split("\n")
42+
.map(line =>
43+
line.includes(
44+
location.origin + $aero.config.aeroPrefix
45+
)
46+
? ""
47+
: line
48+
)
49+
.join("\n")
50+
.replace(
51+
/^(at )([A-Za-z\.]+ )?.+(?=:\d+:\d+)/g,
52+
(_match, g1, g2, g3) =>
53+
g1 + g2 + $aero.afterPrefix(g3)
54+
)
55+
.replace(
56+
/(?<=\().+(?=:\d+:\d+\))/g,
57+
(_match, g1, g2) => g1 + $aero.afterPrefix(g2)
58+
);
59+
// TODO: Support Safari
60+
61+
return ret;
62+
},
63+
});
64+
}

0 commit comments

Comments
 (0)