Please note that this is an SDK for webhooks integration, and not the FormSG system.
FormSG Golang SDK
This SDK provides convenient utilities for verifying FormSG webhooks and decrypting submissions in golang.
Installation
Install the package with
go get github.com/afnexus/formsg-golang-sdk
Configuration
import (
"github.com/afnexus/formsg-golang-sdk"
)
mode | 'production' | Set to 'staging' if integrating against FormSG staging servers. |
Usage
Webhook Authentication and Decrypting Submissions
:warning: If you are testing on localhost: Please remember to comment the check for X-FormSG-Signature as you will be using http protocol!
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"github.com/afnexus/formsg-golang-sdk/crypto"
"github.com/afnexus/formsg-golang-sdk/webhooks"
)
const (
has_attachments = true
)
func submissions(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
err := webhooks.Authenticate(r.Header.Get("X-FormSG-Signature"))
if err != nil {
http.Error(w, `{ "message": "Unauthorized" }`, http.StatusUnauthorized)
return
}
var encryptedBody crypto.EncryptedBody
err = json.NewDecoder(r.Body).Decode(&encryptedBody)
if err != nil {
http.Error(w, `{ "message": "Invalid request" }`, http.StatusBadRequest)
return
}
decryptedBody, err := crypto.Decrypt(encryptedBody)
if err != nil {
log.Println(err.Error())
http.Error(w, `{ "message": "decryption fail"}`, http.StatusBadRequest)
return
}
file, err := os.Create(fmt.Sprintf("./temp/%s.json", decryptedBody.Data.SubmissionID))
if err != nil {
http.Error(w, `{ "message": "file open fail"}`, http.StatusBadRequest)
return
}
defer file.Close()
err = json.NewEncoder(file).Encode(decryptedBody)
if err != nil {
http.Error(w, `{ "message": "file write fail"}`, http.StatusBadRequest)
return
}
if has_attachments {
for _, field := range decryptedBody.Data.DecryptedContent {
if field.FieldType == "attachment" {
if download_url, ok := encryptedBody.Data.AttachmentDownloadUrls[field.ID]; ok {
decBytes, err := crypto.DownloadAttachment(download_url)
if err != nil {
log.Println(err.Error())
http.Error(w, `{ "message": "download attachment fail"}`, http.StatusBadRequest)
return
}
file2, err := os.Create(fmt.Sprintf("./temp/%s.%s", field.ID, field.Answer))
if err != nil {
log.Panicln(err.Error())
http.Error(w, `{ "message": "file open fail"}`, http.StatusBadRequest)
return
}
defer file2.Close()
_, err = file2.Write(decBytes)
if err != nil {
log.Panicln(err.Error())
http.Error(w, `{ "message": "file write fail"}`, http.StatusBadRequest)
return
}
}
}
}
}
w.Write([]byte("ok"))
}
func main() {
if os.Getenv("FORM_PUBLIC_KEY") == "" {
os.Setenv("FORM_PUBLIC_KEY", "3Tt8VduXsjjd4IrpdCd7BAkdZl/vUCstu9UvTX84FWw=")
}
if os.Getenv("FORM_SECRET_KEY") == "" {
os.Setenv("FORM_SECRET_KEY", "FORM_SECRET_KEY")
}
if os.Getenv("FORM_POST_URI") == "" {
os.Setenv("FORM_POST_URI", "https://example.com/submissions")
}
_, err := os.Stat("temp")
if os.IsNotExist(err) {
log.Println("Folder does not exist.")
err := os.Mkdir("temp", 0755)
if err != nil {
log.Fatal(err)
}
} else {
log.Println("Folder exist.")
}
http.Handle("/temp/", http.StripPrefix("/temp/", http.FileServer(http.Dir("./temp"))))
http.HandleFunc("/submissions", submissions)
http.ListenAndServe(":8080", nil)
}
Contributing
We welcome all contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas to improve the SDK. Please see our contributing guide.
License
Distributed under the GNU GPLv3 License. See LICENSE
for more information.
Acknowledgements
Special thanks to the group of FormSG software engineers in Open Government Products who created the javascript version of the SDK.