Skip to content

Commit

Permalink
[webhook] support cbor as metadata format
Browse files Browse the repository at this point in the history
  • Loading branch information
williamchong committed Jun 3, 2024
1 parent efd3a0a commit 52aa9e4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 17 deletions.
6 changes: 3 additions & 3 deletions webhook/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import (
"github.com/starlinglab/integrity-v2/aa"
)

// ParseJsonToAttributes parses a JSON map and a file stat map
// ParseMapToAttributes parses a map and a file stat map
// to a slice of attributes for POSTing to the AA server
func ParseJsonToAttributes(jsonMap map[string]any, fileAttributes map[string]any) []aa.PostKV {
func ParseMapToAttributes(attrMap map[string]any, fileAttributes map[string]any) []aa.PostKV {

var attributes []aa.PostKV

for k, v := range jsonMap {
for k, v := range attrMap {
// TODO: add whitelist/blacklist for attributes in config
if k != "private" {
attributes = append(attributes, aa.PostKV{Key: k, Value: v})
Expand Down
32 changes: 28 additions & 4 deletions webhook/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
"io"
"mime/multipart"
"net/http"
"net/textproto"
urlpkg "net/url"
"os"
"path/filepath"
"strings"

"github.com/fxamacker/cbor/v2"
"github.com/starlinglab/integrity-v2/config"
)

Expand All @@ -20,13 +23,24 @@ var client = &http.Client{}
type PostGenericWebhookOpt struct {
Source string // Source is the origin of the asset, which is used to determine the webhook endpoint
ProjectId string // ProjectId is the project specific ID where the asset belongs
Format string // Format is "json" or "cbor"
}

type PostGenericWebhookResponse struct {
Cid string `json:"cid,omitempty"`
Error error `json:"error,omitempty"`
}

// createFormFieldWithContentType is a modified multipart.Writer.CreateFormField
// which allow setting of content-type
func createFormFieldWithContentType(w *multipart.Writer, fieldName string, contentType string) (io.Writer, error) {
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition",
fmt.Sprintf(`form-data; name="%s"`, strings.NewReplacer("\\", "\\\\", `"`, "\\\"").Replace(fieldName)))
h.Set("Content-Type", contentType)
return w.CreatePart(h)
}

// PostFileToWebHook posts a file and its metadata to the webhook server
func PostFileToWebHook(filePath string, metadata map[string]any, opts PostGenericWebhookOpt) (*PostGenericWebhookResponse, error) {
sourcePath := opts.Source
Expand All @@ -44,13 +58,23 @@ func PostFileToWebHook(filePath string, metadata map[string]any, opts PostGeneri
pr, pw := io.Pipe()
mp := multipart.NewWriter(pw)

metadataFormatType := "application/json"
if opts.Format == "cbor" {
metadataFormatType = "application/cbor"
}

go func() {
metadataString, err := json.Marshal(metadata)
metadataPart, err := createFormFieldWithContentType(mp, "metadata", metadataFormatType)
if err != nil {
pw.CloseWithError(err)
return
}
err = mp.WriteField("metadata", string(metadataString))
if metadataFormatType == "application/cbor" {
err = cbor.NewEncoder(metadataPart).Encode(metadata)

} else {
err = json.NewEncoder(metadataPart).Encode(metadata)
}
if err != nil {
pw.CloseWithError(err)
return
Expand All @@ -61,12 +85,12 @@ func PostFileToWebHook(filePath string, metadata map[string]any, opts PostGeneri
return
}
defer file.Close()
part, err := mp.CreateFormFile("file", filepath.Base(filePath))
filePart, err := mp.CreateFormFile("file", filepath.Base(filePath))
if err != nil {
pw.CloseWithError(err)
return
}
_, err = io.Copy(part, file)
_, err = io.Copy(filePart, file)
if err != nil {
pw.CloseWithError(err)
return
Expand Down
26 changes: 16 additions & 10 deletions webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"os"
"path/filepath"

"github.com/fxamacker/cbor/v2"
"github.com/go-chi/chi/v5"
"github.com/go-chi/jwtauth/v5"
"github.com/starlinglab/integrity-v2/aa"
Expand Down Expand Up @@ -73,7 +74,6 @@ func handleGenericFileUpload(w http.ResponseWriter, r *http.Request) {
writeJsonResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
metadataString := []byte{}

outputDirectory, err := getFileOutputDirectory()
if err != nil {
Expand All @@ -89,6 +89,7 @@ func handleGenericFileUpload(w http.ResponseWriter, r *http.Request) {
defer os.Remove(tempFile.Name())
cid := ""
fileAttributes := map[string]any{}
var metadataMap map[string]any
for {
part, err := form.NextPart()
if err == io.EOF {
Expand All @@ -98,13 +99,24 @@ func handleGenericFileUpload(w http.ResponseWriter, r *http.Request) {
return
}
if part.FormName() == "metadata" {
metadataString, err = io.ReadAll(part)
metadataFormatType := part.Header.Get("Content-Type")
metadataValue, err := io.ReadAll(part)
defer part.Close()
if err != nil {
writeJsonResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}
//do something with files
switch metadataFormatType {
case "application/cbor":
err = cbor.Unmarshal(metadataValue, &metadataMap)
case "application/json":
err = json.Unmarshal(metadataValue, &metadataMap)
}
if err != nil {
writeJsonResponse(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
return
}

} else if part.FormName() == "file" {
pr, pw := io.Pipe()
cidChan := make(chan string, 1)
Expand Down Expand Up @@ -161,13 +173,7 @@ func handleGenericFileUpload(w http.ResponseWriter, r *http.Request) {
return
}

var jsonMap map[string]any
err = json.Unmarshal(metadataString, &jsonMap)
if err != nil {
writeJsonResponse(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
return
}
attributes := ParseJsonToAttributes(jsonMap, fileAttributes)
attributes := ParseMapToAttributes(metadataMap, fileAttributes)
err = aa.SetAttestations(cid, false, attributes)
if err != nil {
fmt.Println("Error setting attestations:", err)
Expand Down

0 comments on commit 52aa9e4

Please sign in to comment.