Purge Cyclone

This commit is contained in:
Cohen Erickson 2022-10-16 17:14:57 +00:00
parent ce625b6d3a
commit 5885af8ebf
15 changed files with 170 additions and 909 deletions

14
.devcontainer/Dockerfile Normal file
View file

@ -0,0 +1,14 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>"

View file

@ -0,0 +1,55 @@
# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM node:${VARIANT}
# [Option] Install zsh
ARG INSTALL_ZSH="true"
# [Option] Upgrade OS packages to their latest versions
ARG UPGRADE_PACKAGES="true"
# Install needed packages, yarn, nvm and setup non-root user. Use a separate RUN statement to add your own dependencies.
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID
ARG NPM_GLOBAL=/usr/local/share/npm-global
ENV NVM_DIR=/usr/local/share/nvm
ENV NVM_SYMLINK_CURRENT=true \
PATH=${NPM_GLOBAL}/bin:${NVM_DIR}/current/bin:${PATH}
COPY library-scripts/*.sh library-scripts/*.env /tmp/library-scripts/
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# Remove imagemagick due to https://security-tracker.debian.org/tracker/CVE-2019-10131
&& apt-get purge -y imagemagick imagemagick-6-common \
# Install common packages, non-root user, update yarn and install nvm
&& bash /tmp/library-scripts/common-debian.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" "true" "true" \
# Install yarn, nvm
&& rm -rf /opt/yarn-* /usr/local/bin/yarn /usr/local/bin/yarnpkg \
&& bash /tmp/library-scripts/node-debian.sh "${NVM_DIR}" "none" "${USERNAME}" \
# Configure global npm install location, use group to adapt to UID/GID changes
&& if ! cat /etc/group | grep -e "^npm:" > /dev/null 2>&1; then groupadd -r npm; fi \
&& usermod -a -G npm ${USERNAME} \
&& umask 0002 \
&& mkdir -p ${NPM_GLOBAL} \
&& touch /usr/local/etc/npmrc \
&& chown ${USERNAME}:npm ${NPM_GLOBAL} /usr/local/etc/npmrc \
&& chmod g+s ${NPM_GLOBAL} \
&& npm config -g set prefix ${NPM_GLOBAL} \
&& sudo -u ${USERNAME} npm config -g set prefix ${NPM_GLOBAL} \
# Install eslint
&& su ${USERNAME} -c "umask 0002 && npm install -g eslint" \
&& npm cache clean --force > /dev/null 2>&1 \
# Install python-is-python3 on bullseye to prevent node-gyp regressions
&& . /etc/os-release \
&& if [ "${VERSION_CODENAME}" = "bullseye" ]; then apt-get -y install --no-install-recommends python-is-python3; fi \
# Clean up
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /root/.gnupg /tmp/library-scripts
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>
# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"
# [Optional] Uncomment if you want to install more global node modules
# RUN su node -c "npm install -g <your-package-list-here>""

View file

@ -0,0 +1,32 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/javascript-node
{
"name": "Node.js",
"build": {
"dockerfile": "Dockerfile",
// Update 'VARIANT' to pick a Node version: 18, 16, 14.
// Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local arm64/Apple Silicon.
"args": { "VARIANT": "16-bullseye" }
},
// Configure tool-specific properties.
"customizations": {
// Configure properties specific to VS Code.
"vscode": {
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"dbaeumer.vscode-eslint"
]
}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "npm install",
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "node"
}

View file

@ -31,7 +31,6 @@ $ npm start
- Partical.JS
- UV Backend Proxy
- Osana Backend Proxy
- Cyclone Backend Proxy
- **Server:** Bare server on Node
@ -116,7 +115,6 @@ sudo nohup PORT=80 node . &
## Acknowledgements
- [UV (one of the back-end proxy we use)](https://github.com/titaniumnetwork-dev/Ultraviolet)
- [Cyclone (one of the back-end proxy we use)](https://github.com/NebulaServices/Cyclone)
- [Osana (one of the back-end proxy we use)](https://github.com/NebulaServices/Osana)
- [Bare Server](https://github.com/tomphttp/bare-server-node)
- [Partical.JS (v4, 5, 6.1 &< only)](https://github.com/VincentGarreau/particles.js)

2
app.js
View file

@ -3,7 +3,6 @@ import http from 'http';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import serveStatic from 'serve-static';
import * as custombare from './static/customBare.mjs';
const PORT = process.env.PORT || 3000;
const bareServer = createBareServer('/bare/', {
@ -23,7 +22,6 @@ const server = http.createServer();
server.on('request', (request, response) => {
try {
if (custombare.route(request, response)) return true;
if (bareServer.shouldRoute(request)) {
bareServer.routeRequest(request, response);

109
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "nebula-web",
"version": "7.10",
"version": "7.10.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nebula-web",
"version": "7.10",
"version": "7.10.0",
"license": "GNU AGPL V3",
"dependencies": {
"@tomphttp/bare-server-node": "^1.0.2-beta-readme5",
@ -15,29 +15,29 @@
"node-fetch": "^3.2.6",
"serve-static": "^1.15.0",
"ws": "^8.8.1"
}
},
"node_modules/@tomphttp/bare-server-node": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tomphttp/bare-server-node/-/bare-server-node-1.0.3.tgz",
"integrity": "sha512-mKMipi9qntDy3wcalWGuK3iKzM0XQT4sW3E6yRXeIU4BxFZVSLzSDejPxL6wWwniKGm0faSwZ4Pk0dQ04JEFNA==",
"dependencies": {
"commander": "^9.0.0",
"dotenv": "^16.0.1",
"headers-polyfill": "^3.0.10",
"http-errors": "^2.0.0"
},
"bin": {
"bare-server-node": "scripts/cli.js"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@tomphttp/bare-server-node": {
"version": "1.0.2-beta-readme5",
"resolved": "https://registry.npmjs.org/@tomphttp/bare-server-node/-/bare-server-node-1.0.2-beta-readme5.tgz",
"integrity": "sha512-WOYNae3faSj9Yt4dKVqzjbh1ovpKRhsevnJaM2BgC6LkRULFN/GhtslXDXG6KLbqeokFFj0XqpZ8TTzdxKyhkw==",
"dependencies": {
"commander": "^9.0.0",
"dotenv": "^16.0.1",
"fetch-headers": "^3.0.1",
"http-errors": "^2.0.0"
},
"bin": {
"bare-server-node": "scripts/start.js"
}
},
"node_modules/commander": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==",
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz",
"integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==",
"engines": {
"node": "^12.20.0 || >=14"
}
@ -99,9 +99,9 @@
}
},
"node_modules/dotenv": {
"version": "16.0.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz",
"integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==",
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
"engines": {
"node": ">=12"
}
@ -154,6 +154,24 @@
"node": "^12.20 || >= 14.13"
}
},
"node_modules/fetch-headers": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/fetch-headers/-/fetch-headers-3.0.1.tgz",
"integrity": "sha512-Kq+NyED/wLgT29St7aW47gAWg8EmmE5QmhwQ5RmPRULYLqpglA7Kc/ZnbqXu2vhH6mw1koikew2g94WiHLPmpA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=12.20"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
@ -173,11 +191,6 @@
"node": ">= 0.6"
}
},
"node_modules/headers-polyfill": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.0.10.tgz",
"integrity": "sha512-lOhQU7iG3AMcjmb8NIWCa+KwfJw5bY44BoWPtrj5A4iDbSD3ylGf5QcYr0ZyQnhkKQ2GgWNLdF2rfrXtXlF3nQ=="
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -356,9 +369,9 @@
}
},
"node_modules/ws": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz",
"integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==",
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz",
"integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==",
"engines": {
"node": ">=10.0.0"
},
@ -378,20 +391,20 @@
},
"dependencies": {
"@tomphttp/bare-server-node": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tomphttp/bare-server-node/-/bare-server-node-1.0.3.tgz",
"integrity": "sha512-mKMipi9qntDy3wcalWGuK3iKzM0XQT4sW3E6yRXeIU4BxFZVSLzSDejPxL6wWwniKGm0faSwZ4Pk0dQ04JEFNA==",
"version": "1.0.2-beta-readme5",
"resolved": "https://registry.npmjs.org/@tomphttp/bare-server-node/-/bare-server-node-1.0.2-beta-readme5.tgz",
"integrity": "sha512-WOYNae3faSj9Yt4dKVqzjbh1ovpKRhsevnJaM2BgC6LkRULFN/GhtslXDXG6KLbqeokFFj0XqpZ8TTzdxKyhkw==",
"requires": {
"commander": "^9.0.0",
"dotenv": "^16.0.1",
"headers-polyfill": "^3.0.10",
"fetch-headers": "^3.0.1",
"http-errors": "^2.0.0"
}
},
"commander": {
"version": "9.4.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz",
"integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw=="
"version": "9.4.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-9.4.1.tgz",
"integrity": "sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw=="
},
"crypto-js": {
"version": "4.1.1",
@ -438,9 +451,9 @@
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"dotenv": {
"version": "16.0.2",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.2.tgz",
"integrity": "sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA=="
"version": "16.0.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
"integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ=="
},
"ee-first": {
"version": "1.1.1",
@ -471,6 +484,11 @@
"web-streams-polyfill": "^3.0.3"
}
},
"fetch-headers": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/fetch-headers/-/fetch-headers-3.0.1.tgz",
"integrity": "sha512-Kq+NyED/wLgT29St7aW47gAWg8EmmE5QmhwQ5RmPRULYLqpglA7Kc/ZnbqXu2vhH6mw1koikew2g94WiHLPmpA=="
},
"formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
@ -484,11 +502,6 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
},
"headers-polyfill": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.0.10.tgz",
"integrity": "sha512-lOhQU7iG3AMcjmb8NIWCa+KwfJw5bY44BoWPtrj5A4iDbSD3ylGf5QcYr0ZyQnhkKQ2GgWNLdF2rfrXtXlF3nQ=="
},
"http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -611,9 +624,9 @@
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
},
"ws": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz",
"integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==",
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz",
"integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==",
"requires": {}
}
}

View file

@ -1,6 +1,6 @@
{
"name": "nebula-web",
"version": "7.10",
"version": "7.10.0",
"description": "Explore the web. Freely.",
"type": "module",
"main": "app.js",
@ -13,11 +13,14 @@
"author": "Nebula Services",
"license": "GNU AGPL V3",
"dependencies": {
"@tomphttp/bare-server-node": "1.0.2-beta-readme5",
"@tomphttp/bare-server-node": "^1.0.2-beta-readme5",
"crypto-js": "4.1.1",
"css-tree": "^2.1.0",
"node-fetch": "^3.2.6",
"serve-static": "^1.15.0",
"ws": "^8.8.1"
},
"engines": {
"node": ">=16.0.0"
}
}

View file

@ -1,137 +0,0 @@
import fetch from 'node-fetch';
import { URL } from 'url';
import fs from 'fs';
import * as csstree from 'css-tree';
import * as ws from 'ws';
import filter from './cyclone/filter.cyclone.mjs';
import * as security from './cyclone/security.cyclone.mjs';
const config = {
prefix: "/service/next",
requireSSL: true, // Requires SSL?
defaultHeaders: {
'X-Content-Type-Options': 'no-sniff',
},
}
if (config.requireSSL) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "1";
} else {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
function rewriteJavascript(js) {
var javascript = js.replace(/window\.location/g, 'window._dlocation')
javascript = javascript.replace(/document\.location/g, 'document._dlocation')
javascript = javascript.replace(/location\./g, '_location.')
return javascript
}
function insertScript(html) {
var res = `<!DOCTYPE html>
<html>
<head>
<script preload src="/cyclone/cyclone.js"></script>
</head>
<body>
${html}
</body>
</html>`
return res
}
async function fetchBare(url, res, req) {
try {
var options = {
method: req.method,
headers: {
"Referer": url.href,
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36",
"Cookie": req.headers.cookie,
},
}
var request = await fetch(url.href, options);
try {
var contentType = request.headers.get('content-type') || 'application/javascript'
} catch {
var contentType = 'application/javascript';
}
if (url.href.endsWith('.js') || url.href.endsWith(".js")) contentType = "application/javascript";
if (url.href.endsWith('.css') || url.href.endsWith(".css")) contentType = "text/css";
var output = null;
if (contentType.includes('html') || contentType.includes('javascript')) {
var doc = await request.text();
}
res.setHeader('content-type', contentType);
if (contentType.includes('html')) {
output = insertScript(doc);
res.write(output);
res.end();
} else if (contentType.includes('javascript')) {
output = rewriteJavascript(doc)
res.write(output);
res.end()
} else {
request.body.pipe(res)
}
} catch (e) {
res.writeHead(500, 'Internal Server Error', {
'Content-Type': 'text/plain'
})
res.end(e.stack);
}
}
function websocketIntercept(req, res) {
console.log(req);
}
function route(req, res) {
var path = req.url;
if (path.startsWith(config.prefix + "/")) {
var decoded = path.split(config.prefix + "/")[1];
try {
var url = new URL(decoded);
} catch {
var url = new URL("https://" + decoded);
}
if (filter(req, res)) return;
return fetchBare(url, res, req);
} else {
return false;
}
}
function isBare(req, res) {
return (req.url.startsWith(config.prefix));
}
function routeSocket(req, socket) {
var path = req.url;
try {
var url = new URL(path(config.prefix + "/")[1])
} catch {
var url = new URL("wss://" + path(config.prefix + "/")[1])
}
console.log(url);
}
export {
route,
routeSocket,
isBare,
}

View file

@ -1,109 +0,0 @@
class Cyclone {
constructor() {
tmp = location.pathname.split('/service')[1]
tmp = tmp.substring(1, tmp.length);
let re = /(http(s|):)/g
//if (tmp.match(re)) {
tmp = tmp.replace("http://", '')
tmp = tmp.replace("https://", '')
tmp = tmp.replace("http:/", '')
tmp = tmp.replace("https:/", '')
tmp = location.protocol + "//" + tmp
document._location = new URL(tmp);
this.url = new URL(document._location.href);
this.bareEndpoint = location.host + "/service";
if (this.url.pathname == "/") {
this.paths = ['/']
} else {
this.paths = this.url.pathname.split('/')
}
this.host = 'https://' + this.url.host
this.targetAttrs = ['href', 'src', 'action', 'srcdoc', 'srcset'];
console.log("Cyclone Injected with paths of:", this.paths, this.url.pathname)
/*const LocationHandler = {
get(target, prop, reciver) {
return loc[prop]
},
set(target, prop, val) {
return 'hi'
}
}
document._location = new Proxy(LocationHandler, loc)*/
}
rewriteUrl(link) {
var rewritten;
if (link.startsWith('https://') || link.startsWith('http://') || link.startsWith('//')) {
if (link.startsWith('//')) {
rewritten = 'https:' + link;
} else {
rewritten = link;
};
} else {
if (link.startsWith('.')) {
let offset = 1;
if (link.startsWith('..')) {
offset = 2;
}
let file = link.substr(link.indexOf('.') + 1 + offset, link.length)
rewritten = this.url.hostname + file
} else {
if (link.startsWith('/')) {
rewritten = this.host + link
} else {
rewritten = this.host + '/' + link;
}
}
}
var exceptions = ['about:', 'mailto:', 'javascript:', 'data:']
let needstowrite = true;
for (let i = 0; i < exceptions.length; i++) {
if (link.startsWith(exceptions[i])) {
needstowrite = false
}
}
if (needstowrite) {
rewritten = location.protocol + '//' + this.bareEndpoint + '/' + rewritten
return rewritten;
} else {
return link;
}
}
rewriteSrcset(sample) {
return sample.split(',').map(e => {
return (e.split(' ').map(a => {
if (a.startsWith('http') || (a.startsWith('/') && !a.startsWith(this.prefix))) {
var url = this.rewriteUrl(a)
}
return a.replace(a, (url || a))
}).join(' '))
}).join(',')
}
}
self.addEventListener('fetch', function(event) {
var uri = new URL(event.request.url);
if (!uri.pathname.startsWith('/service') && uri.pathname == "/facicon.ico") {
var tmp = uri.href;
event.respondWith(
fetch("https://Cyclone2.jimmynuetron.repl.co/service/" + tmp)
)
}
});

View file

@ -1,476 +0,0 @@
const config = {
}
const encryptWithAES = (text) => {
const passphrase = '123';
return CryptoJS.AES.encrypt(text, passphrase).toString();
};
const decryptWithAES = (ciphertext) => {
const passphrase = '123';
const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase);
const originalText = bytes.toString(CryptoJS.enc.Utf8);
return originalText;
};
class Cyclone {
constructor() {
this.tmp = (location.pathname.split('/service/')[1]);
this.tmp = this.tmp.substring(0, this.tmp.length);
this.tmp = this.tmp.replace("http://", '')
this.tmp = this.tmp.replace("https://", '')
this.tmp = this.tmp.replace("http:/", '')
this.tmp = this.tmp.replace("https:/", '')
this.tmp = location.protocol + "//" + this.tmp
document._location = new URL(this.tmp);
var l = new URL(this.tmp);
this.url = new URL(document._location.href);
this.prefix = (location.pathname).split('/')[1];
this.bareEndpoint = location.host + "/" + this.prefix;
if (this.url.pathname == "/") {
this.paths = ['/']
} else {
this.paths = this.url.pathname.split('/')
}
this.host = 'https://' + this.url.host
this.targetAttrs = ['href', 'src', 'action', 'srcdoc', 'srcset'];
if (!document.cycloneInjected) {
console.log("Cyclone Injected with paths of:", this.paths, this.url.pathname)
document.cycloneInjected = true
}
const LocationHandler = {
get(target, prop, reciver) {
return document._location[prop]
},
set(target, prop, val) {
return false
}
}
//const locProxy = new Proxy(document.location, LocationHandler)
Object.defineProperty(document, '_location', {
writable: true,
configurable: true,
enumerable: true,
value: l
});
Object.defineProperty(window.document, '_location', {
writable: true,
configurable: true,
enumerable: true,
value: l
});
Object.defineProperty(window, '_location', {
writable: true,
configurable: true,
enumerable: true,
value: l
});
}
rewriteUrl(link) {
if (!link) {
link = "";
}
var rewritten;
if (link.startsWith('https://') || link.startsWith('http://') || link.startsWith('//')) {
if (link.startsWith('//')) {
rewritten = 'https:' + link;
} else {
rewritten = link;
};
} else {
if (link.startsWith('.')) {
let offset = 1;
if (link.startsWith('..')) {
offset = 2;
}
let file = link.substr(link.indexOf('.') + 1 + offset, link.length)
rewritten = this.url.hostname + file
} else {
if (link.startsWith('/')) {
rewritten = this.host + link
} else {
rewritten = this.host + '/' + link;
}
}
}
var exceptions = ['about:', 'mailto:', 'javascript:', 'data:']
let needstowrite = true;
for (let i = 0; i < exceptions.length; i++) {
if (link.startsWith(exceptions[i])) {
needstowrite = false
}
}
if (needstowrite) {
rewritten = location.protocol + '//' + this.bareEndpoint + '/' + rewritten
return (rewritten);
} else {
return link;
}
}
rewriteSrcset(sample) {
return sample.split(',').map(e => {
return (e.split(' ').map(a => {
if (a.startsWith('http') || (a.startsWith('/') && !a.startsWith(this.prefix))) {
var url = this.rewriteUrl(url);
}
return a.replace(a, (url || a))
}).join(' '))
}).join(',')
}
}
// Rewriting of data types
// CSS
class CSSRewriter extends Cyclone {
rewriteCSS(tag) {
var styles = window.getComputedStyle(tag)
var _values = styles['_values']
var prop = styles.getPropertyValue('background-image')
var name = "background-image"
if (prop == "") {
if (!styles.getPropertyValue('background') == "") {
prop = styles.getPropertyValue('background')
name = "background"
} else {
name = "";
prop = "";
}
}
if (prop.includes("url(")) {
var start = prop.indexOf('url(') + 4
var end = prop.indexOf(')') - 4
var url = prop.substring(start, end).toString('ascii');
if (url.startsWith(location.origin)) {
url = url.split(location.origin)
} else {
url = url.slice(url.indexOf(location.origin));
}
url = this.rewriteUrl(url)
tag.style[name] = url
}
}
}
// JS
class JavaScriptRewriter extends Cyclone {
constructor(proxy) {
super();
//Proxied methods
this.setAttrCy = HTMLElement.prototype.setAttribute;
this.getAttrCy = HTMLElement.prototype.getAttribute;
this.proxy = proxy
}
rewriteJavascript(js) {
var javascript = js.replace(/window\.location/g, 'document._location')
javascript = javascript.replace(/document\.location/g, 'document._location')
return javascript
}
setAttribute(attr, value, mode) {
const setAttrCy = HTMLElement.prototype.setAttribute;
if (mode) {
this.setAttrCy.call(this, attr, value);
} else {
var url = attr
if (cyclone.targetAttrs.includes(attr)) {
url = cyclone.rewriteUrl(url);
}
setAttrCy.call(this, attr, value);
}
}
getAttribute(attrN, mode) {
const getAttrCy = HTMLElement.prototype.getAttribute;
if (mode) {
return getAttrCy.call(this, attrN);
} else {
var val = getAttrCy.call(this, attrN);
if (cyclone.targetAttrs.includes(attrN)) {
val = getAttrCy.call(this, 'data-origin-' + attrN);
}
return val;
}
}
}
// HTML
class HTMLRewriter extends Cyclone {
rewriteElement(element) {
var targetAttrs = this.targetAttrs;
var attrs;
try {
attrs = [...element.attributes || {}].reduce((attrs, attribute) => {
attrs[attribute.name] = attribute.value;
return attrs;
}, {});
} catch {
attrs = {};
}
if (element.__proto__.getAttribute) {
var jsWrite = new JavaScriptRewriter();
var elementAttributes = [];
for (var i = 0; i < targetAttrs.length; i++) {
var attr = targetAttrs[i]
var attrName = Object.keys(attrs)[i];
var data = {
name: attr,
value: element.getAttribute('data-origin-' + attr, 'cyclone') || element.getAttribute(attr, 'cyclone')
}
if (data.value) {
elementAttributes.push(data);
}
if (element.nonce) {
element.setAttribute('nononce', element.nonce, '')
element.removeAttribute('nonce')
}
if (element.integrity) {
element.setAttribute('nointegrity', element.integrity, '')
element.removeAttribute('integrity')
}
if (element.tagName == "script") {
if (!element.getAttribute('src')) {
var jsRewrite = new JavaScriptRewriter();
element.innerHTML = jsRewrite.rewriteJavascript(element.innerHTML)
}
}
// Css
var cssRewrite = new CSSRewriter();
cssRewrite.rewriteCSS(element)
}
for (var i = 0; i < elementAttributes.length; i++) {
var attr = elementAttributes[i];
var attrName = attr.name;
var value = attr.value;
var bareValue = this.rewriteUrl(value);
if (attrName == "srcset" || attrName == 'srcset') {
bareValue = this.rewriteSrcset(value);
}
element.setAttribute(attrName, bareValue);
element.setAttribute("data-origin-" + attrName, value);
}
}
}
rewriteDocument() {
var docElements = document.querySelectorAll('*');
for (var i = 0; i < docElements.length; i++) {
var element = docElements[i];
this.rewriteElement(element)
}
}
rewriteiFrame(iframe) {
var frameDoc = (iframe.contentWindow || iframe.contentDocument || iframe.document);
let tags = frameDoc.querySelectorAll('*')
for (var i = 0; i < tags.length; i++) {
var tag = tags[i]
this.rewriteElement(tag)
}
}
rewriteDocObject(docObj) {
var docElements = docObj.querySelectorAll('*');
for (var i = 0; i < docElements.length; i++) {
var element = docElements[i];
this.rewriteElement(element)
}
}
}
const cyclone = new Cyclone();
const htmlRewriter = new HTMLRewriter();
const FetchIntercept = window.fetch;
window.fetch = async(...args) => {
let [resource, config] = args;
resource = cyclone.rewriteUrl(resource);
const response = await FetchIntercept(resource, config);
return response;
}
const MessageIntercept = window.postMessage;
const messageInterceptionFunc = (...args) => {
let [message, target, config] = args;
target = cyclone.rewriteUrl(target);
const response = MessageIntercept(message, target, config);
console.log(response);
return response;
}
Object.defineProperty(window, 'postMessage', {
writable: false,
value: messageInterceptionFunc
})
var CWOriginal = Object.getOwnPropertyDescriptor(window.HTMLIFrameElement.prototype, 'contentWindow')
Object.defineProperty(window.HTMLIFrameElement.prototype, 'contentWindow', {
get() {
var iWindow = CWOriginal.get.call(this);
htmlRewriter.rewriteiFrame(iWindow);
return iWindow
},
set() {
return false;
}
})
const open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
url = cyclone.rewriteUrl(url)
return open.call(this, method, url, ...rest);
};
var oPush = window.history.pushState;
var oPlace = window.history.replaceState;
function CycloneStates(dat, unused, url) {
var cyUrl = cyclone.rewriteUrl(url);
oPush.call(this, dat, unused, cyUrl);
}
window.history.pushState = CycloneStates
window.history.replaceState = CycloneStates
history.pushState = CycloneStates
history.replaceState = CycloneStates
const OriginalWebsocket = window.WebSocket
const ProxiedWebSocket = function() {
const ws = new OriginalWebsocket(...arguments)
const originalAddEventListener = ws.addEventListener
const proxiedAddEventListener = function() {
if (arguments[0] === "message") {
const cb = arguments[1]
arguments[1] = function() {
var origin = arguments[0].origin
arguments[0].origin = cyclone.rewriteUrl(origin);
return cb.apply(this, arguments)
}
}
return originalAddEventListener.apply(this, arguments)
}
ws.addEventListener = proxiedAddEventListener
Object.defineProperty(ws, "onmessage", {
set(func) {
return proxiedAddEventListener.apply(this, [
"message",
func,
false
]);
}
});
return ws;
};
window.WebSocket = ProxiedWebSocket;
// Request
var requestProxyHandler = {
get(target, prop, receiver) {
console.log(target);
if (prop == "url") {
return 'the j';
}
return Reflect.get(...arguments);
}
}
Request.prototype = new Proxy(Request.prototype, requestProxyHandler);
Request.__proto__ = new Proxy(Request.__proto__, requestProxyHandler);
const nwtb = window.open
function openNewTab(url, target, features) {
url = cyclone.rewriteUrl(url)
nwtb(url, target, features)
}
window.open = openNewTab;
window.onload = function() {
for (var i = 0; i < 50; i++) {
setTimeout(() => {
htmlRewriter.rewriteDocument();
}, 500)
}
}
let mutationE = new MutationObserver((mutationList, observer) => {
for (const mutation of mutationList) {
mutation.addedNodes.forEach(node => {
htmlRewriter.rewriteElement(node);
});
}
}).observe(document, {
childList: true,
subtree: true
})
//For intercepting all requests
if (!document.serviceWorkerRegistered) {
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register(location.origin + '/cySw.js').then(function(registration) {
console.log('Service worker registered with scope: ', registration.scope);
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
document.serviceWorkerRegistered = true
}

View file

@ -1,82 +0,0 @@
import fs from 'fs';
const xor = {
encode: (url) => encodeURIComponent(url.toString().split("").map((char, ind) => ind % 2 ? String
.fromCharCode(char.charCodeAt() ^ 2) : char).join("")),
decode: (url) => decodeURIComponent(url.split("?")[0]).split("").map((char, ind) => ind % 2 ? String
.fromCharCode(char.charCodeAt(0) ^ 2) : char).join("") + (url.split("?").slice(1).length ? "?" +
url.split("?").slice(1).join("?") : "")
}
function getBlockPage(site, reason) {
return `<!DOCTYPE html>
<html>
<head>
<style>
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap');
body {
background-color: #ff4f4f;
color: white;
font-family: 'Roboto', sans-serif;
}
p {
font-size: 54px;
}
</style>
</head>
<body>
<center>
<p>Access Denied</p>
<div class="main">
<img src="/images/denied_sign.svg" width="200" onclick="location.pathname = '/service/google.com'">
</div>
<a style="position: absolute; bottom: 10; right: 0; left: 0; display: inline;">
Looks like ${site} is blocked for ${reason}
</a>
</center>
</body>
</html>`
}
const blacklist = [
'netflix.com',
'www.netflix.com',
'accounts.google.com',
]
function filter(req, res) {
var decode = req.url.split("/service/")[1];
decode = decode.replace("http://", '')
decode = decode.replace("https://", '')
decode = decode.replace("http:/", '')
decode = decode.replace("https:/", '')
decode = 'https://' + decode;
var uri = new URL(decode);
var toBlock = (blacklist.includes(uri.host));
if (toBlock) {
var b = getBlockPage(uri.host, 'cyclone__DenyURL');
res.end(b);
return true;
} else {
return false
}
}
export {
filter as
default
} // don't want Netflix's legal team to go sicko mode

View file

@ -1,18 +0,0 @@
import CryptoJS from 'crypto-js';
const encryptWithAES = (text) => {
const passphrase = '123';
return CryptoJS.AES.encrypt(text, passphrase).toString();
};
const decryptWithAES = (ciphertext) => {
const passphrase = '123';
const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase);
const originalText = bytes.toString(CryptoJS.enc.Utf8);
return originalText;
};
export {
encryptWithAES as encrypt,
decryptWithAES as decrypt
}

View file

@ -41,8 +41,6 @@
<br>
<li> <a style='color:black;' href="https://github.com/cohenerickson"> Cohen </a></li>
<br>
<li> <a style='color:black;' href="https://github.com/SmartCoder3000"> System32 </a></li>
<br>
<li> <a style='color:black;' href="https://github.com/schooldev49"> simplydeveloper </a></li>
<br>
<br>
@ -67,7 +65,6 @@
<div style='color:black;'> Acknowledgements are resources Nebula is using/has used.
<ul style='color:black;'>
<li><a style='color:black;' href="https://github.com/titaniumnetwork-dev/Ultraviolet">UV (one of the back-end proxy we use)</a></li>
<li><a style='color:black;' href="https://github.com/NebulaServices/Cyclone">Cyclone (one of the back-end proxy we use)</a></li>
<li><a style='color:black;' href="https://github.com/NebulaServices/Osana">Osana (one of the back-end proxy we use)</a></li>
<li><a style='color:black;' href="https://github.com/tomphttp/bare-server-node">Bare Server</a></li>
<br>
@ -115,7 +112,6 @@
<a onclick="unsavedChanges();"> <select class="dropdown" id="proxySwitcher">
<option value="uv">UltraViolet</option>
<option value="osana">Osana (beta)</option>
<option value="cyclone">Cyclone (Legacy)</option>
</select>
</a>

View file

@ -140,19 +140,6 @@ window.addEventListener('load', () => {
blob.body.appendChild(iframe)
}
});
} else if (proxy == 'cyclone') {
const value = event.target.firstElementChild.value;
let url = value.trim();
if (!isUrl(url)) url = 'www.google.com/search?q=' + url;
if (!(url.startsWith('https://') || url.startsWith('http://'))) url = 'http://' + url;
let redirectTo = '/cyclone/' + url;
const option = localStorage.getItem('nogg');
if (option === 'on') {
stealthEngine(redirectTo);
} else location.pathname = redirectTo;
}
});
@ -1291,7 +1278,7 @@ console.log(day + ", " + formatAMPM(new Date))
// Search Result.
const suggestFromString = async(input) => {
var request = await fetch("https://tomphttp-bare.jimmynuetron.repl.co/v1/", { headers: { 'x-bare-host': 'duckduckgo.com', 'x-bare-protocol': 'https:', 'x-bare-path': '/ac/?q=' + encodeURIComponent(input), 'x-bare-port': '443', 'x-bare-headers': JSON.stringify({ Host: 'duckduckgo.com' }), 'x-bare-forward-headers': '[]' } });
var request = await fetch("/bare/v1/", { headers: { 'x-bare-host': 'duckduckgo.com', 'x-bare-protocol': 'https:', 'x-bare-path': '/ac/?q=' + encodeURIComponent(input), 'x-bare-port': '443', 'x-bare-headers': JSON.stringify({ Host: 'duckduckgo.com' }), 'x-bare-forward-headers': '[]' } });
var json = await request.json();
return json;
}

View file

@ -154,19 +154,6 @@ scope: '/service/'
}, 1000);
}
});
} else if (proxy == 'cyclone') {
const value = event.target.firstElementChild.value;
let url = value.trim();
if (!isUrl(url)) url = 'www.google.com/search?q=' + url;
if (!(url.startsWith('https://') || url.startsWith('http://'))) url = 'http://' + url;
let redirectTo = '/service/next/' + url;
const option = localStorage.getItem('nogg');
if (option === 'on') {
stealthEngine(redirectTo);
} else location.pathname = redirectTo;
}
});
@ -1311,7 +1298,7 @@ console.log(day + ", " + formatAMPM(new Date))
// Search Result.
const suggestFromString = async(input) => {
var request = await fetch("https://tomphttp-bare.jimmynuetron.repl.co/v1/", { headers: { 'x-bare-host': 'duckduckgo.com', 'x-bare-protocol': 'https:', 'x-bare-path': '/ac/?q=' + encodeURIComponent(input), 'x-bare-port': '443', 'x-bare-headers': JSON.stringify({ Host: 'duckduckgo.com' }), 'x-bare-forward-headers': '[]' } });
var request = await fetch("/bare/v1", { headers: { 'x-bare-host': 'duckduckgo.com', 'x-bare-protocol': 'https:', 'x-bare-path': '/ac/?q=' + encodeURIComponent(input), 'x-bare-port': '443', 'x-bare-headers': JSON.stringify({ Host: 'duckduckgo.com' }), 'x-bare-forward-headers': '[]' } });
var json = await request.json();
return json;
}