html-pipeline 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGELOG.md +6 -0
- data/lib/html/pipeline/camo_filter.rb +33 -10
- data/lib/html/pipeline/version.rb +1 -1
- data/test/html/pipeline/camo_filter_test.rb +41 -8
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a991b217bf4c9c658d1843fe35e6a9ba989b180
|
4
|
+
data.tar.gz: 24763a9cac62ba2047a64e2c42bfee4107e00ae3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8433da8334030909b29622d615aa693117c89fdcb06ce581d2dfae7e1a14dee705e3c60fbfbebb8d1c1227ee80d279aded108a1d7491305279d0994195b03c2c
|
7
|
+
data.tar.gz: 34cd18428fdf6b408347ffc6d5e5eb95e6f6ee0dfff098b2a5114ecbb73bc4f78931baabaee145abf070cd2b2df6e1edfb6d28a9b6ad49d53c5ccb156db006d2
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'openssl'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module HTML
|
4
5
|
class Pipeline
|
@@ -13,27 +14,34 @@ module HTML
|
|
13
14
|
# Context options:
|
14
15
|
# :asset_proxy (required) - Base URL for constructed asset proxy URLs.
|
15
16
|
# :asset_proxy_secret_key (required) - The shared secret used to encode URLs.
|
17
|
+
# :asset_proxy_whitelist - Array of host Strings or Regexps to skip
|
18
|
+
# src rewriting.
|
16
19
|
#
|
17
20
|
# This filter does not write additional information to the context.
|
18
21
|
class CamoFilter < Filter
|
19
22
|
# Hijacks images in the markup provided, replacing them with URLs that
|
20
23
|
# go through the github asset proxy.
|
21
24
|
def call
|
25
|
+
return unless asset_proxy_enabled?
|
26
|
+
|
22
27
|
doc.search("img").each do |element|
|
23
28
|
next if element['src'].nil?
|
24
|
-
src = element['src'].strip
|
25
|
-
src = src.sub(%r!^http://github.com!, 'https://github.com')
|
26
|
-
next if context[:disable_asset_proxy]
|
27
29
|
|
28
|
-
|
29
|
-
element['src']
|
30
|
-
|
31
|
-
|
30
|
+
begin
|
31
|
+
uri = URI.parse(element['src'])
|
32
|
+
rescue Exception
|
33
|
+
next
|
32
34
|
end
|
35
|
+
|
36
|
+
next if uri.host.nil?
|
37
|
+
next if asset_host_whitelisted?(uri.host)
|
38
|
+
|
39
|
+
element['src'] = asset_proxy_url(uri.to_s)
|
40
|
+
element['data-canonical-src'] = uri.to_s
|
33
41
|
end
|
34
42
|
doc
|
35
43
|
end
|
36
|
-
|
44
|
+
|
37
45
|
# Implementation of validate hook.
|
38
46
|
# Errors should raise exceptions or use an existing validator.
|
39
47
|
def validate
|
@@ -51,7 +59,12 @@ module HTML
|
|
51
59
|
OpenSSL::HMAC.hexdigest(digest, asset_proxy_secret_key, url)
|
52
60
|
end
|
53
61
|
|
54
|
-
# Private:
|
62
|
+
# Private: Return true if asset proxy filter should be enabled
|
63
|
+
def asset_proxy_enabled?
|
64
|
+
!context[:disable_asset_proxy]
|
65
|
+
end
|
66
|
+
|
67
|
+
# Private: the host to use for generated asset proxied URLs.
|
55
68
|
def asset_proxy_host
|
56
69
|
context[:asset_proxy]
|
57
70
|
end
|
@@ -60,6 +73,16 @@ module HTML
|
|
60
73
|
context[:asset_proxy_secret_key]
|
61
74
|
end
|
62
75
|
|
76
|
+
def asset_proxy_whitelist
|
77
|
+
context[:asset_proxy_whitelist] || []
|
78
|
+
end
|
79
|
+
|
80
|
+
def asset_host_whitelisted?(host)
|
81
|
+
asset_proxy_whitelist.any? do |test|
|
82
|
+
test.is_a?(String) ? host == test : test.match(host)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
63
86
|
# Private: helper to hexencode a string. Each byte ends up encoded into
|
64
87
|
# two characters, zero padded value in the range [0-9a-f].
|
65
88
|
def hexencode(str)
|
@@ -67,4 +90,4 @@ module HTML
|
|
67
90
|
end
|
68
91
|
end
|
69
92
|
end
|
70
|
-
end
|
93
|
+
end
|
@@ -8,7 +8,8 @@ class HTML::Pipeline::CamoFilterTest < Test::Unit::TestCase
|
|
8
8
|
@asset_proxy_secret_key = 'ssssh-secret'
|
9
9
|
@options = {
|
10
10
|
:asset_proxy => @asset_proxy_url,
|
11
|
-
:asset_proxy_secret_key => @asset_proxy_secret_key
|
11
|
+
:asset_proxy_secret_key => @asset_proxy_secret_key,
|
12
|
+
:asset_proxy_whitelist => [/(^|\.)github\.com$/]
|
12
13
|
}
|
13
14
|
end
|
14
15
|
|
@@ -16,17 +17,49 @@ class HTML::Pipeline::CamoFilterTest < Test::Unit::TestCase
|
|
16
17
|
orig = %(<p><img src="http://twitter.com/img.png"></p>)
|
17
18
|
assert_includes 'img src="' + @asset_proxy_url,
|
18
19
|
CamoFilter.call(orig, @options).to_s
|
20
|
+
assert_includes 'data-canonical-src="http://twitter.com/img.png"',
|
21
|
+
CamoFilter.call(orig, @options).to_s
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
22
|
-
orig = %(<p><img src="
|
24
|
+
def test_doesnt_rewrite_dotcom_image_urls
|
25
|
+
orig = %(<p><img src="https://github.com/img.png"></p>)
|
23
26
|
assert_equal "<p><img src=\"https://github.com/img.png\"></p>",
|
24
27
|
CamoFilter.call(orig, @options).to_s
|
25
28
|
end
|
26
29
|
|
27
|
-
def
|
30
|
+
def test_doesnt_rewrite_dotcom_subdomain_image_urls
|
31
|
+
orig = %(<p><img src="https://raw.github.com/img.png"></p>)
|
32
|
+
assert_equal "<p><img src=\"https://raw.github.com/img.png\"></p>",
|
33
|
+
CamoFilter.call(orig, @options).to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_doesnt_rewrite_dotcom_subsubdomain_image_urls
|
37
|
+
orig = %(<p><img src="https://f.assets.github.com/img.png"></p>)
|
38
|
+
assert_equal "<p><img src=\"https://f.assets.github.com/img.png\"></p>",
|
39
|
+
CamoFilter.call(orig, @options).to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_camouflaging_github_prefixed_image_urls
|
43
|
+
orig = %(<p><img src="https://notgithub.com/img.png"></p>)
|
44
|
+
assert_includes 'img src="' + @asset_proxy_url,
|
45
|
+
CamoFilter.call(orig, @options).to_s
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_doesnt_rewrite_absolute_image_urls
|
49
|
+
orig = %(<p><img src="/img.png"></p>)
|
50
|
+
assert_equal "<p><img src=\"/img.png\"></p>",
|
51
|
+
CamoFilter.call(orig, @options).to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_doesnt_rewrite_relative_image_urls
|
55
|
+
orig = %(<p><img src="img.png"></p>)
|
56
|
+
assert_equal "<p><img src=\"img.png\"></p>",
|
57
|
+
CamoFilter.call(orig, @options).to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_camouflaging_https_image_urls
|
28
61
|
orig = %(<p><img src="https://foo.com/img.png"></p>)
|
29
|
-
|
62
|
+
assert_includes 'img src="' + @asset_proxy_url,
|
30
63
|
CamoFilter.call(orig, @options).to_s
|
31
64
|
end
|
32
65
|
|
@@ -36,10 +69,10 @@ class HTML::Pipeline::CamoFilterTest < Test::Unit::TestCase
|
|
36
69
|
CamoFilter.call(orig, @options).to_s
|
37
70
|
end
|
38
71
|
end
|
39
|
-
|
72
|
+
|
40
73
|
def test_required_context_validation
|
41
|
-
exception = assert_raise(ArgumentError) {
|
42
|
-
CamoFilter.call("", {})
|
74
|
+
exception = assert_raise(ArgumentError) {
|
75
|
+
CamoFilter.call("", {})
|
43
76
|
}
|
44
77
|
assert_match /:asset_proxy[^_]/, exception.message
|
45
78
|
assert_match /:asset_proxy_secret_key/, exception.message
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html-pipeline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Tomayko
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
version: '0'
|
116
116
|
requirements: []
|
117
117
|
rubyforge_project:
|
118
|
-
rubygems_version: 2.0.
|
118
|
+
rubygems_version: 2.0.14
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: Helpers for processing content through a chain of filters
|