From 844a11aaa811518e1baa10ee7611eb24878e9db9 Mon Sep 17 00:00:00 2001 From: Will McCutchen Date: Sun, 5 Nov 2023 08:22:21 -0500 Subject: [PATCH] fix: /base64 endpoint decodes both URL-safe and standard b64 encodings (#153) As reported in #152, the `/base64` endpoint can only decode the "URL-safe" base64 encoding, but the error it returns is not very useful if you're not already familiar with different base64 encoding variants. Here we follow [Postel's law][1] and accept either the URL-safe or standard encodings, while continuing to use the URL-safe variant when encoding ourselves. Fixes #152. [1]: https://en.wikipedia.org/wiki/Robustness_principle --- httpbin/handlers_test.go | 13 +++++++------ httpbin/helpers.go | 10 +++++++--- httpbin/static/index.html | 4 ++-- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/httpbin/handlers_test.go b/httpbin/handlers_test.go index 716dd697..fc5387d8 100644 --- a/httpbin/handlers_test.go +++ b/httpbin/handlers_test.go @@ -2707,6 +2707,13 @@ func TestBase64(t *testing.T) { "/base64/decode/YWJjMTIzIT8kKiYoKSctPUB-", "abc123!?$*&()'-=@~", }, + { + // Std base64 is also supported for decoding (+ instead of - in + // encoded input string). See also: + // https://github.com/mccutchen/go-httpbin/issues/152 + "/base64/decode/8J+Ziywg8J+MjSEK4oCm", + "šŸ™‹, šŸŒ!\nā€¦", + }, { // URL-safe base64 is used for encoding (note the - instead of + in // encoded output string) @@ -2764,12 +2771,6 @@ func TestBase64(t *testing.T) { "/base64/unknown/dmFsaWRfYmFzZTY0X2VuY29kZWRfc3RyaW5n", "invalid operation: unknown", }, - { - // we only support URL-safe base64 encoded strings (note the + - // instead of - in encoded input string) - "/base64/decode/YWJjMTIzIT8kKiYoKSctPUB+", - "illegal base64 data", - }, } for _, test := range errorTests { diff --git a/httpbin/helpers.go b/httpbin/helpers.go index c1e170f8..cff9b9cb 100644 --- a/httpbin/helpers.go +++ b/httpbin/helpers.go @@ -429,16 +429,20 @@ func newBase64Helper(path string) (*base64Helper, error) { return &b, nil } -// Encode - encode data as base64 +// Encode - encode data as URL-safe base64 func (b *base64Helper) Encode() ([]byte, error) { buff := make([]byte, base64.URLEncoding.EncodedLen(len(b.data))) base64.URLEncoding.Encode(buff, []byte(b.data)) return buff, nil } -// Decode - decode data from base64 +// Decode - decode data from base64, attempting both URL-safe and standard +// encodings. func (b *base64Helper) Decode() ([]byte, error) { - return base64.URLEncoding.DecodeString(b.data) + if result, err := base64.URLEncoding.DecodeString(b.data); err == nil { + return result, nil + } + return base64.StdEncoding.DecodeString(b.data) } func wildCardToRegexp(pattern string) string { diff --git a/httpbin/static/index.html b/httpbin/static/index.html index 4d94d0b5..1599af8b 100644 --- a/httpbin/static/index.html +++ b/httpbin/static/index.html @@ -61,9 +61,9 @@

ENDPOINTS

  • / This page.
  • /absolute-redirect/:n 302 Absolute redirects n times.
  • /anything/:anything Returns anything that is passed to request.
  • -
  • /base64/:value Decodes a Base64 encoded string.
  • +
  • /base64/:value Decodes a Base64-encoded string.
  • /base64/decode/:value Explicit URL for decoding a Base64 encoded string.
  • -
  • /base64/encode/:value Encodes a string into Base64.
  • +
  • /base64/encode/:value Encodes a string into URL-safe Base64.
  • /basic-auth/:user/:passwd Challenges HTTPBasic Auth.
  • /bearer Checks Bearer token header - returns 401 if not set.
  • /brotli Returns brotli-encoded data. Not implemented!