Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49e1105763 | ||
|
|
5fde0b6658 | ||
|
|
6b769ef998 | ||
|
|
458ba6dd35 | ||
|
|
82f6e1dae8 | ||
|
|
9de327fb29 | ||
|
|
0e88bb62b5 | ||
|
|
ef1b6eab6b | ||
|
|
fb90213e33 | ||
|
|
a87e298002 |
114
api/router.go
114
api/router.go
@@ -4,6 +4,7 @@ import (
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
_ "github.com/heroku/x/hmetrics/onload"
|
||||
@@ -13,7 +14,7 @@ import (
|
||||
"github.com/zu1k/proxypool/pkg/provider"
|
||||
)
|
||||
|
||||
const version = "v0.3.4"
|
||||
const version = "v0.3.5"
|
||||
|
||||
var router *gin.Engine
|
||||
|
||||
@@ -75,41 +76,124 @@ func setupRouter() {
|
||||
text = cache.GetString("clashproxies")
|
||||
if text == "" {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
clash := provider.Clash{Proxies: proxies}
|
||||
clash := provider.Clash{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
},
|
||||
}
|
||||
text = clash.Provide()
|
||||
cache.SetString("clashproxies", text)
|
||||
}
|
||||
} else if proxyTypes == "all" {
|
||||
proxies := cache.GetProxies("allproxies")
|
||||
clash := provider.Clash{
|
||||
Proxies: proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
},
|
||||
}
|
||||
text = clash.Provide()
|
||||
} else {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
clash := provider.Clash{
|
||||
Proxies: proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
},
|
||||
}
|
||||
text = clash.Provide()
|
||||
}
|
||||
c.String(200, text)
|
||||
})
|
||||
router.GET("/surge/proxies", func(c *gin.Context) {
|
||||
text := cache.GetString("surgeproxies")
|
||||
if text == "" {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
surge := provider.Surge{Proxies: proxies}
|
||||
proxyTypes := c.DefaultQuery("type", "")
|
||||
proxyCountry := c.DefaultQuery("c", "")
|
||||
proxyNotCountry := c.DefaultQuery("nc", "")
|
||||
text := ""
|
||||
if proxyTypes == "" && proxyCountry == "" && proxyNotCountry == "" {
|
||||
text = cache.GetString("surgeproxies")
|
||||
if text == "" {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
surge := provider.Surge{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
},
|
||||
}
|
||||
text = surge.Provide()
|
||||
cache.SetString("surgeproxies", text)
|
||||
}
|
||||
} else if proxyTypes == "all" {
|
||||
proxies := cache.GetProxies("allproxies")
|
||||
surge := provider.Surge{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
},
|
||||
}
|
||||
text = surge.Provide()
|
||||
} else {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
surge := provider.Surge{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: proxyTypes,
|
||||
Country: proxyCountry,
|
||||
NotCountry: proxyNotCountry,
|
||||
},
|
||||
}
|
||||
text = surge.Provide()
|
||||
cache.SetString("surgeproxies", text)
|
||||
}
|
||||
c.String(200, text)
|
||||
})
|
||||
|
||||
router.GET("/ss/sub", func(c *gin.Context) {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
ssSub := provider.SSSub{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: "ss",
|
||||
},
|
||||
}
|
||||
c.String(200, ssSub.Provide())
|
||||
})
|
||||
router.GET("/ssr/sub", func(c *gin.Context) {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
ssrSub := provider.SSRSub{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: "ssr",
|
||||
},
|
||||
}
|
||||
c.String(200, ssrSub.Provide())
|
||||
})
|
||||
router.GET("/vmess/sub", func(c *gin.Context) {
|
||||
proxies := cache.GetProxies("proxies")
|
||||
vmessSub := provider.VmessSub{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
Types: "vmess",
|
||||
},
|
||||
}
|
||||
c.String(200, vmessSub.Provide())
|
||||
})
|
||||
router.GET("/link/:id", func(c *gin.Context) {
|
||||
idx := c.Param("id")
|
||||
proxies := cache.GetProxies("allproxies")
|
||||
id, err := strconv.Atoi(idx)
|
||||
if err != nil {
|
||||
c.String(500, err.Error())
|
||||
}
|
||||
if id >= proxies.Len() {
|
||||
c.String(500, "id too big")
|
||||
}
|
||||
c.String(200, proxies[id].Link())
|
||||
})
|
||||
}
|
||||
|
||||
func Run() {
|
||||
|
||||
2
go.mod
2
go.mod
@@ -9,7 +9,7 @@ require (
|
||||
github.com/antchfx/htmlquery v1.2.3 // indirect
|
||||
github.com/antchfx/xmlquery v1.2.4 // indirect
|
||||
github.com/antchfx/xpath v1.1.8 // indirect
|
||||
github.com/cloudflare/cloudflare-go v0.13.1
|
||||
github.com/cloudflare/cloudflare-go v0.13.2
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect
|
||||
|
||||
3
go.sum
3
go.sum
@@ -30,6 +30,8 @@ github.com/cloudflare/cloudflare-go v0.13.0 h1:Mx2gNz/r4H0eHETENq5ZPtc/kOX/uzEfT
|
||||
github.com/cloudflare/cloudflare-go v0.13.0/go.mod h1:6rZ6s/XWxP8WIWMATgDM7aUop0Z0ZOAfcm/4rEd0lOY=
|
||||
github.com/cloudflare/cloudflare-go v0.13.1 h1:8i8E5CubfAlD/2zWM7VGKoIPS2/x/lO/nRnqDl0j5Dk=
|
||||
github.com/cloudflare/cloudflare-go v0.13.1/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM=
|
||||
github.com/cloudflare/cloudflare-go v0.13.2 h1:bhMGoNhAg21DuqJjU9jQepRRft6vYfo6pejT3NN4V6A=
|
||||
github.com/cloudflare/cloudflare-go v0.13.2/go.mod h1:27kfc1apuifUmJhp069y0+hwlKDg4bd8LWlu7oKeZvM=
|
||||
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -201,6 +203,7 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a h1:pa8hGb/2YqsZKovtsgrwcDH1RZhVbTKCjLp47XpqCDs=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soveran/redisurl v0.0.0-20180322091936-eb325bc7a4b8/go.mod h1:FVJ8jbHu7QrNFs3bZEsv/L5JjearIAY9N0oXh2wk+6Y=
|
||||
github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
|
||||
@@ -19,7 +19,7 @@ func CrawlGo() {
|
||||
wg.Add(1)
|
||||
go g.Get2Chan(pc, wg)
|
||||
}
|
||||
proxies := cache.GetProxies("proxies")
|
||||
proxies := cache.GetProxies("allproxies")
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(pc)
|
||||
@@ -32,7 +32,11 @@ func CrawlGo() {
|
||||
// 节点去重
|
||||
proxies = proxies.Deduplication()
|
||||
log.Println("CrawlGo node count:", len(proxies))
|
||||
proxies = provider.Clash{Proxies: proxies}.CleanProxies()
|
||||
proxies = provider.Clash{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
},
|
||||
}.CleanProxies()
|
||||
log.Println("CrawlGo cleaned node count:", len(proxies))
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex().NameAddTG()
|
||||
log.Println("Proxy rename DONE!")
|
||||
@@ -58,6 +62,14 @@ func CrawlGo() {
|
||||
cache.SetProxies("proxies", proxies)
|
||||
cache.UsefullProxiesCount = proxies.Len()
|
||||
|
||||
cache.SetString("clashproxies", provider.Clash{Proxies: proxies}.Provide())
|
||||
cache.SetString("surgeproxies", provider.Surge{Proxies: proxies}.Provide())
|
||||
cache.SetString("clashproxies", provider.Clash{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
},
|
||||
}.Provide())
|
||||
cache.SetString("surgeproxies", provider.Surge{
|
||||
provider.Base{
|
||||
Proxies: &proxies,
|
||||
},
|
||||
}.Provide())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/pkg/proxy"
|
||||
)
|
||||
|
||||
type Provider interface {
|
||||
Provide() string
|
||||
}
|
||||
@@ -12,3 +18,72 @@ func checkInList(list []string, item string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Base struct {
|
||||
Proxies *proxy.ProxyList `yaml:"proxies"`
|
||||
Types string `yaml:"type"`
|
||||
Country string `yaml:"country"`
|
||||
NotCountry string `yaml:"not_country"`
|
||||
}
|
||||
|
||||
func (b *Base) preFilter() {
|
||||
proxies := make(proxy.ProxyList, 0)
|
||||
|
||||
needFilterType := true
|
||||
needFilterCountry := true
|
||||
needFilterNotCountry := true
|
||||
if b.Types == "" || b.Types == "all" {
|
||||
needFilterType = false
|
||||
}
|
||||
if b.Country == "" || b.Country == "all" {
|
||||
needFilterCountry = false
|
||||
}
|
||||
if b.NotCountry == "" {
|
||||
needFilterNotCountry = false
|
||||
}
|
||||
types := strings.Split(b.Types, ",")
|
||||
countries := strings.Split(b.Country, ",")
|
||||
notCountries := strings.Split(b.NotCountry, ",")
|
||||
|
||||
bProxies := *b.Proxies
|
||||
for _, p := range bProxies {
|
||||
if needFilterType {
|
||||
typeOk := false
|
||||
for _, t := range types {
|
||||
if p.TypeName() == t {
|
||||
typeOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !typeOk {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
|
||||
if needFilterNotCountry {
|
||||
for _, c := range notCountries {
|
||||
if strings.Contains(p.BaseInfo().Name, c) {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if needFilterCountry {
|
||||
countryOk := false
|
||||
for _, c := range countries {
|
||||
if strings.Contains(p.BaseInfo().Name, c) {
|
||||
countryOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !countryOk {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
|
||||
proxies = append(proxies, p)
|
||||
exclude:
|
||||
}
|
||||
|
||||
b.Proxies = &proxies
|
||||
}
|
||||
|
||||
@@ -7,15 +7,12 @@ import (
|
||||
)
|
||||
|
||||
type Clash struct {
|
||||
Proxies proxy.ProxyList `yaml:"proxies"`
|
||||
Types string `yaml:"type"`
|
||||
Country string `yaml:"country"`
|
||||
NotCountry string `yaml:"not_country"`
|
||||
Base
|
||||
}
|
||||
|
||||
func (c Clash) CleanProxies() (proxies proxy.ProxyList) {
|
||||
proxies = make(proxy.ProxyList, 0)
|
||||
for _, p := range c.Proxies {
|
||||
for _, p := range *c.Proxies {
|
||||
if checkClashSupport(p) {
|
||||
proxies = append(proxies, p)
|
||||
}
|
||||
@@ -24,68 +21,15 @@ func (c Clash) CleanProxies() (proxies proxy.ProxyList) {
|
||||
}
|
||||
|
||||
func (c Clash) Provide() string {
|
||||
c.preFilter()
|
||||
|
||||
var resultBuilder strings.Builder
|
||||
resultBuilder.WriteString("proxies:\n")
|
||||
|
||||
needFilterType := true
|
||||
needFilterCountry := true
|
||||
needFilterNotCountry := true
|
||||
if c.Types == "" || c.Types == "all" {
|
||||
needFilterType = false
|
||||
}
|
||||
if c.Country == "" || c.Country == "all" {
|
||||
needFilterCountry = false
|
||||
}
|
||||
if c.NotCountry == "" {
|
||||
needFilterNotCountry = false
|
||||
}
|
||||
types := strings.Split(c.Types, ",")
|
||||
countries := strings.Split(c.Country, ",")
|
||||
notCountries := strings.Split(c.NotCountry, ",")
|
||||
|
||||
for _, p := range c.Proxies {
|
||||
if !checkClashSupport(p) {
|
||||
continue
|
||||
for _, p := range *c.Proxies {
|
||||
if checkClashSupport(p) {
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
}
|
||||
|
||||
if needFilterType {
|
||||
typeOk := false
|
||||
for _, t := range types {
|
||||
if p.TypeName() == t {
|
||||
typeOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !typeOk {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
|
||||
if needFilterNotCountry {
|
||||
for _, c := range notCountries {
|
||||
if strings.Contains(p.BaseInfo().Name, c) {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if needFilterCountry {
|
||||
countryOk := false
|
||||
for _, c := range countries {
|
||||
if strings.Contains(p.BaseInfo().Name, c) {
|
||||
countryOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !countryOk {
|
||||
goto exclude
|
||||
}
|
||||
}
|
||||
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
exclude:
|
||||
}
|
||||
|
||||
return resultBuilder.String()
|
||||
}
|
||||
|
||||
|
||||
21
pkg/provider/ssrsub.go
Normal file
21
pkg/provider/ssrsub.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/pkg/tool"
|
||||
)
|
||||
|
||||
type SSRSub struct {
|
||||
Base
|
||||
}
|
||||
|
||||
func (sub SSRSub) Provide() string {
|
||||
sub.Types = "ssr"
|
||||
sub.preFilter()
|
||||
var resultBuilder strings.Builder
|
||||
for _, p := range *sub.Proxies {
|
||||
resultBuilder.WriteString(p.Link() + "\n")
|
||||
}
|
||||
return tool.Base64EncodeString(resultBuilder.String(), false)
|
||||
}
|
||||
45
pkg/provider/sssub.go
Normal file
45
pkg/provider/sssub.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/zu1k/proxypool/pkg/proxy"
|
||||
)
|
||||
|
||||
type SSSub struct {
|
||||
Base
|
||||
}
|
||||
|
||||
type ssJson struct {
|
||||
Remarks string `json:"remarks"`
|
||||
Server string `json:"server"`
|
||||
ServerPort string `json:"server_port"`
|
||||
Method string `json:"method"`
|
||||
Password string `json:"password"`
|
||||
Plugin string `json:"plugin"`
|
||||
PluginOpts map[string]interface{} `json:"plugin_opts"`
|
||||
}
|
||||
|
||||
func (sub SSSub) Provide() string {
|
||||
sub.Types = "ss"
|
||||
sub.preFilter()
|
||||
proxies := make([]ssJson, 0, sub.Proxies.Len())
|
||||
for _, p := range *sub.Proxies {
|
||||
pp := p.(*proxy.Shadowsocks)
|
||||
proxies = append(proxies, ssJson{
|
||||
Remarks: pp.Name,
|
||||
Server: pp.Server,
|
||||
ServerPort: strconv.Itoa(pp.Port),
|
||||
Method: pp.Cipher,
|
||||
Password: pp.Password,
|
||||
Plugin: pp.Plugin,
|
||||
PluginOpts: pp.PluginOpts,
|
||||
})
|
||||
}
|
||||
text, err := json.Marshal(proxies)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(text)
|
||||
}
|
||||
@@ -7,18 +7,18 @@ import (
|
||||
)
|
||||
|
||||
type Surge struct {
|
||||
Proxies proxy.ProxyList `yaml:"proxies"`
|
||||
Base
|
||||
}
|
||||
|
||||
func (s Surge) Provide() string {
|
||||
var resultBuilder strings.Builder
|
||||
s.preFilter()
|
||||
|
||||
for _, p := range s.Proxies {
|
||||
var resultBuilder strings.Builder
|
||||
for _, p := range *s.Proxies {
|
||||
if checkSurgeSupport(p) {
|
||||
resultBuilder.WriteString(p.ToSurge() + "\n")
|
||||
resultBuilder.WriteString(p.ToClash() + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
return resultBuilder.String()
|
||||
}
|
||||
|
||||
|
||||
21
pkg/provider/vmesssub.go
Normal file
21
pkg/provider/vmesssub.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/zu1k/proxypool/pkg/tool"
|
||||
)
|
||||
|
||||
type VmessSub struct {
|
||||
Base
|
||||
}
|
||||
|
||||
func (sub VmessSub) Provide() string {
|
||||
sub.Types = "vmess"
|
||||
sub.preFilter()
|
||||
var resultBuilder strings.Builder
|
||||
for _, p := range *sub.Proxies {
|
||||
resultBuilder.WriteString(p.Link() + "\n")
|
||||
}
|
||||
return tool.Base64EncodeString(resultBuilder.String(), false)
|
||||
}
|
||||
@@ -36,6 +36,7 @@ type Proxy interface {
|
||||
String() string
|
||||
ToClash() string
|
||||
ToSurge() string
|
||||
Link() string
|
||||
Identifier() string
|
||||
SetName(name string)
|
||||
SetIP(ip string)
|
||||
|
||||
62
pkg/proxy/link_test.go
Normal file
62
pkg/proxy/link_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSSLink(t *testing.T) {
|
||||
ss, err := ParseSSLink("ss://YWVzLTI1Ni1jZmI6ZUlXMERuazY5NDU0ZTZuU3d1c3B2OURtUzIwMXRRMERAMTcyLjEwNC4xNjEuNTQ6ODA5OQ==#翻墙党223.13新加坡")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(ss)
|
||||
fmt.Println(ss.Link())
|
||||
ss, err = ParseSSLink(ss.Link())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(ss)
|
||||
}
|
||||
|
||||
func TestSSRLink(t *testing.T) {
|
||||
ssr, err := ParseSSRLink("ssr://MTcyLjEwNC4xNjEuNTQ6ODA5OTpvcmlnaW46YWVzLTI1Ni1jZmI6cGxhaW46WlVsWE1FUnVhelk1TkRVMFpUWnVVM2QxYzNCMk9VUnRVekl3TVhSUk1FUT0vP29iZnNwYXJhbT0mcHJvdG9wYXJhbT0mcmVtYXJrcz01Ny03NWFLWjVZV2FNakl6TGpFejVwYXc1WXFnNVoyaCZncm91cD01cGF3NVlxZzVaMmg=")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(ssr)
|
||||
fmt.Println(ssr.Link())
|
||||
ssr, err = ParseSSRLink(ssr.Link())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(ssr)
|
||||
}
|
||||
|
||||
func TestTrojanLink(t *testing.T) {
|
||||
trojan, err := ParseTrojanLink("trojan://65474277@sqcu.hostmsu.ru:55551?allowinsecure=0&peer=mza.hkfq.xyz&mux=1&ws=0&wspath=&wshost=&ss=0&ssmethod=aes-128-gcm&sspasswd=&group=#%E9%A6%99%E6%B8%AFCN2-MZA%E8%8A%82%E7%82%B9-%E5%AE%BF%E8%BF%81%E8%81%94%E9%80%9A%E4%B8%AD%E8%BD%AC")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(trojan)
|
||||
fmt.Println(trojan.Link())
|
||||
trojan, err = ParseTrojanLink(trojan.Link())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(trojan)
|
||||
}
|
||||
|
||||
func TestVmessLink(t *testing.T) {
|
||||
v, err := ParseVmessLink("vmess://ew0KICAidiI6ICIyIiwNCiAgInBzIjogIuW+ruS/oeWFrOS8l+WPtyDlpJrlvannmoTlpKfljYPkuJbnlYwiLA0KICAiYWRkIjogInMyNzEuc25vZGUueHl6IiwNCiAgInBvcnQiOiAiNDQzIiwNCiAgImlkIjogIjZhOTAwZDYzLWNiOTItMzVhMC1hZWYwLTNhMGMxMWFhODUyMyIsDQogICJhaWQiOiAiMSIsDQogICJuZXQiOiAid3MiLA0KICAidHlwZSI6ICJub25lIiwNCiAgImhvc3QiOiAiczI3MS5zbm9kZS54eXoiLA0KICAicGF0aCI6ICIvcGFuZWwiLA0KICAidGxzIjogInRscyINCn0=")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
fmt.Println(v.Link())
|
||||
v, err = ParseVmessLink(v.Link())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
fmt.Println(v)
|
||||
}
|
||||
@@ -65,6 +65,13 @@ func (ss Shadowsocks) Clone() Proxy {
|
||||
return &ss
|
||||
}
|
||||
|
||||
// https://shadowsocks.org/en/config/quick-guide.html
|
||||
func (ss Shadowsocks) Link() (link string) {
|
||||
payload := fmt.Sprintf("%s:%s@%s:%d", ss.Cipher, ss.Password, ss.Server, ss.Port)
|
||||
payload = tool.Base64EncodeString(payload, false)
|
||||
return fmt.Sprintf("ss://%s#%s", payload, ss.Name)
|
||||
}
|
||||
|
||||
func ParseSSLink(link string) (*Shadowsocks, error) {
|
||||
if !strings.HasPrefix(link, "ss://") {
|
||||
return nil, ErrorNotSSRLink
|
||||
|
||||
@@ -3,6 +3,7 @@ package proxy
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -61,6 +62,19 @@ func (ssr ShadowsocksR) Clone() Proxy {
|
||||
return &ssr
|
||||
}
|
||||
|
||||
// https://github.com/HMBSbige/ShadowsocksR-Windows/wiki/SSR-QRcode-scheme
|
||||
func (ssr ShadowsocksR) Link() (link string) {
|
||||
payload := fmt.Sprintf("%s:%d:%s:%s:%s:%s",
|
||||
ssr.Server, ssr.Port, ssr.Protocol, ssr.Cipher, ssr.Obfs, tool.Base64EncodeString(ssr.Password, true))
|
||||
query := url.Values{}
|
||||
query.Add("obfsparam", tool.Base64EncodeString(ssr.ObfsParam, true))
|
||||
query.Add("protoparam", tool.Base64EncodeString(ssr.ProtocolParam, true))
|
||||
query.Add("remarks", tool.Base64EncodeString(ssr.Name, true))
|
||||
query.Add("group", tool.Base64EncodeString("proxy.tgbot.co", true))
|
||||
payload = tool.Base64EncodeString(fmt.Sprintf("%s/?%s", payload, query.Encode()), true)
|
||||
return fmt.Sprintf("ssr://%s", payload)
|
||||
}
|
||||
|
||||
func ParseSSRLink(link string) (*ShadowsocksR, error) {
|
||||
if !strings.HasPrefix(link, "ssr") {
|
||||
return nil, ErrorNotSSRLink
|
||||
|
||||
@@ -66,6 +66,24 @@ func (t Trojan) Clone() Proxy {
|
||||
return &t
|
||||
}
|
||||
|
||||
// https://p4gefau1t.github.io/trojan-go/developer/url/
|
||||
func (t Trojan) Link() (link string) {
|
||||
query := url.Values{}
|
||||
if t.SNI != "" {
|
||||
query.Set("sni", url.QueryEscape(t.SNI))
|
||||
}
|
||||
|
||||
uri := url.URL{
|
||||
Scheme: "trojan",
|
||||
User: url.User(url.QueryEscape(t.Password)),
|
||||
Host: net.JoinHostPort(t.Server, strconv.Itoa(t.Port)),
|
||||
RawQuery: query.Encode(),
|
||||
Fragment: t.Name,
|
||||
}
|
||||
|
||||
return uri.String()
|
||||
}
|
||||
|
||||
func ParseTrojanLink(link string) (*Trojan, error) {
|
||||
if !strings.HasPrefix(link, "trojan://") && !strings.HasPrefix(link, "trojan-go://") {
|
||||
return nil, ErrorNotTrojanink
|
||||
|
||||
@@ -86,6 +86,14 @@ func (v Vmess) Clone() Proxy {
|
||||
return &v
|
||||
}
|
||||
|
||||
func (v Vmess) Link() (link string) {
|
||||
vjv, err := json.Marshal(v.toLinkJson())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return fmt.Sprintf("vmess://%s", tool.Base64EncodeBytes(vjv))
|
||||
}
|
||||
|
||||
type vmessLinkJson struct {
|
||||
Add string `json:"add"`
|
||||
V string `json:"v"`
|
||||
@@ -100,6 +108,27 @@ type vmessLinkJson struct {
|
||||
Tls string `json:"tls"`
|
||||
}
|
||||
|
||||
func (v Vmess) toLinkJson() vmessLinkJson {
|
||||
vj := vmessLinkJson{
|
||||
Add: v.Server,
|
||||
Ps: v.Name,
|
||||
Port: v.Port,
|
||||
Id: v.UUID,
|
||||
Aid: strconv.Itoa(v.AlterID),
|
||||
Net: v.Network,
|
||||
Path: v.WSPath,
|
||||
Host: v.ServerName,
|
||||
V: "2",
|
||||
}
|
||||
if v.TLS {
|
||||
vj.Tls = "tls"
|
||||
}
|
||||
if host, ok := v.WSHeaders["HOST"]; ok && host != "" {
|
||||
vj.Host = host
|
||||
}
|
||||
return vj
|
||||
}
|
||||
|
||||
func ParseVmessLink(link string) (*Vmess, error) {
|
||||
if !strings.HasPrefix(link, "vmess") {
|
||||
return nil, ErrorNotVmessLink
|
||||
@@ -190,10 +219,11 @@ func ParseVmessLink(link string) (*Vmess, error) {
|
||||
}
|
||||
port := 443
|
||||
portInterface := vmessJson.Port
|
||||
if i, ok := portInterface.(int); ok {
|
||||
port = i
|
||||
} else if s, ok := portInterface.(string); ok {
|
||||
port, _ = strconv.Atoi(s)
|
||||
switch portInterface.(type) {
|
||||
case int:
|
||||
port = portInterface.(int)
|
||||
case string:
|
||||
port, _ = strconv.Atoi(portInterface.(string))
|
||||
}
|
||||
|
||||
alterId, err := strconv.Atoi(vmessJson.Aid)
|
||||
|
||||
@@ -26,3 +26,14 @@ func Base64DecodeString(src string) (dst string, err error) {
|
||||
dst = string(dstbytes)
|
||||
return
|
||||
}
|
||||
|
||||
func Base64EncodeString(origin string, urlsafe bool) (result string) {
|
||||
if urlsafe {
|
||||
return base64.URLEncoding.EncodeToString([]byte(origin))
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString([]byte(origin))
|
||||
}
|
||||
|
||||
func Base64EncodeBytes(origin []byte) (result string) {
|
||||
return base64.StdEncoding.EncodeToString([]byte(origin))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user