// Copyright 2024 Matthew Rich . All rights reserved. package source import ( _ "context" _ "encoding/json" "fmt" _ "gopkg.in/yaml.v3" "net/url" "net/http" _ "path/filepath" "decl/internal/resource" "decl/internal/iofilter" "decl/internal/signature" _ "os" "io" "errors" "crypto/sha256" ) type HTTP struct { Endpoint string `yaml:"endpoint" json:"endpoint"` } func NewHTTP() *HTTP { return &HTTP{} } func init() { SourceTypes.Register([]string{"http","https"}, func(u *url.URL) DocSource { t := NewHTTP() t.Endpoint = u.String() return t }) } func (d *HTTP) Type() string { return "http" } func (h *HTTP) ExtractResources(filter ResourceSelector) ([]*resource.Document, error) { documents := make([]*resource.Document, 0, 100) resp, err := http.Get(h.Endpoint) if err != nil { return documents, err } defer resp.Body.Close() documentSignature := resp.Header.Get("Signature") if documentSignature == "" { signatureResp, signatureErr := http.Get(fmt.Sprintf("%s.sig", h.Endpoint)) if signatureErr == nil { defer signatureResp.Body.Close() readSignatureBody, readSignatureErr := io.ReadAll(resp.Body) if readSignatureErr == nil { documentSignature = string(readSignatureBody) } } } hash := sha256.New() sumReadData := iofilter.NewReader(resp.Body, func(p []byte, readn int, readerr error) (n int, err error) { hash.Write(p) return }) decoder := resource.NewYAMLDecoder(sumReadData) index := 0 for { doc := resource.NewDocument() e := decoder.Decode(doc) if errors.Is(e, io.EOF) { break } if e != nil { return documents, e } if validationErr := doc.Validate(); validationErr != nil { return documents, validationErr } documents = append(documents, doc) index++ } if documentSignature != "" { sig := &signature.Ident{} sigErr := sig.VerifySum(hash.Sum(nil), []byte(documentSignature)) if sigErr != nil { return documents, sigErr } } return documents, nil }