本文整理汇总了Golang中github.com/snapcore/snapd/asserts.Encode函数的典型用法代码示例。如果您正苦于以下问题:Golang Encode函数的具体用法?Golang Encode怎么用?Golang Encode使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了Encode函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: DeviceSessionRequest
// DeviceSessionRequest produces a device-session-request with the given nonce, it also returns the encoded device serial assertion. It returns ErrNoSerial if the device serial is not yet initialized.
func (ac *authContext) DeviceSessionRequest(nonce string) (deviceSessionRequest []byte, serial []byte, err error) {
if ac.deviceAsserts == nil {
return nil, nil, ErrNoSerial
}
req, ser, err := ac.deviceAsserts.DeviceSessionRequest(nonce)
if err == state.ErrNoState {
return nil, nil, ErrNoSerial
}
if err != nil {
return nil, nil, err
}
return asserts.Encode(req), asserts.Encode(ser), nil
}
开发者ID:clobrano,项目名称:snappy,代码行数:14,代码来源:auth.go
示例2: TestCheckForgery
func (chks *checkSuite) TestCheckForgery(c *C) {
trustedKey := testPrivKey0
cfg := &asserts.DatabaseConfig{
Backstore: chks.bs,
Trusted: []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
}
db, err := asserts.OpenDatabase(cfg)
c.Assert(err, IsNil)
encoded := asserts.Encode(chks.a)
content, encodedSig := chks.a.Signature()
// forgery
forgedSig := new(packet.Signature)
forgedSig.PubKeyAlgo = packet.PubKeyAlgoRSA
forgedSig.Hash = crypto.SHA512
forgedSig.CreationTime = time.Now()
h := crypto.SHA512.New()
h.Write(content)
pk1 := packet.NewRSAPrivateKey(time.Unix(1, 0), testPrivKey1RSA)
err = forgedSig.Sign(h, pk1, &packet.Config{DefaultHash: crypto.SHA512})
c.Assert(err, IsNil)
buf := new(bytes.Buffer)
forgedSig.Serialize(buf)
b := append([]byte{0x1}, buf.Bytes()...)
forgedSigEncoded := base64.StdEncoding.EncodeToString(b)
forgedEncoded := bytes.Replace(encoded, encodedSig, []byte(forgedSigEncoded), 1)
c.Assert(forgedEncoded, Not(DeepEquals), encoded)
forgedAssert, err := asserts.Decode(forgedEncoded)
c.Assert(err, IsNil)
err = db.Check(forgedAssert)
c.Assert(err, ErrorMatches, "failed signature verification: .*")
}
开发者ID:pedronis,项目名称:snappy,代码行数:35,代码来源:database_test.go
示例3: TestImportAssertionsFromSeedHappy
func (s *FirstBootTestSuite) TestImportAssertionsFromSeedHappy(c *C) {
ovld, err := overlord.New()
c.Assert(err, IsNil)
st := ovld.State()
// add a bunch of assert files
assertsChain := s.makeModelAssertionChain(c)
for i, as := range assertsChain {
fn := filepath.Join(dirs.SnapSeedDir, "assertions", strconv.Itoa(i))
err := ioutil.WriteFile(fn, asserts.Encode(as), 0644)
c.Assert(err, IsNil)
}
// import them
err = boot.ImportAssertionsFromSeed(st)
c.Assert(err, IsNil)
// verify that the model was added
st.Lock()
defer st.Unlock()
db := assertstate.DB(st)
as, err := db.Find(asserts.ModelType, map[string]string{
"series": "16",
"brand-id": "my-brand",
"model": "my-model",
})
c.Assert(err, IsNil)
_, ok := as.(*asserts.Model)
c.Check(ok, Equals, true)
ds, err := auth.Device(st)
c.Assert(err, IsNil)
c.Check(ds.Brand, Equals, "my-brand")
c.Check(ds.Model, Equals, "my-model")
}
开发者ID:clobrano,项目名称:snappy,代码行数:35,代码来源:firstboot_test.go
示例4: TestSerialRequestHappy
func (ss *serialSuite) TestSerialRequestHappy(c *C) {
sreq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType,
map[string]interface{}{
"brand-id": "brand-id1",
"model": "baz-3000",
"device-key": ss.encodedDevKey,
"request-id": "REQID",
}, []byte("HW-DETAILS"), ss.deviceKey)
c.Assert(err, IsNil)
// roundtrip
a, err := asserts.Decode(asserts.Encode(sreq))
c.Assert(err, IsNil)
sreq2, ok := a.(*asserts.SerialRequest)
c.Assert(ok, Equals, true)
// standalone signature check
err = asserts.SignatureCheck(sreq2, sreq2.DeviceKey())
c.Check(err, IsNil)
c.Check(sreq2.BrandID(), Equals, "brand-id1")
c.Check(sreq2.Model(), Equals, "baz-3000")
c.Check(sreq2.RequestID(), Equals, "REQID")
c.Check(sreq2.Serial(), Equals, "")
}
开发者ID:pedronis,项目名称:snappy,代码行数:27,代码来源:device_asserts_test.go
示例5: TestAccountKeyRequestUntil
func (aks *accountKeySuite) TestAccountKeyRequestUntil(c *C) {
db := aks.openDB(c)
aks.prereqAccount(c, db)
tests := []struct {
untilHeader string
until time.Time
}{
{"", time.Time{}}, // zero time default
{aks.until.Format(time.RFC3339), aks.until}, // in the future
{aks.since.Format(time.RFC3339), aks.since}, // same as since
}
for _, test := range tests {
c.Log(test)
headers := map[string]interface{}{
"account-id": "acc-id1",
"name": "default",
"public-key-sha3-384": aks.keyID,
"since": aks.since.Format(time.RFC3339),
}
if test.untilHeader != "" {
headers["until"] = test.untilHeader
}
akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType, headers, []byte(aks.pubKeyBody), aks.privKey)
c.Assert(err, IsNil)
a, err := asserts.Decode(asserts.Encode(akr))
c.Assert(err, IsNil)
akr2 := a.(*asserts.AccountKeyRequest)
c.Check(akr2.Until(), Equals, test.until)
err = db.Check(akr2)
c.Check(err, IsNil)
}
}
开发者ID:pedronis,项目名称:snappy,代码行数:34,代码来源:account_key_test.go
示例6: TestAssembleRoundtrip
func (as *assertsSuite) TestAssembleRoundtrip(c *C) {
encoded := []byte("type: test-only\n" +
"format: 1\n" +
"authority-id: auth-id2\n" +
"primary-key: abc\n" +
"revision: 5\n" +
"header1: value1\n" +
"header2: value2\n" +
"body-length: 8\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij\n\n" +
"THE-BODY" +
"\n\n" +
"AXNpZw==")
a, err := asserts.Decode(encoded)
c.Assert(err, IsNil)
cont, sig := a.Signature()
reassembled, err := asserts.Assemble(a.Headers(), a.Body(), cont, sig)
c.Assert(err, IsNil)
c.Check(reassembled.Headers(), DeepEquals, a.Headers())
c.Check(reassembled.Body(), DeepEquals, a.Body())
reassembledEncoded := asserts.Encode(reassembled)
c.Check(reassembledEncoded, DeepEquals, encoded)
}
开发者ID:niemeyer,项目名称:snapd,代码行数:26,代码来源:asserts_test.go
示例7: generateSerialRequestAssertion
func generateSerialRequestAssertion() (string, error) {
privateKey, err := generatePrivateKey()
if err != nil {
return "", err
}
encodedPubKey, err := asserts.EncodePublicKey(privateKey.PublicKey())
if err != nil {
return "", err
}
// Generate a request-id
r, _ := getRequestID()
headers := map[string]interface{}{
"brand-id": request.Brand,
"device-key": string(encodedPubKey),
"request-id": r,
"model": request.Model,
"serial": request.SerialNumber,
}
sreq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, headers, []byte(""), privateKey)
if err != nil {
return "", err
}
assertSR := asserts.Encode(sreq)
return string(assertSR), nil
}
开发者ID:ubuntu-core,项目名称:identity-vault,代码行数:29,代码来源:createserialrequest.go
示例8: TestSignFormatSanitySupportMultilineHeaderValues
func (as *assertsSuite) TestSignFormatSanitySupportMultilineHeaderValues(c *C) {
headers := map[string]interface{}{
"authority-id": "auth-id1",
"primary-key": "0",
}
multilineVals := []string{
"a\n",
"\na",
"a\n\b\nc",
"a\n\b\nc\n",
"\na\n",
"\n\na\n\nb\n\nc",
}
for _, multilineVal := range multilineVals {
headers["multiline"] = multilineVal
if len(multilineVal)%2 == 1 {
headers["odd"] = "true"
}
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1)
c.Assert(err, IsNil)
decoded, err := asserts.Decode(asserts.Encode(a))
c.Assert(err, IsNil)
c.Check(decoded.Header("multiline"), Equals, multilineVal)
}
}
开发者ID:niemeyer,项目名称:snapd,代码行数:30,代码来源:asserts_test.go
示例9: TestDeviceSessionRequest
func (s *authContextSetupSuite) TestDeviceSessionRequest(c *C) {
st := s.o.State()
st.Lock()
defer st.Unlock()
st.Unlock()
_, _, err := s.ac.DeviceSessionRequest("NONCE")
st.Lock()
c.Check(err, Equals, auth.ErrNoSerial)
// setup serial and key in system state
err = assertstate.Add(st, s.serial)
c.Assert(err, IsNil)
kpMgr, err := asserts.OpenFSKeypairManager(dirs.SnapDeviceDir)
c.Assert(err, IsNil)
err = kpMgr.Put(deviceKey)
c.Assert(err, IsNil)
auth.SetDevice(st, &auth.DeviceState{
Brand: s.serial.BrandID(),
Model: s.serial.Model(),
Serial: s.serial.Serial(),
KeyID: deviceKey.PublicKey().ID(),
})
st.Unlock()
req, encSerial, err := s.ac.DeviceSessionRequest("NONCE")
st.Lock()
c.Assert(err, IsNil)
c.Check(bytes.HasPrefix(req, []byte("type: device-session-request\n")), Equals, true)
c.Check(encSerial, DeepEquals, asserts.Encode(s.serial))
}
开发者ID:chipaca,项目名称:snappy,代码行数:31,代码来源:managers_test.go
示例10: TestDeviceSessionRequest
func (ss *serialSuite) TestDeviceSessionRequest(c *C) {
ts := time.Now().UTC().Round(time.Second)
sessReq, err := asserts.SignWithoutAuthority(asserts.DeviceSessionRequestType,
map[string]interface{}{
"brand-id": "brand-id1",
"model": "baz-3000",
"serial": "99990",
"nonce": "NONCE",
"timestamp": ts.Format(time.RFC3339),
}, nil, ss.deviceKey)
c.Assert(err, IsNil)
// roundtrip
a, err := asserts.Decode(asserts.Encode(sessReq))
c.Assert(err, IsNil)
sessReq2, ok := a.(*asserts.DeviceSessionRequest)
c.Assert(ok, Equals, true)
// standalone signature check
err = asserts.SignatureCheck(sessReq2, ss.deviceKey.PublicKey())
c.Check(err, IsNil)
c.Check(sessReq2.BrandID(), Equals, "brand-id1")
c.Check(sessReq2.Model(), Equals, "baz-3000")
c.Check(sessReq2.Serial(), Equals, "99990")
c.Check(sessReq2.Nonce(), Equals, "NONCE")
c.Check(sessReq2.Timestamp().Equal(ts), Equals, true)
}
开发者ID:pedronis,项目名称:snappy,代码行数:29,代码来源:device_asserts_test.go
示例11: TestAccountKeyRequestHappy
func (aks *accountKeySuite) TestAccountKeyRequestHappy(c *C) {
akr, err := asserts.SignWithoutAuthority(asserts.AccountKeyRequestType,
map[string]interface{}{
"account-id": "acc-id1",
"name": "default",
"public-key-sha3-384": aks.keyID,
"since": aks.since.Format(time.RFC3339),
}, []byte(aks.pubKeyBody), aks.privKey)
c.Assert(err, IsNil)
// roundtrip
a, err := asserts.Decode(asserts.Encode(akr))
c.Assert(err, IsNil)
akr2, ok := a.(*asserts.AccountKeyRequest)
c.Assert(ok, Equals, true)
db := aks.openDB(c)
aks.prereqAccount(c, db)
err = db.Check(akr2)
c.Check(err, IsNil)
c.Check(akr2.AccountID(), Equals, "acc-id1")
c.Check(akr2.Name(), Equals, "default")
c.Check(akr2.PublicKeyID(), Equals, aks.keyID)
c.Check(akr2.Since(), Equals, aks.since)
}
开发者ID:pedronis,项目名称:snappy,代码行数:28,代码来源:account_key_test.go
示例12: getSerial
func getSerial(t *state.Task, privKey asserts.PrivateKey, device *auth.DeviceState, cfg *serialRequestConfig) (*asserts.Serial, error) {
var serialSup serialSetup
err := t.Get("serial-setup", &serialSup)
if err != nil && err != state.ErrNoState {
return nil, err
}
if serialSup.Serial != "" {
// we got a serial, just haven't managed to save its info yet
a, err := asserts.Decode([]byte(serialSup.Serial))
if err != nil {
return nil, fmt.Errorf("internal error: cannot decode previously saved serial: %v", err)
}
return a.(*asserts.Serial), nil
}
client := &http.Client{Timeout: 30 * time.Second}
// NB: until we get at least an Accepted (202) we need to
// retry from scratch creating a new request-id because the
// previous one used could have expired
if serialSup.SerialRequest == "" {
serialRequest, err := prepareSerialRequest(t, privKey, device, client, cfg)
if err != nil { // errors & retries
return nil, err
}
serialSup.SerialRequest = serialRequest
}
serial, err := submitSerialRequest(t, serialSup.SerialRequest, client, cfg)
if err == errPoll {
// we can/should reuse the serial-request
t.Set("serial-setup", serialSup)
return nil, errPoll
}
if err != nil { // errors & retries
return nil, err
}
keyID := privKey.PublicKey().ID()
if serial.BrandID() != device.Brand || serial.Model() != device.Model || serial.DeviceKey().ID() != keyID {
return nil, fmt.Errorf("obtained serial assertion does not match provided device identity information (brand, model, key id): %s / %s / %s != %s / %s / %s", serial.BrandID(), serial.Model(), serial.DeviceKey().ID(), device.Brand, device.Model, keyID)
}
serialSup.Serial = string(asserts.Encode(serial))
t.Set("serial-setup", serialSup)
if repeatRequestSerial == "after-got-serial" {
// For testing purposes, ensure a crash in this state works.
return nil, &state.Retry{}
}
return serial, nil
}
开发者ID:niemeyer,项目名称:snapd,代码行数:56,代码来源:devicemgr.go
示例13: TestHappyDecodeModelAssertion
func (s *imageSuite) TestHappyDecodeModelAssertion(c *C) {
fn := filepath.Join(c.MkDir(), "model.assertion")
err := ioutil.WriteFile(fn, asserts.Encode(s.model), 0644)
c.Assert(err, IsNil)
a, err := image.DecodeModelAssertion(&image.Options{
ModelFile: fn,
})
c.Assert(err, IsNil)
c.Check(a.Type(), Equals, asserts.ModelType)
}
开发者ID:elopio,项目名称:snappy,代码行数:11,代码来源:image_test.go
示例14: TestSignFormatSanityEmptyBody
func (as *assertsSuite) TestSignFormatSanityEmptyBody(c *C) {
headers := map[string]interface{}{
"authority-id": "auth-id1",
"primary-key": "0",
}
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey1)
c.Assert(err, IsNil)
_, err = asserts.Decode(asserts.Encode(a))
c.Check(err, IsNil)
}
开发者ID:niemeyer,项目名称:snapd,代码行数:11,代码来源:asserts_test.go
示例15: TestImportAssertionsFromSeedTwoModelAsserts
func (s *FirstBootTestSuite) TestImportAssertionsFromSeedTwoModelAsserts(c *C) {
st := s.overlord.State()
st.Lock()
defer st.Unlock()
// write out two model assertions
model := s.makeModelAssertion(c, "my-model")
fn := filepath.Join(dirs.SnapSeedDir, "assertions", "model")
err := ioutil.WriteFile(fn, asserts.Encode(model), 0644)
c.Assert(err, IsNil)
model2 := s.makeModelAssertion(c, "my-second-model")
fn = filepath.Join(dirs.SnapSeedDir, "assertions", "model2")
err = ioutil.WriteFile(fn, asserts.Encode(model2), 0644)
c.Assert(err, IsNil)
// try import and verify that its rejects because other assertions are
// missing
err = devicestate.ImportAssertionsFromSeed(st)
c.Assert(err, ErrorMatches, "cannot add more than one model assertion")
}
开发者ID:pedronis,项目名称:snappy,代码行数:21,代码来源:firstboot_test.go
示例16: mockServer
func (s *deviceMgrSuite) mockServer(c *C, reqID string) *httptest.Server {
var mu sync.Mutex
count := 0
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/identity/api/v1/request-id":
w.WriteHeader(http.StatusOK)
io.WriteString(w, fmt.Sprintf(`{"request-id": "%s"}`, reqID))
case "/identity/api/v1/serial":
c.Check(r.Header.Get("X-Extra-Header"), Equals, "extra")
fallthrough
case "/identity/api/v1/devices":
mu.Lock()
serialNum := 9999 + count
count++
mu.Unlock()
b, err := ioutil.ReadAll(r.Body)
c.Assert(err, IsNil)
a, err := asserts.Decode(b)
c.Assert(err, IsNil)
serialReq, ok := a.(*asserts.SerialRequest)
c.Assert(ok, Equals, true)
err = asserts.SignatureCheck(serialReq, serialReq.DeviceKey())
c.Assert(err, IsNil)
c.Check(serialReq.BrandID(), Equals, "canonical")
c.Check(serialReq.Model(), Equals, "pc")
if reqID == "REQID-POLL" && serialNum != 10002 {
w.WriteHeader(http.StatusAccepted)
return
}
serialStr := fmt.Sprintf("%d", serialNum)
if serialReq.Serial() != "" {
// use proposed serial
serialStr = serialReq.Serial()
}
serial, err := s.storeSigning.Sign(asserts.SerialType, map[string]interface{}{
"brand-id": "canonical",
"model": "pc",
"serial": serialStr,
"device-key": serialReq.HeaderString("device-key"),
"device-key-sha3-384": serialReq.SignKeyID(),
"timestamp": time.Now().Format(time.RFC3339),
}, serialReq.Body(), "")
c.Assert(err, IsNil)
w.Header().Set("Content-Type", asserts.MediaType)
w.WriteHeader(http.StatusOK)
w.Write(asserts.Encode(serial))
}
}))
}
开发者ID:pedronis,项目名称:snappy,代码行数:52,代码来源:devicemgr_test.go
示例17: TestAssertionsEndpointPreloaded
func (s *storeTestSuite) TestAssertionsEndpointPreloaded(c *C) {
// something preloaded
resp, err := s.StoreGet(`/assertions/account/testrootorg`)
c.Assert(err, IsNil)
defer resp.Body.Close()
c.Assert(resp.StatusCode, Equals, 200)
c.Check(resp.Header.Get("Content-Type"), Equals, "application/x.ubuntu.assertion")
body, err := ioutil.ReadAll(resp.Body)
c.Assert(err, IsNil)
c.Check(string(body), Equals, string(asserts.Encode(systestkeys.TestRootAccount)))
}
开发者ID:pedronis,项目名称:snappy,代码行数:13,代码来源:store_test.go
示例18: TestSignFormatSanityNonEmptyBody
func (as *assertsSuite) TestSignFormatSanityNonEmptyBody(c *C) {
headers := map[string]interface{}{
"authority-id": "auth-id1",
"primary-key": "0",
}
body := []byte("THE-BODY")
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, body, testPrivKey1)
c.Assert(err, IsNil)
c.Check(a.Body(), DeepEquals, body)
decoded, err := asserts.Decode(asserts.Encode(a))
c.Assert(err, IsNil)
c.Check(decoded.Body(), DeepEquals, body)
}
开发者ID:niemeyer,项目名称:snapd,代码行数:14,代码来源:asserts_test.go
示例19: prepareSerialRequest
func prepareSerialRequest(t *state.Task, privKey asserts.PrivateKey, device *auth.DeviceState, client *http.Client, cfg *serialRequestConfig) (string, error) {
st := t.State()
st.Unlock()
defer st.Lock()
req, err := http.NewRequest("POST", cfg.requestIDURL, nil)
if err != nil {
return "", fmt.Errorf("internal error: cannot create request-id request %q", cfg.requestIDURL)
}
cfg.applyHeaders(req)
resp, err := client.Do(req)
if err != nil {
return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return "", retryErr(t, "cannot retrieve request-id for making a request for a serial: unexpected status %d", resp.StatusCode)
}
dec := json.NewDecoder(resp.Body)
var requestID requestIDResp
err = dec.Decode(&requestID)
if err != nil { // assume broken i/o
return "", retryErr(t, "cannot read response with request-id for making a request for a serial: %v", err)
}
encodedPubKey, err := asserts.EncodePublicKey(privKey.PublicKey())
if err != nil {
return "", fmt.Errorf("internal error: cannot encode device public key: %v", err)
}
headers := map[string]interface{}{
"brand-id": device.Brand,
"model": device.Model,
"request-id": requestID.RequestID,
"device-key": string(encodedPubKey),
}
if cfg.proposedSerial != "" {
headers["serial"] = cfg.proposedSerial
}
serialReq, err := asserts.SignWithoutAuthority(asserts.SerialRequestType, headers, cfg.body, privKey)
if err != nil {
return "", err
}
return string(asserts.Encode(serialReq)), nil
}
开发者ID:niemeyer,项目名称:snapd,代码行数:50,代码来源:devicemgr.go
示例20: Execute
func (x *cmdSignBuild) Execute(args []string) error {
if len(args) > 0 {
return ErrExtraArgs
}
snapDigest, snapSize, err := asserts.SnapFileSHA3_384(x.Positional.Filename)
if err != nil {
return err
}
gkm := asserts.NewGPGKeypairManager()
privKey, err := gkm.GetByName(x.KeyName)
if err != nil {
// TRANSLATORS: %q is the key name, %v the error message
return fmt.Errorf(i18n.G("cannot use %q key: %v"), x.KeyName, err)
}
pubKey := privKey.PublicKey()
timestamp := time.Now().Format(time.RFC3339)
headers := map[string]interface{}{
"developer-id": x.DeveloperID,
"authority-id": x.DeveloperID,
"snap-sha3-384": snapDigest,
"snap-id": x.SnapID,
"snap-size": fmt.Sprintf("%d", snapSize),
"grade": x.Grade,
"timestamp": timestamp,
}
adb, err := asserts.OpenDatabase(&asserts.DatabaseConfig{
KeypairManager: gkm,
})
if err != nil {
return fmt.Errorf(i18n.G("cannot open the assertions database: %v"), err)
}
a, err := adb.Sign(asserts.SnapBuildType, headers, nil, pubKey.ID())
if err != nil {
return fmt.Errorf(i18n.G("cannot sign assertion: %v"), err)
}
_, err = Stdout.Write(asserts.Encode(a))
if err != nil {
return err
}
return nil
}
开发者ID:niemeyer,项目名称:snapd,代码行数:49,代码来源:cmd_sign_build.go
注:本文中的github.com/snapcore/snapd/asserts.Encode函数示例由纯净天空整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论