forked from xmdhs/clash2sfa
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 628a350
Showing
12 changed files
with
568 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
bbolt.db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
{ | ||
"log": {}, | ||
"dns": { | ||
"servers": [ | ||
{ | ||
"tag": "remote", | ||
"address": "https://1.1.1.1/dns-query", | ||
"detour": "select" | ||
}, | ||
{ | ||
"tag": "local", | ||
"address": "https://223.5.5.5/dns-query", | ||
"detour": "direct" | ||
} | ||
], | ||
"rules": [ | ||
{ | ||
"domain": [], | ||
"geosite": "cn", | ||
"server": "local" | ||
} | ||
], | ||
"strategy": "ipv4_only" | ||
}, | ||
"inbounds": [ | ||
{ | ||
"type": "tun", | ||
"inet4_address": "172.19.0.1/30", | ||
"sniff": true, | ||
"sniff_override_destination": true, | ||
"domain_strategy": "ipv4_only", | ||
"strict_route": true, | ||
"mtu": 9000, | ||
"stack": "gvisor", | ||
"endpoint_independent_nat": true, | ||
"auto_route": true | ||
}, | ||
{ | ||
"type": "socks", | ||
"tag": "socks-in", | ||
"listen": "127.0.0.1", | ||
"sniff": true, | ||
"sniff_override_destination": true, | ||
"domain_strategy": "ipv4_only", | ||
"listen_port": 2333, | ||
"users": [] | ||
}, | ||
{ | ||
"type": "mixed", | ||
"tag": "mixed-in", | ||
"sniff": true, | ||
"sniff_override_destination": true, | ||
"domain_strategy": "ipv4_only", | ||
"listen": "127.0.0.1", | ||
"listen_port": 2334, | ||
"users": [] | ||
} | ||
], | ||
"outbounds": [ | ||
{ | ||
"type": "direct", | ||
"tag": "direct" | ||
}, | ||
{ | ||
"type": "block", | ||
"tag": "block" | ||
}, | ||
{ | ||
"type": "dns", | ||
"tag": "dns-out" | ||
} | ||
], | ||
"route": { | ||
"rules": [ | ||
{ | ||
"geosite": "category-ads-all", | ||
"outbound": "block" | ||
}, | ||
{ | ||
"protocol": "dns", | ||
"outbound": "dns-out" | ||
}, | ||
{ | ||
"clash_mode": "direct", | ||
"outbound": "direct" | ||
}, | ||
{ | ||
"clash_mode": "global", | ||
"outbound": "select" | ||
}, | ||
{ | ||
"geoip": [ | ||
"cn", | ||
"private" | ||
], | ||
"outbound": "direct" | ||
}, | ||
{ | ||
"geosite": "geolocation-!cn", | ||
"outbound": "select" | ||
}, | ||
{ | ||
"geosite": "cn", | ||
"outbound": "direct" | ||
} | ||
], | ||
"auto_detect_interface": true | ||
}, | ||
"experimental": { | ||
"clash_api": { | ||
"external_controller": "127.0.0.1:9090", | ||
"store_selected": true, | ||
"secret": "" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package db | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
"github.com/xmdhs/clash2sfa/model" | ||
"go.etcd.io/bbolt" | ||
) | ||
|
||
type BBolt struct { | ||
db *bbolt.DB | ||
} | ||
|
||
func NewBBolt(path string) (*BBolt, error) { | ||
db, err := bbolt.Open(path, 0666, bbolt.DefaultOptions) | ||
if err != nil { | ||
return nil, fmt.Errorf("NewBBolt: %w", err) | ||
} | ||
err = db.Update(func(tx *bbolt.Tx) error { | ||
_, err := tx.CreateBucketIfNotExists([]byte("arg")) | ||
return err | ||
}) | ||
if err != nil { | ||
return nil, fmt.Errorf("NewBBolt: %w", err) | ||
} | ||
return &BBolt{db: db}, nil | ||
} | ||
|
||
func (b *BBolt) GetArg(cxt context.Context, blake3 string) (model.ConvertArg, error) { | ||
m := model.ConvertArg{} | ||
err := b.db.View(func(tx *bbolt.Tx) error { | ||
buc := tx.Bucket([]byte("arg")) | ||
b := buc.Get([]byte(blake3)) | ||
err := json.Unmarshal(b, &m) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
return m, fmt.Errorf("GetArg: %w", err) | ||
} | ||
return m, nil | ||
} | ||
|
||
func (b *BBolt) PutArg(cxt context.Context, blake3 string, arg model.ConvertArg) error { | ||
rb, err := json.Marshal(arg) | ||
if err != nil { | ||
return fmt.Errorf("PutArg: %w", err) | ||
} | ||
err = b.db.Update(func(tx *bbolt.Tx) error { | ||
buc := tx.Bucket([]byte("arg")) | ||
return buc.Put([]byte(blake3), rb) | ||
}) | ||
if err != nil { | ||
return fmt.Errorf("PutArg: %w", err) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package db | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/xmdhs/clash2sfa/model" | ||
) | ||
|
||
type DB interface { | ||
GetArg(cxt context.Context, blake3 string) (model.ConvertArg, error) | ||
PutArg(cxt context.Context, blake3 string, arg model.ConvertArg) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<!DOCTYPE html> | ||
<html lang="zh-CN"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>clash 订阅链接转 sing-box</title> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/picocss/1.5.7/pico.min.css"> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.47/vue.global.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js" | ||
integrity="sha512-g2TeAWw5GPnX7z0Kn8nFbYfeHcvAu/tx6d6mrLe/90mkCxO+RcptyYpksUz35EO337F83bZwcmUyHiHamspkfg==" | ||
crossorigin="anonymous" referrerpolicy="no-referrer"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/base64.min.js"></script> | ||
<style type="text/css"> | ||
header { | ||
border-bottom: 1px solid #e5e5e5; | ||
margin-bottom: 30px; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<div id="app"> | ||
<header> | ||
<nav class="container-fluid"> | ||
<ul> | ||
<li><strong>clash 订阅链接转 sing-box</strong></li> | ||
</ul> | ||
<ul> | ||
</ul> | ||
</nav> | ||
</header> | ||
<main class="container"> | ||
<p>将 clash 格式的订阅链接转换为 sing-box 的工具,转换后的链接可用于安卓版本的 <a | ||
href="https://sing-box.sagernet.org/installation/clients/sfa/">SFA</a>,ios 版本的未测试。</p> | ||
<input placeholder="订阅链接" v-model="sub" /> | ||
<input placeholder="url test 中包含的节点名(可用正则)" v-model="include" /> | ||
<input placeholder="url test 中排除的节点名(可用正则)" v-model="exclude" /> | ||
|
||
<details> | ||
<summary>配置文件模板</summary> | ||
<textarea style="resize: none;height: 25em;" v-model="config"></textarea> | ||
</details> | ||
<button @click="click">获取 sing-box 格式订阅链接</button> | ||
<code v-if="newsub">{{ newsub }}</code> | ||
</main> | ||
</div> | ||
</body> | ||
|
||
<script type="module"> | ||
Vue.createApp({ | ||
setup(props, context) { | ||
const sub = Vue.ref(''); | ||
const newsub = Vue.ref(''); | ||
const include = Vue.ref(''); | ||
const exclude = Vue.ref(''); | ||
const config = Vue.ref('加载中'); | ||
let oldConfig = ""; | ||
|
||
(async () => { | ||
const f = await fetch("/config") | ||
config.value = await f.text() | ||
oldConfig = config.value | ||
})(); | ||
|
||
|
||
async function click() { | ||
if (sub.value == "") { | ||
return "" | ||
} | ||
const u = new URL(new URL(location.href).origin) | ||
u.pathname = "/put" | ||
if (config.value != oldConfig) { | ||
const compressed = pako.gzip(config.value); | ||
const base64String = Base64.fromUint8Array(compressed, true) | ||
u.searchParams.set("config", base64String) | ||
} | ||
if (include.value != "") { | ||
u.searchParams.set("include", include.value) | ||
} | ||
if (exclude.value != "") { | ||
u.searchParams.set("exclude", exclude.value) | ||
} | ||
u.searchParams.set("sub", sub.value) | ||
const url = u.toString() | ||
const text = await (await fetch(url)).text() | ||
const subUrl = new URL(new URL(location.href).origin) | ||
subUrl.pathname = "/sub" | ||
subUrl.searchParams.set("id",text) | ||
newsub.value = subUrl.toString() | ||
} | ||
|
||
return { | ||
sub, | ||
config, | ||
include, | ||
exclude, | ||
newsub, | ||
click | ||
} | ||
|
||
}, | ||
}).mount('#app') | ||
</script> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
module github.com/xmdhs/clash2sfa | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/xmdhs/clash2singbox v0.0.0-20230408094726-758016fd4c71 | ||
go.etcd.io/bbolt v1.3.7 | ||
gopkg.in/yaml.v3 v3.0.1 | ||
lukechampine.com/blake3 v1.1.7 | ||
) | ||
|
||
require ( | ||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect | ||
golang.org/x/sys v0.4.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= | ||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||
github.com/xmdhs/clash2singbox v0.0.0-20230408094726-758016fd4c71 h1:T3ZbnXBgwlIMQeiPuDCeC4D3Duob0q3T/pEbtIM6Ebc= | ||
github.com/xmdhs/clash2singbox v0.0.0-20230408094726-758016fd4c71/go.mod h1:o8BYyqbnGtrfEDL4W+Zls3uMN/YnXi1Dji0UBOgTXDM= | ||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= | ||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= | ||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= | ||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= | ||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package handle | ||
|
||
import ( | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/xmdhs/clash2sfa/db" | ||
"github.com/xmdhs/clash2sfa/model" | ||
"github.com/xmdhs/clash2sfa/service" | ||
) | ||
|
||
func PutArg(db db.DB) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
cxt := r.Context() | ||
c := r.FormValue("config") | ||
sub := r.FormValue("sub") | ||
if sub == "" { | ||
http.Error(w, "订阅链接不得为空", 400) | ||
return | ||
} | ||
include := r.FormValue("include") | ||
exclude := r.FormValue("exclude") | ||
|
||
arg := model.ConvertArg{ | ||
Sub: sub, | ||
Include: include, | ||
Exclude: exclude, | ||
Config: c, | ||
} | ||
|
||
s, err := service.PutArg(cxt, arg, db) | ||
if err != nil { | ||
http.Error(w, err.Error(), 500) | ||
} | ||
w.Write([]byte(s)) | ||
} | ||
} | ||
|
||
func Frontend(frontendByte []byte, age int) http.HandlerFunc { | ||
sage := strconv.Itoa(age) | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
w.Header().Set("Cache-Control", "max-age="+sage) | ||
w.Write(frontendByte) | ||
} | ||
} | ||
|
||
func Sub(c *http.Client, db db.DB, frontendByte []byte) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
id := r.FormValue("id") | ||
if id == "" { | ||
http.Error(w, "id 不得为空", 400) | ||
return | ||
} | ||
b, err := service.GetSub(r.Context(), c, db, id, frontendByte) | ||
if err != nil { | ||
http.Error(w, err.Error(), 500) | ||
} | ||
w.Write(b) | ||
} | ||
} |
Oops, something went wrong.