diff --git a/claim.go b/claim.go
new file mode 100644
index 0000000..39455b8
--- /dev/null
+++ b/claim.go
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+package ontology_go_sdk
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "github.com/ontio/ontology/common"
+ "time"
+)
+
+type Claim struct {
+ context string
+ id string
+ claim map[string]interface{}
+ claimStr string
+}
+
+func NewClaim(controller *Controller, ctx string, clmMap map[string]interface{},
+ metadata map[string]string, clmRevMap map[string]interface{}, publicKeyId string, expireTime int64) (*Claim, error) {
+ iss := metadata["Issuer"]
+ sub := metadata["Subject"]
+ header := NewHeader(publicKeyId)
+ payload, err := NewPayload("v1.0", iss, sub, time.Now().Unix(), expireTime, ctx, clmMap, clmRevMap)
+ if err != nil {
+ return nil, err
+ }
+ headerBs, err := header.getJson()
+ if err != nil {
+ return nil, err
+ }
+ payloadBs, err := payload.getJson()
+ if err != nil {
+ return nil, err
+ }
+ headerStr := base64.StdEncoding.EncodeToString(headerBs)
+ payloadStr := base64.StdEncoding.EncodeToString(payloadBs)
+ sig, err := controller.Sign([]byte(headerStr + "." + payloadStr))
+ if err != nil {
+ return nil, err
+ }
+ claimStr := headerStr + "." + payloadStr + "." + base64.StdEncoding.EncodeToString(sig)
+ return &Claim{
+ context: ctx,
+ claimStr: claimStr,
+ }, nil
+}
+
+func (this *Claim) GetClaimStr() string {
+ return this.claimStr
+}
+
+type Header struct {
+ Alg string `json:"alg"`
+ Typ string `json:"typ"`
+ Kid string `json:"kid"`
+}
+
+func NewHeader(kid string) *Header {
+ return &Header{
+ Alg: "ONT-ES256",
+ Typ: "JWT-X",
+ Kid: kid,
+ }
+}
+func (this *Header) getJson() ([]byte, error) {
+ bs, err := json.Marshal(this)
+ if err != nil {
+ return nil, err
+ }
+ return bs, nil
+}
+
+type Payload struct {
+ Ver string `json:"ver"`
+ Iss string `json:"iss"`
+ Sub string `json:"sub"`
+ Iat int64 `json:"iat"`
+ Exp int64 `json:"exp"`
+ Jti string `json:"jti"`
+ Context string `json:"@context"`
+ ClmMap map[string]interface{} `json:"clm"`
+ ClmRevMap map[string]interface{} `json:"clm-rev"`
+}
+
+func NewPayload(ver, iss, sub string, iat, exp int64, ctx string, clmMap, clmRevMap map[string]interface{}) (*Payload, error) {
+ payload := &Payload{
+ Ver: ver,
+ Iss: iss,
+ Sub: sub,
+ Iat: iat,
+ Exp: exp,
+ Context: ctx,
+ ClmMap: clmMap,
+ ClmRevMap: clmRevMap,
+ }
+ pbs, err := json.Marshal(payload)
+ if err != nil {
+ return nil, err
+ }
+ payload.Jti = common.ToHexString(pbs)
+ return payload, nil
+}
+
+func (this *Payload) getJson() ([]byte, error) {
+ bs, err := json.Marshal(this)
+ if err != nil {
+ return nil, err
+ }
+ return bs, nil
+}
+
+type MetaData struct {
+ createTime string
+ meta map[string]string
+}
+
+func (this *MetaData) GetJson() interface{} {
+ this.meta["CreateTime"] = this.createTime
+
+ return this.meta
+}
+
+type SignatureInfo struct {
+ format string
+ algorithm string
+ value []byte
+ publicKeyId string
+}
+
+func NewSignatureInfo(publicKeyId string, val []byte) *SignatureInfo {
+ return &SignatureInfo{
+ format: "pgp",
+ algorithm: "ECDSAwithSHA256",
+ value: val,
+ publicKeyId: publicKeyId,
+ }
+}
+
+func (this *SignatureInfo) getJson() map[string]interface{} {
+ signature := make(map[string]interface{})
+ signature["Format"] = this.format
+ signature["Algorithm"] = this.algorithm
+ signature["Value"] = this.value
+ signature["PublicKeyId"] = this.publicKeyId
+ return signature
+}
diff --git a/claim_test.go b/claim_test.go
new file mode 100644
index 0000000..f97300d
--- /dev/null
+++ b/claim_test.go
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The ontology Authors
+ * This file is part of The ontology library.
+ *
+ * The ontology is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ontology is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with The ontology. If not, see .
+ */
+package ontology_go_sdk
+
+import (
+ "testing"
+
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "time"
+)
+
+func TestNewClaim(t *testing.T) {
+ wallet := NewWallet("./wallet.dat")
+ pwd := []byte("111111")
+ acct, err := wallet.NewDefaultSettingIdentity(pwd)
+ assert.Nil(t, err)
+ clmMap := map[string]interface{}{
+ "1111": "1111",
+ }
+ metadata := map[string]string{
+ "2222": "2222",
+ }
+ clmRevMap := map[string]interface{}{
+ "333": "333",
+ }
+ con, err := acct.controllers[0].GetController(pwd)
+ assert.Nil(t, err)
+ claim, err := NewClaim(con, "", clmMap, metadata, clmRevMap, "", time.Now().Unix()+20)
+ assert.Nil(t, err)
+ fmt.Println(claim.claimStr)
+}
diff --git a/native_contract.go b/native_contract.go
index ff01ac8..cbdc6a6 100644
--- a/native_contract.go
+++ b/native_contract.go
@@ -19,9 +19,12 @@ package ontology_go_sdk
import (
"bytes"
+ "encoding/base64"
"encoding/hex"
+ "encoding/json"
"fmt"
"github.com/ontio/ontology-crypto/keypair"
+ "github.com/ontio/ontology-crypto/signature"
sdkcom "github.com/ontio/ontology-go-sdk/common"
"github.com/ontio/ontology-go-sdk/utils"
"github.com/ontio/ontology/common"
@@ -30,6 +33,9 @@ import (
cutils "github.com/ontio/ontology/core/utils"
"github.com/ontio/ontology/smartcontract/service/native/global_params"
"github.com/ontio/ontology/smartcontract/service/native/ont"
+ "strconv"
+ "strings"
+ "time"
)
var (
@@ -665,6 +671,125 @@ func (this *OntId) RegIDWithPublicKey(gasPrice, gasLimit uint64, payer *Account,
return this.ontSdk.SendTransaction(tx)
}
+func (this *OntId) CreateOntIdClaim(ontidController *Controller, context string,
+ metaData map[string]string, claimMap, clmRevMap map[string]interface{}, expire int64) (string, error) {
+ if ontidController == nil || context == "" || claimMap == nil || metaData == nil ||
+ clmRevMap == nil || expire < 0 {
+ return "", fmt.Errorf("[CreateOntIdClaim] param should not be nil")
+ }
+ curr := time.Now().Unix()
+ if expire < curr {
+ return "", fmt.Errorf("[CreateOntIdClaim] expire:%d should not be less than current time: %d", expire, curr)
+ }
+ issuerDid := metaData["Issuer"]
+ receiverDid := metaData["Subject"]
+ if issuerDid == "" || receiverDid == "" {
+ return "", fmt.Errorf("issuer ontid and receiver ontid should not be nil")
+ }
+ issuerDdo, err := this.GetDDO(issuerDid)
+ if err != nil {
+ return "", fmt.Errorf("[CreateOntIdClaim] GetDDO issuerDid failed: %s, ontid: %s", err, issuerDid)
+ }
+ owners := issuerDdo.Owners
+ if owners == nil {
+ return "", fmt.Errorf("[CreateOntIdClaim] not exist cliam issuer")
+ }
+ pk := common.ToHexString(keypair.SerializePublicKey(ontidController.PublicKey))
+ pubkeyId := ""
+ for _, owner := range owners {
+ if owner.Value == pk {
+ pubkeyId = owner.PubKeyId
+ break
+ }
+ }
+ if pubkeyId == "" {
+ return "", fmt.Errorf("not found publickeyid")
+ }
+ receiverDidStr := strings.Split(receiverDid, ":")
+ if len(receiverDidStr) != 3 {
+ return "", fmt.Errorf("[CreateOntIdClaim]receiverDid is wrong")
+ }
+ clai, err := NewClaim(ontidController, context, claimMap, metaData, clmRevMap, pubkeyId, expire)
+ if err != nil {
+ return "", fmt.Errorf("[CreateOntIdClaim] NewClaim failed: %s", err)
+ }
+ return clai.GetClaimStr(), nil
+}
+
+func (this *OntId) VerifyOntIdClaim(claimStr string) (bool, error) {
+ if claimStr == "" {
+ return false, fmt.Errorf("[VerifyOntIdClaim]param is nil")
+ }
+ arr := strings.Split(claimStr, ".")
+ if len(arr) != 3 {
+ return false, fmt.Errorf("[VerifyOntIdClaim] param is wrong")
+ }
+ payloadBytes, err := base64.StdEncoding.DecodeString(arr[1])
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] base64 decode failed: %s", err)
+ }
+ payload := &Payload{}
+ err = json.Unmarshal(payloadBytes, payload)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] Unmarshal payload failed: %s", err)
+ }
+ issuerDid := payload.Iss
+ issArr := strings.Split(issuerDid, ":")
+ if len(issArr) != 3 {
+ return false, fmt.Errorf("[VerifyOntIdClaim] payload iss is wrong")
+ }
+ issuerDdo, err := this.GetDDO(issuerDid)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] GetDDO failed: %s", err)
+ }
+ owners := issuerDdo.Owners
+ if owners == nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] owners is nil, issuerDid: %s", issuerDid)
+ }
+ signatureBytes, err := base64.StdEncoding.DecodeString(arr[2])
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] sig base64 decode failed: %s, sig: %s", err, arr[2])
+ }
+ headerBytes, err := base64.StdEncoding.DecodeString(arr[0])
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] header base64 decode failed: %s, header: %s", err, arr[0])
+ }
+ header := &Header{}
+ err = json.Unmarshal(headerBytes, header)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] header Unmarshal failed: %s, header: %s", err, arr[0])
+ }
+ kid := header.Kid
+ idArr := strings.Split(kid, "#keys-")
+ if len(idArr) < 2 {
+ return false, fmt.Errorf("[VerifyOntIdClaim] header kid is wrong: %s", kid)
+ }
+ idStr := idArr[1]
+ id, err := strconv.Atoi(idStr)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] Atoi is failed: %s, id: %s", err, idStr)
+ }
+ id -= 1
+ if id < 0 || id >= len(owners) {
+ return false, fmt.Errorf("[VerifyOntIdClaim] error id: %d", id)
+ }
+ pubkeyStr := owners[id].Value
+ data := arr[0] + "." + arr[1]
+ pkBs, err := common.HexToBytes(pubkeyStr)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] publickey error: %s", err)
+ }
+ pk, err := keypair.DeserializePublicKey(pkBs)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] DeserializePublicKey failed: %s", err)
+ }
+ sig, err := signature.Deserialize(signatureBytes)
+ if err != nil {
+ return false, fmt.Errorf("[VerifyOntIdClaim] sig Deserialize failed: %s", err)
+ }
+ return signature.Verify(pk, []byte(data), sig), nil
+}
+
func (this *OntId) NewRegIDWithAttributesTransaction(gasPrice, gasLimit uint64, ontId string, pubKey keypair.PublicKey, attributes []*DDOAttribute) (*types.MutableTransaction, error) {
type regIDWithAttribute struct {
OntId string
diff --git a/native_contract_test.go b/native_contract_test.go
index 2ec82fd..0602560 100644
--- a/native_contract_test.go
+++ b/native_contract_test.go
@@ -21,6 +21,7 @@ import (
"encoding/hex"
"fmt"
"github.com/ontio/ontology-crypto/keypair"
+ "github.com/stretchr/testify/assert"
"testing"
"time"
)
@@ -349,3 +350,52 @@ func TestOntId_Recovery(t *testing.T) {
return
}
}
+
+func TestOntId_CreateOntIdClaim(t *testing.T) {
+ return
+ testIdentity, err := testWallet.NewDefaultSettingIdentity(testPasswd)
+ assert.Nil(t, err)
+ testIdentity2, err := testWallet.NewDefaultSettingIdentity(testPasswd)
+ assert.Nil(t, err)
+ payer, err := testWallet.NewDefaultSettingAccount(testPasswd)
+ assert.Nil(t, err)
+
+ testOntSdk.NewRpcClient().SetAddress("http://127.0.0.1:20336")
+
+ controller, err := testIdentity.controllers[0].GetController(testPasswd)
+ _, err = testOntSdk.Native.OntId.RegIDWithPublicKey(0, 20000, payer, payer, testIdentity.ID, controller)
+ controller2, err := testIdentity2.controllers[0].GetController(testPasswd)
+ _, err = testOntSdk.Native.OntId.RegIDWithPublicKey(0, 20000, payer, payer, testIdentity.ID, controller2)
+ assert.Nil(t, err)
+ time.Sleep(6 * time.Second)
+ ddo, err := testOntSdk.Native.OntId.GetDDO(testIdentity.ID)
+ assert.NotNil(t, ddo)
+ assert.Nil(t, err)
+ ddo, err = testOntSdk.Native.OntId.GetDDO(testIdentity.ID)
+ assert.Nil(t, err)
+ assert.NotNil(t, ddo)
+ metaData := map[string]string{
+ "Issuer": testIdentity.ID,
+ "Subject": testIdentity2.ID,
+ }
+ clmRevMap := map[string]interface{}{
+ "typ": "AttestContract",
+ "addr": testIdentity.ID,
+ }
+ claim, err := testOntSdk.Native.OntId.CreateOntIdClaim(controller, "claim:context", metaData, clmRevMap, clmRevMap, time.Now().Unix()+1000)
+ assert.Nil(t, err)
+ boo, err := testOntSdk.Native.OntId.VerifyOntIdClaim(claim)
+ assert.Nil(t, err)
+ assert.True(t, boo)
+ fmt.Println("claim:", claim)
+}
+
+func TestOntId_VerifyOntIdClaim(t *testing.T) {
+ return
+ testOntSdk.NewRpcClient().SetAddress("http://127.0.0.1:20336")
+ //generate by java-sdk
+ claimStr := "eyJraWQiOiJkaWQ6b250OkFTejlOZENCVUdEclpZVGhuY2hGZkp0ZVFWcnUyUDNtcXEja2V5cy0xIiwidHlwIjoiSldULVgiLCJhbGciOiJPTlQtRVMyNTYifQ==.eyJjbG0tcmV2Ijp7Iklzc3VlciI6ImRpZDpvbnQ6QVN6OU5kQ0JVR0RyWllUaG5jaEZmSnRlUVZydTJQM21xcSIsIlN1YmplY3QiOiJkaWQ6b250OkFhcnJNQnkxaUdKU1o1VG1VUUNvak55VlZUdWdpUExQaWsifSwic3ViIjoiZGlkOm9udDpBYXJyTUJ5MWlHSlNaNVRtVVFDb2pOeVZWVHVnaVBMUGlrIiwidmVyIjoidjEuMCIsImNsbSI6eyIkcmVmIjoiJC5jbG0tcmV2In0sImlzcyI6ImRpZDpvbnQ6QVN6OU5kQ0JVR0RyWllUaG5jaEZmSnRlUVZydTJQM21xcSIsImV4cCI6MTU4NjQ5OTEwNCwiaWF0IjoxNTg2NDk4MTA1LCJAY29udGV4dCI6ImNsYWltOmNvbnRleHQiLCJqdGkiOiI1MzlhMzlmNWYyY2E1NzRlNTdkMjY2NzRiMDBhZTc5ZTBkODdiYjExMTNmODBlZWNmZDFkZDhjNThhOTNiM2NjIn0=.AZ1jo4XYus7+ovFK5FKr3l5GxJihfDUPlsiOhY4vyiRf283L8AYG7fIguE2HLUEDLIE7rGxc6jnU8/ts77MLo6U="
+ res, err := testOntSdk.Native.OntId.VerifyOntIdClaim(claimStr)
+ assert.Nil(t, err)
+ assert.True(t, res)
+}
diff --git a/ont_sdk_test.go b/ont_sdk_test.go
index ecac085..2d4cc57 100644
--- a/ont_sdk_test.go
+++ b/ont_sdk_test.go
@@ -49,13 +49,9 @@ var (
func init() {
var err error
- testWallet, err = testOntSdk.OpenWallet("./wallet.dat")
- if err != nil {
- fmt.Printf("OpenWallet err: %s\n", err)
- return
- }
+ testWallet = NewWallet("./wallet.dat")
testOntSdk = NewOntologySdk()
- testOntSdk.NewRpcClient().SetAddress(testNetUrl)
+ testOntSdk.NewRpcClient().SetAddress("http://127.0.0.1:20336")
testDefAcc, err = testWallet.GetDefaultAccount(testPasswd)
if err != nil {
fmt.Printf("GetDefaultAccount err: %s\n", err)