mirror of
https://github.com/jeessy2/ddns-go.git
synced 2025-10-20 15:33:46 +08:00
feat: support huaweicloud
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__debug_bin
|
||||
.DS_Store
|
217
dns/huawei.go
Normal file
217
dns/huawei.go
Normal file
@ -0,0 +1,217 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"ddns-go/config"
|
||||
"ddns-go/util"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
huaweicloudEndpoint string = "https://dns.myhuaweicloud.com"
|
||||
)
|
||||
|
||||
// Huaweicloud Huaweicloud
|
||||
type Huaweicloud struct {
|
||||
DNSConfig config.DNSConfig
|
||||
Domains
|
||||
}
|
||||
|
||||
// HuaweicloudZonesResp zones response
|
||||
type HuaweicloudZonesResp struct {
|
||||
Zones []struct {
|
||||
ID string
|
||||
Name string
|
||||
Recordsets []HuaweicloudRecordsets
|
||||
}
|
||||
}
|
||||
|
||||
// HuaweicloudRecordsResp 记录返回结果
|
||||
type HuaweicloudRecordsResp struct {
|
||||
Recordsets []HuaweicloudRecordsets
|
||||
}
|
||||
|
||||
// HuaweicloudRecordsets 记录
|
||||
type HuaweicloudRecordsets struct {
|
||||
ID string
|
||||
Name string `json:"name"`
|
||||
ZoneID string `json:"zone_id"`
|
||||
Status string
|
||||
Type string `json:"type"`
|
||||
Records []string `json:"records"`
|
||||
}
|
||||
|
||||
// Init 初始化
|
||||
func (hw *Huaweicloud) Init(conf *config.Config) {
|
||||
hw.DNSConfig = conf.DNS
|
||||
hw.Domains.ParseDomain(conf)
|
||||
}
|
||||
|
||||
// AddUpdateIpv4DomainRecords 添加或更新IPV4记录
|
||||
func (hw *Huaweicloud) AddUpdateIpv4DomainRecords() {
|
||||
hw.addUpdateDomainRecords("A")
|
||||
}
|
||||
|
||||
// AddUpdateIpv6DomainRecords 添加或更新IPV6记录
|
||||
func (hw *Huaweicloud) AddUpdateIpv6DomainRecords() {
|
||||
hw.addUpdateDomainRecords("AAAA")
|
||||
}
|
||||
|
||||
func (hw *Huaweicloud) addUpdateDomainRecords(recordType string) {
|
||||
ipAddr := hw.Ipv4Addr
|
||||
domains := hw.Ipv4Domains
|
||||
if recordType == "AAAA" {
|
||||
ipAddr = hw.Ipv6Addr
|
||||
domains = hw.Ipv6Domains
|
||||
}
|
||||
|
||||
if ipAddr == "" {
|
||||
return
|
||||
}
|
||||
|
||||
for _, domain := range domains {
|
||||
|
||||
var records HuaweicloudRecordsResp
|
||||
|
||||
err := hw.request(
|
||||
"GET",
|
||||
fmt.Sprintf(huaweicloudEndpoint+"/v2/recordsets?type=%s&name=%s", recordType, domain),
|
||||
nil,
|
||||
&records,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
find := false
|
||||
for _, record := range records.Recordsets {
|
||||
// 名称相同才更新。华为云默认是模糊搜索
|
||||
if record.Name == domain.String()+"." {
|
||||
// 更新
|
||||
hw.modify(record, domain, recordType, ipAddr)
|
||||
find = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !find {
|
||||
// 新增
|
||||
hw.create(domain, recordType, ipAddr)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 创建
|
||||
func (hw *Huaweicloud) create(domain *Domain, recordType string, ipAddr string) {
|
||||
zone, err := hw.getZones(domain)
|
||||
if err != nil || len(zone.Zones) == 0 {
|
||||
log.Println("未能找到公网域名, 请检查域名是否添加")
|
||||
return
|
||||
}
|
||||
|
||||
zoneID := zone.Zones[0].ID
|
||||
for _, z := range zone.Zones {
|
||||
if z.Name == domain.DomainName+"." {
|
||||
zoneID = z.ID
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
record := &HuaweicloudRecordsets{
|
||||
Type: recordType,
|
||||
Name: domain.String() + ".",
|
||||
Records: []string{ipAddr},
|
||||
}
|
||||
var result HuaweicloudRecordsets
|
||||
err = hw.request(
|
||||
"POST",
|
||||
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets", zoneID),
|
||||
record,
|
||||
&result,
|
||||
)
|
||||
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
|
||||
log.Printf("新增域名解析 %s 成功!IP: %s", domain, ipAddr)
|
||||
} else {
|
||||
log.Printf("新增域名解析 %s 失败!Status: %s", domain, result.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// 修改
|
||||
func (hw *Huaweicloud) modify(record HuaweicloudRecordsets, domain *Domain, recordType string, ipAddr string) {
|
||||
|
||||
// 相同不修改
|
||||
if len(record.Records) > 0 && record.Records[0] == ipAddr {
|
||||
log.Printf("你的IP %s 没有变化, 域名 %s", ipAddr, domain)
|
||||
return
|
||||
}
|
||||
|
||||
var request map[string]interface{} = make(map[string]interface{})
|
||||
request["records"] = []string{ipAddr}
|
||||
|
||||
var result HuaweicloudRecordsets
|
||||
|
||||
err := hw.request(
|
||||
"PUT",
|
||||
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones/%s/recordsets/%s", record.ZoneID, record.ID),
|
||||
&request,
|
||||
&result,
|
||||
)
|
||||
|
||||
if err == nil && (len(result.Records) > 0 && result.Records[0] == ipAddr) {
|
||||
log.Printf("更新域名解析 %s 成功!IP: %s, 状态: %s", domain, ipAddr, result.Status)
|
||||
} else {
|
||||
log.Printf("更新域名解析 %s 失败!Status: %s", domain, result.Status)
|
||||
}
|
||||
}
|
||||
|
||||
// 获得域名记录列表
|
||||
func (hw *Huaweicloud) getZones(domain *Domain) (result HuaweicloudZonesResp, err error) {
|
||||
err = hw.request(
|
||||
"GET",
|
||||
fmt.Sprintf(huaweicloudEndpoint+"/v2/zones?name=%s", domain.DomainName),
|
||||
nil,
|
||||
&result,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// request 统一请求接口
|
||||
func (hw *Huaweicloud) request(method string, url string, data interface{}, result interface{}) (err error) {
|
||||
jsonStr := make([]byte, 0)
|
||||
if data != nil {
|
||||
jsonStr, _ = json.Marshal(data)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(
|
||||
method,
|
||||
url,
|
||||
bytes.NewBuffer(jsonStr),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Println("http.NewRequest失败. Error: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
s := util.Signer{
|
||||
Key: hw.DNSConfig.ID,
|
||||
Secret: hw.DNSConfig.Secret,
|
||||
}
|
||||
s.Sign(req)
|
||||
|
||||
req.Header.Add("content-type", "application/json")
|
||||
|
||||
clt := http.Client{}
|
||||
clt.Timeout = 1 * time.Minute
|
||||
resp, err := clt.Do(req)
|
||||
err = util.GetHTTPResponse(resp, url, err, result)
|
||||
|
||||
return
|
||||
}
|
@ -78,6 +78,8 @@ func RunOnce() {
|
||||
dnsSelected = &Dnspod{}
|
||||
case "cloudflare":
|
||||
dnsSelected = &Cloudflare{}
|
||||
case "huaweicloud":
|
||||
dnsSelected = &Huaweicloud{}
|
||||
default:
|
||||
dnsSelected = &Alidns{}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ func bootstrapMinCss() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "bootstrap.min.css", size: 160403, mode: os.FileMode(420), modTime: time.Unix(1598592638, 0)}
|
||||
info := bindataFileInfo{name: "bootstrap.min.css", size: 160403, mode: os.FileMode(420), modTime: time.Unix(1599874470, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -203,7 +203,7 @@ func commonCss() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "common.css", size: 1053, mode: os.FileMode(420), modTime: time.Unix(1599713357, 0)}
|
||||
info := bindataFileInfo{name: "common.css", size: 1053, mode: os.FileMode(420), modTime: time.Unix(1599874470, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -223,7 +223,7 @@ func faviconIco() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "favicon.ico", size: 4286, mode: os.FileMode(420), modTime: time.Unix(1598592638, 0)}
|
||||
info := bindataFileInfo{name: "favicon.ico", size: 4286, mode: os.FileMode(420), modTime: time.Unix(1599874470, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
@ -243,7 +243,7 @@ func jquery351MinJs() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "jquery-3.5.1.min.js", size: 89476, mode: os.FileMode(420), modTime: time.Unix(1599812064, 0)}
|
||||
info := bindataFileInfo{name: "jquery-3.5.1.min.js", size: 89476, mode: os.FileMode(420), modTime: time.Unix(1599874470, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
@ -64,6 +64,12 @@
|
||||
Cloudflare
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline col-form-label">
|
||||
<input class="form-check-input" type="radio" name="DnsName" id="huaweicloud" value="huaweicloud" onclick="huaweicloudCheckedFun()" {{if eq $.DNS.Name "huaweicloud"}}checked{{end}}>
|
||||
<label class="form-check-label" for="huaweicloud">
|
||||
华为云
|
||||
</label>
|
||||
</div>
|
||||
<small id="dns_help" class="form-text text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
@ -224,7 +230,7 @@
|
||||
|
||||
document.getElementById("dnsIdLabel").innerHTML = "AccessKey ID"
|
||||
document.getElementById("dnsSecretLabel").innerHTML = "AccessKey Secret"
|
||||
document.getElementById("dns_help").innerHTML = "https://ram.console.aliyun.com/manage/ak"
|
||||
document.getElementById("dns_help").innerHTML = "<a target='_blank' href='https://ram.console.aliyun.com/manage/ak?spm=5176.12818093.nav-right.dak.488716d0mHaMgg'>创建 AccessKey</a>"
|
||||
}
|
||||
|
||||
function dnspodCheckedFun() {
|
||||
@ -234,7 +240,7 @@
|
||||
|
||||
document.getElementById("dnsIdLabel").innerHTML = "ID"
|
||||
document.getElementById("dnsSecretLabel").innerHTML = "Token"
|
||||
document.getElementById("dns_help").innerHTML = "https://console.dnspod.cn/account/token"
|
||||
document.getElementById("dns_help").innerHTML = "<a target='_blank' href='https://console.dnspod.cn/account/token'>创建密钥</a>"
|
||||
}
|
||||
|
||||
function cloudflareCheckedFun() {
|
||||
@ -243,7 +249,17 @@
|
||||
document.getElementById("DnsID").disabled= true
|
||||
document.getElementById("DnsID").value= ""
|
||||
document.getElementById("dnsSecretLabel").innerHTML = "Token"
|
||||
document.getElementById("dns_help").innerHTML = "https://dash.cloudflare.com/profile/api-tokens"
|
||||
document.getElementById("dns_help").innerHTML = "<a target='_blank' href='https://dash.cloudflare.com/profile/api-tokens'>创建令牌->编辑区域 DNS(使用模板)</a>"
|
||||
}
|
||||
|
||||
function huaweicloudCheckedFun() {
|
||||
document.getElementById("DnsID").disabled= false
|
||||
if (beforeDnsID)
|
||||
document.getElementById("DnsID").value= beforeDnsID
|
||||
|
||||
document.getElementById("dnsIdLabel").innerHTML = "Access Key Id"
|
||||
document.getElementById("dnsSecretLabel").innerHTML = "Secret Access Key"
|
||||
document.getElementById("dns_help").innerHTML = "<a target='_blank' href='https://console.huaweicloud.com/iam/?locale=zh-cn#/mine/accessKey'>新增访问密钥</a>"
|
||||
}
|
||||
|
||||
var dnsName = '{{$.DNS.Name}}'
|
||||
@ -261,6 +277,10 @@
|
||||
cloudflareCheckedFun()
|
||||
break;
|
||||
}
|
||||
case "huaweicloud": {
|
||||
huaweicloudCheckedFun()
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
alidnsCheckedFun()
|
||||
break;
|
||||
|
42
util/escape.go
Normal file
42
util/escape.go
Normal file
@ -0,0 +1,42 @@
|
||||
// based on https://github.com/golang/go/blob/master/src/net/url/url.go
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
func shouldEscape(c byte) bool {
|
||||
if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c == '-' || c == '~' || c == '.' {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func escape(s string) string {
|
||||
hexCount := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if shouldEscape(c) {
|
||||
hexCount++
|
||||
}
|
||||
}
|
||||
|
||||
if hexCount == 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
t := make([]byte, len(s)+2*hexCount)
|
||||
j := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch c := s[i]; {
|
||||
case shouldEscape(c):
|
||||
t[j] = '%'
|
||||
t[j+1] = "0123456789ABCDEF"[c>>4]
|
||||
t[j+2] = "0123456789ABCDEF"[c&15]
|
||||
j += 3
|
||||
default:
|
||||
t[j] = s[i]
|
||||
j++
|
||||
}
|
||||
}
|
||||
return string(t)
|
||||
}
|
@ -20,11 +20,12 @@ func GetHTTPResponse(resp *http.Response, url string, err error, result interfac
|
||||
log.Printf("请求接口%s失败! ERROR: %s\n", url, err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode != 200 && resp.StatusCode != 202 {
|
||||
log.Printf("请求接口%s失败! %s\n", url, string(body))
|
||||
err = fmt.Errorf("请求接口%s失败! %s", url, string(body))
|
||||
}
|
||||
|
||||
// log.Println(string(body))
|
||||
err = json.Unmarshal(body, &result)
|
||||
|
||||
if err != nil {
|
||||
|
208
util/signer.go
Normal file
208
util/signer.go
Normal file
@ -0,0 +1,208 @@
|
||||
// HWS API Gateway Signature
|
||||
// based on https://github.com/datastream/aws/blob/master/signv4.go
|
||||
// Copyright (c) 2014, Xianjie
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
BasicDateFormat = "20060102T150405Z"
|
||||
Algorithm = "SDK-HMAC-SHA256"
|
||||
HeaderXDate = "X-Sdk-Date"
|
||||
HeaderHost = "host"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderContentSha256 = "X-Sdk-Content-Sha256"
|
||||
)
|
||||
|
||||
func hmacsha256(key []byte, data string) ([]byte, error) {
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
if _, err := h.Write([]byte(data)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h.Sum(nil), nil
|
||||
}
|
||||
|
||||
// Build a CanonicalRequest from a regular request string
|
||||
//
|
||||
// CanonicalRequest =
|
||||
// HTTPRequestMethod + '\n' +
|
||||
// CanonicalURI + '\n' +
|
||||
// CanonicalQueryString + '\n' +
|
||||
// CanonicalHeaders + '\n' +
|
||||
// SignedHeaders + '\n' +
|
||||
// HexEncode(Hash(RequestPayload))
|
||||
func CanonicalRequest(r *http.Request, signedHeaders []string) (string, error) {
|
||||
var hexencode string
|
||||
var err error
|
||||
if hex := r.Header.Get(HeaderContentSha256); hex != "" {
|
||||
hexencode = hex
|
||||
} else {
|
||||
data, err := RequestPayload(r)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
hexencode, err = HexEncodeSHA256Hash(data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s", r.Method, CanonicalURI(r), CanonicalQueryString(r), CanonicalHeaders(r, signedHeaders), strings.Join(signedHeaders, ";"), hexencode), err
|
||||
}
|
||||
|
||||
// CanonicalURI returns request uri
|
||||
func CanonicalURI(r *http.Request) string {
|
||||
pattens := strings.Split(r.URL.Path, "/")
|
||||
var uri []string
|
||||
for _, v := range pattens {
|
||||
uri = append(uri, escape(v))
|
||||
}
|
||||
urlpath := strings.Join(uri, "/")
|
||||
if len(urlpath) == 0 || urlpath[len(urlpath)-1] != '/' {
|
||||
urlpath = urlpath + "/"
|
||||
}
|
||||
return urlpath
|
||||
}
|
||||
|
||||
// CanonicalQueryString
|
||||
func CanonicalQueryString(r *http.Request) string {
|
||||
var keys []string
|
||||
query := r.URL.Query()
|
||||
for key := range query {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var a []string
|
||||
for _, key := range keys {
|
||||
k := escape(key)
|
||||
sort.Strings(query[key])
|
||||
for _, v := range query[key] {
|
||||
kv := fmt.Sprintf("%s=%s", k, escape(v))
|
||||
a = append(a, kv)
|
||||
}
|
||||
}
|
||||
queryStr := strings.Join(a, "&")
|
||||
r.URL.RawQuery = queryStr
|
||||
return queryStr
|
||||
}
|
||||
|
||||
// CanonicalHeaders
|
||||
func CanonicalHeaders(r *http.Request, signerHeaders []string) string {
|
||||
var a []string
|
||||
header := make(map[string][]string)
|
||||
for k, v := range r.Header {
|
||||
header[strings.ToLower(k)] = v
|
||||
}
|
||||
for _, key := range signerHeaders {
|
||||
value := header[key]
|
||||
if strings.EqualFold(key, HeaderHost) {
|
||||
value = []string{r.Host}
|
||||
}
|
||||
sort.Strings(value)
|
||||
for _, v := range value {
|
||||
a = append(a, key+":"+strings.TrimSpace(v))
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s\n", strings.Join(a, "\n"))
|
||||
}
|
||||
|
||||
// SignedHeaders
|
||||
func SignedHeaders(r *http.Request) []string {
|
||||
var a []string
|
||||
for key := range r.Header {
|
||||
a = append(a, strings.ToLower(key))
|
||||
}
|
||||
sort.Strings(a)
|
||||
return a
|
||||
}
|
||||
|
||||
// RequestPayload
|
||||
func RequestPayload(r *http.Request) ([]byte, error) {
|
||||
if r.Body == nil {
|
||||
return []byte(""), nil
|
||||
}
|
||||
b, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
|
||||
return b, err
|
||||
}
|
||||
|
||||
// Create a "String to Sign".
|
||||
func StringToSign(canonicalRequest string, t time.Time) (string, error) {
|
||||
hash := sha256.New()
|
||||
_, err := hash.Write([]byte(canonicalRequest))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s\n%s\n%x",
|
||||
Algorithm, t.UTC().Format(BasicDateFormat), hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Create the HWS Signature.
|
||||
func SignStringToSign(stringToSign string, signingKey []byte) (string, error) {
|
||||
hm, err := hmacsha256(signingKey, stringToSign)
|
||||
return fmt.Sprintf("%x", hm), err
|
||||
}
|
||||
|
||||
// HexEncodeSHA256Hash returns hexcode of sha256
|
||||
func HexEncodeSHA256Hash(body []byte) (string, error) {
|
||||
hash := sha256.New()
|
||||
if body == nil {
|
||||
body = []byte("")
|
||||
}
|
||||
_, err := hash.Write(body)
|
||||
return fmt.Sprintf("%x", hash.Sum(nil)), err
|
||||
}
|
||||
|
||||
// Get the finalized value for the "Authorization" header. The signature parameter is the output from SignStringToSign
|
||||
func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string {
|
||||
return fmt.Sprintf("%s Access=%s, SignedHeaders=%s, Signature=%s", Algorithm, accessKey, strings.Join(signedHeaders, ";"), signature)
|
||||
}
|
||||
|
||||
// Signature HWS meta
|
||||
type Signer struct {
|
||||
Key string
|
||||
Secret string
|
||||
}
|
||||
|
||||
// SignRequest set Authorization header
|
||||
func (s *Signer) Sign(r *http.Request) error {
|
||||
var t time.Time
|
||||
var err error
|
||||
var dt string
|
||||
if dt = r.Header.Get(HeaderXDate); dt != "" {
|
||||
t, err = time.Parse(BasicDateFormat, dt)
|
||||
}
|
||||
if err != nil || dt == "" {
|
||||
t = time.Now()
|
||||
r.Header.Set(HeaderXDate, t.UTC().Format(BasicDateFormat))
|
||||
}
|
||||
signedHeaders := SignedHeaders(r)
|
||||
canonicalRequest, err := CanonicalRequest(r, signedHeaders)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringToSign, err := StringToSign(canonicalRequest, t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signature, err := SignStringToSign(stringToSign, []byte(s.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authValue := AuthHeaderValue(signature, s.Key, signedHeaders)
|
||||
r.Header.Set(HeaderAuthorization, authValue)
|
||||
return nil
|
||||
}
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user