github.com/weplanx/server@v0.2.6-0.20240318110640-f7e75155779a/api/tencent/service.go (about) 1 package tencent 2 3 import ( 4 "context" 5 "crypto/hmac" 6 "crypto/sha1" 7 "encoding/base64" 8 "encoding/hex" 9 "fmt" 10 "github.com/bytedance/sonic" 11 "github.com/bytedance/sonic/decoder" 12 tcommon "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" 13 "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" 14 sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" 15 "github.com/tencentyun/cos-go-sdk-v5" 16 "github.com/weplanx/go/help" 17 "github.com/weplanx/server/common" 18 "net/http" 19 "net/url" 20 "sort" 21 "strings" 22 "time" 23 ) 24 25 type Service struct { 26 *common.Inject 27 } 28 29 func (x *Service) Cos() (_ *cos.Client) { 30 u, _ := url.Parse(fmt.Sprintf(`https://%s.cos.%s.myqcloud.com`, x.V.TencentCosBucket, x.V.TencentCosRegion)) 31 return cos.NewClient(&cos.BaseURL{BucketURL: u}, &http.Client{ 32 Transport: &cos.AuthorizationTransport{ 33 SecretID: x.V.TencentSecretId, 34 SecretKey: x.V.TencentSecretKey, 35 }, 36 }) 37 } 38 39 func (x *Service) CosPresigned() (_ M, err error) { 40 date := time.Now() 41 expired := date.Add(time.Duration(x.V.TencentCosExpired) * time.Second) 42 keyTime := fmt.Sprintf(`%d;%d`, date.Unix(), expired.Unix()) 43 name := help.Uuid() 44 key := fmt.Sprintf(`%s/%s/%s`, 45 x.V.Namespace, date.Format("20060102"), name) 46 policy := M{ 47 "expiration": expired.Format("2006-01-02T15:04:05.000Z"), 48 "conditions": []interface{}{ 49 M{"bucket": x.V.TencentCosBucket}, 50 []interface{}{"starts-with", "$key", key}, 51 M{"q-sign-algorithm": "sha1"}, 52 M{"q-ak": x.V.TencentSecretId}, 53 M{"q-sign-time": keyTime}, 54 }, 55 } 56 var policyText []byte 57 if policyText, err = sonic.Marshal(policy); err != nil { 58 return 59 } 60 signKeyHash := hmac.New(sha1.New, []byte(x.V.TencentSecretKey)) 61 signKeyHash.Write([]byte(keyTime)) 62 signKey := hex.EncodeToString(signKeyHash.Sum(nil)) 63 stringToSignHash := sha1.New() 64 stringToSignHash.Write(policyText) 65 stringToSign := hex.EncodeToString(stringToSignHash.Sum(nil)) 66 signatureHash := hmac.New(sha1.New, []byte(signKey)) 67 signatureHash.Write([]byte(stringToSign)) 68 signature := hex.EncodeToString(signatureHash.Sum(nil)) 69 return M{ 70 "key": key, 71 "policy": policyText, 72 "q-sign-algorithm": "sha1", 73 "q-ak": x.V.TencentSecretId, 74 "q-key-time": keyTime, 75 "q-signature": signature, 76 }, nil 77 } 78 79 func (x *Service) CosImageInfo(ctx context.Context, url string) (r M, err error) { 80 client := x.Cos() 81 var res *cos.Response 82 if res, err = client.CI.Get(ctx, url, "imageInfo", nil); err != nil { 83 return 84 } 85 if err = decoder.NewStreamDecoder(res.Body).Decode(&r); err != nil { 86 return 87 } 88 return 89 } 90 91 type TC3Option struct { 92 Service string 93 Headers map[string]string 94 Timestamp int64 95 Body interface{} 96 } 97 98 func (x *Service) TC3Authorization(option TC3Option) string { 99 algorithm := "TC3-HMAC-SHA256" 100 canonicalURI := "/" 101 canonicalQueryString := "" 102 103 var keys []string 104 for key := range option.Headers { 105 keys = append(keys, key) 106 } 107 sort.Strings(keys) 108 109 var canonicalHeaders string 110 var signedHeaders string 111 for _, key := range keys { 112 k, v := strings.ToLower(key), strings.ToLower(option.Headers[key]) 113 canonicalHeaders += fmt.Sprintf("%s:%s\n", k, v) 114 signedHeaders += ";" + k 115 } 116 117 signedHeaders = signedHeaders[1:] 118 119 payload, _ := sonic.MarshalString(option.Body) 120 hashedRequestPayload := common.Sha256hex(payload) 121 canonicalRequest := fmt.Sprintf("POST\n%s\n%s\n%s\n%s\n%s", 122 canonicalURI, 123 canonicalQueryString, 124 canonicalHeaders, 125 signedHeaders, 126 hashedRequestPayload, 127 ) 128 129 date := time.Unix(option.Timestamp, 0).UTC().Format("2006-01-02") 130 credentialScope := fmt.Sprintf("%s/%s/tc3_request", date, option.Service) 131 hashedCanonicalRequest := common.Sha256hex(canonicalRequest) 132 string2sign := fmt.Sprintf("%s\n%d\n%s\n%s", 133 algorithm, 134 option.Timestamp, 135 credentialScope, 136 hashedCanonicalRequest, 137 ) 138 139 secretDate := common.Hmacsha256(date, "TC3"+x.V.TencentSecretKey) 140 secretService := common.Hmacsha256(option.Service, secretDate) 141 secretSigning := common.Hmacsha256("tc3_request", secretService) 142 signature := hex.EncodeToString([]byte(common.Hmacsha256(string2sign, secretSigning))) 143 144 return fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s", 145 algorithm, 146 x.V.TencentSecretId, 147 credentialScope, 148 signedHeaders, 149 signature, 150 ) 151 } 152 153 type KeyAuthResult struct { 154 Date string 155 Txt string 156 } 157 158 func (x *Service) KeyAuth(source string, id string, key string) (r *KeyAuthResult, err error) { 159 r = new(KeyAuthResult) 160 location, _ := time.LoadLocation("Etc/UTC") 161 r.Date = time.Now().In(location).Format("Mon, 02 Jan 2006 15:04:05 GMT") 162 signStr := fmt.Sprintf("x-date: %s\nx-source: %s", r.Date, source) 163 164 mac := hmac.New(sha1.New, []byte(key)) 165 mac.Write([]byte(signStr)) 166 sign := base64.StdEncoding.EncodeToString(mac.Sum(nil)) 167 168 r.Txt = fmt.Sprintf("hmac id=\"%s\", algorithm=\"hmac-sha1\", headers=\"x-date x-source\", signature=\"%s\"", 169 id, sign) 170 return 171 } 172 173 type IpResult interface { 174 GetMsg() string 175 IsSuccess() bool 176 GetDetail() interface{} 177 } 178 179 type Ipv4Result struct { 180 Msg string `json:"msg"` 181 Success bool `json:"success"` 182 Code int `json:"code"` 183 Data struct { 184 OrderNo string `json:"orderNo"` 185 Result Ipv4Detail `json:"result"` 186 } `json:"data"` 187 } 188 189 func (x *Ipv4Result) GetMsg() string { 190 return x.Msg 191 } 192 193 func (x *Ipv4Result) IsSuccess() bool { 194 return x.Success 195 } 196 197 func (x *Ipv4Result) GetDetail() interface{} { 198 return x.Data.Result 199 } 200 201 type Ipv4Detail struct { 202 Continent string `bson:"continent" json:"continent"` 203 Country string `bson:"country" json:"country"` 204 Province string `bson:"prov" json:"prov"` 205 City string `bson:"city" json:"city"` 206 Owner string `bson:"owner" json:"owner"` 207 ISP string `bson:"isp" json:"isp"` 208 Areacode string `bson:"areacode" json:"areacode"` 209 Asnumber string `bson:"asnumber" json:"asnumber"` 210 Adcode string `bson:"adcode" json:"adcode"` 211 Zipcode string `bson:"zipcode" json:"zipcode"` 212 Timezone string `bson:"timezone" json:"timezone"` 213 Accuracy string `bson:"accuracy" json:"accuracy"` 214 Lat string `bson:"lat" json:"lat"` 215 Lng string `bson:"lng" json:"lng"` 216 Radius string `bson:"radius" json:"radius"` 217 Source string `bson:"source" json:"source"` 218 } 219 220 func (x *Service) GetIpv4(ctx context.Context, ip string) (_ IpResult, err error) { 221 source, kar := "market", new(KeyAuthResult) 222 if kar, err = x.KeyAuth(source, x.V.IpSecretId, x.V.IpSecretKey); err != nil { 223 return 224 } 225 var r *Ipv4Result 226 var msg string 227 if _, err = common.HttpClient(x.V.IpAddress).R(). 228 SetContext(ctx). 229 SetHeader("X-Source", source). 230 SetHeader("X-Date", kar.Date). 231 SetHeader("Authorization", kar.Txt). 232 SetQueryParam("ip", ip). 233 SetSuccessResult(&r). 234 SetErrorResult(&msg). 235 Get("/ip/city/query"); err != nil { 236 return nil, help.E("Tencent.GetIpv4Fail", err.Error()) 237 } 238 if msg != "" { 239 return nil, help.E("Tencent.GetIpv4Fail", msg) 240 } 241 return r, nil 242 } 243 244 type Ipv6Result struct { 245 Msg string `json:"msg"` 246 Success bool `json:"success"` 247 Code int `json:"code"` 248 Data struct { 249 OrderNo string `json:"orderNo"` 250 Result Ipv6Detail `json:"result"` 251 } `json:"data"` 252 } 253 254 func (x *Ipv6Result) GetMsg() string { 255 return x.Msg 256 } 257 258 func (x *Ipv6Result) IsSuccess() bool { 259 return x.Success 260 } 261 262 func (x *Ipv6Result) GetDetail() interface{} { 263 return x.Data.Result 264 } 265 266 type Ipv6Detail struct { 267 Continent string `bson:"continent" json:"continent"` 268 Country string `bson:"country" json:"country"` 269 Province string `bson:"prov" json:"province"` 270 City string `bson:"city" json:"city"` 271 Owner string `bson:"owner" json:"owner"` 272 ISP string `bson:"isp" json:"isp"` 273 Areacode string `bson:"areacode" json:"areacode"` 274 Asnumber string `bson:"asnumber" json:"asnumber"` 275 Adcode string `bson:"adcode" json:"adcode"` 276 Zipcode string `bson:"zipcode" json:"zipcode"` 277 Timezone string `bson:"timezone" json:"timezone"` 278 Accuracy string `bson:"accuracy" json:"accuracy"` 279 Lat string `bson:"lat" json:"lat"` 280 Lng string `bson:"lng" json:"lng"` 281 Radius string `bson:"radius" json:"radius"` 282 Source string `bson:"source" json:"source"` 283 } 284 285 func (x *Service) GetIpv6(ctx context.Context, ip string) (_ IpResult, err error) { 286 source, kar := "market", new(KeyAuthResult) 287 if kar, err = x.KeyAuth(source, x.V.Ipv6SecretId, x.V.Ipv6SecretKey); err != nil { 288 return 289 } 290 291 var r *Ipv6Result 292 var msg string 293 if _, err = common.HttpClient(x.V.Ipv6Address).R(). 294 SetContext(ctx). 295 SetHeader("X-Source", source). 296 SetHeader("X-Date", kar.Date). 297 SetHeader("Authorization", kar.Txt). 298 SetQueryParam("ip", ip). 299 SetSuccessResult(&r). 300 SetErrorResult(&msg). 301 Get("/ip/ipv6/query"); err != nil { 302 return nil, help.E("Tencent.GetIpv6Fail", err.Error()) 303 } 304 if msg != "" { 305 return nil, help.E("Tencent.GetIpv6Fail", msg) 306 } 307 308 return r, nil 309 } 310 311 func (x *Service) SmsSend(ctx context.Context, sign string, tid string, params []string, phone []string) (err error) { 312 credential := tcommon.NewCredential( 313 x.V.SmsSecretId, 314 x.V.SmsSecretKey, 315 ) 316 cpf := profile.NewClientProfile() 317 cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com" 318 client, _ := sms.NewClient(credential, x.V.SmsRegion, cpf) 319 request := sms.NewSendSmsRequest() 320 request.SmsSdkAppId = tcommon.StringPtr(x.V.SmsAppId) 321 request.SignName = tcommon.StringPtr(sign) 322 request.TemplateId = tcommon.StringPtr(tid) 323 request.TemplateParamSet = tcommon.StringPtrs(params) 324 request.PhoneNumberSet = tcommon.StringPtrs(phone) 325 request.SetContext(ctx) 326 if _, err = client.SendSms(request); err != nil { 327 return 328 } 329 return 330 }