storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/crypto/json.go (about)

     1  // MinIO Cloud Storage, (C) 2020 MinIO, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package crypto
    16  
    17  import (
    18  	"bytes"
    19  	"unicode/utf8"
    20  )
    21  
    22  // Adapted from Go stdlib.
    23  
    24  var hexTable = "0123456789abcdef"
    25  
    26  // EscapeStringJSON will escape a string for JSON and write it to dst.
    27  func EscapeStringJSON(dst *bytes.Buffer, s string) {
    28  	start := 0
    29  	for i := 0; i < len(s); {
    30  		if b := s[i]; b < utf8.RuneSelf {
    31  			if htmlSafeSet[b] {
    32  				i++
    33  				continue
    34  			}
    35  			if start < i {
    36  				dst.WriteString(s[start:i])
    37  			}
    38  			dst.WriteByte('\\')
    39  			switch b {
    40  			case '\\', '"':
    41  				dst.WriteByte(b)
    42  			case '\n':
    43  				dst.WriteByte('n')
    44  			case '\r':
    45  				dst.WriteByte('r')
    46  			case '\t':
    47  				dst.WriteByte('t')
    48  			default:
    49  				// This encodes bytes < 0x20 except for \t, \n and \r.
    50  				// If escapeHTML is set, it also escapes <, >, and &
    51  				// because they can lead to security holes when
    52  				// user-controlled strings are rendered into JSON
    53  				// and served to some browsers.
    54  				dst.WriteString(`u00`)
    55  				dst.WriteByte(hexTable[b>>4])
    56  				dst.WriteByte(hexTable[b&0xF])
    57  			}
    58  			i++
    59  			start = i
    60  			continue
    61  		}
    62  		c, size := utf8.DecodeRuneInString(s[i:])
    63  		if c == utf8.RuneError && size == 1 {
    64  			if start < i {
    65  				dst.WriteString(s[start:i])
    66  			}
    67  			dst.WriteString(`\ufffd`)
    68  			i += size
    69  			start = i
    70  			continue
    71  		}
    72  		// U+2028 is LINE SEPARATOR.
    73  		// U+2029 is PARAGRAPH SEPARATOR.
    74  		// They are both technically valid characters in JSON strings,
    75  		// but don't work in JSONP, which has to be evaluated as JavaScript,
    76  		// and can lead to security holes there. It is valid JSON to
    77  		// escape them, so we do so unconditionally.
    78  		// See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
    79  		if c == '\u2028' || c == '\u2029' {
    80  			if start < i {
    81  				dst.WriteString(s[start:i])
    82  			}
    83  			dst.WriteString(`\u202`)
    84  			dst.WriteByte(hexTable[c&0xF])
    85  			i += size
    86  			start = i
    87  			continue
    88  		}
    89  		i += size
    90  	}
    91  	if start < len(s) {
    92  		dst.WriteString(s[start:])
    93  	}
    94  }
    95  
    96  // htmlSafeSet holds the value true if the ASCII character with the given
    97  // array position can be safely represented inside a JSON string, embedded
    98  // inside of HTML <script> tags, without any additional escaping.
    99  //
   100  // All values are true except for the ASCII control characters (0-31), the
   101  // double quote ("), the backslash character ("\"), HTML opening and closing
   102  // tags ("<" and ">"), and the ampersand ("&").
   103  var htmlSafeSet = [utf8.RuneSelf]bool{
   104  	' ':      true,
   105  	'!':      true,
   106  	'"':      false,
   107  	'#':      true,
   108  	'$':      true,
   109  	'%':      true,
   110  	'&':      false,
   111  	'\'':     true,
   112  	'(':      true,
   113  	')':      true,
   114  	'*':      true,
   115  	'+':      true,
   116  	',':      true,
   117  	'-':      true,
   118  	'.':      true,
   119  	'/':      true,
   120  	'0':      true,
   121  	'1':      true,
   122  	'2':      true,
   123  	'3':      true,
   124  	'4':      true,
   125  	'5':      true,
   126  	'6':      true,
   127  	'7':      true,
   128  	'8':      true,
   129  	'9':      true,
   130  	':':      true,
   131  	';':      true,
   132  	'<':      false,
   133  	'=':      true,
   134  	'>':      false,
   135  	'?':      true,
   136  	'@':      true,
   137  	'A':      true,
   138  	'B':      true,
   139  	'C':      true,
   140  	'D':      true,
   141  	'E':      true,
   142  	'F':      true,
   143  	'G':      true,
   144  	'H':      true,
   145  	'I':      true,
   146  	'J':      true,
   147  	'K':      true,
   148  	'L':      true,
   149  	'M':      true,
   150  	'N':      true,
   151  	'O':      true,
   152  	'P':      true,
   153  	'Q':      true,
   154  	'R':      true,
   155  	'S':      true,
   156  	'T':      true,
   157  	'U':      true,
   158  	'V':      true,
   159  	'W':      true,
   160  	'X':      true,
   161  	'Y':      true,
   162  	'Z':      true,
   163  	'[':      true,
   164  	'\\':     false,
   165  	']':      true,
   166  	'^':      true,
   167  	'_':      true,
   168  	'`':      true,
   169  	'a':      true,
   170  	'b':      true,
   171  	'c':      true,
   172  	'd':      true,
   173  	'e':      true,
   174  	'f':      true,
   175  	'g':      true,
   176  	'h':      true,
   177  	'i':      true,
   178  	'j':      true,
   179  	'k':      true,
   180  	'l':      true,
   181  	'm':      true,
   182  	'n':      true,
   183  	'o':      true,
   184  	'p':      true,
   185  	'q':      true,
   186  	'r':      true,
   187  	's':      true,
   188  	't':      true,
   189  	'u':      true,
   190  	'v':      true,
   191  	'w':      true,
   192  	'x':      true,
   193  	'y':      true,
   194  	'z':      true,
   195  	'{':      true,
   196  	'|':      true,
   197  	'}':      true,
   198  	'~':      true,
   199  	'\u007f': true,
   200  }