mirror of
https://github.com/wyx2685/V2bX.git
synced 2026-02-04 04:30:08 +00:00
update
refactor limiter fix getLink bug add connection limit move limit config to ControllerConfig del dynamic speed limit (next version will be re add) del online ip sync (next version will be re add)
This commit is contained in:
104
node/lego/cert.go
Normal file
104
node/lego/cert.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package lego
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge/http01"
|
||||
"github.com/go-acme/lego/v4/providers/dns"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (l *Lego) SetProvider() error {
|
||||
switch l.config.CertMode {
|
||||
case "http":
|
||||
err := l.client.Challenge.SetHTTP01Provider(http01.NewProviderServer("", "80"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "dns":
|
||||
for k, v := range l.config.DNSEnv {
|
||||
os.Setenv(k, v)
|
||||
}
|
||||
p, err := dns.NewDNSChallengeProviderByName(l.config.Provider)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create dns challenge provider error: %s", err)
|
||||
}
|
||||
err = l.client.Challenge.SetDNS01Provider(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("set dns provider error: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lego) CreateCert() (err error) {
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: []string{l.config.CertDomain},
|
||||
}
|
||||
certificates, err := l.client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
return fmt.Errorf("obtain certificate error: %s", err)
|
||||
}
|
||||
err = l.writeCert(certificates)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lego) RenewCert() error {
|
||||
file, err := os.ReadFile(l.config.CertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read cert file error: %s", err)
|
||||
}
|
||||
if e, err := l.CheckCert(file); !e {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("check cert error: %s", err)
|
||||
}
|
||||
res, err := l.client.Certificate.Renew(certificate.Resource{
|
||||
Domain: l.config.CertDomain,
|
||||
Certificate: file,
|
||||
}, false, false, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = l.writeCert(res)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Lego) CheckCert(file []byte) (bool, error) {
|
||||
cert, err := certcrypto.ParsePEMCertificate(file)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
notAfter := int(time.Until(cert.NotAfter).Hours() / 24.0)
|
||||
if notAfter > 30 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
func (l *Lego) parseParmas(path string) string {
|
||||
r := strings.NewReplacer("{domain}", l.config.CertDomain,
|
||||
"{email}", l.config.Email)
|
||||
return r.Replace(path)
|
||||
}
|
||||
func (l *Lego) writeCert(certificates *certificate.Resource) error {
|
||||
err := checkPath(l.config.CertFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("check path error: %s", err)
|
||||
}
|
||||
err = os.WriteFile(l.parseParmas(l.config.CertFile), certificates.Certificate, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkPath(l.config.KeyFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("check path error: %s", err)
|
||||
}
|
||||
err = os.WriteFile(l.parseParmas(l.config.KeyFile), certificates.PrivateKey, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
node/lego/lego.go
Normal file
51
node/lego/lego.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package lego
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Yuzuki616/V2bX/common/file"
|
||||
"github.com/Yuzuki616/V2bX/conf"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
type Lego struct {
|
||||
client *lego.Client
|
||||
config *conf.CertConfig
|
||||
}
|
||||
|
||||
func New(config *conf.CertConfig) (*Lego, error) {
|
||||
user, err := NewUser(path.Join("/etc/V2bX/cert/user/",
|
||||
fmt.Sprintf("user-%s.json", config.Email)),
|
||||
config.Email)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create user error: %s", err)
|
||||
}
|
||||
c := lego.NewConfig(user)
|
||||
//c.CADirURL = "http://192.168.99.100:4000/directory"
|
||||
c.Certificate.KeyType = certcrypto.RSA2048
|
||||
client, err := lego.NewClient(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
l := Lego{
|
||||
client: client,
|
||||
config: config,
|
||||
}
|
||||
err = l.SetProvider()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("set provider error: %s", err)
|
||||
}
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
func checkPath(p string) error {
|
||||
if !file.IsExist(path.Dir(p)) {
|
||||
err := os.MkdirAll(path.Dir(p), 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create dir error: %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
40
node/lego/lego_test.go
Normal file
40
node/lego/lego_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package lego
|
||||
|
||||
import (
|
||||
"github.com/Yuzuki616/V2bX/conf"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var l *Lego
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
l, err = New(&conf.CertConfig{
|
||||
CertMode: "dns",
|
||||
Email: "test@test.com",
|
||||
CertDomain: "test.test.com",
|
||||
Provider: "cloudflare",
|
||||
DNSEnv: map[string]string{
|
||||
"CF_DNS_API_TOKEN": "123",
|
||||
},
|
||||
CertFile: "./cert/1.pem",
|
||||
KeyFile: "./cert/1.key",
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLego_CreateCertByDns(t *testing.T) {
|
||||
err := l.CreateCert()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLego_RenewCert(t *testing.T) {
|
||||
log.Println(l.RenewCert())
|
||||
}
|
||||
129
node/lego/user.go
Normal file
129
node/lego/user.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package lego
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"github.com/Yuzuki616/V2bX/common/file"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
"github.com/goccy/go-json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Email string `json:"Email"`
|
||||
Registration *registration.Resource `json:"Registration"`
|
||||
key crypto.PrivateKey
|
||||
KeyEncoded string `json:"Key"`
|
||||
}
|
||||
|
||||
func (u *User) GetEmail() string {
|
||||
return u.Email
|
||||
}
|
||||
func (u *User) GetRegistration() *registration.Resource {
|
||||
return u.Registration
|
||||
}
|
||||
func (u *User) GetPrivateKey() crypto.PrivateKey {
|
||||
return u.key
|
||||
}
|
||||
|
||||
func NewUser(path string, email string) (*User, error) {
|
||||
var user User
|
||||
if file.IsExist(path) {
|
||||
err := user.Load(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user.Email != email {
|
||||
user.Registration = nil
|
||||
user.Email = email
|
||||
err := registerUser(&user, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
user.Email = email
|
||||
err := registerUser(&user, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func registerUser(user *User, path string) error {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate key error: %s", err)
|
||||
}
|
||||
user.key = privateKey
|
||||
c := lego.NewConfig(user)
|
||||
client, err := lego.NewClient(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create lego client error: %s", err)
|
||||
}
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Registration = reg
|
||||
err = user.Save(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("save user error: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func EncodePrivate(privKey *ecdsa.PrivateKey) (string, error) {
|
||||
encoded, err := x509.MarshalECPrivateKey(privKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: encoded})
|
||||
return string(pemEncoded), nil
|
||||
}
|
||||
func (u *User) Save(path string) error {
|
||||
err := checkPath(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("check path error: %s", err)
|
||||
}
|
||||
u.KeyEncoded, _ = EncodePrivate(u.key.(*ecdsa.PrivateKey))
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.NewEncoder(f).Encode(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal json error: %s", err)
|
||||
}
|
||||
u.KeyEncoded = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) DecodePrivate(pemEncodedPriv string) (*ecdsa.PrivateKey, error) {
|
||||
blockPriv, _ := pem.Decode([]byte(pemEncodedPriv))
|
||||
x509EncodedPriv := blockPriv.Bytes
|
||||
privateKey, err := x509.ParseECPrivateKey(x509EncodedPriv)
|
||||
return privateKey, err
|
||||
}
|
||||
func (u *User) Load(path string) error {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open file error: %s", err)
|
||||
}
|
||||
err = json.NewDecoder(f).Decode(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal json error: %s", err)
|
||||
}
|
||||
u.key, err = u.DecodePrivate(u.KeyEncoded)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode private key error: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user