28
"github.com/cubefs/cubefs/util/caps"
29
"github.com/cubefs/cubefs/util/cryptoutil"
30
"github.com/cubefs/cubefs/util/keystore"
47
ClientMessage = "Token"
48
OwnerVOLRsc = "OwnerVOL"
49
NoneOwnerVOLRsc = "NoneOwnerVOL"
56
ClientGetTicket = "/client/getticket"
59
AdminCreateKey = "/admin/createkey"
60
AdminDeleteKey = "/admin/deletekey"
61
AdminGetKey = "/admin/getkey"
62
AdminAddCaps = "/admin/addcaps"
63
AdminDeleteCaps = "/admin/deletecaps"
64
AdminGetCaps = "/admin/getcaps"
67
AdminAddRaftNode = "/admin/addraftnode"
68
AdminRemoveRaftNode = "/admin/removeraftnode"
71
OSAddCaps = "/os/addcaps"
72
OSDeleteCaps = "/os/deletecaps"
73
OSGetCaps = "/os/getcaps"
78
AuthServiceID = "AuthService"
81
MasterServiceID = "MasterService"
84
MetaServiceID = "MetanodeService"
87
DataServiceID = "DatanodeService"
90
ObjectServiceID = "ObjectService"
101
MsgAuthBase MsgType = 0x100000
104
MsgAuthTicketReq MsgType = MsgAuthBase + 0x10000
107
MsgAuthTicketResp MsgType = MsgAuthBase + 0x10001
110
MsgMasterTicketReq MsgType = MsgAuthBase + 0x20000
113
MsgMasterTicketResp MsgType = MsgAuthBase + 0x20001
116
MsgMetaTicketReq MsgType = MsgAuthBase + 0x30000
119
MsgMetaTicketResp MsgType = MsgAuthBase + 0x30001
122
MsgDataTicketReq MsgType = MsgAuthBase + 0x40000
125
MsgDataTicketResp MsgType = MsgAuthBase + 0x40001
128
MsgAuthCreateKeyReq MsgType = MsgAuthBase + 0x51000
131
MsgAuthCreateKeyResp MsgType = MsgAuthBase + 0x51001
134
MsgAuthDeleteKeyReq MsgType = MsgAuthBase + 0x52000
137
MsgAuthDeleteKeyResp MsgType = MsgAuthBase + 0x52001
140
MsgAuthGetKeyReq MsgType = MsgAuthBase + 0x53000
143
MsgAuthGetKeyResp MsgType = MsgAuthBase + 0x53001
146
MsgAuthAddCapsReq MsgType = MsgAuthBase + 0x54000
149
MsgAuthAddCapsResp MsgType = MsgAuthBase + 0x54001
152
MsgAuthDeleteCapsReq MsgType = MsgAuthBase + 0x55000
155
MsgAuthDeleteCapsResp MsgType = MsgAuthBase + 0x55001
158
MsgAuthGetCapsReq MsgType = MsgAuthBase + 0x56000
161
MsgAuthGetCapsResp MsgType = MsgAuthBase + 0x56001
164
MsgAuthAddRaftNodeReq MsgType = MsgAuthBase + 0x57000
167
MsgAuthAddRaftNodeResp MsgType = MsgAuthBase + 0x57001
170
MsgAuthRemoveRaftNodeReq MsgType = MsgAuthBase + 0x58000
173
MsgAuthRemoveRaftNodeResp MsgType = MsgAuthBase + 0x58001
176
MsgAuthOSAddCapsReq MsgType = MsgAuthBase + 0x61000
179
MsgAuthOSAddCapsResp MsgType = MsgAuthBase + 0x61001
182
MsgAuthOSDeleteCapsReq MsgType = MsgAuthBase + 0x62000
185
MsgAuthOSDeleteCapsResp MsgType = MsgAuthBase + 0x62001
188
MsgAuthOSGetCapsReq MsgType = MsgAuthBase + 0x63000
191
MsgAuthOSGetCapsResp MsgType = MsgAuthBase + 0x63001
194
MsgMasterAPIAccessReq MsgType = 0x60000
197
MsgMasterAPIAccessResp MsgType = 0x60001
200
MsgMasterFetchVolViewReq MsgType = MsgMasterAPIAccessReq + 0x10000
203
MsgMasterClusterFreezeReq MsgType = MsgMasterAPIAccessReq + 0x20100
204
MsgMasterAddRaftNodeReq MsgType = MsgMasterAPIAccessReq + 0x20200
205
MsgMasterRemoveRaftNodeReq MsgType = MsgMasterAPIAccessReq + 0x20300
206
MsgMasterSetNodeInfoReq MsgType = MsgMasterAPIAccessReq + 0x20400
207
MsgMasterSetNodeRdOnlyReq MsgType = MsgMasterAPIAccessReq + 0x20500
208
MsgMasterAutoDecommissionReq MsgType = MsgMasterAPIAccessReq + 0x20600
211
MsgMasterCreateVolReq MsgType = MsgMasterAPIAccessReq + 0x30100
212
MsgMasterDeleteVolReq MsgType = MsgMasterAPIAccessReq + 0x30200
213
MsgMasterUpdateVolReq MsgType = MsgMasterAPIAccessReq + 0x30300
214
MsgMasterVolShrinkReq MsgType = MsgMasterAPIAccessReq + 0x30400
215
MsgMasterVolExpandReq MsgType = MsgMasterAPIAccessReq + 0x30500
218
MsgMasterLoadMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40100
219
MsgMasterDecommissionMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40200
220
MsgMasterChangeMetaPartitionLeaderReq MsgType = MsgMasterAPIAccessReq + 0x40300
221
MsgMasterCreateMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40400
222
MsgMasterAddMetaReplicaReq MsgType = MsgMasterAPIAccessReq + 0x40500
223
MsgMasterDeleteMetaReplicaReq MsgType = MsgMasterAPIAccessReq + 0x40600
224
MsgMasterQosUpdateReq MsgType = MsgMasterAPIAccessReq + 0x40700
225
MsgMasterQosUpdateZoneLimitReq MsgType = MsgMasterAPIAccessReq + 0x40800
226
MsgMasterQosUpdateMasterLimitReq MsgType = MsgMasterAPIAccessReq + 0x40900
227
MsgMasterQosUpdateClientParamReq MsgType = MsgMasterAPIAccessReq + 0x40a00
230
MsgMasterCreateDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50100
231
MsgMasterDataPartitionChangeLeaderReq MsgType = MsgMasterAPIAccessReq + 0x50200
232
MsgMasterLoadDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50300
233
MsgMasterDecommissionDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50400
234
MsgMasterAddDataReplicaReq MsgType = MsgMasterAPIAccessReq + 0x50500
235
MsgMasterDeleteDataReplicaReq MsgType = MsgMasterAPIAccessReq + 0x50600
236
MsgMasterSetDpRdOnlyReq MsgType = MsgMasterAPIAccessReq + 0x50700
237
MsgMasterReportLackDataPartitions MsgType = MsgMasterAPIAccessReq + 0x50800
240
MsgMasterAddMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60100
241
MsgMasterDecommissionMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60200
242
MsgMasterMigrateMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60300
243
MsgMasterSetMetaNodeThresholdReq MsgType = MsgMasterAPIAccessReq + 0x60400
244
MsgMasterUpdateMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60500
247
MsgMasterAddDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70100
248
MsgMasterDecommissionDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70200
249
MsgMasterMigrateDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70300
250
MsgMasterCancelDecommissionDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70400
251
MsgMasterDecommissionDiskReq MsgType = MsgMasterAPIAccessReq + 0x70500
252
MsgMasterUpdateNodeSetCapcityReq MsgType = MsgMasterAPIAccessReq + 0x70600
253
MsgMasterUpdateNodeSetIdReq MsgType = MsgMasterAPIAccessReq + 0x70700
254
MsgMasterUpdateDomainDataUseRatioReq MsgType = MsgMasterAPIAccessReq + 0x70800
255
MsgMasterUpdateZoneExcludeRatioReq MsgType = MsgMasterAPIAccessReq + 0x70900
256
MsgMasterRecommissionDiskReq MsgType = MsgMasterAPIAccessReq + 0x70a00
259
MsgMasterUserCreateReq MsgType = MsgMasterAPIAccessReq + 0x80100
260
MsgMasterUserDeleteReq MsgType = MsgMasterAPIAccessReq + 0x80200
261
MsgMasterUserUpdateReq MsgType = MsgMasterAPIAccessReq + 0x80300
262
MsgMasterUserUpdatePolicyReq MsgType = MsgMasterAPIAccessReq + 0x80400
263
MsgMasterUserRemovePolicyReq MsgType = MsgMasterAPIAccessReq + 0x80500
264
MsgMasterUserDeleteVolPolicyReq MsgType = MsgMasterAPIAccessReq + 0x80600
265
MsgMasterUserTransferVolReq MsgType = MsgMasterAPIAccessReq + 0x80700
268
MsgMasterUpdateZoneReq MsgType = MsgMasterAPIAccessReq + 0x90100
272
type HTTPAuthReply = HTTPReply
275
var MsgType2ResourceMap = map[MsgType]string{
276
MsgAuthCreateKeyReq: "auth:createkey",
277
MsgAuthDeleteKeyReq: "auth:deletekey",
278
MsgAuthGetKeyReq: "auth:getkey",
279
MsgAuthAddCapsReq: "auth:addcaps",
280
MsgAuthDeleteCapsReq: "auth:deletecaps",
281
MsgAuthGetCapsReq: "auth:getcaps",
282
MsgAuthAddRaftNodeReq: "auth:addnode",
283
MsgAuthRemoveRaftNodeReq: "auth:removenode",
284
MsgAuthOSAddCapsReq: "auth:osaddcaps",
285
MsgAuthOSDeleteCapsReq: "auth:osdeletecaps",
286
MsgAuthOSGetCapsReq: "auth:osgetcaps",
288
MsgMasterFetchVolViewReq: "master:getvol",
291
MsgMasterClusterFreezeReq: "master:clusterfreeze",
292
MsgMasterAddRaftNodeReq: "master:addraftnode",
293
MsgMasterRemoveRaftNodeReq: "master:removeraftnode",
294
MsgMasterSetNodeInfoReq: "master:setnodeinfo",
295
MsgMasterSetNodeRdOnlyReq: "master:sernoderdonly",
296
MsgMasterAutoDecommissionReq: "master:autodecommission",
299
MsgMasterCreateVolReq: "master:createvol",
300
MsgMasterDeleteVolReq: "master:deletevol",
301
MsgMasterUpdateVolReq: "master:updatevol",
302
MsgMasterVolShrinkReq: "master:volshrink",
303
MsgMasterVolExpandReq: "master:volexpand",
306
MsgMasterLoadMetaPartitionReq: "master:loadmetapartition",
307
MsgMasterDecommissionMetaPartitionReq: "master:decommissionmetapartition",
308
MsgMasterChangeMetaPartitionLeaderReq: "master:changemetapartitionleader",
309
MsgMasterCreateMetaPartitionReq: "master:createmetapartition",
310
MsgMasterAddMetaReplicaReq: "master:addmetareplica",
311
MsgMasterDeleteMetaReplicaReq: "master:deletemetareplica",
312
MsgMasterQosUpdateReq: "master:qosupdate",
313
MsgMasterQosUpdateZoneLimitReq: "master:qosupdatezonelimit",
314
MsgMasterQosUpdateMasterLimitReq: "master:qosupdatemasterlimit",
315
MsgMasterQosUpdateClientParamReq: "master:qosupdateclientparam",
318
MsgMasterCreateDataPartitionReq: "master:createdatapartition",
319
MsgMasterDataPartitionChangeLeaderReq: "master:changedatapartitionleader",
320
MsgMasterLoadDataPartitionReq: "master:loaddatapartition",
321
MsgMasterDecommissionDataPartitionReq: "master:decommissiondatapartition",
322
MsgMasterAddDataReplicaReq: "master:adddatareplica",
323
MsgMasterDeleteDataReplicaReq: "master:removedatareplica",
324
MsgMasterSetDpRdOnlyReq: "master:setdprdonly",
325
MsgMasterReportLackDataPartitions: "master:reportLackDataPartitions",
328
MsgMasterAddMetaNodeReq: "master:addmetanode",
329
MsgMasterDecommissionMetaNodeReq: "master:decommissionmetanode",
330
MsgMasterMigrateMetaNodeReq: "master:migratemetanode",
331
MsgMasterSetMetaNodeThresholdReq: "master:setmetanodethreshold",
332
MsgMasterUpdateMetaNodeReq: "master:updatemetanode",
335
MsgMasterAddDataNodeReq: "master:adddatannode",
336
MsgMasterDecommissionDataNodeReq: "master:decommissiondatannode",
337
MsgMasterMigrateDataNodeReq: "master:migratedatannode",
338
MsgMasterCancelDecommissionDataNodeReq: "master:canceldecommissiondatannode",
339
MsgMasterDecommissionDiskReq: "master:decommissiondisk",
340
MsgMasterUpdateNodeSetCapcityReq: "master:updatenodesetcapcity",
341
MsgMasterUpdateNodeSetIdReq: "master:updatenodesetid",
342
MsgMasterUpdateDomainDataUseRatioReq: "master:updatedomaindatauseratio",
343
MsgMasterUpdateZoneExcludeRatioReq: "master:updatezoneexcluderatio",
344
MsgMasterRecommissionDiskReq: "master:recommissiondisk",
347
MsgMasterUserCreateReq: "master:usercreate",
348
MsgMasterUserDeleteReq: "master:userdelete",
349
MsgMasterUserUpdateReq: "master:userupdate",
350
MsgMasterUserUpdatePolicyReq: "master:userupdatepolicy",
351
MsgMasterUserRemovePolicyReq: "master:userremotepolicy",
352
MsgMasterUserDeleteVolPolicyReq: "master:userdeletevolpolicy",
353
MsgMasterUserTransferVolReq: "master:usertransfervol",
356
MsgMasterUpdateZoneReq: "master:updatezone",
362
type AuthGetTicketReq struct {
363
Type MsgType `json:"type"`
364
ClientID string `json:"client_id"`
365
ServiceID string `json:"service_id"`
366
Verifier string `json:"verifier"`
370
type AuthGetTicketResp struct {
371
Type MsgType `json:"type"`
372
ClientID string `json:"client_id"`
373
ServiceID string `json:"service_id"`
374
Verifier int64 `json:"verifier"`
375
Ticket string `json:"ticket"`
376
SessionKey cryptoutil.CryptoKey `json:"session_key"`
382
type APIAccessReq struct {
383
Type MsgType `json:"type"`
384
ClientID string `json:"client_id"`
385
ServiceID string `json:"service_id"`
386
Verifier string `json:"verifier"`
387
Ticket string `json:"ticket"`
393
type APIAccessResp struct {
394
Type MsgType `json:"type"`
395
ClientID string `json:"client_id"`
396
ServiceID string `json:"service_id"`
397
Verifier int64 `json:"verifier"`
401
type AuthAPIAccessReq struct {
402
APIReq APIAccessReq `json:"api_req"`
403
KeyInfo keystore.KeyInfo `json:"key_info"`
407
type AuthAPIAccessResp struct {
408
APIResp APIAccessResp `json:"api_resp"`
409
KeyInfo keystore.KeyInfo `json:"key_info"`
410
AuthIDKey string `json:"auth_id_key"`
414
type AuthRaftNodeInfo struct {
415
ID uint64 `json:"id"`
416
Addr string `json:"addr"`
420
type AuthRaftNodeReq struct {
421
APIReq APIAccessReq `json:"api_req"`
422
RaftNodeInfo AuthRaftNodeInfo `json:"node_info"`
426
type AuthRaftNodeResp struct {
427
APIResp APIAccessResp `json:"api_resp"`
428
Msg string `json:"msg"`
432
type AuthOSAccessKeyReq struct {
433
APIReq APIAccessReq `json:"api_req"`
434
AKCaps keystore.AccessKeyCaps `json:"access_key_caps"`
438
type AuthOSAccessKeyResp struct {
439
APIResp APIAccessResp `json:"api_resp"`
440
AKCaps keystore.AccessKeyCaps `json:"access_key_caps"`
444
func IsValidServiceID(serviceID string) (err error) {
445
if serviceID != AuthServiceID && serviceID != MasterServiceID && serviceID != MetaServiceID && serviceID != DataServiceID {
446
err = fmt.Errorf("invalid service ID [%s]", serviceID)
453
func IsValidMsgReqType(serviceID string, msgType MsgType) (err error) {
458
case "MasterService":
459
if msgType|MsgAuthBase != 0 {
466
err = fmt.Errorf("invalid request type [%x] and serviceID[%s]", msgType, serviceID)
473
func IsValidClientID(id string) (err error) {
474
re := regexp.MustCompile("^[A-Za-z]{1,1}[A-Za-z0-9_]{0,20}$")
475
if !re.MatchString(id) {
476
err = fmt.Errorf("clientID invalid format [%s]", id)
483
func ParseAuthReply(body []byte) (jobj HTTPAuthReply, err error) {
484
if err = json.Unmarshal(body, &jobj); err != nil {
488
err = fmt.Errorf(jobj.Msg)
495
func GetDataFromResp(body []byte, key []byte) (plaintext []byte, err error) {
496
jobj, err := ParseAuthReply(body)
500
data := fmt.Sprint(jobj.Data)
502
if plaintext, err = cryptoutil.DecodeMessage(data, key); err != nil {
510
func ParseAuthGetTicketResp(body []byte, key []byte) (resp AuthGetTicketResp, err error) {
513
if plaintext, err = GetDataFromResp(body, key); err != nil {
517
if err = json.Unmarshal(plaintext, &resp); err != nil {
525
func ParseAuthAPIAccessResp(body []byte, key []byte) (resp AuthAPIAccessResp, err error) {
528
if plaintext, err = GetDataFromResp(body, key); err != nil {
532
if err = json.Unmarshal(plaintext, &resp); err != nil {
540
func ParseAuthRaftNodeResp(body []byte, key []byte) (resp AuthRaftNodeResp, err error) {
543
if plaintext, err = GetDataFromResp(body, key); err != nil {
547
if err = json.Unmarshal(plaintext, &resp); err != nil {
554
func ParseAuthOSAKResp(body []byte, key []byte) (resp AuthOSAccessKeyResp, err error) {
557
if plaintext, err = GetDataFromResp(body, key); err != nil {
561
if err = json.Unmarshal(plaintext, &resp); err != nil {
568
func ExtractTicket(str string, key []byte) (ticket cryptoutil.Ticket, err error) {
571
if plaintext, err = cryptoutil.DecodeMessage(str, key); err != nil {
575
if err = json.Unmarshal(plaintext, &ticket); err != nil {
582
func checkTicketCaps(ticket *cryptoutil.Ticket, kind string, cap string) (err error) {
584
if err = c.Init(ticket.Caps); err != nil {
587
if b := c.ContainCaps(kind, cap); !b {
588
err = fmt.Errorf("no permission to access %v", kind)
595
func ParseVerifier(verifier string, key []byte) (ts int64, err error) {
596
var plainttext []byte
598
if plainttext, err = cryptoutil.DecodeMessage(verifier, key); err != nil {
602
ts = int64(binary.LittleEndian.Uint64(plainttext))
604
if time.Now().Unix()-ts >= reqLiveLength {
605
err = fmt.Errorf("req verifier is timeout [%d] >= [%d]", time.Now().Unix()-ts, reqLiveLength)
613
func VerifyAPIAccessReqIDs(req *APIAccessReq) (err error) {
614
if err = IsValidClientID(req.ClientID); err != nil {
615
err = fmt.Errorf("IsValidClientID failed: %s", err.Error())
619
if err = IsValidServiceID(req.ServiceID); err != nil {
620
err = fmt.Errorf("IsValidServiceID failed: %s", err.Error())
624
if err = IsValidMsgReqType(req.ServiceID, req.Type); err != nil {
625
err = fmt.Errorf("IsValidMsgReqType failed: %s", err.Error())
632
func ExtractAPIAccessTicket(req *APIAccessReq, key []byte) (ticket cryptoutil.Ticket, ts int64, err error) {
633
if ticket, err = ExtractTicket(req.Ticket, key); err != nil {
634
err = fmt.Errorf("extractTicket failed: %s", err.Error())
638
if time.Now().Unix() >= ticket.Exp {
639
err = ErrExpiredTicket
643
if ts, err = ParseVerifier(req.Verifier, ticket.SessionKey.Key); err != nil {
644
err = fmt.Errorf("parseVerifier failed: %s", err.Error())
652
func CheckAPIAccessCaps(ticket *cryptoutil.Ticket, rscType string, mp MsgType, action string) (err error) {
653
if _, ok := MsgType2ResourceMap[mp]; !ok {
654
err = fmt.Errorf("MsgType2ResourceMap key not found [%d]", mp)
658
rule := MsgType2ResourceMap[mp] + capSeparator + action
660
if err = checkTicketCaps(ticket, rscType, rule); err != nil {
661
err = fmt.Errorf("checkTicketCaps failed: %s", err.Error())
667
func GenAuthIDKey(id string, authKey []byte) (authIDKey string, err error) {
668
type AuthIDKey struct {
669
ID string `json:"id"`
670
AuthKey []byte `json:"auth_key"`
672
tmpAuthIDKey := AuthIDKey{
676
var jAuthIDKey []byte
677
if jAuthIDKey, err = json.Marshal(tmpAuthIDKey); err != nil {
678
err = fmt.Errorf("json marshal authIDKey failed %s", err.Error())
681
authIDKey = cryptoutil.Base64Encode(jAuthIDKey)
685
func ExtractIDAndAuthKey(authIDKey string) (id string, authKey []byte, err error) {
686
type AuthIDKey struct {
687
ID string `json:"id"`
688
AuthKey string `json:"auth_key"`
690
var jAuthIDKey []byte
691
jAuthIDKey, err = cryptoutil.Base64Decode(authIDKey)
693
err = fmt.Errorf("decode authIDKey failed %s", err.Error())
696
tmpAuthIDKey := &AuthIDKey{}
697
if err = json.Unmarshal(jAuthIDKey, &tmpAuthIDKey); err != nil {
698
err = fmt.Errorf("json unmarshal authIDKey failed %s", err.Error())
702
authKey = []byte(tmpAuthIDKey.AuthKey)
706
func CheckVOLAccessCaps(ticket *cryptoutil.Ticket, volName string, action string, accessNode string) (err error) {
707
rule := accessNode + capSeparator + volName + capSeparator + action
709
if err = checkTicketCaps(ticket, OwnerVOLRsc, rule); err != nil {
710
if err = checkTicketCaps(ticket, NoneOwnerVOLRsc, rule); err != nil {
711
err = fmt.Errorf("checkTicketCaps failed: %s", err.Error())
720
func VerifyAPIRespComm(apiResp *APIAccessResp, msg MsgType, clientID string, serviceID string, ts int64) (err error) {
721
if ts+1 != apiResp.Verifier {
722
err = fmt.Errorf("verifier verification failed")
726
if apiResp.Type != msg+1 {
727
err = fmt.Errorf("msg verification failed")
731
if apiResp.ClientID != clientID {
732
err = fmt.Errorf("id verification failed")
736
if apiResp.ServiceID != serviceID {
737
err = fmt.Errorf("service id verification failed")
744
func VerifyTicketRespComm(ticketResp *AuthGetTicketResp, msg MsgType, clientID string, serviceID string, ts int64) (err error) {
745
if ts+1 != ticketResp.Verifier {
746
err = fmt.Errorf("verifier verification failed")
750
if ticketResp.Type != msg+1 {
751
err = fmt.Errorf("msg verification failed")
755
if ticketResp.ClientID != clientID {
756
err = fmt.Errorf("id verification failed")
760
if ticketResp.ServiceID != serviceID {
761
err = fmt.Errorf("service id verification failed")
768
func SendBytes(client *http.Client, target string, data []byte) (res []byte, err error) {
769
message := base64.StdEncoding.EncodeToString(data)
770
resp, err := client.PostForm(target, url.Values{ClientMessage: {message}})
772
err = fmt.Errorf("action[SendData] failed:" + err.Error())
775
defer resp.Body.Close()
776
body, err := io.ReadAll(resp.Body)
778
err = fmt.Errorf("action[doRealSend] failed:" + err.Error())
786
func SendData(client *http.Client, target string, data interface{}) (res []byte, err error) {
787
messageJSON, err := json.Marshal(data)
789
err = fmt.Errorf("action[doRealSend] failed:" + err.Error())
792
if res, err = SendBytes(client, target, messageJSON); err != nil {