...

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

Documentation: gopkg.in/square/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  	"io"
    25  	"math/big"
    26  	"strings"
    27  	"unicode"
    28  
    29  	"gopkg.in/square/go-jose.v2/json"
    30  )
    31  
    32  // Helper function to serialize known-good objects.
    33  // Precondition: value is not a nil pointer.
    34  func mustSerializeJSON(value interface{}) []byte {
    35  	out, err := json.Marshal(value)
    36  	if err != nil {
    37  		panic(err)
    38  	}
    39  	// We never want to serialize the top-level value "null," since it's not a
    40  	// valid JOSE message. But if a caller passes in a nil pointer to this method,
    41  	// MarshalJSON will happily serialize it as the top-level value "null". If
    42  	// that value is then embedded in another operation, for instance by being
    43  	// base64-encoded and fed as input to a signing algorithm
    44  	// (https://github.com/square/go-jose/issues/22), the result will be
    45  	// incorrect. Because this method is intended for known-good objects, and a nil
    46  	// pointer is not a known-good object, we are free to panic in this case.
    47  	// Note: It's not possible to directly check whether the data pointed at by an
    48  	// interface is a nil pointer, so we do this hacky workaround.
    49  	// https://groups.google.com/forum/#!topic/golang-nuts/wnH302gBa4I
    50  	if string(out) == "null" {
    51  		panic("Tried to serialize a nil pointer.")
    52  	}
    53  	return out
    54  }
    55  
    56  // Strip all newlines and whitespace
    57  func stripWhitespace(data string) string {
    58  	buf := strings.Builder{}
    59  	buf.Grow(len(data))
    60  	for _, r := range data {
    61  		if !unicode.IsSpace(r) {
    62  			buf.WriteRune(r)
    63  		}
    64  	}
    65  	return buf.String()
    66  }
    67  
    68  // Perform compression based on algorithm
    69  func compress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) {
    70  	switch algorithm {
    71  	case DEFLATE:
    72  		return deflate(input)
    73  	default:
    74  		return nil, ErrUnsupportedAlgorithm
    75  	}
    76  }
    77  
    78  // Perform decompression based on algorithm
    79  func decompress(algorithm CompressionAlgorithm, input []byte) ([]byte, error) {
    80  	switch algorithm {
    81  	case DEFLATE:
    82  		return inflate(input)
    83  	default:
    84  		return nil, ErrUnsupportedAlgorithm
    85  	}
    86  }
    87  
    88  // Compress with DEFLATE
    89  func deflate(input []byte) ([]byte, error) {
    90  	output := new(bytes.Buffer)
    91  
    92  	// Writing to byte buffer, err is always nil
    93  	writer, _ := flate.NewWriter(output, 1)
    94  	_, _ = io.Copy(writer, bytes.NewBuffer(input))
    95  
    96  	err := writer.Close()
    97  	return output.Bytes(), err
    98  }
    99  
   100  // Decompress with DEFLATE
   101  func inflate(input []byte) ([]byte, error) {
   102  	output := new(bytes.Buffer)
   103  	reader := flate.NewReader(bytes.NewBuffer(input))
   104  
   105  	_, err := io.Copy(output, reader)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	err = reader.Close()
   111  	return output.Bytes(), err
   112  }
   113  
   114  // byteBuffer represents a slice of bytes that can be serialized to url-safe base64.
   115  type byteBuffer struct {
   116  	data []byte
   117  }
   118  
   119  func newBuffer(data []byte) *byteBuffer {
   120  	if data == nil {
   121  		return nil
   122  	}
   123  	return &byteBuffer{
   124  		data: data,
   125  	}
   126  }
   127  
   128  func newFixedSizeBuffer(data []byte, length int) *byteBuffer {
   129  	if len(data) > length {
   130  		panic("square/go-jose: invalid call to newFixedSizeBuffer (len(data) > length)")
   131  	}
   132  	pad := make([]byte, length-len(data))
   133  	return newBuffer(append(pad, data...))
   134  }
   135  
   136  func newBufferFromInt(num uint64) *byteBuffer {
   137  	data := make([]byte, 8)
   138  	binary.BigEndian.PutUint64(data, num)
   139  	return newBuffer(bytes.TrimLeft(data, "\x00"))
   140  }
   141  
   142  func (b *byteBuffer) MarshalJSON() ([]byte, error) {
   143  	return json.Marshal(b.base64())
   144  }
   145  
   146  func (b *byteBuffer) UnmarshalJSON(data []byte) error {
   147  	var encoded string
   148  	err := json.Unmarshal(data, &encoded)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	if encoded == "" {
   154  		return nil
   155  	}
   156  
   157  	decoded, err := base64.RawURLEncoding.DecodeString(encoded)
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	*b = *newBuffer(decoded)
   163  
   164  	return nil
   165  }
   166  
   167  func (b *byteBuffer) base64() string {
   168  	return base64.RawURLEncoding.EncodeToString(b.data)
   169  }
   170  
   171  func (b *byteBuffer) bytes() []byte {
   172  	// Handling nil here allows us to transparently handle nil slices when serializing.
   173  	if b == nil {
   174  		return nil
   175  	}
   176  	return b.data
   177  }
   178  
   179  func (b byteBuffer) bigInt() *big.Int {
   180  	return new(big.Int).SetBytes(b.data)
   181  }
   182  
   183  func (b byteBuffer) toInt() int {
   184  	return int(b.bigInt().Int64())
   185  }
   186  

View as plain text