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.fetch(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.start_with?('"') && data.end_with?('"')) ||
      (data.start_with?("'") && data.end_with?("'")))
    unescape(data[1..-2])
  else
    data
  end
end