mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-01-23 10:28:13 -05:00
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
|
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
|
||
|
}
|