дȫÏîĿÉó²éÎÊÌⲢ·¢²¼ v1.1.9
¸ÄÓñ¾»ú¶ÀÁ¢ CA£¬»ָ´ CLI TLS УÑ飬±£»¤ƾ¾ÝÓëÅäÖò¢·¢±£´档 д Cursor Êý¾ݡ¢»Ự·¾¶¡¢´úÀíÉúÃüÖÜÆڡ¢ģÐÍÇëÇóÓë Skills Îļþ²Ù×÷¡£ Ϊ¶ÀÁ¢ Tab ·þÎñÔö¼ӿͻ§¶˼øȨ£¬Éý¼¶ÒÀÀµÓ빤¾ßÁ´£¬ÍêÉƷ¢²¼ԪÐÅϢͬ²½¡£ Ñé֤£ºÁ½¸ö Go ģ¿éµIJâÊÔ/vet¡¢¹ؼüģ¿é race¡¢ǰ¶˲âÊÔ/Éú²ú¹¹½¨/Éó¼ơ¢ Go ¿ɴï©¶´ɨÃèÓë macOS/Linux ¿ÉÐÐģ¿齻²æ±àÒë¾ùͨ¹ý¡£ Windows ¸ôÀëÆô¶¯ͨ¹ý£»δÍê³ɵĵã»÷ðÑ̺ÍԭÉúƽ̨Ñé֤¼ûÉó²鱨¸档
This commit is contained in:
78
internal/certs/local.go
Normal file
78
internal/certs/local.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"cursor/internal/securefile"
|
||||
)
|
||||
|
||||
// LoadOrCreateLocalCA persists one private CA per application data directory.
|
||||
// A single private bundle is the authority; ca.crt is a public export for clients.
|
||||
func LoadOrCreateLocalCA(dir string) (*Manager, error) {
|
||||
if err := securefile.PrivateDir(dir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
unlock, err := securefile.Lock(filepath.Join(dir, "ca.lock"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer unlock()
|
||||
bundlePath := filepath.Join(dir, "local-ca.pem")
|
||||
bundle, err := os.ReadFile(bundlePath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
key, keyErr := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
serial, keyErr := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
now := time.Now()
|
||||
template := &x509.Certificate{SerialNumber: serial, Subject: pkix.Name{CommonName: "Local-Cursor Private CA", Organization: []string{"Local-Cursor"}}, NotBefore: now.Add(-time.Hour), NotAfter: now.AddDate(10, 0, 0), IsCA: true, BasicConstraintsValid: true, KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign}
|
||||
der, keyErr := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key)
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
keyPEM, keyErr := marshalPrivateKeyPEM(key)
|
||||
if keyErr != nil {
|
||||
return nil, keyErr
|
||||
}
|
||||
bundle = append(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}), keyPEM...)
|
||||
if err = securefile.Write(bundlePath, bundle); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = securefile.Protect(bundlePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certBlock, rest := pem.Decode(bundle)
|
||||
if certBlock == nil {
|
||||
return nil, fmt.Errorf("本机 CA 文件损坏,请先备份并修复")
|
||||
}
|
||||
manager, err := NewManagerFromPEM(pem.EncodeToMemory(certBlock), rest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("本机 CA 校验失败(不会自动轮换): %w", err)
|
||||
}
|
||||
if err = securefile.Write(filepath.Join(dir, "ca.crt"), manager.CACertPEM()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return manager, nil
|
||||
}
|
||||
|
||||
func (m *Manager) CACertPEM() []byte {
|
||||
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: m.caCert.Raw})
|
||||
}
|
||||
Reference in New Issue
Block a user