bsn.go
5.2 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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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/http/httputil"
"sort"
"time"
)
type (
BSNBlockChain struct {
PublicPem []byte
PrivatePem []byte
PublicKey string
Host string
EnableDebugLog bool
}
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时必填
IssueId string `json:"issueId,omitempty"`
// type为3时必填
Value string `json:"value,omitempty"`
// 当type=1或者2必填,为false只显示密文,为true溯源才会显示原文
ShowValue bool `json:"showValue"`
}
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, "/chainApi/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 := RsaSign(c.PrivatePem, 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", c.PublicKey) //url.QueryEscape(string(c.PublicKey))
req.Header("signature", secret) //url.QueryEscape(secret)
req.SetTimeout(time.Second*5, time.Second*5)
if httpMethod == http.MethodPost || httpMethod == http.MethodPut {
req.JSONBody(obj)
}
if c.EnableDebugLog {
data, _ := httputil.DumpRequest(req.GetRequest(), true)
fmt.Println(string(data))
}
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
}
if c.EnableDebugLog {
fmt.Println("\nHttp Response-> \n", string(data))
}
if response.Code != 0 {
return nil, fmt.Errorf("upchain code:%v msg:%v", response.Code, response.Message)
}
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
}