Skip to content

Commit

Permalink
fix: support base64 conversion for multiple http/https links (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
7Sageer committed Sep 10, 2024
1 parent 79bd111 commit 74cdb92
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 33 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ Sublink Worker 是一个可部署在 Cloudflare Worker 上轻量级的订阅转

## 最近更新

- 2024-09-09
- ([#23](https://github.com/7Sageer/sublink-worker/issues/23)) 修复了Github规则无效的问题
- 2024-09-10
- ([#25](https://github.com/7Sageer/sublink-worker/issues/25)) 修复了Base64无法转换多个HTTP的问题

[查看更新日志](/doc/update-log.md)

Expand Down
8 changes: 6 additions & 2 deletions doc/update-log.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# 更新日志

## 2024-09-10

- ([#25](https://github.com/7Sageer/sublink-worker/issues/25)) 修复了Base64无法转换多个HTTP的问题

## 2024-09-09

- (#23) 修复了Github规则无效的问题
- ([#23](https://github.com/7Sageer/sublink-worker/issues/23)) 修复了Github规则无效的问题

## 2024-09-07

- (#16)修复了导入base64订阅时出现乱码的问题
- ([#16](https://github.com/7Sageer/sublink-worker/issues/16)) 修复了导入base64订阅时出现乱码的问题

## 2024-09-03

Expand Down
2 changes: 1 addition & 1 deletion src/ProxyParsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class ProxyParser {
let [base64, serverPart] = mainPart.split('@');
let [method, password] = atob(base64).split(':');

// 匹配 IPv6 地址
// Match IPv6 address
let match = serverPart.match(/\[([^\]]+)\]:(\d+)/);
let server, server_port;

Expand Down
83 changes: 55 additions & 28 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ConfigBuilder } from './SingboxConfigBuilder.js';
import { generateHtml } from './htmlBuilder.js';
import { ClashConfigBuilder } from './ClashConfigBuilder.js';
import { encodeBase64, GenerateWebPath} from './utils.js';
import { encodeBase64, decodeBase64, GenerateWebPath } from './utils.js';
import { PREDEFINED_RULE_SETS } from './config.js';

addEventListener('fetch', event => {
Expand All @@ -17,7 +17,7 @@ async function handleRequest(request) {
return new Response(generateHtml('', '', ''), {
headers: { 'Content-Type': 'text/html' }
});
} else if (request.method === 'POST' && url.pathname === '/') {
} else if (request.method === 'POST' && url.pathname === '/') {
const formData = await request.formData();
const inputString = formData.get('input');
const selectedRules = formData.getAll('selectedRules');
Expand All @@ -29,31 +29,31 @@ async function handleRequest(request) {
ips: customRuleIPs[index].split(',').map(ip => ip.trim()),
outbound: customRuleNames[index]
}));

if (!inputString) {
return new Response('Missing input parameter', { status: 400 });
}

// If no rules are selected, use the default rules
const rulesToUse = selectedRules.length > 0 ? selectedRules : ['广告拦截', '谷歌服务', '国外媒体', '电报消息'];

const xrayUrl = `${url.origin}/xray?config=${encodeURIComponent(inputString)}`;
const singboxUrl = `${url.origin}/singbox?config=${encodeURIComponent(inputString)}&selectedRules=${encodeURIComponent(JSON.stringify(rulesToUse))}&customRules=${encodeURIComponent(JSON.stringify(customRules))}`;
const clashUrl = `${url.origin}/clash?config=${encodeURIComponent(inputString)}&selectedRules=${encodeURIComponent(JSON.stringify(rulesToUse))}&customRules=${encodeURIComponent(JSON.stringify(customRules))}`;

return new Response(generateHtml(xrayUrl, singboxUrl, clashUrl), {
headers: { 'Content-Type': 'text/html' }
});
} else if (url.pathname.startsWith('/singbox') || url.pathname.startsWith('/clash')) {
const inputString = url.searchParams.get('config');
let selectedRules = url.searchParams.get('selectedRules');
let customRules = url.searchParams.get('customRules');

if (!inputString) {
return new Response('Missing config parameter', { status: 400 });
}
// 处理预定义规则集

// Deal with predefined rules
if (PREDEFINED_RULE_SETS[selectedRules]) {
selectedRules = PREDEFINED_RULE_SETS[selectedRules];
} else {
Expand All @@ -64,71 +64,98 @@ async function handleRequest(request) {
selectedRules = PREDEFINED_RULE_SETS.minimal;
}
}
// 处理自定义规则

// Deal with custom rules
try {
customRules = JSON.parse(decodeURIComponent(customRules));
} catch (error) {
console.error('Error parsing customRules:', error);
customRules = [];
}

let configBuilder;
if (url.pathname.startsWith('/singbox')) {
configBuilder = new ConfigBuilder(inputString, selectedRules, customRules);
} else {
configBuilder = new ClashConfigBuilder(inputString, selectedRules, customRules);
}

const config = await configBuilder.build();

return new Response(
url.pathname.startsWith('/singbox') ? JSON.stringify(config, null, 2) : config,
{
headers: {
'content-type': url.pathname.startsWith('/singbox')
? 'application/json; charset=utf-8'
: 'text/yaml; charset=utf-8'
headers: {
'content-type': url.pathname.startsWith('/singbox')
? 'application/json; charset=utf-8'
: 'text/yaml; charset=utf-8'
}
}
);
);

} else if (url.pathname === '/shorten') {
const originalUrl = url.searchParams.get('url');
if (!originalUrl) {
return new Response('Missing URL parameter', { status: 400 });
}

const shortCode = GenerateWebPath();
await SUBLINK_KV.put(shortCode, originalUrl);

const shortUrl = `${url.origin}/s/${shortCode}`;
return new Response(JSON.stringify({ shortUrl }), {
headers: { 'Content-Type': 'application/json' }
});
} else if (url.pathname.startsWith('/s/')) {
const shortCode = url.pathname.split('/')[2];
const originalUrl = await SUBLINK_KV.get(shortCode);

if (originalUrl === null) {
return new Response('Short URL not found', { status: 404 });
}

return Response.redirect(originalUrl, 302);
} else if (url.pathname.startsWith('/xray')) {
// Handle Xray config requests
const inputString = url.searchParams.get('config');
const proxylist = inputString.split('\n');

if (!inputString) {
const finalProxyList = [];

for (const proxy of proxylist) {
console.log(proxy);
if (proxy.startsWith('http://') || proxy.startsWith('https://')) {
try {
const response = await fetch(proxy)
const text = await response.text();
let decodedText;
decodedText = decodeBase64(text.trim());
console.log(decodedText);
// Check if the decoded text needs URL decoding
if (decodedText.includes('%')) {
decodedText = decodeURIComponent(decodedText);
}
finalProxyList.push(...decodedText.split('\n'));
} catch (e) {
console.warn('Failed to fetch the proxy:', e);
}
} else {
finalProxyList.push(proxy);
}
}

const finalString = finalProxyList.join('\n');

if (!finalString) {
return new Response('Missing config parameter', { status: 400 });
}

return new Response(encodeBase64(inputString), {
return new Response(encodeBase64(finalString), {
headers: { 'content-type': 'application/json; charset=utf-8' }
});
} else if (url.pathname === '/favicon.ico') {
return Response.redirect('https://cravatar.cn/avatar/9240d78bbea4cf05fb04f2b86f22b18d?s=160&d=retro&r=g', 301)
}
return Response.redirect('https://cravatar.cn/avatar/9240d78bbea4cf05fb04f2b86f22b18d?s=160&d=retro&r=g', 301)
}

return new Response('Not Found', { status: 404 });
} catch (error) {
Expand Down

0 comments on commit 74cdb92

Please sign in to comment.