¸ÄÓñ¾»ú¶ÀÁ¢ CA£¬»ָ´ CLI TLS УÑ飬±£»¤ƾ¾ÝÓëÅäÖò¢·¢±£´档 д Cursor Êý¾ݡ¢»Ự·¾¶¡¢´úÀíÉúÃüÖÜÆڡ¢ģÐÍÇëÇóÓë Skills Îļþ²Ù×÷¡£ Ϊ¶ÀÁ¢ Tab ·þÎñÔö¼ӿͻ§¶˼øȨ£¬Éý¼¶ÒÀÀµÓ빤¾ßÁ´£¬ÍêÉƷ¢²¼ԪÐÅϢͬ²½¡£ Ñé֤£ºÁ½¸ö Go ģ¿éµIJâÊÔ/vet¡¢¹ؼüģ¿é race¡¢ǰ¶˲âÊÔ/Éú²ú¹¹½¨/Éó¼ơ¢ Go ¿ɴï©¶´ɨÃèÓë macOS/Linux ¿ÉÐÐģ¿齻²æ±àÒë¾ùͨ¹ý¡£ Windows ¸ôÀëÆô¶¯ͨ¹ý£»δÍê³ɵĵã»÷ðÑ̺ÍԭÉúƽ̨Ñé֤¼ûÉó²鱨¸档
79 lines
2.4 KiB
Go
79 lines
2.4 KiB
Go
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})
|
|
}
|