bsn.go
4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package blockchain
import (
"bytes"
"encoding/base64"
rawjson "encoding/json"
"fmt"
"github.com/beego/beego/v2/client/httplib"
"github.com/linmadan/egglib-go/utils/json"
"net/http"
"net/url"
"sort"
"time"
)
type (
BSNBlockChain struct {
PublicPem []byte
privatePem []byte
PublicKey string
Host string
}
UpToChainRequest struct {
// 上链数据的数据库、数据表等的标识值 (非必填)
InnerDBTable string `json:"innerDBTable,omitempty"`
// 上链数据的唯一标识主键值 (非必填)
InnerPrimaryKey string `json:"innerPrimaryKey,omitempty"`
// 上链记录的一个标记值(IssueId), 数据溯源出所有相关事件内容,例如快递单号,过滤出该快递的所有相关事件内容并用于展示 (非必填)
InnerPrimaryIssueId string `json:"innerPrimaryIssueId,omitempty"`
// 作用与key1相同 (非必填)
InnerSecondIssueId string `json:"innerSecondIssueId,omitempty"`
// 数据原文 (必填)
Value string `json:"value,omitempty"`
// 数据描述: 对value的描述,无论needHash为何值,本字段均会原文存储到链上
Desc string `json:"desc,omitempty"`
// 是否哈希: true: 需要哈希,会将value进行hash上链,false:不需要哈希,明文上链,链上所有用户都可看到明文,默认false
NeedHash bool `json:"needHash"`
}
UpToChainResponse string
GetTokenRequest struct {
// 操作类型:
//1-交易哈希溯源
//2-溯源ID溯源
//3-验真
Type int `json:"type"`
// type为1或者3时必填
TsTxId string `json:"tsTxId,omitempty"`
// type为2时必填
InnerPrimaryKey string `json:"innerPrimaryKey,omitempty"`
// type为3时必填
Value string `json:"value,omitempty"`
}
GetTokenResponse struct {
Token string `json:"token"`
}
Response struct {
Data rawjson.RawMessage `json:"data"`
Code int `json:"code"`
Message string `json:"message"`
}
)
// 上链
func (c *BSNBlockChain) UpToChain(options *UpToChainOptions) (*UpToChainResponse, error) {
req, err := c.MakeRequest(options, "/chainApi/upToChain", "upToChain", http.MethodPost)
if err != nil {
return nil, err
}
var upToChainResponse UpToChainResponse
_, err = c.HandlerResponse(req, &upToChainResponse)
return &upToChainResponse, err
}
// 浏览器溯源验真申请
func (c *BSNBlockChain) GetToken(options *GetTokenRequest) (*GetTokenResponse, error) {
req, err := c.MakeRequest(options, "/getToken", "getToken", http.MethodPost)
if err != nil {
return nil, err
}
var getTokenResponse = GetTokenResponse{}
_, err = c.HandlerResponse(req, &getTokenResponse)
return &getTokenResponse, err
}
// 签名
func (c *BSNBlockChain) Signature(body map[string]interface{}, method string) (string, error) {
var keys []string
for key, _ := range body {
keys = append(keys, key)
}
sort.Strings(keys)
encryptString := bytes.NewBuffer(nil)
for i := range keys {
key := keys[i]
if v, ok := body[key]; ok {
encryptString.WriteString(fmt.Sprintf("%s=%v&", key, v))
}
}
encryptString.WriteString(fmt.Sprintf("method=%v", method))
encryptData, err := RsaEncrypt(c.PublicPem, encryptString.Bytes())
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(encryptData), nil
}
func (c *BSNBlockChain) MakeRequest(obj interface{}, action string, signAction, httpMethod string) (*httplib.BeegoHTTPRequest, error) {
var mapBlockInfo = make(map[string]interface{})
json.UnmarshalFromString(json.MarshalToString(obj), &mapBlockInfo)
secret, err := c.Signature(mapBlockInfo, signAction)
if err != nil {
return nil, err
}
req := httplib.NewBeegoRequest(c.Host+action, httpMethod)
req.Header("pubKey", url.QueryEscape(string(c.PublicKey)))
req.Header("signature", url.QueryEscape(secret))
req.SetTimeout(time.Second*5, time.Second*5)
if httpMethod == http.MethodPost || httpMethod == http.MethodPut {
req.JSONBody(obj)
}
return req, nil
}
func (c *BSNBlockChain) HandlerResponse(req *httplib.BeegoHTTPRequest, value interface{}) (*Response, error) {
response := &Response{}
data, err := req.Bytes()
if err != nil {
return nil, err
}
rsp, err := req.Response()
if err != nil {
return nil, err
}
if rsp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("response code:%v status:%v", rsp.StatusCode, rsp.Status)
}
err = json.Unmarshal(data, response)
if err != nil {
return nil, err
}
json.Unmarshal(response.Data, value)
return response, nil
}
func (b *UpToChainRequest) Complete(options *UpToChainOptions) {
b.InnerDBTable = options.InnerDBTable
b.InnerPrimaryKey = options.InnerPrimaryKey
b.InnerPrimaryIssueId = options.InnerPrimaryIssueId
b.InnerSecondIssueId = options.InnerSecondIssueId
b.Value = options.Value
b.Desc = options.Desc
b.NeedHash = options.NeedHash
}