joliegg 0.1.0 → 0.2.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/lib/jolie/moderation/url_blocklist.rb +64 -31
- data/lib/jolie/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9191af5aa744f9251907a02c5951ab251e88e1398ba40f4f78103a38b94e7cf8
|
|
4
|
+
data.tar.gz: 226262ee89d48d83d33401b7328bb1160b8053d8380e07eb4d92604afdb9a0b6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a481cda89dd46a9294df6165357656feac6f502610fecb3dfbc37d7c795dae59b8768cc99bb3a1cad75df7ceca6d0b6229c7181488203499fda7f11a816eeb9
|
|
7
|
+
data.tar.gz: 2a137407c21298fb394312b8cb916f16cc6dfff2c907bdb6fdb9465d3ab40091a9f14e00a170c55dbbb0a3d9571fc3616af9739297016eefefca6e2553428fbd
|
|
@@ -43,37 +43,48 @@ module Jolie
|
|
|
43
43
|
find_in(shorteners, input)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
# Reduces a URL, bare domain, or email address to
|
|
46
|
+
# Reduces a URL, bare domain, or email address to its primary host:
|
|
47
47
|
# "User@Sub.Example.COM" -> "sub.example.com"
|
|
48
48
|
# "HTTPS://example.com:8080/a?b" -> "example.com"
|
|
49
49
|
# "a/b@mailinator.com" -> "mailinator.com"
|
|
50
50
|
# "example.com." -> "example.com"
|
|
51
|
-
# Returns "" when nothing host-like can be extracted.
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# A schemeless input containing @ is treated as an email address FIRST:
|
|
55
|
-
# the local part may legally contain / ? # (RFC 5322 atext), so applying
|
|
56
|
-
# URL delimiters to it would sever the domain ("a/b@mailinator.com" would
|
|
57
|
-
# otherwise read as host "a"). The host is everything after the LAST @.
|
|
58
|
-
#
|
|
59
|
-
# With a scheme:// present it's a URL: the authority is isolated BEFORE
|
|
60
|
-
# any @ handling, so an @ in the path/query/fragment
|
|
61
|
-
# ("/redirect?to=user@mailinator.com") is never mistaken for userinfo,
|
|
62
|
-
# and only the LAST @ within the authority is the userinfo delimiter (per
|
|
63
|
-
# RFC 3986), so "example.com@evil.example" still resolves to
|
|
64
|
-
# "evil.example".
|
|
51
|
+
# Returns "" when nothing host-like can be extracted. This is the FIRST
|
|
52
|
+
# candidate host; matching uses candidate_hosts, which can hold both
|
|
53
|
+
# readings of an ambiguous input.
|
|
65
54
|
def extract_host(input)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if !candidate.match?(%r{\A[a-z][a-z0-9+.-]*://}) && candidate.include?("@")
|
|
69
|
-
return candidate.split("@").last.to_s.sub(/:\d*\z/, "").sub(/\.\z/, "")
|
|
70
|
-
end
|
|
55
|
+
candidate_hosts(input).first.to_s
|
|
56
|
+
end
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
# Every host an input may resolve to, deduplicated, most likely reading
|
|
59
|
+
# first. Whitespace is stripped EVERYWHERE (not just the ends), matching
|
|
60
|
+
# the normalization URL validators and crawlers apply before resolving —
|
|
61
|
+
# "https://mai linator.com" resolves to mailinator.com for them, so it
|
|
62
|
+
# must match here too.
|
|
63
|
+
#
|
|
64
|
+
# - With a scheme:// the URL authority only: an @ later in the URL is
|
|
65
|
+
# path/query content, not userinfo, and only the LAST @ within the
|
|
66
|
+
# authority is the userinfo delimiter (RFC 3986), so
|
|
67
|
+
# "example.com@evil.example" resolves to "evil.example".
|
|
68
|
+
# - Schemeless with an @ is ambiguous: an email whose local part may
|
|
69
|
+
# legally contain / ? # (RFC 5322 atext — "a/b@mailinator.com"), or a
|
|
70
|
+
# bare URL carrying an @ ("mailinator.com/path@allowed.example", whose
|
|
71
|
+
# crawled host is mailinator.com). Both readings are returned so
|
|
72
|
+
# neither interpretation slips a listed host past the guard.
|
|
73
|
+
# - Otherwise the bare host itself.
|
|
74
|
+
def candidate_hosts(input)
|
|
75
|
+
candidate = input.to_s.downcase.gsub(/\s+/, "")
|
|
76
|
+
return [] if candidate.empty?
|
|
77
|
+
|
|
78
|
+
hosts =
|
|
79
|
+
if candidate.match?(%r{\A[a-z][a-z0-9+.-]*://})
|
|
80
|
+
[authority_host(candidate)]
|
|
81
|
+
elsif candidate.include?("@")
|
|
82
|
+
[candidate.split("@").last.to_s, authority_host(candidate)]
|
|
83
|
+
else
|
|
84
|
+
[authority_host(candidate)]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
hosts.map { |host| normalize_host(host) }.reject(&:empty?).uniq
|
|
77
88
|
end
|
|
78
89
|
|
|
79
90
|
def blocklist
|
|
@@ -98,18 +109,40 @@ module Jolie
|
|
|
98
109
|
@shorteners = nil
|
|
99
110
|
end
|
|
100
111
|
|
|
112
|
+
# The candidate host that produced a blocklist match, or nil — e.g.
|
|
113
|
+
# "sub.mailinator.com" for a match on entry "mailinator.com".
|
|
114
|
+
def matched_host(input)
|
|
115
|
+
match_in(blocklist, input)&.last
|
|
116
|
+
end
|
|
117
|
+
|
|
101
118
|
def find_in(set, input)
|
|
102
|
-
|
|
103
|
-
|
|
119
|
+
match_in(set, input)&.first
|
|
120
|
+
end
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
(
|
|
107
|
-
|
|
108
|
-
|
|
122
|
+
def match_in(set, input)
|
|
123
|
+
candidate_hosts(input).each do |host|
|
|
124
|
+
parts = host.split(".")
|
|
125
|
+
(parts.length - 1).downto(0) do |index|
|
|
126
|
+
suffix = parts[index..].join(".")
|
|
127
|
+
return [suffix, host] if set.include?(suffix)
|
|
128
|
+
end
|
|
109
129
|
end
|
|
110
130
|
nil
|
|
111
131
|
end
|
|
112
132
|
|
|
133
|
+
# The host out of a URL authority: strips any scheme, cuts path/query/
|
|
134
|
+
# fragment, and keeps only what follows the LAST @ (userinfo delimiter).
|
|
135
|
+
def authority_host(candidate)
|
|
136
|
+
candidate
|
|
137
|
+
.sub(%r{\A[a-z][a-z0-9+.-]*://}, "")
|
|
138
|
+
.split(%r{[/\\?#]}).first.to_s
|
|
139
|
+
.split("@").last.to_s
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def normalize_host(host)
|
|
143
|
+
host.sub(/:\d*\z/, "").sub(/\.\z/, "")
|
|
144
|
+
end
|
|
145
|
+
|
|
113
146
|
def load_set(path)
|
|
114
147
|
Set.new(JSON.parse(File.read(path)))
|
|
115
148
|
end
|
data/lib/jolie/version.rb
CHANGED