Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7a8a9ff8b | ||
|
|
a9fa94c8c1 | ||
|
|
4cfb143f88 | ||
|
|
3fbdb91e7d | ||
|
|
6b462f6310 | ||
|
|
32c1c7c127 | ||
|
|
be46f914de | ||
|
|
89338d7152 | ||
|
|
1fee5e87ff | ||
|
|
2ba481e388 | ||
|
|
daea47552d | ||
|
|
59ea871190 |
@@ -32,6 +32,12 @@
|
||||
|
||||
## 安装
|
||||
|
||||
### 使用Heroku
|
||||
|
||||
首先 Fork 仓库到你的用户名下,然后修改 assets 文件夹下的html文件,将里面的域名修改为你自己的,最后点击按钮进行部署
|
||||
|
||||
[](https://heroku.com/deploy)
|
||||
|
||||
### 从源码编译
|
||||
|
||||
需要安装Golang
|
||||
|
||||
7
app.json
Normal file
7
app.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "proxypool",
|
||||
"description": "自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess节点信息,聚合去重测试可用性后提供节点列表",
|
||||
"repository": "https://github.com/zu1k/proxypool",
|
||||
"logo": "https://raw.githubusercontent.com/zu1k/proxypool/master/assets/proxy.jpg",
|
||||
"keywords": ["golang", "ss", "ssr", "vmess", "shadowsocks", "shadowsocksr"]
|
||||
}
|
||||
4
app/cache/cache.go
vendored
4
app/cache/cache.go
vendored
@@ -13,10 +13,10 @@ var c = cache.New(cache.NoExpiration, 10*time.Minute)
|
||||
func GetProxies(key string) proxy.ProxyList {
|
||||
result, found := c.Get(key)
|
||||
if found {
|
||||
log.Println(len(result.(proxy.ProxyList)))
|
||||
log.Println("found cache for:", key, "length:", len(result.(proxy.ProxyList)))
|
||||
return result.(proxy.ProxyList)
|
||||
}
|
||||
log.Println("Cache not found")
|
||||
log.Println("cache not found:", key)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ import (
|
||||
)
|
||||
|
||||
func Cron() {
|
||||
_ = gocron.Every(10).Minutes().Do(CrawlGo)
|
||||
_ = gocron.Every(15).Minutes().Do(CrawlGo)
|
||||
<-gocron.Start()
|
||||
}
|
||||
|
||||
@@ -39,17 +39,13 @@ func CrawlGo() {
|
||||
// 节点去重
|
||||
proxies = proxies.Deduplication()
|
||||
log.Println("CrawlGo node count:", len(proxies))
|
||||
proxies = provider.Clash{Proxies: proxies}.CleanProxies()
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex()
|
||||
cache.SetProxies("allproxies", proxies)
|
||||
|
||||
// 可用性检测
|
||||
proxiesUseful := proxy.CleanProxies(provider.Clash{Proxies: proxies}.CleanProxies())
|
||||
proxies = make(proxy.ProxyList, len(proxiesUseful))
|
||||
copy(proxies, proxiesUseful)
|
||||
|
||||
proxies = proxy.CleanBadProxies(proxies)
|
||||
log.Println("CrawlGo clash useable node count:", len(proxies))
|
||||
|
||||
// 排序和重命名
|
||||
proxies.NameAddCounrty().Sort().NameAddIndex()
|
||||
cache.SetProxies("proxies", proxies)
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<div class='section friendly'>
|
||||
<h1><strong>免费Clash节点</strong></h1>
|
||||
<div class='article'>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess节点信息,聚合去重后提供clash配置,每10分钟更新</p>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess节点信息,聚合去重后提供clash配置,每15分钟更新</p>
|
||||
<br>
|
||||
<p>Clash配置文件:<a href="https://proxy.tgbot.co/clash/config">https://proxy.tgbot.co/clash/config</a> <a href="clash://install-config?url=https://proxy.tgbot.co/clash/config">一键导入</a></p>
|
||||
<p>Clash proxy-provider(Shadowrocket添加订阅方式可用):<a href="https://proxy.tgbot.co/clash/proxies">https://proxy.tgbot.co/clash/proxies</a></p>
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="HandheldFriendly" content="True">
|
||||
<title>免费节点</title>
|
||||
<meta property="og:site_name" content="免费节点">
|
||||
<meta property="og:description" content="免费ss,免费ssr,免费v2ray,免费vmess,免费vless,免费shadowsocks,免费shadowsocksr,免费shadowsocksrr,免费shadowrocket,免费quan,免费quanx,免费surge,免费小火箭,白嫖ss,白嫖ssr,白嫖v2ray,白嫖vmess,白嫖vless,白嫖shadowsocks,白嫖shadowsocksr,白嫖shadowsocksrr,白嫖shadowrocket,白嫖quan,白嫖quanx,白嫖surge,白嫖小火箭,高速ss,高速ssr,高速v2ray,高速vmess,高速vless,高速shadowsocks,高速shadowsocksr,高速shadowsocksrr,高速shadowrocket,高速quan,高速quanx,高速surge,高速小火箭,公益ss,公益ssr,公益v2ray,公益vmess,公益vless,公益shadowsocks,公益shadowsocksr,公益shadowsocksrr,公益shadowrocket,公益quan,公益quanx,公益surge,公益小火箭,windowsss,windowsssr,windowsv2ray,windowsvmess,windowsvless,windowsshadowsocks,windowsshadowsocksr,windowsshadowsocksrr,windowsshadowrocket,windowsquan,windowsquanx,windowssurge,windows小火箭,androidss,androidssr,androidv2ray,androidvmess,androidvless,androidshadowsocks,androidshadowsocksr,androidshadowsocksrr,androidshadowrocket,androidquan,androidquanx,androidsurge,android小火箭,iosss,iosssr,iosv2ray,iosvmess,iosvless,iosshadowsocks,iosshadowsocksr,iosshadowsocksrr,iosshadowrocket,iosquan,iosquanx,iossurge,ios小火箭,macss,macssr,macv2ray,macvmess,macvless,macshadowsocks,macshadowsocksr,macshadowsocksrr,macshadowrocket,macquan,macquanx,macsurge,mac小火箭,苹果ss,苹果ssr,苹果v2ray,苹果vmess,苹果vless,苹果shadowsocks,苹果shadowsocksr,苹果shadowsocksrr,苹果shadowrocket,苹果quan,苹果quanx,苹果surge,苹果小火箭,安卓ss,安卓ssr,安卓v2ray,安卓vmess,安卓vless,安卓shadowsocks,安卓shadowsocksr,安卓shadowsocksrr,安卓shadowrocket,安卓quan,安卓quanx,安卓surge,安卓小火箭">
|
||||
<meta name="keywords" content="免费ss,免费ssr,免费v2ray,免费vmess,免费vless,免费shadowsocks,免费shadowsocksr,免费shadowsocksrr,免费shadowrocket,免费quan,免费quanx,免费surge,免费小火箭,白嫖ss,白嫖ssr,白嫖v2ray,白嫖vmess,白嫖vless,白嫖shadowsocks,白嫖shadowsocksr,白嫖shadowsocksrr,白嫖shadowrocket,白嫖quan,白嫖quanx,白嫖surge,白嫖小火箭,高速ss,高速ssr,高速v2ray,高速vmess,高速vless,高速shadowsocks,高速shadowsocksr,高速shadowsocksrr,高速shadowrocket,高速quan,高速quanx,高速surge,高速小火箭,公益ss,公益ssr,公益v2ray,公益vmess,公益vless,公益shadowsocks,公益shadowsocksr,公益shadowsocksrr,公益shadowrocket,公益quan,公益quanx,公益surge,公益小火箭,windowsss,windowsssr,windowsv2ray,windowsvmess,windowsvless,windowsshadowsocks,windowsshadowsocksr,windowsshadowsocksrr,windowsshadowrocket,windowsquan,windowsquanx,windowssurge,windows小火箭,androidss,androidssr,androidv2ray,androidvmess,androidvless,androidshadowsocks,androidshadowsocksr,androidshadowsocksrr,androidshadowrocket,androidquan,androidquanx,androidsurge,android小火箭,iosss,iosssr,iosv2ray,iosvmess,iosvless,iosshadowsocks,iosshadowsocksr,iosshadowsocksrr,iosshadowrocket,iosquan,iosquanx,iossurge,ios小火箭,macss,macssr,macv2ray,macvmess,macvless,macshadowsocks,macshadowsocksr,macshadowsocksrr,macshadowrocket,macquan,macquanx,macsurge,mac小火箭,苹果ss,苹果ssr,苹果v2ray,苹果vmess,苹果vless,苹果shadowsocks,苹果shadowsocksr,苹果shadowsocksrr,苹果shadowrocket,苹果quan,苹果quanx,苹果surge,苹果小火箭,安卓ss,安卓ssr,安卓v2ray,安卓vmess,安卓vless,安卓shadowsocks,安卓shadowsocksr,安卓shadowsocksrr,安卓shadowrocket,安卓quan,安卓quanx,安卓surge,安卓小火箭">
|
||||
<style type='text/css'>
|
||||
body {
|
||||
background-color: white;
|
||||
@@ -103,7 +106,7 @@
|
||||
<div class='section friendly'>
|
||||
<h1><strong>免费节点</strong></h1>
|
||||
<div class='article'>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess节点信息,聚合去重后提供节点列表,每10分钟更新</p>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、ssr、vmess节点信息,聚合去重后提供节点列表,每15分钟更新</p>
|
||||
<br>
|
||||
<h5><a href="/clash">Clash</a></h5>
|
||||
<p>Clash配置文件:<a href="https://proxy.tgbot.co/clash/config">https://proxy.tgbot.co/clash/config</a> <a
|
||||
|
||||
BIN
assets/proxy.jpg
Normal file
BIN
assets/proxy.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@@ -1,4 +1,8 @@
|
||||
sources:
|
||||
- type: webfuzzsub
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/du5/free/master/sub.list
|
||||
|
||||
- type: subscribe
|
||||
options:
|
||||
url: https://raw.githubusercontent.com/ssrsub/ssr/master/v2ray
|
||||
@@ -19,6 +23,3 @@ sources:
|
||||
|
||||
- type: web-freessrxyz
|
||||
options:
|
||||
|
||||
- type: web-lucnorg
|
||||
options:
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<div class='section friendly'>
|
||||
<h1><strong>免费Surge节点</strong></h1>
|
||||
<div class='article'>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、vmess节点信息,聚合去重后提供Surge节点列表,每10分钟更新</p>
|
||||
<p>自动抓取tg频道、订阅地址、公开互联网上的ss、vmess节点信息,聚合去重后提供Surge节点列表,每15分钟更新</p>
|
||||
<br>
|
||||
<p>Surge配置文件:<a href="https://proxy.tgbot.co/surge/config">https://proxy.tgbot.co/surge/config</a> <a href="surge3:///install-config?url=https://proxy.tgbot.co/surge/config">一键导入</a></p>
|
||||
<p>Surge proxy list:<a href="https://proxy.tgbot.co/surge/proxies">https://proxy.tgbot.co/surge/proxies</a></p>
|
||||
|
||||
@@ -49,10 +49,16 @@ func NewTGChannelGetter(options tool.Options) (getter Getter, err error) {
|
||||
}
|
||||
|
||||
func (g *TGChannelGetter) Get() proxy.ProxyList {
|
||||
result := make(proxy.ProxyList, 0)
|
||||
g.results = make([]string, 0)
|
||||
// 找到所有的文字消息
|
||||
g.c.OnHTML("div.tgme_widget_message_text", func(e *colly.HTMLElement) {
|
||||
g.results = append(g.results, GrepLinksFromString(e.Text)...)
|
||||
// 抓取到http链接,有可能是订阅链接或其他链接,无论如何试一下
|
||||
subUrls := urlRe.FindAllString(e.Text, -1)
|
||||
for _, url := range subUrls {
|
||||
result = append(result, (&Subscribe{Url: url}).Get()...)
|
||||
}
|
||||
})
|
||||
|
||||
// 找到之前消息页面的链接,加入访问队列
|
||||
@@ -67,8 +73,7 @@ func (g *TGChannelGetter) Get() proxy.ProxyList {
|
||||
if err != nil {
|
||||
_ = fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
|
||||
return StringArray2ProxyArray(g.results)
|
||||
return append(result, StringArray2ProxyArray(g.results)...)
|
||||
}
|
||||
|
||||
func (g *TGChannelGetter) Get2Chan(pc chan proxy.Proxy, wg *sync.WaitGroup) {
|
||||
|
||||
@@ -80,7 +80,7 @@ const (
|
||||
domainPattern = `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
|
||||
|
||||
// 匹配 URL
|
||||
urlPattern = `((https|http|ftp|rtsp|mms)?://)?` + // 协议
|
||||
urlPattern = `((https|http)?://)?` + // 协议
|
||||
`(([0-9a-zA-Z]+:)?[0-9a-zA-Z_-]+@)?` + // pwd:user@
|
||||
"(" + ipPattern + "|(" + domainPattern + "))" + // IP 或域名
|
||||
`(:\d{1,5})?` + // 端口
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
package getter
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"github.com/zu1k/proxypool/proxy"
|
||||
"github.com/zu1k/proxypool/tool"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Register("web-lucnorg", NewWebLucnorg)
|
||||
}
|
||||
|
||||
const lucnorgSsrLink = "https://lncn.org/api/ssrList"
|
||||
|
||||
type WebLucnOrg struct {
|
||||
}
|
||||
|
||||
func NewWebLucnorg(options tool.Options) (getter Getter, err error) {
|
||||
return &WebLucnOrg{}, nil
|
||||
}
|
||||
|
||||
func (w *WebLucnOrg) Get() proxy.ProxyList {
|
||||
resp, err := tool.GetHttpClient().Post(lucnorgSsrLink, nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
response := struct {
|
||||
Code string `json:"code"`
|
||||
Ssrs string `json:"ssrs"`
|
||||
}{}
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
dec := decryptAesForLucn(response.Code, response.Ssrs)
|
||||
if dec == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
type node struct {
|
||||
Url string `json:"url"`
|
||||
}
|
||||
ssrs := make([]node, 0)
|
||||
err = json.Unmarshal(dec, &ssrs)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([]string, 0)
|
||||
for _, node := range ssrs {
|
||||
result = append(result, node.Url)
|
||||
}
|
||||
return StringArray2ProxyArray(result)
|
||||
}
|
||||
|
||||
func (w *WebLucnOrg) Get2Chan(pc chan proxy.Proxy, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
nodes := w.Get()
|
||||
for _, node := range nodes {
|
||||
pc <- node
|
||||
}
|
||||
}
|
||||
|
||||
func decryptAesForLucn(code string, c string) []byte {
|
||||
if code == "" {
|
||||
code = "abclnv561cqqfg30"
|
||||
}
|
||||
cipher, err := base64.StdEncoding.DecodeString(c)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
result := tool.AesEcbDecryptWithPKCS7Unpadding(cipher, []byte(code))
|
||||
return result
|
||||
}
|
||||
@@ -23,6 +23,11 @@ func (b *Base) BaseInfo() *Base {
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Base) Clone() Base {
|
||||
c := *b
|
||||
return c
|
||||
}
|
||||
|
||||
type Proxy interface {
|
||||
String() string
|
||||
ToClash() string
|
||||
@@ -31,4 +36,5 @@ type Proxy interface {
|
||||
SetName(name string)
|
||||
TypeName() string
|
||||
BaseInfo() *Base
|
||||
Clone() Proxy
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func testDelay(p Proxy) (delay uint16, err error) {
|
||||
return delay, err
|
||||
}
|
||||
|
||||
func CleanProxies(proxies []Proxy) (cproxies []Proxy) {
|
||||
func CleanBadProxies(proxies []Proxy) (cproxies []Proxy) {
|
||||
c := make(chan checkResult, 40)
|
||||
defer close(c)
|
||||
for _, p := range proxies {
|
||||
@@ -52,7 +52,7 @@ func CleanProxies(proxies []Proxy) (cproxies []Proxy) {
|
||||
cproxies = make([]Proxy, 0)
|
||||
for _, p := range proxies {
|
||||
if _, ok := okMap[p.Identifier()]; ok {
|
||||
cproxies = append(cproxies, p)
|
||||
cproxies = append(cproxies, p.Clone())
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -71,3 +71,13 @@ func Deduplication(src ProxyList) ProxyList {
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (ps ProxyList) Clone() ProxyList {
|
||||
result := make(ProxyList, 0, len(ps))
|
||||
for _, pp := range ps {
|
||||
if pp != nil {
|
||||
result = append(result, pp.Clone())
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ func (ss Shadowsocks) ToSurge() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (ss Shadowsocks) Clone() Proxy {
|
||||
return &ss
|
||||
}
|
||||
|
||||
func ParseSSLink(link string) (*Shadowsocks, error) {
|
||||
if !strings.HasPrefix(link, "ss://") {
|
||||
return nil, ErrorNotSSRLink
|
||||
|
||||
@@ -57,6 +57,10 @@ func (ssr ShadowsocksR) ToSurge() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (ssr ShadowsocksR) Clone() Proxy {
|
||||
return &ssr
|
||||
}
|
||||
|
||||
func ParseSSRLink(link string) (*ShadowsocksR, error) {
|
||||
if !strings.HasPrefix(link, "ssr") {
|
||||
return nil, ErrorNotSSRLink
|
||||
|
||||
@@ -40,7 +40,7 @@ type HTTPOptions struct {
|
||||
}
|
||||
|
||||
func (v Vmess) Identifier() string {
|
||||
return net.JoinHostPort(v.Server, strconv.Itoa(v.Port)) + v.Cipher
|
||||
return net.JoinHostPort(v.Server, strconv.Itoa(v.Port)) + v.Cipher + v.UUID
|
||||
}
|
||||
|
||||
func (v Vmess) String() string {
|
||||
@@ -82,6 +82,10 @@ func (v Vmess) ToSurge() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (v Vmess) Clone() Proxy {
|
||||
return &v
|
||||
}
|
||||
|
||||
type vmessLinkJson struct {
|
||||
Add string `json:"add"`
|
||||
V string `json:"v"`
|
||||
|
||||
@@ -311,6 +311,3 @@ sources:
|
||||
|
||||
- type: web-freessrxyz
|
||||
options:
|
||||
|
||||
- type: web-lucnorg
|
||||
options:
|
||||
|
||||
43
tool/aes.go
43
tool/aes.go
@@ -1,43 +0,0 @@
|
||||
package tool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
)
|
||||
|
||||
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
func PKCS7UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
func AesEcbDecryptWithPKCS7Unpadding(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
decrypted := make([]byte, len(data))
|
||||
size := block.BlockSize()
|
||||
|
||||
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
|
||||
block.Decrypt(decrypted[bs:be], data[bs:be])
|
||||
}
|
||||
|
||||
return PKCS7UnPadding(decrypted)
|
||||
}
|
||||
|
||||
func AesEcbEncryptWithPKCS7Padding(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
data = PKCS7Padding(data, block.BlockSize())
|
||||
decrypted := make([]byte, len(data))
|
||||
size := block.BlockSize()
|
||||
|
||||
for bs, be := 0, size; bs < len(data); bs, be = bs+size, be+size {
|
||||
block.Encrypt(decrypted[bs:be], data[bs:be])
|
||||
}
|
||||
|
||||
return decrypted
|
||||
}
|
||||
Reference in New Issue
Block a user