Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add claim support #102

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions claim.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
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
}
47 changes: 47 additions & 0 deletions claim_test.go
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
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)
}
125 changes: 125 additions & 0 deletions native_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 (
Expand Down Expand Up @@ -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
Expand Down
Loading