...

Source file src/gopkg.in/go-jose/go-jose.v2/encoding.go

Documentation: gopkg.in/go-jose/go-jose.v2

     1  /*-
     2   * Copyright 2014 Square Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package jose
    18  
    19  import (
    20  	"bytes"
    21  	"compress/flate"
    22  	"encoding/base64"
    23  	"encoding/binary"
    24  	"fmt"
    25  	"io"
    26  	"math/big"
    27  	"strings"
    28  	"unicode"
    29  
    30  	"gopkg.in/go-jose/go-jose.v2/json"
    31  )
    32  
    33  // Helper function to serialize known-good objects.
    34  // Precondition: value is not a nil pointer.
    35  func mustSerializeJSON(value interface{}) []byte {
    36  	out, err := json.Marshal(value)
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	// We never want to serialize the top-level value "null," since it's not a
    41  	// valid JOSE message. But if a caller passes in a nil pointer to this method,
    42  	// MarshalJSON will happily serialize it as the top-level value "null". If
    43  	// that value is then embedded in another operation, for instance by being
    44  	// base64-encoded and fed as input to a signing algorithm
    45  	// (https://github.com/go-jose/go-jose/issues/22), the result will be
    46  	// incorrect. Because this method is intended for known-good objects, and a nil
    47  	// pointer is not a known-good object, we are free to panic in this case.
    48  	// Note: It's not possible to directly check whether the data pointed at by an
    49  	// interface is a nil pointer, so we do this hacky workaround.
    50  	// https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I
    51  	if string(out) == "null" {
    52  		panic("Tried to serialize a nil pointer.")
    53  	}
    54  	return out
    55  }
    56  
    57  // Strip all newlines and whitespace
    58  func stripWhitespace(data string) string {
    59  	buf := strings.Builder{}
    60  	buf.Grow(len(data))
    61  	for _, r := range data {
    62  		if !unicode.IsSpace(r) {
    63  			buf.WriteRune(r)
    64  		}
    65  	}
    66  	return buf.String()
    67  }
    68  
    69  // Perform compression based on algorithm
    70  func compress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) {
    71  	switch algorithm {
    72  	case DEFLATE:
    73  		return deflate(input)
    74  	default:
    75  		return nil, ErrUnsupportedAlgorithm
    76  	}
    77  }
    78  
    79  // Perform decompression based on algorithm
    80  func decompress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) {
    81  	switch algorithm {
    82  	case DEFLATE:
    83  		return inflate(input)
    84  	default:
    85  		return nil, ErrUnsupportedAlgorithm
    86  	}
    87  }
    88  
    89  // deflate compresses the input.
    90  func deflate(input []byte) ([]byte, error) {
    91  	output := new(bytes.Buffer)
    92  
    93  	// Writing to byte buffer, err is always nil
    94  	writer, _ := flate.NewWriter(output, 1)
    95  	_, _ = io.Copy(writer, bytes.NewBuffer(input))
    96  
    97  	err := writer.Close()
    98  	return output.Bytes(), err
    99  }
   100  
   101  // inflate decompresses the input.
   102  //
   103  // Errors if the decompressed data would be >250kB or >10x the size of the
   104  // compressed data, whichever is larger.
   105  func inflate(input []byte) ([]byte, error) {
   106  	output := new(bytes.Buffer)
   107  	reader := flate.NewReader(bytes.NewBuffer(input))
   108  
   109  	maxCompressedSize := 10 * int64(len(input))
   110  	if maxCompressedSize < 250000 {
   111  		maxCompressedSize = 250000
   112  	}
   113  
   114  	limit := maxCompressedSize + 1
   115  	n, err := io.CopyN(output, reader, limit)
   116  	if err != nil && err != io.EOF {
   117  		return nil, err
   118  	}
   119  	if n == limit {
   120  		return nil, fmt.Errorf("uncompressed data would be too large (>%d bytes)", maxCompressedSize)
   121  	}
   122  
   123  	err = reader.Close()
   124  	return output.Bytes(), err
   125  }
   126  
   127  // byteBuffer represents a slice of bytes that can be serialized to url-safe base64.
   128  type byteBuffer struct {
   129  	data []byte
   130  }
   131  
   132  func newBuffer(data []byte) *byteBuffer {
   133  	if data == nil {
   134  		return nil
   135  	}
   136  	return &byteBuffer{
   137  		data: data,
   138  	}
   139  }
   140  
   141  func newFixedSizeBuffer(data []byte, length int) *byteBuffer {
   142  	if len(data) > length {
   143  		panic("go-jose/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)")
   144  	}
   145  	pad := make([]byte, length-len(data))
   146  	return newBuffer(append(pad, data...))
   147  }
   148  
   149  func newBufferFromInt(num uint64) *byteBuffer {
   150  	data := make([]byte, 8)
   151  	binary.BigEndian.PutUint64(data, num)
   152  	return newBuffer(bytes.TrimLeft(data, "\x00"))
   153  }
   154  
   155  func (b *byteBuffer) MarshalJSON() ([]byte, error) {
   156  	return json.Marshal(b.base64())
   157  }
   158  
   159  func (b *byteBuffer) UnmarshalJSON(data []byte) error {
   160  	var encoded string
   161  	err := json.Unmarshal(data, &encoded)
   162  	if err != nil {
   163  		return err
   164  	}
   165  
   166  	if encoded == "" {
   167  		return nil
   168  	}
   169  
   170  	decoded, err := base64.RawURLEncoding.DecodeString(encoded)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	*b = *newBuffer(decoded)
   176  
   177  	return nil
   178  }
   179  
   180  func (b *byteBuffer) base64() string {
   181  	return base64.RawURLEncoding.EncodeToString(b.data)
   182  }
   183  
   184  func (b *byteBuffer) bytes() []byte {
   185  	// Handling nil here allows us to transparently handle nil slices when serializing.
   186  	if b == nil {
   187  		return nil
   188  	}
   189  	return b.data
   190  }
   191  
   192  func (b byteBuffer) bigInt() *big.Int {
   193  	return new(big.Int).SetBytes(b.data)
   194  }
   195  
   196  func (b byteBuffer) toInt() int {
   197  	return int(b.bigInt().Int64())
   198  }
   199  

View as plain text