本文整理汇总了Golang中github.com/cloudflare/cfssl/errors.New函数的典型用法代码示例。如果您正苦于以下问题:Golang New函数的具体用法?Golang New怎么用?Golang New使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了New函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: NewBundlerFromPEM
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and
// intermediate certificates.
func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) {
b := &Bundler{
RootPool: x509.NewCertPool(),
IntermediatePool: x509.NewCertPool(),
KnownIssuers: map[string]bool{},
}
log.Debug("parsing root certificates from PEM")
roots, err := helpers.ParseCertificatesPEM(caBundlePEM)
if err != nil {
log.Errorf("failed to parse root bundle: %v", err)
return nil, errors.New(errors.RootError, errors.ParseFailed)
}
log.Debug("parse intermediate certificates from PEM")
var intermediates []*x509.Certificate
if intermediates, err = helpers.ParseCertificatesPEM(intBundlePEM); err != nil {
log.Errorf("failed to parse intermediate bundle: %v", err)
return nil, errors.New(errors.IntermediatesError, errors.ParseFailed)
}
log.Debug("building certificate pools")
for _, c := range roots {
b.RootPool.AddCert(c)
b.KnownIssuers[string(c.Signature)] = true
}
for _, c := range intermediates {
b.IntermediatePool.AddCert(c)
b.KnownIssuers[string(c.Signature)] = true
}
log.Debug("bundler set up")
return b, nil
}
开发者ID:jgeromero,项目名称:cfssl,代码行数:37,代码来源:bundler.go
示例2: Dial
// Dial initiates a TLS connection to an outbound server. It returns a
// TLS connection to the server.
func Dial(address string, tr *Transport) (*tls.Conn, error) {
host, _, err := net.SplitHostPort(address)
if err != nil {
// Assume address is a hostname, and that it should
// use the HTTPS port number.
host = address
address = net.JoinHostPort(address, "443")
}
cfg, err := tr.TLSClientAuthClientConfig(host)
if err != nil {
return nil, err
}
conn, err := tls.Dial("tcp", address, cfg)
if err != nil {
return nil, err
}
state := conn.ConnectionState()
if len(state.VerifiedChains) == 0 {
return nil, errors.New(errors.CertificateError, errors.VerifyFailed)
}
for _, chain := range state.VerifiedChains {
for _, cert := range chain {
revoked, ok := revoke.VerifyCertificate(cert)
if (!tr.RevokeSoftFail && !ok) || revoked {
return nil, errors.New(errors.CertificateError, errors.VerifyFailed)
}
}
}
return conn, nil
}
开发者ID:jfrazelle,项目名称:cfssl,代码行数:37,代码来源:client.go
示例3: Sign
// Sign signs a new certificate based on the PEM-encoded client
// certificate or certificate request with the signing profile, specified by profileName.
// The certificate will be valid for the host named in the hostName parameter.
func (s *Signer) Sign(hostName string, in []byte, profileName string) (cert []byte, err error) {
profile := s.Policy.Profiles[profileName]
block, _ := pem.Decode(in)
if block == nil {
return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed, err)
}
var template *x509.Certificate
switch block.Type {
case "CERTIFICATE":
template, err = helpers.ParseSelfSignedCertificatePEM(in)
case "CERTIFICATE REQUEST":
template, err = s.parseCertificateRequest(block.Bytes)
default:
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed, errors.New("Not a certificate or csr."))
}
if err != nil {
return
}
if ip := net.ParseIP(hostName); ip != nil {
template.IPAddresses = []net.IP{ip}
} else {
template.DNSNames = []string{hostName}
}
return s.sign(template, profile)
}
开发者ID:kalw,项目名称:cfssl,代码行数:31,代码来源:signer.go
示例4: ParsePrivateKeyDER
// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve
// DER-encoded private key. The key must not be in PEM format.
func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
if err != nil {
generalKey, err = x509.ParsePKCS1PrivateKey(keyDER)
if err != nil {
generalKey, err = x509.ParseECPrivateKey(keyDER)
if err != nil {
// We don't include the actual error into
// the final error. The reason might be
// we don't want to leak any info about
// the private key.
return nil, cferr.New(cferr.PrivateKeyError,
cferr.ParseFailed)
}
}
}
switch generalKey.(type) {
case *rsa.PrivateKey:
return generalKey.(*rsa.PrivateKey), nil
case *ecdsa.PrivateKey:
return generalKey.(*ecdsa.PrivateKey), nil
}
// should never reach here
return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed)
}
开发者ID:CadeLaRen,项目名称:docker-3,代码行数:29,代码来源:derhelpers.go
示例5: NewSignHandlerFromSigner
// NewSignHandlerFromSigner generates a new SignHandler directly from
// an existing signer.
func NewSignHandlerFromSigner(s signer.Signer) (h http.Handler, err error) {
policy := s.Policy()
if policy == nil {
err = errors.New(errors.PolicyError, errors.InvalidPolicy)
return
}
// Sign will only respond for profiles that have no auth provider.
// So if all of the profiles require authentication, we return an error.
haveUnauth := (policy.Default.Provider == nil)
for _, profile := range policy.Profiles {
if !haveUnauth {
break
}
haveUnauth = (profile.Provider == nil)
}
if !haveUnauth {
err = errors.New(errors.PolicyError, errors.InvalidPolicy)
return
}
return &api.HTTPHandler{
Handler: &SignHandler{
signer: s,
},
Methods: []string{"POST"},
}, nil
}
开发者ID:jgeromero,项目名称:cfssl,代码行数:31,代码来源:remote_test.go
示例6: ParsePrivateKeyPEM
// ParsePrivateKeyPEM parses and returns a PEM-encoded private
// key. The private key may be either an unencrypted PKCS#8, PKCS#1,
// or elliptic private key.
func ParsePrivateKeyPEM(keyPEM []byte) (key interface{}, err error) {
keyDER, _ := pem.Decode(keyPEM)
if keyDER == nil {
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed, nil)
}
if procType, ok := keyDER.Headers["Proc-Type"]; ok {
if strings.Contains(procType, "ENCRYPTED") {
return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted, nil)
}
}
key, err = x509.ParsePKCS8PrivateKey(keyDER.Bytes)
if err != nil {
key, err = x509.ParsePKCS1PrivateKey(keyDER.Bytes)
if err != nil {
key, err = x509.ParseECPrivateKey(keyDER.Bytes)
if err != nil {
// We don't include the actual error into the final error.
// The reason might be we don't want to leak any info about
// the private key.
return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed, nil)
}
}
}
return
}
开发者ID:kalw,项目名称:cfssl,代码行数:28,代码来源:helpers.go
示例7: ParseCertificatesDER
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
// either PKCS #7, PKCS #12, or raw x509.
func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) {
certsDER = bytes.TrimSpace(certsDER)
pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
if err != nil {
var pkcs12data interface{}
certs = make([]*x509.Certificate, 1)
pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password)
if err != nil {
certs, err = x509.ParseCertificates(certsDER)
if err != nil {
return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
} else {
key = pkcs12data.(crypto.Signer)
}
} else {
if pkcs7data.ContentInfo != "SignedData" {
return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
}
certs = pkcs7data.Content.SignedData.Certificates
}
if certs == nil {
return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
return certs, key, nil
}
开发者ID:jamesbjackson,项目名称:cfssl,代码行数:28,代码来源:helpers.go
示例8: NewBundler
// NewBundler creates a new Bundler from the files passed in; these
// files should contain a list of valid root certificates and a list
// of valid intermediate certificates, respectively.
func NewBundler(caBundleFile, intBundleFile string) (*Bundler, error) {
log.Debug("Loading CA bundle: ", caBundleFile)
caBundlePEM, err := ioutil.ReadFile(caBundleFile)
if err != nil {
log.Errorf("root bundle failed to load: %v", err)
return nil, errors.New(errors.RootError, errors.None, err)
}
log.Debug("Loading Intermediate bundle: ", intBundleFile)
intBundlePEM, err := ioutil.ReadFile(intBundleFile)
if err != nil {
log.Errorf("intermediate bundle failed to load: %v", err)
return nil, errors.New(errors.IntermediatesError, errors.None, err)
}
if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
err = os.MkdirAll(IntermediateStash, 0755)
if err != nil {
log.Errorf("failed to create intermediate stash directory %s: %v", err)
return nil, err
}
log.Infof("intermediate stash directory %s created", IntermediateStash)
}
return NewBundlerFromPEM(caBundlePEM, intBundlePEM)
}
开发者ID:kalw,项目名称:cfssl,代码行数:29,代码来源:bundler.go
示例9: NewAuthHandlerFromSigner
// NewAuthHandlerFromSigner creates a new AuthHandler from the signer
// that is passed in.
func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) {
policy := signer.Policy()
if policy == nil {
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
}
if policy.Default == nil && policy.Profiles == nil {
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
}
// AuthSign will not respond for profiles that have no auth provider.
// So if there are no profiles with auth providers in this policy,
// we return an error.
haveAuth := (policy.Default.Provider != nil)
for _, profile := range policy.Profiles {
if haveAuth {
break
}
haveAuth = (profile.Provider != nil)
}
if !haveAuth {
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
}
return &api.HTTPHandler{
Handler: &AuthHandler{
signer: signer,
},
Methods: []string{"POST"},
}, nil
}
开发者ID:jgeromero,项目名称:cfssl,代码行数:34,代码来源:sign.go
示例10: ParseCertificatesDER
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
// either PKCS #7, PKCS #12, or raw x509.
func ParseCertificatesDER(certsDER []byte, password string) ([]*x509.Certificate, crypto.Signer, error) {
var certs []*x509.Certificate
var key crypto.Signer
certsDER = bytes.TrimSpace(certsDER)
pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
if err != nil {
pkcs12data, err := pkcs12.ParsePKCS12(certsDER, []byte(password))
if err != nil {
certs, err = x509.ParseCertificates(certsDER)
if err != nil {
return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
} else {
key = pkcs12data.PrivateKey
certs = pkcs12data.Certificates
}
} else {
if pkcs7data.ContentInfo != "SignedData" {
return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
}
certs = pkcs7data.Content.SignedData.Certificates
}
if certs == nil {
return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
}
return certs, key, nil
}
开发者ID:geligaoli,项目名称:cfssl,代码行数:29,代码来源:helpers.go
示例11: BundleFromRemote
// BundleFromRemote fetches the certificate chain served by the server at
// serverName (or ip, if the ip argument is not the empty string). It
// is expected that the method will be able to make a connection at
// port 443. The chain used by the server in this connection is
// used to rebuild the bundle.
func (b *Bundler) BundleFromRemote(serverName, ip string) (*Bundle, error) {
config := &tls.Config{
RootCAs: b.RootPool,
ServerName: serverName,
}
// Dial by IP if present
var dialName string
if ip != "" {
dialName = ip + ":443"
} else {
dialName = serverName + ":443"
}
log.Debugf("bundling from remote %s", dialName)
conn, err := tls.Dial("tcp", dialName, config)
var dialError string
// If there's an error in tls.Dial, try again with
// InsecureSkipVerify to fetch the remote bundle to (re-)bundle with.
// If the bundle is indeed not usable (expired, mismatched hostnames, etc.),
// report the error.
// Otherwise, create a working bundle and insert the tls error in the bundle.Status.
if err != nil {
log.Debugf("dial failed: %v", err)
// record the error msg
dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err)
// dial again with InsecureSkipVerify
log.Debugf("try again with InsecureSkipVerify.")
config.InsecureSkipVerify = true
conn, err = tls.Dial("tcp", dialName, config)
if err != nil {
log.Debugf("dial with InsecureSkipVerify failed: %v", err)
return nil, errors.New(errors.DialError, errors.Unknown, err)
}
}
connState := conn.ConnectionState()
certs := connState.PeerCertificates
err = conn.VerifyHostname(serverName)
if err != nil {
log.Debugf("failed to verify hostname: %v", err)
return nil, errors.New(errors.CertificateError, errors.VerifyFailed, err)
}
// verify peer intermediates and store them if there is any missing from the bundle.
// Don't care if there is error, will throw it any way in Bundle() call.
b.fetchIntermediates(certs)
// Bundle with remote certs. Inject the initial dial error, if any, to the status reporting.
bundle, err := b.Bundle(certs, nil, Ubiquitous)
if err != nil {
return nil, err
} else if dialError != "" {
bundle.Status.Messages = append(bundle.Status.Messages, dialError)
}
return bundle, err
}
开发者ID:kalw,项目名称:cfssl,代码行数:63,代码来源:bundler.go
示例12: NewSigner
// NewSigner generates a new certificate signer from a Root structure.
// This is one of two standard signers: local or remote. If the root
// structure specifies a force remote, then a remote signer is created,
// otherwise either a remote or local signer is generated based on the
// policy. For a local signer, the CertFile and KeyFile need to be
// defined in Root.
func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) {
if policy == nil {
policy = &config.Signing{
Profiles: map[string]*config.SigningProfile{},
Default: config.DefaultConfig(),
}
}
if !policy.Valid() {
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
var s signer.Signer
var err error
if root.ForceRemote {
s, err = remote.NewSigner(policy)
} else {
if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() {
// Currently we don't support a hybrid signer
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
if policy.NeedsLocalSigner() {
// shouldProvide indicates whether the
// function *should* have produced a key. If
// it's true, we should use the signer and
// error returned. Otherwise, keep looking for
// signers.
var shouldProvide bool
// localSignerList is defined in the
// universal_signers*.go files. These activate
// and deactivate signers based on build
// flags; for example,
// universal_signers_pkcs11.go contains a list
// of valid signers when PKCS #11 is turned
// on.
for _, possibleSigner := range localSignerList {
s, shouldProvide, err = possibleSigner(&root, policy)
if shouldProvide {
break
}
}
if s == nil {
err = cferr.New(cferr.PrivateKeyError, cferr.Unknown)
}
}
if policy.NeedsRemoteSigner() {
s, err = remote.NewSigner(policy)
}
}
return s, err
}
开发者ID:40a,项目名称:cfssl,代码行数:61,代码来源:universal.go
示例13: ParseCertificatePEM
// ParseCertificatePEM parses and returns a PEM-encoded certificate.
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
certPEM = bytes.TrimSpace(certPEM)
cert, rest, err := ParseOneCertificateFromPEM(certPEM)
if err != nil {
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed, err)
} else if cert == nil {
return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed, nil)
} else if len(rest) > 0 {
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed, errors.New("The PEM file should contain only one certificate."))
}
return cert, nil
}
开发者ID:kalw,项目名称:cfssl,代码行数:13,代码来源:helpers.go
示例14: NewSigner
// NewSigner creates a new remote Signer directly from a
// signing policy.
func NewSigner(policy *config.Signing) (*Signer, error) {
if policy != nil {
if !policy.Valid() {
return nil, cferr.New(cferr.PolicyError,
cferr.InvalidPolicy)
}
return &Signer{policy: policy}, nil
}
return nil, cferr.New(cferr.PolicyError,
cferr.InvalidPolicy)
}
开发者ID:40a,项目名称:cfssl,代码行数:14,代码来源:remote.go
示例15: GetKeyDERFromPEM
// GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes.
func GetKeyDERFromPEM(in []byte) ([]byte, error) {
keyDER, _ := pem.Decode(in)
if keyDER != nil {
if procType, ok := keyDER.Headers["Proc-Type"]; ok {
if strings.Contains(procType, "ENCRYPTED") {
return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted)
}
}
return keyDER.Bytes, nil
}
return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed)
}
开发者ID:jamesbjackson,项目名称:cfssl,代码行数:14,代码来源:helpers.go
示例16: ParseCertificatePEM
// ParseCertificatePEM parses and returns a PEM-encoded certificate,
// can handle PEM encoded PKCS #7 structures.
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
certPEM = bytes.TrimSpace(certPEM)
cert, rest, err := ParseOneCertificateFromPEM(certPEM)
if err != nil {
// Log the actual parsing error but throw a default parse error message.
log.Debugf("Certificate parsing error: %v", err)
return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
} else if cert == nil {
return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
} else if len(rest) > 0 {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object"))
} else if len(cert) > 1 {
return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
}
return cert[0], nil
}
开发者ID:jamesbjackson,项目名称:cfssl,代码行数:18,代码来源:helpers.go
示例17: NewSigner
// NewSigner generates a new certificate signer from a Root structure.
// This is one of two standard signers: local or remote. If the root
// structure specifies a force remote, then a remote signer is created,
// otherwise either a remote or local signer is generated based on the
// policy. For a local signer, the CertFile and KeyFile need to be
// defined in Root.
func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) {
if policy == nil {
policy = &config.Signing{
Profiles: map[string]*config.SigningProfile{},
Default: config.DefaultConfig(),
}
}
if !policy.Valid() {
return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
}
var s signer.Signer
var err error
if root.ForceRemote {
s, err = remote.NewSigner(policy)
} else {
if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() {
s, err = newUniversalSigner(root, policy)
} else {
if policy.NeedsLocalSigner() {
s, err = newLocalSigner(root, policy)
}
if policy.NeedsRemoteSigner() {
s, err = remote.NewSigner(policy)
}
}
}
return s, err
}
开发者ID:mclem,项目名称:cfssl,代码行数:37,代码来源:universal.go
示例18: post
// post connects to the remote server and returns a Response struct
func (srv *server) post(url string, jsonData []byte) (*api.Response, error) {
buf := bytes.NewBuffer(jsonData)
resp, err := http.Post(url, "application/json", buf)
if err != nil {
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(errors.APIClientError, errors.IOError, err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New(string(body)))
}
var response api.Response
err = json.Unmarshal(body, &response)
if err != nil {
log.Debug("Unable to parse response body:", string(body))
return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
}
if !response.Success || response.Result == nil {
if len(response.Errors) > 0 {
return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message))
}
return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed)
}
return &response, nil
}
开发者ID:40a,项目名称:cfssl,代码行数:33,代码来源:client.go
示例19: Generate
// Generate creates a new CSR from a CertificateRequest structure and
// an existing key. The KeyRequest field is ignored.
func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) {
sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256)
if sigAlgo == x509.UnknownSignatureAlgorithm {
return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable)
}
var tpl = x509.CertificateRequest{
Subject: req.Name(),
SignatureAlgorithm: sigAlgo,
}
for i := range req.Hosts {
if ip := net.ParseIP(req.Hosts[i]); ip != nil {
tpl.IPAddresses = append(tpl.IPAddresses, ip)
} else {
tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i])
}
}
csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
if err != nil {
log.Errorf("failed to generate a CSR: %v", err)
err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err)
return
}
block := pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csr,
}
log.Info("encoded CSR")
csr = pem.EncodeToMemory(&block)
return
}
开发者ID:jamesbjackson,项目名称:cfssl,代码行数:36,代码来源:csr.go
示例20: newLocalSigner
func newLocalSigner(root Root, policy *config.Signing) (s signer.Signer, err error) {
// shouldProvide indicates whether the
// function *should* have produced a key. If
// it's true, we should use the signer and
// error returned. Otherwise, keep looking for
// signers.
var shouldProvide bool
// localSignerList is defined in the
// universal_signers*.go files. These activate
// and deactivate signers based on build
// flags; for example,
// universal_signers_pkcs11.go contains a list
// of valid signers when PKCS #11 is turned
// on.
for _, possibleSigner := range localSignerList {
s, shouldProvide, err = possibleSigner(&root, policy)
if shouldProvide {
break
}
}
if s == nil {
err = cferr.New(cferr.PrivateKeyError, cferr.Unknown)
}
return s, err
}
开发者ID:mclem,项目名称:cfssl,代码行数:28,代码来源:universal.go
注:本文中的github.com/cloudflare/cfssl/errors.New函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论