ctf-party 2.1.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a891b890cdf81188caac863846fef9ddd4492126a34645de0bb9c09d4e4ab44
4
- data.tar.gz: bcce5f84823d802900e4d1ff7750eb1a58c370d26f1895603091a237a62e7f2b
3
+ metadata.gz: 41082df14f844e9d331e06352e00af3ab29af0899ad4a54f911ee6cef946258b
4
+ data.tar.gz: ffb31de3ffd71d581c277f10ff0be95e9eaf2e75c161df8af1f9b8d415af64fc
5
5
  SHA512:
6
- metadata.gz: ce15b05e7b38dfe927a6c7035d07fe843f2106b3897d716f685f7b98c3b1a851b09337657d8ee46916c2e7f36aa9ff1a48462b23c989357ad8be59f701e26c9e
7
- data.tar.gz: f76df14283f2002dec8896e1b21ecf0bfb1cf4b778340a000074406a03558c483f262aa026912876cdca34c8353a5a949e8873b4e4fc537640d1e2aa65975e8d
6
+ metadata.gz: e09eff292c815cb2a5de04f8ae901a9ccc83ac30f7cd8b3a634b2b0674b32e3cd568cecfca774641afe23953afc1a9987d810655d236bf6f4fede7a2d48c62e2
7
+ data.tar.gz: 425e78e522566abf5a67650de204e2feea57f800d81f85dd04c87a51c0cbfea1a8096344da8eea61ab9b0a857ef2c511eacb52f97f2e92fb333274897f05b8d9
data/bin/ctf-party CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Ruby internal
5
- require 'pp'
5
+ require 'shellwords' # for shellescape cmd
6
6
  # Project internal
7
7
  require 'ctf_party'
8
8
  require 'ctf_party/version'
@@ -10,11 +10,16 @@ require 'ctf_party/version'
10
10
  require 'docopt'
11
11
 
12
12
  cmd_whitelist = {
13
+ # ctf-party commands
13
14
  alternatecase: 'Change one characte on two upcase and the other downcase',
14
15
  bin2hex: 'Encode an binary string to a hexadecimal string',
15
16
  bin2str: 'Alias for from_bin',
16
17
  dec2hex: 'Encode an decimal string to a hexadecimal string',
17
18
  dec2str: 'Alias for from_dec',
19
+ defang_domain: 'Defang domain name',
20
+ defang_email: 'Defang email address',
21
+ defang_ip: 'Defang IP address',
22
+ defang_uri: 'Defang URI',
18
23
  from_b64: 'Decode the string from base64',
19
24
  from_bin: 'Decode a binary string',
20
25
  from_dec: 'Decode a decimal string (decimal to hexadecimal then hexadecimal to string)',
@@ -29,6 +34,10 @@ cmd_whitelist = {
29
34
  leet: 'Transform into leet speak (l337 5p34k)',
30
35
  md5: 'Calculate the md5 hash of the string',
31
36
  randomcase: 'Change the case of characters randomly',
37
+ refang_domain: 'Refang domain name',
38
+ refang_email: 'Refang email address',
39
+ refang_ip: 'Refang IP address',
40
+ refang_uri: 'Refang URI',
32
41
  rmd160: 'Calculate the RIPEMD-160 hash of the string',
33
42
  rot13: 'Encrypt / Decrypt the string with Caesar cipher with a shift of 13',
34
43
  sha1: 'Calculate the sha1 hash of the string',
@@ -45,27 +54,62 @@ cmd_whitelist = {
45
54
  to_hex: 'Encode a string into hexadecimal',
46
55
  to_hexip: 'Encode a dotted decimal IP into a hexadecimal one',
47
56
  urldecode: 'URL-decode the string',
48
- urlencode: 'URL-encode the string'
57
+ urldecode_component: 'URL-decode the URL component string',
58
+ urlencode: 'URL-encode the string',
59
+ urlencode_component: 'URL-encode the URL component string',
60
+ # native string commands
61
+ bytesize: 'https://rubyapi.org/3.1/o/string#method-i-bytesize',
62
+ capitalize: 'https://rubyapi.org/3.1/o/string#method-i-capitalize',
63
+ chomp: 'https://rubyapi.org/3.1/o/string#method-i-chomp',
64
+ chop: 'https://rubyapi.org/3.1/o/string#method-i-chop',
65
+ downcase: 'https://rubyapi.org/3.1/o/string#method-i-downcase',
66
+ dump: 'https://rubyapi.org/3.1/o/string#method-i-dump',
67
+ hex: 'https://rubyapi.org/3.1/o/string#method-i-hex',
68
+ inspect: 'https://rubyapi.org/3.1/o/string#method-i-inspect',
69
+ length: 'https://rubyapi.org/3.1/o/string#method-i-length',
70
+ lstrip: 'https://rubyapi.org/3.1/o/string#method-i-lstrip',
71
+ reverse: 'https://rubyapi.org/3.1/o/string#method-i-reverse',
72
+ rstrip: 'https://rubyapi.org/3.1/o/string#method-i-rstrip',
73
+ scrub: 'https://rubyapi.org/3.1/o/string#method-i-scrub',
74
+ shellescape: 'https://rubyapi.org/3.1/o/string#method-i-shellescape',
75
+ size: 'https://rubyapi.org/3.1/o/string#method-i-size',
76
+ squeeze: 'https://rubyapi.org/3.1/o/string#method-i-squeeze',
77
+ strip: 'https://rubyapi.org/3.1/o/string#method-i-strip',
78
+ succ: 'https://rubyapi.org/3.1/o/string#method-i-succ',
79
+ swapcase: 'https://rubyapi.org/3.1/o/string#method-i-swapcase',
80
+ undump: 'https://rubyapi.org/3.1/o/string#method-i-undump',
81
+ unicode_normalize: 'https://rubyapi.org/3.1/o/string#method-i-unicode_normalize',
82
+ upcase: 'https://rubyapi.org/3.1/o/string#method-i-upcase'
49
83
  }
50
84
 
51
85
  doc = <<~DOCOPT
52
- ctf-party by noraj
86
+ ctf-party v#{Version::VERSION} by noraj
53
87
 
54
88
  Usage:
55
- ctf-party <string> <cmd>... [--debug]
89
+ ctf-party <string> <cmd>... [--row --file] [--debug]
56
90
  ctf-party --list-commands [--debug]
57
91
  ctf-party -h | --help
58
92
  ctf-party --version
59
93
 
94
+ Parameters:
95
+ <string> The string to manipulate, read from STDIN if equal to "-"
96
+ <cmd> Command to apply to the string, cf. --list-commands
97
+
60
98
  Options:
61
99
  -l, --list-commands List available commands (see https://noraj.github.io/ctf-party/yard/String.html)
100
+ -r, --row Apply the transformation to each row
101
+ -f, --file Interpret the string as a filename, if file doesn't exist it will still be treated as a string
62
102
  --debug Display arguments
63
103
  -h, --help Show this screen
64
104
  --version Show version
65
105
 
66
106
  Examples:
67
107
  ctf-party 'security' to_hex
68
- ctf-party 'NzQ2Zjc0NmY=' from_b64 hex2str str2bin
108
+ ctf-party 'NzQ2Zjc0NmY=' from_b64 hex2bin
109
+ curl -s https://example.org | ctf-party - htmlescape
110
+ seq 1 10 | ctf-party - dec2hex hex2bin --row
111
+ cut -d : -f 1 /etc/passwd | ctf-party - randomcase --row
112
+ ctf-party /etc/passwd str2hex --row --file
69
113
  DOCOPT
70
114
 
71
115
  begin
@@ -73,11 +117,24 @@ begin
73
117
  # use case 1, using the tool
74
118
  pp args if args['--debug']
75
119
  if args['<string>']
120
+ args['<string>'] = $stdin.read.chomp if args['<string>'] == '-'
121
+ args['<string>'] = File.read(args['<string>']) if args['--file'] && File.exist?(args['<string>'])
76
122
  wrong_cmd = args['<cmd>'] - cmd_whitelist.keys.map(&:to_s)
77
123
  if wrong_cmd.empty?
78
- output = args['<string>']
79
- args['<cmd>'].each do |cmd|
80
- output = output.public_send(cmd)
124
+ if args['--row']
125
+ output = ''
126
+ args['<string>'].each_line(chomp: true) do |line|
127
+ output_line = line
128
+ args['<cmd>'].each do |cmd|
129
+ output_line = output_line.public_send(cmd)
130
+ end
131
+ output += "#{output_line}\n"
132
+ end
133
+ else
134
+ output = args['<string>']
135
+ args['<cmd>'].each do |cmd|
136
+ output = output.public_send(cmd)
137
+ end
81
138
  end
82
139
  puts output
83
140
  else
@@ -85,7 +142,7 @@ begin
85
142
  end
86
143
  elsif args['--list-commands']
87
144
  cmd_whitelist.each do |k, v|
88
- puts "#{k.to_s.ljust(15)}#{v}"
145
+ puts "#{k.to_s.ljust(25)}#{v}"
89
146
  end
90
147
  end
91
148
  # use case 2, help: already handled by docopt
data/lib/ctf_party/cgi.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  # Ruby standard library
4
4
  require 'cgi'
5
+ require 'uri'
5
6
 
6
7
  class String
7
8
  # URL-encode the URL string (RFC2396)
@@ -0,0 +1,227 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'uri'
5
+
6
+ class String
7
+ # Defang the string if it is an IP address
8
+ # @param opts [Hash] optional parameters
9
+ # @option opts [Symbol] :unvalid Default value: `false`.
10
+ # If `unvalid: false`, only valid IP address will be defanged.
11
+ # If `unvalid: true`, everything is defanged.
12
+ # @return [String] the defanged string if it is a valid IP address or itself else.
13
+ # @example
14
+ # '1.1.1.1'.defang_ip # => 1[.]1[.]1[.]1
15
+ # '2606:4700:4700::1111'.defang_ip # => '2606[:]4700[:]4700[:][:]1111'
16
+ def defang_ip(opts = {})
17
+ opts[:unvalid] ||= false
18
+ if ipv4?
19
+ gsub('.', '[.]')
20
+ elsif ipv6?
21
+ gsub(':', '[:]')
22
+ elsif opts[:unvalid] == true
23
+ gsub('.', '[.]').gsub(':', '[:]')
24
+ else
25
+ self
26
+ end
27
+ end
28
+
29
+ # Defang the string in place, if it is an IP address, as described for {String#defang_ip}.
30
+ # @return [nil]
31
+ # @example
32
+ # my_str = '127.0.0.1'
33
+ # my_str.defang_ip!
34
+ # my_str # => 127[.]0[.]0[.]1
35
+ def defang_ip!(opts = {})
36
+ replace(defang_ip(opts))
37
+ end
38
+
39
+ # Refang the string if it is an IP address
40
+ # @param opts [Hash] optional parameters
41
+ # @option opts [Symbol] :unvalid Default value: `false`.
42
+ # If `unvalid: false`, only valid IP address will be refanged.
43
+ # If `unvalid: true`, everything is refanged.
44
+ # @return [String] the refanged string if it is a valid IP address or itself else.
45
+ # @example
46
+ # '1[.]1[.]1[.]1'.refang_ip # => 1.1.1.1
47
+ # '2606[:]4700[:]4700[:][:]1111'.refang_ip # => 2606:4700:4700::1111
48
+ def refang_ip(opts = {})
49
+ opts[:unvalid] ||= false
50
+ re_ipv4 = gsub('[.]', '.')
51
+ re_ipv6 = gsub('[:]', ':')
52
+ if re_ipv4.ipv4?
53
+ re_ipv4
54
+ elsif re_ipv6.ipv6?
55
+ re_ipv6
56
+ elsif opts[:unvalid] == true
57
+ gsub('[.]', '.').gsub('[:]', ':')
58
+ else
59
+ self
60
+ end
61
+ end
62
+
63
+ # Refang the string in place, if it is an IP address, as described for {String#refang_ip}.
64
+ # @return [nil]
65
+ def refang_ip!(opts = {})
66
+ replace(refang_ip(opts))
67
+ end
68
+
69
+ # Defang the string if it is an URI.
70
+ # Will defang dot for any scheme and defang scheme as well for supported ones.
71
+ # Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.
72
+ # @return [String] the defanged string if it is an URI or itself else.
73
+ # @example
74
+ # 'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.defang_uri
75
+ # # => fxp://ftp[.]ruby-lang[.]org/pub/ruby/3[.]2/ruby-3[.]2[.]0[.]tar[.]xz
76
+ def defang_uri
77
+ begin
78
+ uri = URI(self)
79
+ rescue URI::InvalidURIError, URI::InvalidComponentError => e
80
+ puts e
81
+ return gsub('.', '[.]')
82
+ end
83
+ case uri
84
+ when URI::HTTP, URI::HTTPS, URI::FTP
85
+ uri.scheme = uri.scheme.gsub(/t/i, 'x')
86
+ when URI::WS, URI::WSS
87
+ uri.scheme = uri.scheme.dup.insert(1, 'x')
88
+ when URI::LDAP, URI::LDAPS
89
+ uri.scheme = uri.scheme.dup.insert(2, 'x')
90
+ when URI::MailTo
91
+ uri.scheme = uri.scheme.dup.insert(4, 'x')
92
+ return uri.to_s.gsub('.', '[.]').gsub('@', '[@]')
93
+ end
94
+ uri.to_s.gsub('.', '[.]')
95
+ end
96
+
97
+ # Defang the string in place, if it is an URI, as described for {String#defang_uri}.
98
+ def defang_uri!
99
+ replace(defang_uri)
100
+ end
101
+
102
+ # Refang the string if it is an URI.
103
+ # Will refang dot for any scheme and refang scheme as well for supported ones.
104
+ # Supported schemes: HTTP, HTTPS, FTP, WS, WSS, LDAP, LDAPS, Mailto.
105
+ # @return [String] the refanged string if it is an URI or itself else.
106
+ # @example
107
+ # 'hxxp://noraj[.]neverssl[.]com/online/'.refang_uri # => http://noraj.neverssl.com/online/
108
+ def refang_uri
109
+ if %r{://}.match?(self)
110
+ scheme, remains = split('://', 2)
111
+ else
112
+ scheme, remains = split(':', 2)
113
+ end
114
+ case scheme
115
+ when /hxxps?/i, /fxp/i
116
+ scheme.gsub!(/x/i, 't')
117
+ when /wxss?/i, /ldxaps?/i
118
+ scheme.gsub!(/x/i, '')
119
+ when /mailxto/i
120
+ scheme.gsub!(/x/i, '')
121
+ remains.gsub!('[.]', '.')
122
+ remains.gsub!('[@]', '@')
123
+ return scheme.concat(":#{remains}")
124
+ end
125
+ remains.gsub!('[.]', '.')
126
+ if %r{://}.match?(self)
127
+ scheme.concat("://#{remains}")
128
+ else
129
+ scheme.concat(":#{remains}")
130
+ end
131
+ end
132
+
133
+ # Refang the string in place, if it is an URI, as described for {String#refang_uri}.
134
+ def refang_uri!
135
+ replace(refang_uri)
136
+ end
137
+
138
+ # Defang the string if it is a domain name
139
+ # @param opts [Hash] optional parameters
140
+ # @option opts [Symbol] :unvalid Default value: `false`.
141
+ # If `unvalid: false`, only valid domain name will be defanged.
142
+ # If `unvalid: true`, everything is defanged.
143
+ # @return [String] the defanged string if it is a valid domain name or itself else.
144
+ # @example
145
+ # 'pwn.by'.defang_domain # => pwn[.]by
146
+ def defang_domain(opts = {})
147
+ opts[:unvalid] ||= false
148
+ if domain? || opts[:unvalid] == true
149
+ gsub('.', '[.]')
150
+ else
151
+ self
152
+ end
153
+ end
154
+
155
+ # Defang the string in place, if it is a domain name, as described for {String#defang_domain}.
156
+ def defang_domain!(opts = {})
157
+ replace(defang_domain(opts))
158
+ end
159
+
160
+ # Refang the string if it is a domain name
161
+ # @param opts [Hash] optional parameters
162
+ # @option opts [Symbol] :unvalid Default value: `false`.
163
+ # If `unvalid: false`, only valid domain name will be refanged.
164
+ # If `unvalid: true`, everything is refanged.
165
+ # @return [String] the refanged string if it is a valid domain name or itself else.
166
+ # @example
167
+ # 'pwn[.]by'.refang_domain # => pwn.by
168
+ def refang_domain(opts = {})
169
+ opts[:unvalid] ||= false
170
+ re_domain = gsub('[.]', '.')
171
+ if re_domain.domain? || opts[:unvalid] == true
172
+ re_domain
173
+ else
174
+ self
175
+ end
176
+ end
177
+
178
+ # Refang the string in place, if it is a domain name, as described for {String#refang_domain}.
179
+ def refang_domain!(opts = {})
180
+ replace(refang_domain(opts))
181
+ end
182
+
183
+ # Defang the string if it is an email address
184
+ # @param opts [Hash] optional parameters
185
+ # @option opts [Symbol] :unvalid Default value: `false`.
186
+ # If `unvalid: false`, only valid email address will be defanged.
187
+ # If `unvalid: true`, everything is defanged.
188
+ # @return [String] the defanged string if it is an email address or itself else.
189
+ # @example
190
+ # 'noraj.rawsec@pwn.by'.defang_email # => noraj[.]rawsec[@]pwn[.]by
191
+ def defang_email(opts = {})
192
+ opts[:unvalid] ||= false
193
+ if email? || opts[:unvalid] == true
194
+ gsub('.', '[.]').gsub('@', '[@]')
195
+ else
196
+ self
197
+ end
198
+ end
199
+
200
+ # Defang the string in place, if it is a email address, as described for {String#defang_email}.
201
+ def defang_email!(opts = {})
202
+ replace(defang_email(opts))
203
+ end
204
+
205
+ # Refang the string if it is an email address
206
+ # @param opts [Hash] optional parameters
207
+ # @option opts [Symbol] :unvalid Default value: `false`.
208
+ # If `unvalid: false`, only valid email address will be refanged.
209
+ # If `unvalid: true`, everything is refanged.
210
+ # @return [String] the refanged string if it is a valid email address or itself else.
211
+ # @example
212
+ # 'noraj+alias[@]pwn[.]by'.refang_email # => noraj.rawsec@pwn.by
213
+ def refang_email(opts = {})
214
+ opts[:unvalid] ||= false
215
+ re_email = gsub('[.]', '.').gsub('[@]', '@')
216
+ if re_email.email? || opts[:unvalid] == true
217
+ re_email
218
+ else
219
+ self
220
+ end
221
+ end
222
+
223
+ # Refang the string in place, if it is a email address, as described for {String#refang_email}.
224
+ def refang_email!(opts = {})
225
+ replace(refang_email(opts))
226
+ end
227
+ end
data/lib/ctf_party/hex.rb CHANGED
@@ -59,8 +59,10 @@ class String
59
59
  out = ('0' * (opts[:padding] - out.size)) + out if out.size < opts[:padding]
60
60
  # char case management
61
61
  out = out.upcase if opts[:case] == :upper
62
- # adding prefix must be done after case change
63
- out = out.scan(/.{2}/).map { |x| opts[:prefixall] + x }.join
62
+ # adding prefix must be done after case change, complex conditional to avoid cropping when odd byte lenght
63
+ out = (out.size.odd? ? [out[0]] + out[1..].scan(/.{1,2}/) : out.scan(/.{2}/)).map do |x|
64
+ opts[:prefixall] + x
65
+ end.join
64
66
  return opts[:prefix] + out
65
67
  end
66
68
 
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+ require 'uri'
5
+
6
+ class String
7
+ # Is the string an IPv4?
8
+ # @return [Boolean] `true` if the string is a valid IPv4, `false` else.
9
+ # @example
10
+ # '1.1.1.1'.ipv4? # => true
11
+ # '127.0.0.300'.ipv4? # => false
12
+ def ipv4?
13
+ IPAddr.new(self).ipv4?
14
+ rescue IPAddr::InvalidAddressError
15
+ false
16
+ end
17
+
18
+ # Is the string an IPv6?
19
+ # @return [Boolean] `true` if the string is a valid IPv6, `false` else.
20
+ # @example
21
+ # '2606:4700:4700::1111'.ipv6? # => true
22
+ # 'fe80::fe80::fe80'.ipv6? # => false
23
+ def ipv6?
24
+ IPAddr.new(self).ipv6?
25
+ rescue IPAddr::InvalidAddressError
26
+ false
27
+ end
28
+
29
+ # Is the string an IP address?
30
+ # @return [Boolean] `true` if the string is a valid IP address, `false` else.
31
+ # @example
32
+ # '127.0.0.1'.ip? # => true
33
+ # '::1'.ip? # => true
34
+ def ip?
35
+ ipv4? || ipv6?
36
+ end
37
+
38
+ # Is the string a valid URI?
39
+ # @param opts [Hash] optional parameters
40
+ # @option opts [Symbol] :lax Default value: `false`.
41
+ # When `lax: false`, only URI matching common protocols (ftp http https ldap ldaps mailto ws wss) are recognized,
42
+ # but is still a bit lax (eg. `http://` is seen as valid).
43
+ # When `lax: true`, the parser will accept more types of URI (gopher magnet matrix), but will be very lax and accept
44
+ # nearly anything including `:`.
45
+ # @return [Boolean] `true` if the string is a valid URI, `false` else.
46
+ # @example
47
+ # 'ftp://ftp.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0.tar.xz'.uri? # => true
48
+ # 'a:'.uri? # => false
49
+ # 'a:'.uri?(lax: true) # => true
50
+ def uri?(opts = {})
51
+ opts[:lax] ||= false
52
+ strict = URI::DEFAULT_PARSER.make_regexp(%w[ftp http https ldap ldaps mailto ws wss]).match?(self)
53
+ lax = URI::DEFAULT_PARSER.make_regexp.match?(self)
54
+ if opts[:lax] == true
55
+ strict || lax
56
+ else
57
+ strict
58
+ end
59
+ end
60
+
61
+ # Is the string a valid domain name?
62
+ # It is a bit lax, for exemple it does not validate if the TLD really exist but
63
+ # still performs more check than many checkers.
64
+ # @return [Boolean] `true` if the string is a valid domain name, `false` else.
65
+ # @example
66
+ # 'pwn.by'.domain? # => true
67
+ # 'a.-b.net'.domain? # => false
68
+ # rubocop:disable Metrics/PerceivedComplexity
69
+ def domain?
70
+ return false unless size.between?(1, 255) # max. domain length
71
+
72
+ # split each hostname into labels
73
+ labels = split('.')
74
+ return false if labels.size > 127 # max. label number
75
+ return false if labels.size < 2 # min. label number
76
+ return false if labels.first[0] == '.' # cannot start with a dot
77
+
78
+ labels.each_with_index do |label, _index|
79
+ return false unless label.size.between?(1, 63) # max. label length
80
+ return false if label[0] == '-' || label[-1] == '-' # label cannot begin or end with hyphen
81
+ # do not set a whitelist for allowed characters ([a-z0-9\-\_]) since there can be
82
+ # Unicode IDN (without punycode transcription)
83
+ # to not deal with punycode translation and validation, let's just do pseudo-validation
84
+ # by checking only for a few illegal ones (blacklist)
85
+ return false if /\p{C}|\p{Z}/.match?(self)
86
+ # skip TLD validity check since the list is large, often change and custom TLD could be used for internal usage
87
+ end
88
+ return false if /\.\./.match?(self) # cannot contain consecutive dots
89
+
90
+ # do not check for trailing dot
91
+ true
92
+ end
93
+ # rubocop:enable Metrics/PerceivedComplexity
94
+
95
+ # Is the string a valid email address?
96
+ # @param opts [Hash] optional parameters
97
+ # @option opts [Symbol] :mode Default value: `:rfc5322`.
98
+ # Other values are `:strict` (`:rfc5322`), `:light` or `:lightwithlength`.
99
+ # ``:strict` / `:rfc5322` is the closest thing to RFC 5322.
100
+ # `:light` is a lighter more practical version of RFC 5322 that will be more useful in real life (omits IP
101
+ # addresses, domain-specific addresses, the syntax using double quotes and square brackets).
102
+ # `:lightwithlength` is the same as the light version but with length limit enforcing.
103
+ # @see https://stackoverflow.com/questions/22993545/ruby-email-validation-with-regex/75050279#75050279
104
+ # @return [Boolean] `true` if the string is a valid email address, `false` else.
105
+ # @example
106
+ # "n#{'o' * 255}raj@pwn.by".email? # => true
107
+ # "n#{'o' * 255}raj@pwn.by".email?(mode: :lightwithlength) # => false
108
+ # '"valid"@domain.com'.email?(mode: :rfc5322) # => true
109
+ # '"valid"@domain.com'.email?(mode: :light) # => false
110
+ def email?(opts = {})
111
+ opts[:mode] ||= :rfc5322
112
+ case opts[:mode]
113
+ when :strict, :rfc5322
114
+ %r{\A(?:[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*|
115
+ "(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|
116
+ \\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|
117
+ \[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|
118
+ [a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|
119
+ \\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])\z}ix.match?(self)
120
+ when :light
121
+ %r{\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
122
+ (?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
123
+ when :lightwithlength
124
+ %r{\A(?=[a-z0-9@.!#$%&'*+/=?^_‘{|}~-]{6,254}\z)
125
+ (?=[a-z0-9.!#$%&'*+/=?^_‘{|}~-]{1,64}@)[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@
126
+ (?:(?=[a-z0-9-]{1,63}\.)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
127
+ (?=[a-z0-9-]{1,63}\z)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z}ix.match?(self)
128
+ end
129
+ end
130
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Version
4
- VERSION = '2.1.0'
4
+ VERSION = '2.3.0'
5
5
  end
data/lib/ctf_party.rb CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  # Project internal
4
4
  require 'ctf_party/base64'
5
- require 'ctf_party/rot'
5
+ require 'ctf_party/binary'
6
+ require 'ctf_party/case'
7
+ require 'ctf_party/cgi'
8
+ require 'ctf_party/dec'
9
+ require 'ctf_party/defang'
6
10
  require 'ctf_party/digest'
7
11
  require 'ctf_party/flag'
8
12
  require 'ctf_party/hex'
9
- require 'ctf_party/case'
10
- require 'ctf_party/cgi'
11
- require 'ctf_party/binary'
12
13
  require 'ctf_party/leet'
13
- require 'ctf_party/dec'
14
14
  require 'ctf_party/misc'
15
+ require 'ctf_party/network'
16
+ require 'ctf_party/rot'
15
17
  require 'ctf_party/xor'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ctf-party
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre ZANNI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-31 00:00:00.000000000 Z
11
+ date: 2023-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docopt
@@ -46,11 +46,13 @@ files:
46
46
  - lib/ctf_party/case.rb
47
47
  - lib/ctf_party/cgi.rb
48
48
  - lib/ctf_party/dec.rb
49
+ - lib/ctf_party/defang.rb
49
50
  - lib/ctf_party/digest.rb
50
51
  - lib/ctf_party/flag.rb
51
52
  - lib/ctf_party/hex.rb
52
53
  - lib/ctf_party/leet.rb
53
54
  - lib/ctf_party/misc.rb
55
+ - lib/ctf_party/network.rb
54
56
  - lib/ctf_party/rot.rb
55
57
  - lib/ctf_party/version.rb
56
58
  - lib/ctf_party/xor.rb
@@ -76,14 +78,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
78
  version: 2.7.0
77
79
  - - "<"
78
80
  - !ruby/object:Gem::Version
79
- version: '3.2'
81
+ version: '3.3'
80
82
  required_rubygems_version: !ruby/object:Gem::Requirement
81
83
  requirements:
82
84
  - - ">="
83
85
  - !ruby/object:Gem::Version
84
86
  version: '0'
85
87
  requirements: []
86
- rubygems_version: 3.3.3
88
+ rubygems_version: 3.4.1
87
89
  signing_key:
88
90
  specification_version: 4
89
91
  summary: A CLI tool & library to enhance and speed up script/exploit writing with