jsobfu 0.1.9 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/jsobfu.rb +4 -3
- data/lib/jsobfu/obfuscator.rb +17 -6
- data/spec/integration_spec.rb +1 -1
- data/spec/jsobfu/obfuscator_spec.rb +34 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OWVkOTRmZDM5ZDZmYzkwOGFhNGM4MDk0ZjQ3NzljZWVkMWI4OWQwMg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MGQzZGZkMTAxZDUxZmJjZjNhNzc0YzE0NDFkNDQ0MzI4ZjJiYTc4MQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZjA5NzRkNWZmMzQ0MDA0ZTkxZWRjMjYyYzc1NWEwZDE5YzcwMDNlZTZiN2E3
|
10
|
+
YTczZmQzZGMxODk1MzBlOTY5NjQwYzIxNTNmZTk5MjdlMzBlZmQ1ZGFiODRm
|
11
|
+
YThhYjAyMjhlYzhiZjliNzg2ZGZlOTc2ZmEwNDliZWNlOTg4MzU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NzhkYTM0OTRlM2EwYzgwNzQ2NmI2MGNhOTUzMDVmMjYzYzk4YmQyOTk3Y2Y2
|
14
|
+
ZmJiMTQyZDAwZGJhZGM2YzhlMzQzODAxMjA1MjlhYjE5NDA2NWEzODI0MWQ2
|
15
|
+
M2JmMzEzMjkyMzhjMWJkNWMwMmQyODU1Zjg4MzcyZWU1MTRjMzQ=
|
data/lib/jsobfu.rb
CHANGED
@@ -47,6 +47,8 @@ class JSObfu
|
|
47
47
|
# the output code (true)
|
48
48
|
# @option opts [Integer] :iterations number of times to run the
|
49
49
|
# obfuscator on this code (1)
|
50
|
+
# @option opts [String] :global the global object to rewrite unresolved lookups to.
|
51
|
+
# Depending on the environment, it may be `window`, `global`, or `this`.
|
50
52
|
# @return [self]
|
51
53
|
def obfuscate(opts={})
|
52
54
|
return self if JSObfu.disabled?
|
@@ -55,7 +57,7 @@ class JSObfu
|
|
55
57
|
strip_whitespace = opts.fetch(:strip_whitespace, true)
|
56
58
|
|
57
59
|
iterations.times do |i|
|
58
|
-
obfuscator = JSObfu::Obfuscator.new(scope: @scope)
|
60
|
+
obfuscator = JSObfu::Obfuscator.new(opts.merge(scope: @scope))
|
59
61
|
@code = obfuscator.accept(ast).to_s
|
60
62
|
if strip_whitespace
|
61
63
|
@code.gsub!(/(^\s+|\s+$)/, '')
|
@@ -98,8 +100,7 @@ protected
|
|
98
100
|
# Generate an Abstract Syntax Tree (#ast) for later obfuscation
|
99
101
|
#
|
100
102
|
def parse
|
101
|
-
|
102
|
-
@ast = parser.parse(@code)
|
103
|
+
@ast = RKelly::Parser.new.parse(@code)
|
103
104
|
end
|
104
105
|
|
105
106
|
end
|
data/lib/jsobfu/obfuscator.rb
CHANGED
@@ -5,17 +5,22 @@ class JSObfu::Obfuscator < JSObfu::ECMANoWhitespaceVisitor
|
|
5
5
|
# @return [JSObfu::Scope] the scope maintained while walking the ast
|
6
6
|
attr_reader :scope
|
7
7
|
|
8
|
-
# Note: At a high level #renames is not that useful, because var shadowing can
|
9
|
-
# cause multiple variables in different contexts to be mapped separately.
|
10
|
-
# - joev
|
11
|
-
|
12
8
|
# @return [Hash] of original var/fn names to our new random neames
|
13
9
|
attr_reader :renames
|
14
10
|
|
11
|
+
# @return [String] the global object in this JS environment
|
12
|
+
attr_reader :global
|
13
|
+
|
14
|
+
# unresolved lookups are rewritten as property lookups on the global object
|
15
|
+
DEFAULT_GLOBAL = 'window'
|
16
|
+
|
15
17
|
# @param opts [Hash] the options hash
|
16
18
|
# @option opts [JSObfu::Scope] :scope the optional scope to save vars to
|
19
|
+
# @option opts [String] :global the global object to rewrite unresolved lookups to.
|
20
|
+
# Depending on the environment, it may be `window`, `global`, or `this`.
|
17
21
|
def initialize(opts={})
|
18
22
|
@scope = opts.fetch(:scope, JSObfu::Scope.new)
|
23
|
+
@global = opts.fetch(:global, DEFAULT_GLOBAL).to_s
|
19
24
|
@renames = {}
|
20
25
|
super()
|
21
26
|
end
|
@@ -87,8 +92,14 @@ class JSObfu::Obfuscator < JSObfu::ECMANoWhitespaceVisitor
|
|
87
92
|
o.value = JSObfu::Utils::random_var_encoding(new_val)
|
88
93
|
super
|
89
94
|
else
|
90
|
-
|
91
|
-
|
95
|
+
if o.value.to_s == global.to_s
|
96
|
+
# if the ref is the global object, don't obfuscate it on itself. This helps
|
97
|
+
# "shimmed" globals (like `window=this` at the top of the script) work reliably.
|
98
|
+
super
|
99
|
+
else
|
100
|
+
# A global is used, at least obfuscate the lookup
|
101
|
+
"#{global}[#{JSObfu::Utils::transform_string(o.value, scope, :quotes => false)}]"
|
102
|
+
end
|
92
103
|
end
|
93
104
|
end
|
94
105
|
|
data/spec/integration_spec.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rkelly'
|
3
|
+
|
4
|
+
describe JSObfu::Obfuscator do
|
5
|
+
let(:opts) { { } }
|
6
|
+
subject(:obfuscator) { described_class.new(opts) }
|
7
|
+
|
8
|
+
describe 'the :global option' do
|
9
|
+
let(:global_str) { 'BLAHBLAH' }
|
10
|
+
let(:opts) { { global: global_str } }
|
11
|
+
let(:simple_js) { 'x;' }
|
12
|
+
let(:simple_ast) { RKelly::Parser.new.parse(simple_js) }
|
13
|
+
|
14
|
+
it 'rewrites unresolved lookups as property lookups on the specified global object' do
|
15
|
+
expect(obfuscator.accept(simple_ast).to_s).to include(global_str)
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when the code contains `this`' do
|
19
|
+
let(:simple_js) { 'this;' }
|
20
|
+
it 'never rewrites `this`' do
|
21
|
+
expect(obfuscator.accept(simple_ast).to_s).not_to include(global_str)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when the global object is specified' do
|
26
|
+
let(:global_str) { 'mywindow2' }
|
27
|
+
let(:simple_js) { "mywindow2;" }
|
28
|
+
it 'never rewrites itself' do
|
29
|
+
expect(obfuscator.accept(simple_ast).to_s).to eq(simple_js)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsobfu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Lee
|
@@ -114,6 +114,7 @@ files:
|
|
114
114
|
- spec/integration_spec.rb
|
115
115
|
- spec/jsobfu/disable_spec.rb
|
116
116
|
- spec/jsobfu/hoister_spec.rb
|
117
|
+
- spec/jsobfu/obfuscator_spec.rb
|
117
118
|
- spec/jsobfu/scope_spec.rb
|
118
119
|
- spec/jsobfu/utils_spec.rb
|
119
120
|
- spec/jsobfu_spec.rb
|