Module: Ronin::Support::Encoding::JS

Defined in:
lib/ronin/support/encoding/js.rb

Overview

Contains methods for encoding/decoding escaping/unescaping JavaScript data.

Core-Ext Methods

Since:

  • 1.0.0

Constant Summary collapse

ESCAPE_BYTES =

Special JavaScript bytes and their escaped Strings.

Since:

  • 1.0.0

{
  0x00 => '\u0000',
  0x01 => '\u0001',
  0x02 => '\u0002',
  0x03 => '\u0003',
  0x04 => '\u0004',
  0x05 => '\u0005',
  0x06 => '\u0006',
  0x07 => '\u0007',
  0x08 => '\b',
  0x09 => '\t',
  0x0a => '\n',
  0x0b => '\u000b',
  0x0c => '\f',
  0x0d => '\r',
  0x0e => '\u000e',
  0x0f => '\u000f',
  0x10 => '\u0010',
  0x11 => '\u0011',
  0x12 => '\u0012',
  0x13 => '\u0013',
  0x14 => '\u0014',
  0x15 => '\u0015',
  0x16 => '\u0016',
  0x17 => '\u0017',
  0x18 => '\u0018',
  0x19 => '\u0019',
  0x1a => '\u001a',
  0x1b => '\u001b',
  0x1c => '\u001c',
  0x1d => '\u001d',
  0x1e => '\u001e',
  0x1f => '\u001f',
  0x22 => '\"',
  0x5c => '\\\\'
}
BACKSLASHED_CHARS =

JavaScript characters that must be back-slashed.

Since:

  • 1.0.0

{
  "\\b"  => "\b",
  "\\t"  => "\t",
  "\\n"  => "\n",
  "\\f"  => "\f",
  "\\r"  => "\r",
  "\\\"" => "\"",
  "\\'"  => "'",
  "\\\\" => "\\"
}

Class Method Summary collapse

Class Method Details

.decode(data) ⇒ String

Alias for unescape.

Parameters:

  • data (String)

    The escaped JavaScript data.

Returns:

  • (String)

    The unescaped JavaScript String.

See Also:

Since:

  • 1.0.0



248
249
250
# File 'lib/ronin/support/encoding/js.rb', line 248

def self.decode(data)
  unescape(data)
end

.encode(data) ⇒ String

JavaScript escapes every character of the String.

Examples:

Encoding::JS.encode("hello")
# => "\\u0068\\u0065\\u006C\\u006C\\u006F"

Parameters:

  • data (String)

    The data to JavaScript escape.

Returns:

  • (String)

    The JavaScript escaped String.

Since:

  • 1.0.0



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/ronin/support/encoding/js.rb', line 221

def self.encode(data)
  encoded = String.new

  if data.valid_encoding?
    data.each_codepoint do |codepoint|
      encoded << encode_byte(codepoint)
    end
  else
    data.each_byte do |byte|
      encoded << encode_byte(byte)
    end
  end

  return encoded
end

.encode_byte(byte) ⇒ String

Encodes the byte as a JavaScript character.

Examples:

Encoding::JS.encode_byte(0x41)
# => "\\x41"

Parameters:

  • byte (Integer)

    The byte to encode.

Returns:

  • (String)

    The encoded JavaScript character.

Since:

  • 1.0.0



124
125
126
127
128
# File 'lib/ronin/support/encoding/js.rb', line 124

def self.encode_byte(byte)
  if byte > 0xff then "\\u%.4X" % byte
  else                "\\x%.2X" % byte
  end
end

.escape(data) ⇒ String

Escapes a String for JavaScript.

Examples:

"hello\nworld\n".js_escape
# => "hello\\nworld\\n"

Parameters:

  • data (String)

    The data to JavaScript escape.

Returns:

  • (String)

    The JavaScript escaped String.

Since:

  • 1.0.0



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ronin/support/encoding/js.rb', line 155

def self.escape(data)
  escaped = String.new

  if data.valid_encoding?
    data.each_codepoint do |codepoint|
      escaped << escape_byte(codepoint)
    end
  else
    data.each_byte do |byte|
      escaped << escape_byte(byte)
    end
  end

  return escaped
end

.escape_byte(byte) ⇒ String

Escapes the byte as a JavaScript character.

Examples:

Encoding::JS.escape_byte(0x41)
# => "A"
Encoding::JS.escape_byte(0x22)
# => "\\\""
Encoding::JS.escape_byte(0x7f)
# => "\\x7F"

Parameters:

  • byte (Integer)

    The byte to escape.

Returns:

  • (String)

    The escaped JavaScript character.

Since:

  • 1.0.0



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ronin/support/encoding/js.rb', line 97

def self.escape_byte(byte)
  if byte >= 0x00 && byte <= 0xff
    ESCAPE_BYTES.fetch(byte) do
      if byte >= 0x20 && byte <= 0x7e
        byte.chr
      else
        encode_byte(byte)
      end
    end
  else
    encode_byte(byte)
  end
end

.quote(data) ⇒ String

Converts the String into a JavaScript string.

Examples:

Encoding::JS.quote("hello\nworld\n")
# => "\"hello\\nworld\\n\""

Parameters:

  • data (String)

    The data to escape and quote.

Returns:

  • (String)

    The unquoted and unescaped String.

Since:

  • 1.0.0



265
266
267
# File 'lib/ronin/support/encoding/js.rb', line 265

def self.quote(data)
  "\"#{escape(data)}\""
end

.unescape(data) ⇒ String

Unescapes a JavaScript escaped String.

Examples:

Encoding::JS.unescape("\\u0068\\u0065\\u006C\\u006C\\u006F world")
# => "hello world"

Parameters:

  • data (String)

    The escaped JavaScript data.

Returns:

  • (String)

    The unescaped JavaScript String.

Since:

  • 1.0.0



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/ronin/support/encoding/js.rb', line 184

def self.unescape(data)
  unescaped = String.new(encoding: Encoding::UTF_8)
  scanner   = StringScanner.new(data)

  until scanner.eos?
    unescaped << if (backslash_escape = scanner.scan(/\\[btnfr'"\\]/))
                   BACKSLASHED_CHARS[backslash_escape]
                 elsif (surrogate_pair = scanner.scan(/\\u[dD][890abAB][0-9a-fA-F]{2}\\u[dD][cdefCDEF][0-9a-fA-F]{2}/))
                   hi = surrogate_pair[2..6].to_i(16)
                   lo = surrogate_pair[8..12].to_i(16)

                   (0x1_0000 + ((hi - 0xd800) * 0x400) + (lo - 0xdc00))
                 elsif (unicode_escape = scanner.scan(/[\\%]u[0-9a-fA-F]{1,4}/))
                   unicode_escape[2..].to_i(16)
                 elsif (hex_escape     = scanner.scan(/[\\%][0-9a-fA-F]{1,2}/))
                   hex_escape[1..].to_i(16)
                 else
                   scanner.getch
                 end
  end

  return unescaped
end

.unquote(data) ⇒ String

Removes the quotes an unescapes a JavaScript string.

Examples:

Encoding::JS.unquote("\"hello\\nworld\"")
# => "hello\nworld"

Parameters:

  • data (String)

    The JavaScript string to unquote.

Returns:

  • (String)

    The un-quoted String if the String begins and ends with quotes, or the same String if it is not quoted.

Since:

  • 1.0.0



283
284
285
286
287
288
289
290
# File 'lib/ronin/support/encoding/js.rb', line 283

def self.unquote(data)
  if ((data[0] == '"' && data[-1] == '"') ||
      (data[0] == "'" && data[-1] == "'"))
    unescape(data[1..-2])
  else
    data
  end
end