Skip to content

Instantly share code, notes, and snippets.

@jirevwe
Forked from subomi/twitter.go
Created July 7, 2022 13:27
Show Gist options
  • Save jirevwe/42722db390cb23842b4a5ead1fa6de8c to your computer and use it in GitHub Desktop.
Save jirevwe/42722db390cb23842b4a5ead1fa6de8c to your computer and use it in GitHub Desktop.
Set up Twitter webhooks in Golang.
// Generate webhook URL.
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"time"
"github.com/dghubble/oauth1"
log "github.com/sirupsen/logrus"
)
type webhookResource struct {
ID string `json:"id"`
URL string `json:"url"`
Valid bool `json:"valid"`
CreatedAt time.Time `json:"created_at"`
}
func main() {
err := configWebhookURL()
if err != nil {
log.WithError(err).Errorf("Failed to config webhooks")
}
}
const consumerKey = "<insert-consumer-key>"
const consumerSecret = "<insert-consumer-secret>"
const accessToken = "<insert-access-token>"
const accessSecret = "<insert-access-secret>"
const format = "https://api.twitter.com/1.1/account_activity/all/%s/webhooks.json?url=%s"
const environment = "staging"
const webhookURL = "<insert-webhook-url>"
func configWebhookURL() error {
config := oauth1.NewConfig(consumerKey, consumerSecret)
token := oauth1.NewToken(accessToken, accessSecret)
client := config.Client(oauth1.NoContext, token)
tURL := fmt.Sprintf(format, environment, url.QueryEscape(webhookURL))
// build webhooks http request.
req, err := http.NewRequest("POST", tURL, nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
err = resp.Body.Close()
if err != nil {
return err
}
if resp.StatusCode != 200 {
fmt.Printf("Failure Body: %+v\n", string(body))
return errors.New("Failed to create webhook resource")
}
// success case.
fmt.Printf("Success Body: %+v\n", string(body))
return nil
}
// Validate CRC
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
log "github.com/sirupsen/logrus"
)
const port = 3000
const consumerSecret = "<insert-consumer-secret>"
type response struct {
ResponseToken string `json:"response_token"`
}
func main() {
log.Info("Starting server...")
http.HandleFunc("/", crcHandler)
portString := fmt.Sprintf(":%d", port)
http.ListenAndServe(portString, nil)
}
func crcHandler(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
mac := hmac.New(sha256.New, []byte(consumerSecret))
mac.Write([]byte(params.Get("crc_token")))
crcHash := mac.Sum(nil)
base64CrcHash := base64.StdEncoding.EncodeToString(crcHash)
resp := response{ResponseToken: fmt.Sprintf("sha256=%s", base64CrcHash)}
data, err := json.Marshal(resp)
if err != nil {
log.WithError(err).Error("Could not marshal")
}
fmt.Fprint(w, string(data))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment