github.com/secure-build/gitlab-runner@v12.5.0+incompatible/helpers/shell_escape.go (about)

     1  package helpers
     2  
     3  // https://github.com/zimbatm/direnv/blob/master/shell.go
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/hex"
     8  	"strings"
     9  )
    10  
    11  /*
    12   * Escaping
    13   */
    14  
    15  const (
    16  	ACK           = 6
    17  	TAB           = 9
    18  	LF            = 10
    19  	CR            = 13
    20  	US            = 31
    21  	SPACE         = 32
    22  	AMPERSTAND    = 38
    23  	SINGLE_QUOTE  = 39
    24  	PLUS          = 43
    25  	NINE          = 57
    26  	QUESTION      = 63
    27  	LOWERCASE_Z   = 90
    28  	OPEN_BRACKET  = 91
    29  	BACKSLASH     = 92
    30  	UNDERSCORE    = 95
    31  	CLOSE_BRACKET = 93
    32  	BACKTICK      = 96
    33  	TILDA         = 126
    34  	DEL           = 127
    35  )
    36  
    37  // ShellEscape is taken from https://github.com/solidsnack/shell-escape/blob/master/Text/ShellEscape/Bash.hs
    38  /*
    39  A Bash escaped string. The strings are wrapped in @$\'...\'@ if any
    40  bytes within them must be escaped; otherwise, they are left as is.
    41  Newlines and other control characters are represented as ANSI escape
    42  sequences. High bytes are represented as hex codes. Thus Bash escaped
    43  strings will always fit on one line and never contain non-ASCII bytes.
    44  */
    45  func ShellEscape(str string) string {
    46  	if str == "" {
    47  		return "''"
    48  	}
    49  	in := []byte(str)
    50  	out := bytes.NewBuffer(make([]byte, 0, len(str)*2))
    51  	i := 0
    52  	l := len(in)
    53  	escape := false
    54  
    55  	hex := func(char byte) {
    56  		escape = true
    57  
    58  		data := []byte{BACKSLASH, 'x', 0, 0}
    59  		hex.Encode(data[2:], []byte{char})
    60  		out.Write(data)
    61  	}
    62  
    63  	backslash := func(char byte) {
    64  		escape = true
    65  		out.Write([]byte{BACKSLASH, char})
    66  	}
    67  
    68  	escaped := func(str string) {
    69  		escape = true
    70  		out.WriteString(str)
    71  	}
    72  
    73  	quoted := func(char byte) {
    74  		escape = true
    75  		out.WriteByte(char)
    76  	}
    77  
    78  	literal := func(char byte) {
    79  		out.WriteByte(char)
    80  	}
    81  
    82  	for i < l {
    83  		char := in[i]
    84  		switch {
    85  		case char == TAB:
    86  			escaped(`\t`)
    87  		case char == LF:
    88  			escaped(`\n`)
    89  		case char == CR:
    90  			escaped(`\r`)
    91  		case char <= US:
    92  			hex(char)
    93  		case char <= AMPERSTAND:
    94  			quoted(char)
    95  		case char == SINGLE_QUOTE:
    96  			backslash(char)
    97  		case char <= PLUS:
    98  			quoted(char)
    99  		case char <= NINE:
   100  			literal(char)
   101  		case char <= QUESTION:
   102  			quoted(char)
   103  		case char <= LOWERCASE_Z:
   104  			literal(char)
   105  		case char == OPEN_BRACKET:
   106  			quoted(char)
   107  		case char == BACKSLASH:
   108  			backslash(char)
   109  		case char <= CLOSE_BRACKET:
   110  			quoted(char)
   111  		case char == UNDERSCORE:
   112  			literal(char)
   113  		case char <= BACKTICK:
   114  			quoted(char)
   115  		case char <= TILDA:
   116  			quoted(char)
   117  		case char == DEL:
   118  			hex(char)
   119  		default:
   120  			hex(char)
   121  		}
   122  		i++
   123  	}
   124  
   125  	outStr := out.String()
   126  
   127  	if escape {
   128  		outStr = "$'" + outStr + "'"
   129  	}
   130  
   131  	return outStr
   132  }
   133  
   134  func ToBackslash(path string) string {
   135  	return strings.Replace(path, "/", "\\", -1)
   136  }
   137  
   138  func ToSlash(path string) string {
   139  	return strings.Replace(path, "\\", "/", -1)
   140  }