mirror of
https://github.com/zizifn/edgetunnel
synced 2024-11-22 18:07:07 +00:00
parent
26a65b5778
commit
620c57e602
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -4,6 +4,7 @@
|
||||
"deno.enablePaths": [
|
||||
"apps/deno-bypass",
|
||||
"apps/deno-vless/src/deno",
|
||||
"apps/deno-vless/src/main.ts"
|
||||
"apps/deno-vless/src/main.ts",
|
||||
"apps/deno-vless/src/deno-test.ts"
|
||||
]
|
||||
}
|
||||
|
@ -42,15 +42,14 @@ https://blog.cloudflare.com/introducing-socket-workers/
|
||||
|
||||
## V2ray Edge server --- Node.js
|
||||
|
||||
很多 Node.js 的平台都是支持 docker 的,所以可以直接部署原版。但是既然很多人要,我就写一个,但是我不承若一定回答关于 Node.js 平台的所有问题。因为太多了。
|
||||
|
||||
### railway.app
|
||||
很多 Node.js 的平台都是支持 docker 的,所以可以直接部署原版。但是既然很多人要,我就写一个。我目前仅仅 render 平台。
|
||||
|
||||
### render.com
|
||||
|
||||
## 客户端 v2rayN 配置
|
||||
|
||||
> ⚠️ 由于 edge 平台限制,无法转发 UDP 包。请在配置时候,把 DNS 的策略改成 "Asis", 否则会影响速度。
|
||||
> 请不要开启 ipv6 优先。
|
||||
|
||||
> [ DNS 科普文章](https://tachyondevel.medium.com/%E6%BC%AB%E8%B0%88%E5%90%84%E7%A7%8D%E9%BB%91%E7%A7%91%E6%8A%80%E5%BC%8F-dns-%E6%8A%80%E6%9C%AF%E5%9C%A8%E4%BB%A3%E7%90%86%E7%8E%AF%E5%A2%83%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8-62c50e58cbd0)
|
||||
|
||||
|
16
apps/deno-vless/src/deno-test.ts
Normal file
16
apps/deno-vless/src/deno-test.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { serve } from 'https://deno.land/std@0.170.0/http/server.ts';
|
||||
|
||||
const handler = async (req: Request) => {
|
||||
console.log('start');
|
||||
|
||||
const connect = await Deno.connect({
|
||||
port: 443,
|
||||
hostname: '2606:4700:0000:0000:0000:0000:6810:7c60',
|
||||
});
|
||||
|
||||
console.log(connect.remoteAddr);
|
||||
return new Response('hello', {
|
||||
status: 200,
|
||||
});
|
||||
};
|
||||
serve(handler, { port: 8081, hostname: '0.0.0.0' });
|
@ -29,7 +29,7 @@ const handler = async (req: Request): Promise<Response> => {
|
||||
const { socket, response } = Deno.upgradeWebSocket(req);
|
||||
socket.addEventListener('open', () => {});
|
||||
|
||||
let test: Deno.TcpConn | null = null;
|
||||
// let test: Deno.TcpConn | null = null;
|
||||
// test!.writable.abort();
|
||||
//
|
||||
processWebSocket({
|
||||
|
18
apps/node-vless/.eslintrc.json
Normal file
18
apps/node-vless/.eslintrc.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
16
apps/node-vless/jest.config.ts
Normal file
16
apps/node-vless/jest.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'node-vless',
|
||||
preset: '../../jest.preset.js',
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
},
|
||||
},
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/apps/node-vless',
|
||||
};
|
61
apps/node-vless/project.json
Normal file
61
apps/node-vless/project.json
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "node-vless",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/node-vless/src",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/webpack:webpack",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"target": "node",
|
||||
"compiler": "tsc",
|
||||
"outputPath": "dist/apps/node-vless",
|
||||
"main": "apps/node-vless/src/main.ts",
|
||||
"tsConfig": "apps/node-vless/tsconfig.app.json",
|
||||
"assets": ["apps/node-vless/src/assets"]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"optimization": true,
|
||||
"extractLicenses": true,
|
||||
"inspect": false,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "apps/node-vless/src/environments/environment.ts",
|
||||
"with": "apps/node-vless/src/environments/environment.prod.ts"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nrwl/js:node",
|
||||
"options": {
|
||||
"buildTarget": "node-vless:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "node-vless:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["apps/node-vless/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "apps/node-vless/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"implicitDependencies": ["cf-page"],
|
||||
"tags": []
|
||||
}
|
0
apps/node-vless/src/app/.gitkeep
Normal file
0
apps/node-vless/src/app/.gitkeep
Normal file
61
apps/node-vless/src/app/utils.ts
Normal file
61
apps/node-vless/src/app/utils.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { createReadStream, existsSync } from 'node:fs';
|
||||
import { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import { resolve, join, extname } from 'node:path';
|
||||
import { cacheHeader } from 'pretty-cache-header';
|
||||
|
||||
const mimeLookup = {
|
||||
'.js': 'application/javascript,charset=UTF-8',
|
||||
'.html': 'text/html,charset=UTF-8',
|
||||
'.css': 'text/css; charset=UTF-8',
|
||||
};
|
||||
const staticPath = 'dist/apps/cf-page/';
|
||||
const file401 = 'dist/apps/node-vless/assets/401.html';
|
||||
let filepath = null;
|
||||
export function serverStaticFile(req: IncomingMessage, resp: ServerResponse) {
|
||||
const url = new URL(req.url, `http://${req.headers['host']}`);
|
||||
let fileurl = url.pathname;
|
||||
fileurl = join(staticPath, fileurl);
|
||||
console.log('....', fileurl);
|
||||
filepath = resolve(fileurl);
|
||||
console.log(filepath);
|
||||
|
||||
if (existsSync(filepath)) {
|
||||
let fileExt = extname(filepath);
|
||||
console.log('fileExt', fileExt);
|
||||
let mimeType = mimeLookup[fileExt];
|
||||
|
||||
resp.writeHead(200, {
|
||||
'Content-Type': mimeType,
|
||||
'Cache-Control': cacheHeader({
|
||||
public: true,
|
||||
maxAge: '1year',
|
||||
staleWhileRevalidate: '1year',
|
||||
}),
|
||||
});
|
||||
return createReadStream(filepath).pipe(resp);
|
||||
} else {
|
||||
resp.writeHead(404);
|
||||
resp.write('not found');
|
||||
resp.end();
|
||||
return resp;
|
||||
}
|
||||
}
|
||||
|
||||
export function index401(req: IncomingMessage, resp: ServerResponse) {
|
||||
const file401Path = resolve(file401);
|
||||
if (existsSync(file401Path)) {
|
||||
createReadStream(file401Path).pipe(resp);
|
||||
} else {
|
||||
resp.writeHead(401);
|
||||
resp.write('UUID env not set');
|
||||
resp.end();
|
||||
}
|
||||
}
|
||||
|
||||
export function serverIndexPage(
|
||||
req: IncomingMessage,
|
||||
resp: ServerResponse,
|
||||
uuid
|
||||
) {
|
||||
// if()
|
||||
}
|
0
apps/node-vless/src/assets/.gitkeep
Normal file
0
apps/node-vless/src/assets/.gitkeep
Normal file
33
apps/node-vless/src/assets/401.html
Normal file
33
apps/node-vless/src/assets/401.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>401 - UUID Not Valid</title>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<h1 style="color: red;">Not set valid UUID in Environment Variables.</h1>
|
||||
<h2>Please use tool to generate and <span style="color: red;">remember</span> UUID or use this one <span
|
||||
style="color: blue;" id="uuidSpan"></span>
|
||||
</h2>
|
||||
<h3> You must use same UUID for login this page after config valid UUID Environment Variables
|
||||
</h3>
|
||||
<h2>Please refer to <a
|
||||
href="https://github.com/zizifn/edgetunnel/blob/main/doc/edge-tunnel-deno.md#%E6%B5%81%E7%A8%8B%E6%BC%94%E7%A4%BA">deno
|
||||
deploy guide</a>
|
||||
</h2>
|
||||
|
||||
<h3>Or maybe check below <a
|
||||
href="https://raw.githubusercontent.com/zizifn/edgetunnel/main/doc/deno-deploy2.gif">GIF</a> </h3>
|
||||
<img src="https://raw.githubusercontent.com/zizifn/edgetunnel/main/doc/deno-deploy2.gif" alt="guide" srcset="">
|
||||
<script>
|
||||
let uuid = URL.createObjectURL(new Blob([])).substr(-36);
|
||||
document.getElementById('uuidSpan').textContent = uuid
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
3
apps/node-vless/src/environments/environment.prod.ts
Normal file
3
apps/node-vless/src/environments/environment.prod.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const environment = {
|
||||
production: true,
|
||||
};
|
3
apps/node-vless/src/environments/environment.ts
Normal file
3
apps/node-vless/src/environments/environment.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const environment = {
|
||||
production: false,
|
||||
};
|
219
apps/node-vless/src/main.ts
Normal file
219
apps/node-vless/src/main.ts
Normal file
@ -0,0 +1,219 @@
|
||||
import { createServer } from 'http';
|
||||
import { parse } from 'url';
|
||||
import { WebSocketServer, WebSocket } from 'ws';
|
||||
import { index401, serverStaticFile } from './app/utils';
|
||||
import * as uuid from 'uuid';
|
||||
import * as lodash from 'lodash';
|
||||
import { createReadStream } from 'node:fs';
|
||||
import {
|
||||
makeReadableWebSocketStream,
|
||||
processVlessHeader,
|
||||
delay,
|
||||
closeWebSocket,
|
||||
} from 'vless-js';
|
||||
import { connect, Socket } from 'node:net';
|
||||
import { Duplex, Readable } from 'stream';
|
||||
import { resolve } from 'path';
|
||||
|
||||
const port = process.env.PORT;
|
||||
const userID = process.env.UUID || '';
|
||||
let isVaildUser = uuid.validate(userID);
|
||||
if (!isVaildUser) {
|
||||
console.log('not set valid UUID');
|
||||
}
|
||||
|
||||
const server = createServer((req, resp) => {
|
||||
if (!isVaildUser) {
|
||||
return index401(req, resp);
|
||||
}
|
||||
const url = new URL(req.url, `http://${req.headers['host']}`);
|
||||
// health check
|
||||
if (req.method === 'GET' && url.pathname.startsWith('/health')) {
|
||||
resp.writeHead(200);
|
||||
resp.write('health 200');
|
||||
resp.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// index page
|
||||
if (url.pathname.includes(userID)) {
|
||||
const index = 'dist/apps/cf-page/index.html';
|
||||
return createReadStream(index).pipe(resp);
|
||||
}
|
||||
if (req.method === 'GET' && url.pathname.startsWith('/assets')) {
|
||||
return serverStaticFile(req, resp);
|
||||
}
|
||||
|
||||
const basicAuth = req.headers.authorization || '';
|
||||
const authStringBase64 = basicAuth.split(' ')?.[1] || '';
|
||||
const authString = Buffer.from(authStringBase64, 'base64').toString('ascii');
|
||||
console.log('-----authString--', authString);
|
||||
if (authString && authString.includes(userID)) {
|
||||
resp.writeHead(302, {
|
||||
'content-type': 'text/html; charset=utf-8',
|
||||
Location: `./${userID}`,
|
||||
});
|
||||
resp.end();
|
||||
} else {
|
||||
resp.writeHead(401, {
|
||||
'content-type': 'text/html; charset=utf-8',
|
||||
'WWW-Authenticate': 'Basic',
|
||||
});
|
||||
resp.end();
|
||||
}
|
||||
});
|
||||
const vlessWServer = new WebSocketServer({ noServer: true });
|
||||
|
||||
vlessWServer.on('connection', async function connection(ws) {
|
||||
let address = '';
|
||||
let portWithRandomLog = '';
|
||||
try {
|
||||
const log = (info: string, event?: any) => {
|
||||
console.log(`[${address}:${portWithRandomLog}] ${info}`, event || '');
|
||||
};
|
||||
let remoteConnection: Socket = null;
|
||||
let remoteConnectionReadyResolve: Function;
|
||||
|
||||
const readableWebSocketStream = makeReadableWebSocketStream(ws, log);
|
||||
let vlessResponseHeader: Uint8Array | null = null;
|
||||
|
||||
// ws --> remote
|
||||
readableWebSocketStream
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
async write(chunk: Buffer, controller) {
|
||||
const vlessBuffer = chunk.buffer.slice(chunk.byteOffset);
|
||||
if (remoteConnection) {
|
||||
await wsAsyncWrite(remoteConnection, vlessBuffer);
|
||||
return;
|
||||
}
|
||||
const {
|
||||
hasError,
|
||||
message,
|
||||
portRemote,
|
||||
addressRemote,
|
||||
rawDataIndex,
|
||||
vlessVersion,
|
||||
} = processVlessHeader(vlessBuffer, userID, uuid, lodash);
|
||||
address = addressRemote || '';
|
||||
portWithRandomLog = `${portRemote}--${Math.random()}`;
|
||||
if (hasError) {
|
||||
controller.error(`[${address}:${portWithRandomLog}] ${message} `);
|
||||
}
|
||||
// const addressType = requestAddr >> 42
|
||||
// const addressLength = requestAddr & 0x0f;
|
||||
console.log(`[${address}:${portWithRandomLog}] connecting`);
|
||||
remoteConnection = await connect2Remote(portRemote, address, log);
|
||||
vlessResponseHeader = new Uint8Array([vlessVersion![0], 0]);
|
||||
|
||||
const rawClientData = vlessBuffer.slice(rawDataIndex!);
|
||||
remoteConnection.write(new Uint8Array(rawClientData));
|
||||
remoteConnectionReadyResolve(remoteConnection);
|
||||
},
|
||||
close() {
|
||||
console.log(
|
||||
`[${address}:${portWithRandomLog}] readableWebSocketStream is close`
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
console.log(
|
||||
`[${address}:${portWithRandomLog}] readableWebSocketStream is abort`,
|
||||
JSON.stringify(reason)
|
||||
);
|
||||
},
|
||||
})
|
||||
)
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
`[${address}:${portWithRandomLog}] readableWebSocketStream pipeto has exception`,
|
||||
error.stack || error
|
||||
);
|
||||
// error is cancel readable stream anyway, no need close websocket in here
|
||||
// closeWebSocket(webSocket);
|
||||
// close remote conn
|
||||
// remoteConnection?.close();
|
||||
});
|
||||
|
||||
await new Promise((resolve) => (remoteConnectionReadyResolve = resolve));
|
||||
// remote --> ws
|
||||
let remoteChunkCount = 0;
|
||||
let totoal = 0;
|
||||
await Readable.toWeb(remoteConnection).pipeTo(
|
||||
new WritableStream({
|
||||
start() {
|
||||
if (ws.readyState === ws.OPEN) {
|
||||
ws.send(vlessResponseHeader!);
|
||||
}
|
||||
},
|
||||
async write(chunk: Uint8Array, controller) {
|
||||
ws.send(chunk);
|
||||
},
|
||||
close() {
|
||||
console.log(
|
||||
`[${address}:${portWithRandomLog}] remoteConnection!.readable is close`
|
||||
);
|
||||
},
|
||||
abort(reason) {
|
||||
closeWebSocket(ws);
|
||||
console.error(
|
||||
`[${address}:${portWithRandomLog}] remoteConnection!.readable abort`,
|
||||
reason
|
||||
);
|
||||
},
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[${address}:${portWithRandomLog}] processWebSocket has exception `,
|
||||
error.stack || error
|
||||
);
|
||||
closeWebSocket(ws);
|
||||
}
|
||||
});
|
||||
|
||||
server.on('upgrade', function upgrade(request, socket, head) {
|
||||
console.log('upgrade');
|
||||
const { pathname } = parse(request.url);
|
||||
|
||||
if (pathname === '/foo') {
|
||||
vlessWServer.handleUpgrade(request, socket, head, function done(ws) {
|
||||
vlessWServer.emit('connection', ws, request);
|
||||
});
|
||||
} else {
|
||||
socket.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(port, () => {
|
||||
console.log(`server listen in http://127.0.0.1:${port}`);
|
||||
});
|
||||
|
||||
async function connect2Remote(port, host, log: Function): Promise<Socket> {
|
||||
return new Promise((resole, reject) => {
|
||||
const remoteSocket = connect(
|
||||
{
|
||||
port: port,
|
||||
host: host,
|
||||
},
|
||||
() => {
|
||||
log(`connected`);
|
||||
resole(remoteSocket);
|
||||
}
|
||||
);
|
||||
remoteSocket.addListener('error', () => {
|
||||
reject('remoteSocket has error');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function wsAsyncWrite(ws: Socket, chunk: ArrayBuffer) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ws.write(Buffer.from(chunk), (error) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve('');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
10
apps/node-vless/tsconfig.app.json
Normal file
10
apps/node-vless/tsconfig.app.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts"],
|
||||
"include": ["**/*.ts"]
|
||||
}
|
13
apps/node-vless/tsconfig.json
Normal file
13
apps/node-vless/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
9
apps/node-vless/tsconfig.spec.json
Normal file
9
apps/node-vless/tsconfig.spec.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts", "**/*.d.ts"]
|
||||
}
|
29
doc/render.md
Normal file
29
doc/render.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Render
|
||||
|
||||
## 登录 render 账户
|
||||
|
||||
https://render.com/
|
||||
|
||||
## 访问 https://dashboard.render.com/
|
||||
|
||||
## New Project
|
||||
|
||||
![render1](./render1.jpg)
|
||||
|
||||
## 关联 github 账户
|
||||
|
||||
![render2](./render2.jpg)
|
||||
|
||||
## 部署新项目
|
||||
|
||||
需要填写如下信息,具体请参考下图.
|
||||
|
||||
| 选项 | 值 |
|
||||
| ------------- | --- |
|
||||
| Build Command | 3 |
|
||||
| Start Command | 3 |
|
||||
|
||||
![render3](./render3.jpg)
|
||||
|
||||
**⚠️ 添加环境变量 UUID**
|
||||
![render4](./render4.jpg)
|
BIN
doc/render1.jpg
Normal file
BIN
doc/render1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
doc/render2.jpg
Normal file
BIN
doc/render2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
BIN
doc/render3.jpg
Normal file
BIN
doc/render3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 207 KiB |
BIN
doc/render4.jpg
Normal file
BIN
doc/render4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
@ -1 +1 @@
|
||||
export { vlessJs, processWebSocket as processSocket } from './lib/vless-js';
|
||||
export * from './lib/vless-js';
|
||||
|
@ -2,7 +2,7 @@ export function vlessJs(): string {
|
||||
return 'vless-js';
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
export function delay(ms: number) {
|
||||
return new Promise((resolve, rej) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
@ -163,16 +163,22 @@ export async function processWebSocket({
|
||||
return;
|
||||
}
|
||||
|
||||
function makeReadableWebSocketStream(ws: WebSocket, log: Function) {
|
||||
export function makeReadableWebSocketStream(
|
||||
ws: WebSocket | any,
|
||||
log: Function
|
||||
) {
|
||||
let readableStreamCancel = false;
|
||||
return new ReadableStream<ArrayBuffer>({
|
||||
start(controller) {
|
||||
ws.addEventListener('message', async (e) => {
|
||||
ws.addEventListener('message', async (e: { data: ArrayBuffer }) => {
|
||||
// console.log('MESSAGE');
|
||||
const vlessBuffer: ArrayBuffer = e.data;
|
||||
// console.log('MESSAGE', vlessBuffer);
|
||||
|
||||
// console.log(`message is ${vlessBuffer.byteLength}`);
|
||||
controller.enqueue(vlessBuffer);
|
||||
});
|
||||
ws.addEventListener('error', (e) => {
|
||||
ws.addEventListener('error', (e: any) => {
|
||||
log('socket has error');
|
||||
readableStreamCancel = true;
|
||||
controller.error(e);
|
||||
@ -202,13 +208,19 @@ function makeReadableWebSocketStream(ws: WebSocket, log: Function) {
|
||||
});
|
||||
}
|
||||
|
||||
function closeWebSocket(socket: WebSocket) {
|
||||
export function closeWebSocket(socket: WebSocket | any) {
|
||||
if (socket.readyState === socket.OPEN) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
function processVlessHeader(
|
||||
//https://github.com/v2ray/v2ray-core/issues/2636
|
||||
// 1 字节 16 字节 1 字节 M 字节 1 字节 2 字节 1 字节 S 字节 X 字节
|
||||
// 协议版本 等价 UUID 附加信息长度 M 附加信息 ProtoBuf 指令 端口 地址类型 地址 请求数据
|
||||
|
||||
// 1 字节 1 字节 N 字节 Y 字节
|
||||
// 协议版本,与请求的一致 附加信息长度 N 附加信息 ProtoBuf 响应数据
|
||||
export function processVlessHeader(
|
||||
vlessBuffer: ArrayBuffer,
|
||||
userID: string,
|
||||
uuidLib: any,
|
||||
|
19
node-test.mjs
Normal file
19
node-test.mjs
Normal file
@ -0,0 +1,19 @@
|
||||
import { connect, Socket } from 'node:net';
|
||||
import { Duplex } from 'node:stream';
|
||||
import { WritableStream } from 'node:stream/web';
|
||||
|
||||
try {
|
||||
const socket = connect(
|
||||
{
|
||||
port: '443',
|
||||
host: 'www.google.com',
|
||||
},
|
||||
() => {
|
||||
console.log('connect ', socket.readyState);
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log('----', err);
|
||||
}
|
||||
|
||||
console.log('end');
|
72
package-lock.json
generated
72
package-lock.json
generated
@ -13,6 +13,8 @@
|
||||
"@heroicons/react": "^2.0.13",
|
||||
"commander": "^9.4.1",
|
||||
"core-js": "^3.6.5",
|
||||
"lodash": "^4.17.21",
|
||||
"pretty-cache-header": "^1.0.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
@ -20,7 +22,8 @@
|
||||
"tslib": "^2.3.0",
|
||||
"undici": "^5.13.0",
|
||||
"uuid": "^9.0.0",
|
||||
"wrangler": "^2.6.2"
|
||||
"wrangler": "^2.6.2",
|
||||
"ws": "^8.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
@ -39,6 +42,7 @@
|
||||
"@nrwl/workspace": "15.2.4",
|
||||
"@testing-library/react": "13.4.0",
|
||||
"@types/jest": "28.1.1",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "18.11.9",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/react": "18.0.25",
|
||||
@ -5857,6 +5861,12 @@
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-3.0.1.tgz",
|
||||
@ -13487,8 +13497,7 @@
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
@ -15896,6 +15905,17 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-cache-header": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/pretty-cache-header/-/pretty-cache-header-1.0.0.tgz",
|
||||
"integrity": "sha512-xtXazslu25CdnGnUkByU1RoOjK55TqwatJkjjJLg5ZAdz2Lngko/mmaUgeET36P2GMlNwh3fdM7FWBO717pNcw==",
|
||||
"dependencies": {
|
||||
"timestring": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-28.1.3.tgz",
|
||||
@ -18099,6 +18119,14 @@
|
||||
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/timestring": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/timestring/-/timestring-6.0.0.tgz",
|
||||
"integrity": "sha512-wMctrWD2HZZLuIlchlkE2dfXJh7J2KDI9Dwl+2abPYg0mswQHfOAyQW3jJg1pY5VfttSINZuKcXoB3FGypVklA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tinybench": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.3.1.tgz",
|
||||
@ -19759,16 +19787,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.11.0.tgz",
|
||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||
"dev": true,
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.12.0.tgz",
|
||||
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
@ -24444,6 +24471,12 @@
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-3.0.1.tgz",
|
||||
@ -30522,8 +30555,7 @@
|
||||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.camelcase": {
|
||||
"version": "4.3.0",
|
||||
@ -32325,6 +32357,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pretty-cache-header": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/pretty-cache-header/-/pretty-cache-header-1.0.0.tgz",
|
||||
"integrity": "sha512-xtXazslu25CdnGnUkByU1RoOjK55TqwatJkjjJLg5ZAdz2Lngko/mmaUgeET36P2GMlNwh3fdM7FWBO717pNcw==",
|
||||
"requires": {
|
||||
"timestring": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/pretty-format/-/pretty-format-28.1.3.tgz",
|
||||
@ -34134,6 +34174,11 @@
|
||||
"integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
|
||||
"dev": true
|
||||
},
|
||||
"timestring": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/timestring/-/timestring-6.0.0.tgz",
|
||||
"integrity": "sha512-wMctrWD2HZZLuIlchlkE2dfXJh7J2KDI9Dwl+2abPYg0mswQHfOAyQW3jJg1pY5VfttSINZuKcXoB3FGypVklA=="
|
||||
},
|
||||
"tinybench": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/tinybench/-/tinybench-2.3.1.tgz",
|
||||
@ -35249,10 +35294,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "8.11.0",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.11.0.tgz",
|
||||
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
|
||||
"dev": true,
|
||||
"version": "8.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.12.0.tgz",
|
||||
"integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
|
||||
"requires": {}
|
||||
},
|
||||
"xml-name-validator": {
|
||||
|
11
package.json
11
package.json
@ -2,10 +2,15 @@
|
||||
"name": "edge-bypass",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "nx serve",
|
||||
"build": "nx build",
|
||||
"cf-page": "nx build cf-page",
|
||||
"node-vless:build": "nx build cf-page --configuration=production && nx build node-vless",
|
||||
"node-vless:start": "node dist/apps/node-vless/main.js",
|
||||
"test": "nx test"
|
||||
},
|
||||
"private": true,
|
||||
@ -14,6 +19,8 @@
|
||||
"@heroicons/react": "^2.0.13",
|
||||
"commander": "^9.4.1",
|
||||
"core-js": "^3.6.5",
|
||||
"lodash": "^4.17.21",
|
||||
"pretty-cache-header": "^1.0.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
@ -21,7 +28,8 @@
|
||||
"tslib": "^2.3.0",
|
||||
"undici": "^5.13.0",
|
||||
"uuid": "^9.0.0",
|
||||
"wrangler": "^2.6.2"
|
||||
"wrangler": "^2.6.2",
|
||||
"ws": "^8.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
@ -40,6 +48,7 @@
|
||||
"@nrwl/workspace": "15.2.4",
|
||||
"@testing-library/react": "13.4.0",
|
||||
"@types/jest": "28.1.1",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "18.11.9",
|
||||
"@types/qrcode": "^1.5.0",
|
||||
"@types/react": "18.0.25",
|
||||
|
Loading…
Reference in New Issue
Block a user