mirror of
https://github.com/alireza0/x-ui.git
synced 2026-10-20 18:51:33 +00:00
generate self-signed certs on the go #1636
This commit is contained in:
parent
2111bf0c5e
commit
767abf52ef
10 changed files with 96 additions and 0 deletions
|
|
@ -132,6 +132,7 @@ func (a *APIController) serverApi(api *gin.RouterGroup) {
|
|||
{"GET", "/getNewmldsa65", a.serverController.getNewmldsa65},
|
||||
|
||||
{"POST", "/getNewEchCert", a.serverController.getNewEchCert},
|
||||
{"POST", "/getNewSelfSignedCert", a.serverController.getNewSelfSignedCert},
|
||||
{"POST", "/getCertHash", a.serverController.getCertHash},
|
||||
{"POST", "/getTlsPing", a.serverController.getTlsPing},
|
||||
{"POST", "/importDB", a.serverController.importDB},
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ func (a *ServerController) initRouter(g *gin.RouterGroup) {
|
|||
g.GET("/getNewX25519Cert", a.getNewX25519Cert)
|
||||
|
||||
g.POST("/getNewEchCert", a.getNewEchCert)
|
||||
g.POST("/getNewSelfSignedCert", a.getNewSelfSignedCert)
|
||||
g.POST("/getCertHash", a.getCertHash)
|
||||
g.POST("/getTlsPing", a.getTlsPing)
|
||||
g.POST("/stopXrayService", a.stopXrayService)
|
||||
|
|
@ -213,6 +214,16 @@ func (a *ServerController) getNewEchCert(c *gin.Context) {
|
|||
jsonObj(c, cert, nil)
|
||||
}
|
||||
|
||||
func (a *ServerController) getNewSelfSignedCert(c *gin.Context) {
|
||||
sni := c.PostForm("sni")
|
||||
cert, err := network.GenerateSelfSignedCert(sni)
|
||||
if err != nil {
|
||||
jsonMsg(c, "generate self-signed certificate", err)
|
||||
return
|
||||
}
|
||||
jsonObj(c, cert, nil)
|
||||
}
|
||||
|
||||
func (a *ServerController) getCertHash(c *gin.Context) {
|
||||
certFile := c.PostForm("certFile")
|
||||
certContent := c.PostForm("certContent")
|
||||
|
|
|
|||
|
|
@ -104,6 +104,10 @@
|
|||
<a-input type="textarea" :rows="3" v-model="cert.key"></a-input>
|
||||
</a-form-item>
|
||||
</template>
|
||||
<a-form-item label=" ">
|
||||
<a-button type="primary" icon="safety-certificate" @click="getNewSelfSignedCert(index)">{{ i18n
|
||||
"pages.inbounds.generateSelfSignedCert" }}</a-button>
|
||||
</a-form-item>
|
||||
<a-form-item label='{{ i18n "pages.inbounds.stream.tls.ocspStapling" }}'>
|
||||
<a-input-number v-model.number="cert.ocspStapling" :min="0"></a-input-number>
|
||||
</a-form-item>
|
||||
|
|
|
|||
|
|
@ -251,6 +251,19 @@
|
|||
this.inbound.stream.tls.echServerKeys = '';
|
||||
this.inbound.stream.tls.settings.echConfigList = '';
|
||||
},
|
||||
async getNewSelfSignedCert(index) {
|
||||
const cert = inModal.inbound.stream.tls.certs[index];
|
||||
if (!cert) return;
|
||||
inModal.loading(true);
|
||||
const msg = await HttpUtil.post('/server/getNewSelfSignedCert', {sni: inModal.inbound.stream.tls.sni});
|
||||
inModal.loading(false);
|
||||
if (!msg.success) {
|
||||
return;
|
||||
}
|
||||
cert.useFile = false;
|
||||
cert.cert = msg.obj.cert;
|
||||
cert.key = msg.obj.key;
|
||||
},
|
||||
async getCertHash() {
|
||||
const cert = inModal.inbound.stream.tls.certs[0];
|
||||
if (!cert) return;
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@ package network
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
|
@ -80,6 +85,63 @@ func GetCertHash(certFile string, certContent string) ([]string, error) {
|
|||
return hashes, nil
|
||||
}
|
||||
|
||||
func GenerateSelfSignedCert(serverName string) (any, error) {
|
||||
var names []string
|
||||
for _, name := range strings.Split(serverName, ",") {
|
||||
if name = strings.TrimSpace(name); name != "" {
|
||||
names = append(names, name)
|
||||
}
|
||||
}
|
||||
if len(names) == 0 {
|
||||
names = []string{"localhost", "127.0.0.1", "::1"}
|
||||
}
|
||||
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, common.NewError("unable to generate private key: ", err)
|
||||
}
|
||||
|
||||
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
||||
if err != nil {
|
||||
return nil, common.NewError("unable to generate serial number: ", err)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{CommonName: names[0]},
|
||||
NotBefore: now.Add(-24 * time.Hour),
|
||||
NotAfter: now.AddDate(10, 0, 0),
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: true,
|
||||
}
|
||||
for _, name := range names {
|
||||
if ip := net.ParseIP(name); ip != nil {
|
||||
template.IPAddresses = append(template.IPAddresses, ip)
|
||||
} else {
|
||||
template.DNSNames = append(template.DNSNames, name)
|
||||
}
|
||||
}
|
||||
|
||||
certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)
|
||||
if err != nil {
|
||||
return nil, common.NewError("unable to create certificate: ", err)
|
||||
}
|
||||
keyBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
|
||||
if err != nil {
|
||||
return nil, common.NewError("unable to encode private key: ", err)
|
||||
}
|
||||
|
||||
certObj := map[string]string{
|
||||
"cert": string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})),
|
||||
"key": string(pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})),
|
||||
}
|
||||
|
||||
return certObj, nil
|
||||
}
|
||||
|
||||
func GetTlsPing(domain string, port string) (any, error) {
|
||||
if domain == "" {
|
||||
return "", common.NewError("domain is empty")
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@
|
|||
"email" = "Email"
|
||||
"emailDesc" = "Please provide a unique email address"
|
||||
"setDefaultCert" = "Set Cert from Panel"
|
||||
"generateSelfSignedCert" = "Generate Self-Signed Cert"
|
||||
"telegramDesc" = "Please provide Chat ID(s) without using the '@' symbol. (Get it here @userinfobot) or (Use '/id' command in the bot)"
|
||||
"subscriptionDesc" = "To find your subscription URL, navigate to the 'More Information'. Additionally, you can use the same name for several clients."
|
||||
"info" = "Info"
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@
|
|||
"email" = "ایمیل"
|
||||
"emailDesc" = "باید یک ایمیل یکتا باشد"
|
||||
"setDefaultCert" = "استفاده از گواهی پنل"
|
||||
"generateSelfSignedCert" = "ساخت گواهی خودامضا"
|
||||
"telegramDesc" = "دریافت کنید '/id'یا دستور @userinfobot آیدی(های) چت مدیر را بدون '@' واردکنید. از"
|
||||
"subscriptionDesc" = "لینک سابسکربپشن خودرا در 'اطلاعات بیشتر' پیدا کنید، همچنین میتوانید از همین نام برای چندین کاربر استفادهکنید"
|
||||
"info" = "اطلاعات"
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@
|
|||
"email" = "Email"
|
||||
"emailDesc" = "Пожалуйста, укажите уникальный Email"
|
||||
"setDefaultCert" = "Установить сертификат с панели"
|
||||
"generateSelfSignedCert" = "Создать самоподписанный сертификат"
|
||||
"telegramDesc" = "Используйте идентификатор Telegram без символа @ или идентификатора чата (можно получить его здесь @userinfobot или использовать команду '/id' в боте)"
|
||||
"subscriptionDesc" = "вы можете найти свою ссылку подписки в разделе «Подробнее», также вы можете использовать одно и то же имя для нескольких клиенты"
|
||||
"info" = "Информация"
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@
|
|||
"email" = "Email"
|
||||
"emailDesc" = "vui lòng cung cấp một địa chỉ email duy nhất."
|
||||
"setDefaultCert" = "Đặt chứng chỉ từ bảng điều khiển"
|
||||
"generateSelfSignedCert" = "Tạo chứng chỉ tự ký"
|
||||
"telegramDesc" = "Sử dụng ID Telegram không có @ hoặc ID trò chuyện (bạn có thể lấy nó tại đây @userinfobot hoặc sử dụng lệnh '/id' trong bot)"
|
||||
"subscriptionDesc" = "Bạn có thể tìm thấy liên kết phụ của mình trên Chi tiết, bạn cũng có thể sử dụng cùng tên cho một số khách hàng"
|
||||
"info" = "Thông tin"
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@
|
|||
"email" = "电子邮件"
|
||||
"emailDesc" = "电子邮件必须完全唯一"
|
||||
"setDefaultCert" = "从面板设置证书"
|
||||
"generateSelfSignedCert" = "生成自签名证书"
|
||||
"telegramDesc" = "使用 Telegram ID,不包含 @ 符号或聊天 ID(可以在 @userinfobot 处获取,或在机器人中使用'/id'命令)"
|
||||
"subscriptionDesc" = "您可以在详细信息上找到您的子链接,你可以为多个客户端使用相同的名称"
|
||||
"info" = "信息"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue