Skip to content

Instantly share code, notes, and snippets.

@ottob
Created October 14, 2013 15:00
Show Gist options
  • Save ottob/6977070 to your computer and use it in GitHub Desktop.
Save ottob/6977070 to your computer and use it in GitHub Desktop.
Sample using duo security sms verify api with go
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"strings"
)
var (
// Define these based on your integration settings
host = "HOST"
skey = []byte(`SKEY`)
ikey = "IKEY"
// Enter your phone number
phone = "46702XXXXXX"
)
func request(uri string, params map[string]string) ([]byte, error) {
duoUrl := "https://" + host + uri
buf := new(bytes.Buffer)
w := multipart.NewWriter(buf)
if err := w.WriteField("phone", params["phone"]); err != nil {
return nil, err
}
if err := w.WriteField("message", params["message"]); err != nil {
return nil, err
}
w.Close()
values := make(url.Values)
values.Set("phone", params["phone"])
values.Set("message", params["message"])
sig := sign_request(uri, values.Encode())
client := &http.Client{}
req, err := http.NewRequest("POST", duoUrl, buf)
req.Header.Add("Authorization", sig)
req.Header.Set("Content-Type", w.FormDataContentType())
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
contents, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return contents, nil
}
func sign_request(uri, paramString string) string {
canon := canon(uri, paramString)
mac := hmac.New(sha1.New, skey)
mac.Write(canon)
md := mac.Sum(nil)
data := ikey + ":" + hex.EncodeToString(md)
b64 := base64.StdEncoding.EncodeToString([]byte(data))
return "Basic " + b64
}
func canon(path, paramString string) []byte {
paramString = strings.Replace(paramString, "+", "%20", -1)
canon := fmt.Sprintf(`POST
%s
%s
%s`, host, path, paramString)
return []byte(canon)
}
func main() {
message := "Din engångskod för XYZ.se: <pin>"
//message := "Your code: <pin>"
params := map[string]string{"message": message,
"phone": "+" + phone}
fmt.Println("Attempting to sms: " + params["phone"])
result, err := request("/verify/v1/sms.json", params)
if err != nil {
fmt.Println(err)
return
}
type Response struct {
Pin string
}
type DuoResponse struct {
Stat string
Code int
Message string
Message_detail string
Response Response
}
var smsResponse DuoResponse
err = json.Unmarshal(result, &smsResponse)
if smsResponse.Stat != "OK" {
fmt.Println("There was an error with the request:", smsResponse.Message)
return
}
fmt.Print("Please enter the pin:")
var inputPin string
fmt.Scanln(&inputPin)
if inputPin == smsResponse.Response.Pin {
fmt.Println("Pin is correct")
} else {
fmt.Println("Pin is incorrect")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment