Verifying your Trello Webhook Subscription

I am having trouble successfully validating a webhook request from Trello. Here is what I know.

The Trello webhook documentation here states:

Each webhook trigger contains an X-Trello-Webhook HTTP header. The header is a base64 digest of the HMAC-SHA1 hash. The hashed content is the concatenation of the body of the full request and callbackURL just like it was provided at the time of the creation of the webcam. The key used to sign this text is the secret of your applications.

It's clear. They keep talking

Due to the specific default values ​​in crypto utilities in node, the useful values ​​that we sign are treated as binary strings, not utf-8. For example, if you take the en-dash character (U + 2013 or 8211 in decimal format) and create a binary buffer in it from node, it will be displayed as a buffer [19], which are the 8 least significant bits of 8211. This is the value that used in the digest to calculate SHA-1.

This is less clear to me. I understand that each payload character (body + callbackURL) was put into an 8-bit integer with ignoring overflow. (Because 8211 == 0b10000000010011 and 0b00010011 == 19) This is where I think my problem is.

The function that I use to solve the problem with Trello node:

func bitShift(s string) []byte {
    var byteString []byte

    // For each rune in the string
    for _, c := range s {

        // Create a byte slice
        b := []byte(string(c))

        // Take the sign off the least significant byte
        tmp := b[len(b)-1] << 1
        tmp = tmp >> 1

        // Append it to the byte string
        byteString = append(byteString, tmp)
    }
    return byteString
}

, - . , .

// VerifyNotificationHeader ...
func VerifyNotificationHeader(signedHeader, trelloAPISecret string, requestURL *url.URL, body []byte) bool {

    // Put callbackURL and body into byte slice
    urlBytes := bitShift(requestURL.String())
    bitBody := bitShift(string(body))

    // Sign, hash, and encode the payload
    secret := []byte(trelloAPISecret)
    keyHMAC := hmac.New(sha1.New, secret)
    keyHMAC.Write(append(bitBody, urlBytes...))
    signedHMAC := keyHMAC.Sum(nil)
    base64signedHMAC := base64.StdEncoding.EncodeToString(signedHMAC)

    if comp := strings.EqualFold(base64signedHMAC, signedHeader); !comp {
        return false
    }
    return true
}

, . !

. , .

+4
2

MSB? rune byte, ( uint8), , .

​​:

func ascii(s string) []byte {
    var ret []byte
    for _, r := range s {
        ret = append(ret, byte(r))
    }
    return ret
}

rune int32, byte 24 , .

(: .)

+2

. requestURL.String() callbackURL.

http.Request.URL:

, Path RawQuery, .

, requestURL.String() [Path] [Scheme]://[Host][Path]. callbackURL -

callbackURL := "https://" + request.Host + request.URL.String()

, , 8- .

+1

Source: https://habr.com/ru/post/1619399/