Skip to content

Commit

Permalink
convert to simple map
Browse files Browse the repository at this point in the history
  • Loading branch information
dropwhile committed Aug 21, 2023
1 parent a4fc635 commit 79f57f8
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 100 deletions.
18 changes: 18 additions & 0 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,24 @@ by default, you could add this to the command line:
----
--

* `--enable-extra-headers`
+
--
When this option is supplied, extra headers may be included with the url payload as part of url generation.
These extra headers will then be returned as part of the response.

These extra headers are part of a 4th encoded url path component, signed under the hmac signature.

The underlying data is a json dict/map of an array of header values (since a given http header can be present with multiple values). Example:
----
{
"content-disposition": "attachment; filename=\"image.png\""
}
----

An possible use-case is setting content-disposition headers on specific image urls.
--

== Upstream Http Proxying

Care should be taken when using upstream http proxy support. go-camo has
Expand Down
12 changes: 4 additions & 8 deletions cmd/url-tool/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package main
import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"strings"
Expand Down Expand Up @@ -38,13 +37,13 @@ func (c *EncodeCommand) Execute(args []string) error {
return errors.New("no url argument provided")
}

extraHeaders := http.Header{}
extraHeaders := encoding.SimpleHeader{}
if len(c.ExtraHeaders) > 0 {
for k, v := range c.ExtraHeaders {
if len(k) == 0 || len(v) == 0 {
continue
}
extraHeaders.Add(k, v)
extraHeaders[strings.TrimSpace(k)] = strings.TrimSpace(v)
}
}

Expand Down Expand Up @@ -107,11 +106,8 @@ func (c *DecodeCommand) Execute(args []string) error {
if c.PrintHeaders {
if len(extraHdr) > 0 {
fmt.Println("Additional Headers: ")
for k, values := range extraHdr {
fmt.Printf(" %s:\n", k)
for _, v := range values {
fmt.Printf(" %s\n", v)
}
for k, v := range extraHdr {
fmt.Printf(" %s: %s\n", k, v)
}
}
}
Expand Down
42 changes: 37 additions & 5 deletions examples/go-base64.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.

//go:build ignore
// +build ignore

package main
Expand All @@ -10,29 +11,60 @@ import (
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
)

var CAMO_HOST = "https://img.example.com"

func b64encode(data []byte) string {
func wrapEncode(data []byte) string {
return strings.TrimRight(base64.URLEncoding.EncodeToString(data), "=")
}

func GenCamoUrl(hmacKey []byte, srcUrl string) string {
func GenCamoUrl(hmacKey []byte, srcUrl string, extraHeaders map[string]string) string {
if strings.HasPrefix(srcUrl, "https:") {
return srcUrl
}

hasExtraHeaders := false
if len(extraHeaders) > 0 {
hasExtraHeaders = true

}

oBytes := []byte(srcUrl)
mac := hmac.New(sha1.New, hmacKey)
mac.Write(oBytes)
macSum := b64encode(mac.Sum(nil))
encodedUrl := b64encode(oBytes)

encodedExtraHeaders := ""
if hasExtraHeaders {
extraHeaderBytes, _ := json.Marshal(extraHeaders)
mac.Write(extraHeaderBytes)
encodedExtraHeaders = wrapEncode(extraHeaderBytes)
}

macSum := wrapEncode(mac.Sum(nil))
encodedUrl := wrapEncode(oBytes)
encurl := CAMO_HOST + "/" + macSum + "/" + encodedUrl
if hasExtraHeaders {
encurl = encurl + "/" + encodedExtraHeaders
}
return encurl
}

func main() {
fmt.Println(GenCamoUrl([]byte("test"), "http://golang.org/doc/gopher/frontpage.png"))
fmt.Println(GenCamoUrl([]byte("test"), "http://golang.org/doc/gopher/frontpage.png", nil))
// https://img.example.com/D23vHLFHsOhPOcvdxeoQyAJTpvM/aHR0cDovL2dvbGFuZy5vcmcvZG9jL2dvcGhlci9mcm9udHBhZ2UucG5n

fmt.Println(
GenCamoUrl(
[]byte("test"),
"http://golang.org/doc/gopher/frontpage.png",
map[string]string{
"content-disposition": "attachment; filename=\"image.png\"",
},
),
)
// https://img.example.com/uLOqbvq5Esc9kQunfCd8HReDR40/aHR0cDovL2dvbGFuZy5vcmcvZG9jL2dvcGhlci9mcm9udHBhZ2UucG5n/eyJjb250ZW50LWRpc3Bvc2l0aW9uIjpbImF0dGFjaG1lbnQ7IGZpbGVuYW1lPVwiaW1hZ2UucG5nXCIiXX0
}
12 changes: 10 additions & 2 deletions man/go-camo.1.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,17 @@ When this option is supplied, extra headers may be included with the url payload
These extra headers will then be returned as part of the response.

These extra headers are part of a 4th encoded url path component, signed under the hmac signature.
The underlying data is a json map of headers.

An example use-case is setting content-disposition headers on specific image urls.
The underlying data is a json map of headers. Example:
----
{
"content-disposition": [
"attachment; filename=\"image.png\""
]
}
----

An possible use-case is setting content-disposition headers on specific image urls.

== METRICS

Expand Down
31 changes: 16 additions & 15 deletions pkg/camo/encoding/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/cactus/mlog"
)

// DecoderFunc is a function type that defines a url decoder.
type DecoderFunc func([]byte, string, string, string) (string, http.Header, error)
type DecoderFunc func([]byte, string, string, string) (string, SimpleHeader, error)

// EncoderFunc is a function type that defines a url encoder.
type EncoderFunc func([]byte, string, http.Header) (string, error)
type EncoderFunc func([]byte, string, SimpleHeader) (string, error)

type SimpleHeader map[string]string

func validateURL(hmackey *[]byte, macBytes *[]byte, urlBytes *[]byte, extraHdrBytes *[]byte) error {
mac := hmac.New(sha1.New, *hmackey)
Expand Down Expand Up @@ -56,16 +57,16 @@ func b64decode(str string) ([]byte, error) {
return decBytes, ok
}

func extraHdrUnmarshal(extraHdrBytes []byte) (http.Header, error) {
var headers http.Header
func extraHdrUnmarshal(extraHdrBytes []byte) (SimpleHeader, error) {
var headers SimpleHeader
err := json.Unmarshal(extraHdrBytes, &headers)
if err != nil {
return nil, err
}
return headers, nil
}

func extraHdrMarshal(headers http.Header) ([]byte, error) {
func extraHdrMarshal(headers SimpleHeader) ([]byte, error) {
headerBytes, err := json.Marshal(headers)
if err != nil {
return nil, err
Expand All @@ -76,7 +77,7 @@ func extraHdrMarshal(headers http.Header) ([]byte, error) {
// HexDecodeURL ensures the url is properly verified via HMAC, and then
// unencodes the url, returning the url (if valid) and whether the
// HMAC was verified.
func HexDecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, http.Header, error) {
func HexDecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, SimpleHeader, error) {
macBytes, err := hex.DecodeString(encDig)
if err != nil {
return "", nil, fmt.Errorf("bad mac decode")
Expand All @@ -102,7 +103,7 @@ func HexDecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, h
return "", nil, fmt.Errorf("invalid signature: %s", err)
}

var extraHdr http.Header
var extraHdr SimpleHeader
if hasExtraHdr {
var err error
// !!only unmarshal _after_ hmac validation!!
Expand All @@ -116,7 +117,7 @@ func HexDecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, h

// HexEncodeURL takes an HMAC key and a url, and returns url
// path partial consisitent of signature and encoded url.
func HexEncodeURL(hmacKey []byte, oURL string, oExtraHdr http.Header) (string, error) {
func HexEncodeURL(hmacKey []byte, oURL string, oExtraHdr SimpleHeader) (string, error) {
oURLBytes := []byte(oURL)

var oExtraHdrBytes []byte
Expand Down Expand Up @@ -150,7 +151,7 @@ func HexEncodeURL(hmacKey []byte, oURL string, oExtraHdr http.Header) (string, e
// B64DecodeURL ensures the url is properly verified via HMAC, and then
// unencodes the url, returning the url (if valid) and whether the
// HMAC was verified.
func B64DecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, http.Header, error) {
func B64DecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, SimpleHeader, error) {
macBytes, err := b64decode(encDig)
if err != nil {
return "", nil, fmt.Errorf("bad mac decode")
Expand All @@ -165,7 +166,7 @@ func B64DecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, h
hasExtraHdr := false
if len(encExtraHdr) > 0 {
var err error
extraHdrBytes, err = hex.DecodeString(encExtraHdr)
extraHdrBytes, err = b64decode(encExtraHdr)
if err != nil {
return "", nil, fmt.Errorf("bad additional data decode")
}
Expand All @@ -177,7 +178,7 @@ func B64DecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, h
}

// !!only unmarshal _after_ hmac validation!!
var extraHdr http.Header
var extraHdr SimpleHeader
if hasExtraHdr {
var err error
// !!only unmarshal _after_ hmac validation!!
Expand All @@ -191,7 +192,7 @@ func B64DecodeURL(hmackey []byte, encDig, encURL, encExtraHdr string) (string, h

// B64EncodeURL takes an HMAC key and a url, and returns url
// path partial consisitent of signature and encoded url.
func B64EncodeURL(hmacKey []byte, oURL string, oExtraHdr http.Header) (string, error) {
func B64EncodeURL(hmacKey []byte, oURL string, oExtraHdr SimpleHeader) (string, error) {
oBytes := []byte(oURL)

var oExtraHdrBytes []byte
Expand All @@ -216,7 +217,7 @@ func B64EncodeURL(hmacKey []byte, oURL string, oExtraHdr http.Header) (string, e
encodedURL := b64encode(oBytes)
encURL := "/" + macSum + "/" + encodedURL
if hasExtraHdr {
encExtraHdr := hex.EncodeToString(oExtraHdrBytes)
encExtraHdr := b64encode(oExtraHdrBytes)
encURL = encURL + "/" + encExtraHdr
}
return encURL, nil
Expand All @@ -226,7 +227,7 @@ func B64EncodeURL(hmacKey []byte, oURL string, oExtraHdr http.Header) (string, e
// unencodes the url, returning the url (if valid) and whether the
// HMAC was verified. Tries either HexDecode or B64Decode, depending on the
// length of the encoded hmac.
func DecodeURL(hmackey []byte, encdig, encURL, encExtraHdr string) (string, http.Header, bool) {
func DecodeURL(hmackey []byte, encdig, encURL, encExtraHdr string) (string, SimpleHeader, bool) {
var decoder DecoderFunc
if len(encdig) == 40 {
decoder = HexDecodeURL
Expand Down
Loading

0 comments on commit 79f57f8

Please sign in to comment.