flatulent 0.0.1 → 0.0.2

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.
Files changed (69) hide show
  1. data/README +60 -16
  2. data/flatulent-0.0.2.gem +0 -0
  3. data/lib/flatulent/crypt/blowfish-tables.rb +190 -0
  4. data/lib/flatulent/crypt/blowfish.rb +109 -0
  5. data/lib/flatulent/crypt/cbc.rb +123 -0
  6. data/lib/flatulent/crypt/gost.rb +140 -0
  7. data/lib/flatulent/crypt/idea.rb +193 -0
  8. data/lib/flatulent/crypt/noise.rb +94 -0
  9. data/lib/flatulent/crypt/purerubystringio.rb +378 -0
  10. data/lib/flatulent/crypt/rijndael-tables.rb +117 -0
  11. data/lib/flatulent/crypt/rijndael.rb +269 -0
  12. data/lib/flatulent/crypt/stringxor.rb +27 -0
  13. data/lib/flatulent.rb +332 -121
  14. data/lib/flatulent.rb.bak +337 -0
  15. data/rails/app/controllers/flatulent_controller.rb +61 -6
  16. data/rails/lib/flatulent/attributes.rb +79 -0
  17. data/rails/lib/flatulent/crypt/blowfish-tables.rb +190 -0
  18. data/rails/lib/flatulent/crypt/blowfish.rb +109 -0
  19. data/rails/lib/flatulent/crypt/cbc.rb +123 -0
  20. data/rails/lib/flatulent/crypt/gost.rb +140 -0
  21. data/rails/lib/flatulent/crypt/idea.rb +193 -0
  22. data/rails/lib/flatulent/crypt/noise.rb +94 -0
  23. data/rails/lib/flatulent/crypt/purerubystringio.rb +378 -0
  24. data/rails/lib/flatulent/crypt/rijndael-tables.rb +117 -0
  25. data/rails/lib/flatulent/crypt/rijndael.rb +269 -0
  26. data/rails/lib/flatulent/fontfiles/banner.flf +2494 -0
  27. data/rails/lib/flatulent/fontfiles/big.flf +2204 -0
  28. data/rails/lib/flatulent/fontfiles/block.flf +1691 -0
  29. data/rails/lib/flatulent/fontfiles/bubble.flf +1630 -0
  30. data/rails/lib/flatulent/fontfiles/digital.flf +1286 -0
  31. data/rails/lib/flatulent/fontfiles/ivrit.flf +900 -0
  32. data/rails/lib/flatulent/fontfiles/lean.flf +1691 -0
  33. data/rails/lib/flatulent/fontfiles/mini.flf +899 -0
  34. data/rails/lib/flatulent/fontfiles/mnemonic.flf +3702 -0
  35. data/rails/lib/flatulent/fontfiles/script.flf +1493 -0
  36. data/rails/lib/flatulent/fontfiles/shadow.flf +1097 -0
  37. data/rails/lib/flatulent/fontfiles/slant.flf +1295 -0
  38. data/rails/lib/flatulent/fontfiles/small.flf +1097 -0
  39. data/rails/lib/flatulent/fontfiles/smscript.flf +1097 -0
  40. data/rails/lib/flatulent/fontfiles/smshadow.flf +899 -0
  41. data/rails/lib/flatulent/fontfiles/smslant.flf +1097 -0
  42. data/rails/lib/flatulent/fontfiles/standard.flf +2227 -0
  43. data/rails/lib/flatulent/fontfiles/term.flf +600 -0
  44. data/rails/lib/flatulent/pervasives.rb +32 -0
  45. data/rails/lib/flatulent/stringxor.rb +27 -0
  46. data/rails/lib/flatulent/text/double_metaphone.rb +356 -0
  47. data/rails/lib/flatulent/text/figlet/font.rb +117 -0
  48. data/rails/lib/flatulent/text/figlet/smusher.rb +64 -0
  49. data/rails/lib/flatulent/text/figlet/typesetter.rb +68 -0
  50. data/rails/lib/flatulent/text/figlet.rb +17 -0
  51. data/rails/lib/flatulent/text/levenshtein.rb +65 -0
  52. data/rails/lib/flatulent/text/metaphone.rb +97 -0
  53. data/rails/lib/flatulent/text/porter_stemming.rb +171 -0
  54. data/rails/lib/flatulent/text/soundex.rb +61 -0
  55. data/rails/lib/flatulent/text.rb +6 -0
  56. data/rails/lib/flatulent.rb +450 -0
  57. data/rails/log/development.log +14297 -0
  58. data/rails/log/fastcgi.crash.log +111 -0
  59. data/rails/log/lighttpd.access.log +3993 -0
  60. data/rails/log/lighttpd.error.log +111 -0
  61. data/rails/tmp/cache/javascripts/prototype.js-gzip-3275912-71260-1183440172 +0 -0
  62. data/rails/tmp/sessions/ruby_sess.32d68bc997054475 +0 -0
  63. data/rails/tmp/sessions/ruby_sess.4694a4b9bdf9bcf4 +0 -0
  64. data/rails/tmp/sessions/ruby_sess.99469fde69043a05 +0 -0
  65. data/rails/tmp/sessions/ruby_sess.a588c0a457345912 +0 -0
  66. data/rails/tmp/sessions/ruby_sess.b3344125a84a3efa +0 -0
  67. data/samples.rb +10 -0
  68. metadata +69 -3
  69. data/flatulent-0.0.0.gem +0 -0
@@ -0,0 +1,450 @@
1
+ # TODO - encrypt time
2
+ # TODO - noise is image chars
3
+ # TODO - newline in value??
4
+ # TODO - vertical offset in chars
5
+
6
+ class Flatulent
7
+ Flatulent::VERSION = '0.0.2' unless defined? Flatulent::VERSION
8
+ def self.flatulent() Flatulent::VERSION end
9
+ def self.libdir() File.expand_path(__FILE__).gsub(%r/\.rb$/, '') end
10
+
11
+ require 'cgi'
12
+ require 'base64'
13
+ require 'digest/md5'
14
+
15
+ begin
16
+ require 'rubygems'
17
+ rescue LoadError
18
+ end
19
+
20
+ begin
21
+ $:.unshift libdir
22
+ require 'text/figlet'
23
+ require 'crypt/blowfish'
24
+ require 'pervasives'
25
+ require 'attributes'
26
+ ensure
27
+ $:.shift
28
+ end
29
+
30
+ class Error < ::StandardError; end
31
+ class EncryptionError < Error; end
32
+ class TimeBombError < Error; end
33
+
34
+
35
+ singleton_class =
36
+ class << self
37
+ self
38
+ end
39
+
40
+ singleton_class.module_eval do
41
+
42
+ attribute('fontdir'){ File.join libdir, 'fontfiles' }
43
+
44
+ attribute('style'){ Hash[
45
+ 'white-space' => 'pre',
46
+ 'font-family' => 'monospace',
47
+ 'font-weight' => 'bold',
48
+ 'font-size' => 'medium',
49
+ 'background' => '#ffc',
50
+ 'color' => '#00f',
51
+ 'margin' => '2px',
52
+ 'padding' => '2px',
53
+ 'display' => 'table',
54
+ ] }
55
+
56
+ attribute('noise_style'){ Hash[
57
+ 'color' => '#ccc',
58
+ ] }
59
+
60
+ attribute('key'){ default_key }
61
+
62
+ def valid? keywords = {}
63
+ begin
64
+ validate! keywords
65
+ true
66
+ rescue EncryptionError, TimeBombError
67
+ false
68
+ end
69
+ end
70
+
71
+ def validate! keywords = {}
72
+ keywords = keywords['flatulent'] if keywords.has_key?('flatulent')
73
+ keywords = keywords[:flatulent] if keywords.has_key?(:flatulent)
74
+
75
+ opts = getopts keywords
76
+
77
+ captcha = opts['c'] or raise 'no captcha'
78
+ string = opts['s'] or raise 'no string'
79
+ time = opts['t'] or raise 'no time'
80
+
81
+ expected = zeroh(decrypt(string))
82
+ actual = zeroh(captcha)
83
+ raise EncryptionError, "expected #{ expected } got #{ actual }" unless
84
+ expected == actual
85
+
86
+ timebomb = Time.at(Integer(decrypt(time))).utc rescue(raise("bad time #{ time }"))
87
+ raise TimeBombError unless Time.now.utc <= timebomb
88
+
89
+ return actual
90
+ end
91
+
92
+ def zeroh string
93
+ string.gsub(%r/[0Oo]/, '0') # ignore diffs between 0/o/O
94
+ end
95
+
96
+ def blowfish
97
+ @blowfish ||= Hash.new{|h,k| h[k] = Crypt::Blowfish.new(key)}
98
+ end
99
+
100
+ def munge string
101
+ string.strip.downcase
102
+ end
103
+
104
+ def encrypt string
105
+ Base64.encode64(blowfish[key].encrypt_string(string.to_s)).chop # kill "\n"
106
+ end
107
+
108
+ def decrypt string
109
+ munge(blowfish[key].decrypt_string(Base64.decode64("#{ string }\n")))
110
+ end
111
+
112
+ def getopts options
113
+ lambda do |key, *default|
114
+ default = default.first
115
+ break options[key] if options.has_key?(key)
116
+ key = key.to_s
117
+ break options[key] if options.has_key?(key)
118
+ key = key.to_sym
119
+ break options[key] if options.has_key?(key)
120
+ break default
121
+ end
122
+ end
123
+
124
+ def default_key
125
+ #attribute('default_key') do
126
+ return @default_key if defined? @default_key
127
+ require 'socket'
128
+ hostname = Socket.gethostname
129
+ maddr = mac_address rescue nil
130
+ warn "could not determine mac addresss!" unless maddr
131
+ #puts(( Digest::MD5.hexdigest "--#{ hostname }--#{ maddr }--" ))
132
+ #Digest::MD5.hexdigest "--#{ hostname }--#{ maddr }--"
133
+ #@default_key = "--#{ hostname }--#{ maddr }--"
134
+ @default_key = "--#{ hostname }--#{ maddr }--"
135
+ end
136
+
137
+ def mac_address
138
+ return @mac_address if defined? @mac_address
139
+ re = %r/[^:\-](?:[0-9A-F][0-9A-F][:\-]){5}[0-9A-F][0-9A-F][^:\-]/io
140
+ cmds = '/sbin/ifconfig', '/bin/ifconfig', 'ifconfig', 'ipconfig /all'
141
+
142
+ null = test(?e, '/dev/null') ? '/dev/null' : 'NUL'
143
+
144
+ lines = nil
145
+ cmds.each do |cmd|
146
+ stdout = IO.popen("#{ cmd } 2> #{ null }"){|fd| fd.readlines} rescue next
147
+ next unless stdout and stdout.size > 0
148
+ lines = stdout and break
149
+ end
150
+ raise "all of #{ cmds.join ' ' } failed" unless lines
151
+
152
+ candidates = lines.select{|line| line =~ re}
153
+ raise 'no mac address candidates' unless candidates.first
154
+ candidates.map!{|c| c[re]}
155
+
156
+ maddr = candidates.first
157
+ raise 'no mac address found' unless maddr
158
+
159
+ maddr.strip!
160
+ maddr.instance_eval{ @list = candidates; def list() @list end }
161
+
162
+ @mac_address = maddr
163
+ end
164
+
165
+ def figlet options = {}
166
+ new(options).figlet
167
+ end
168
+ def figlets options = {}
169
+ new(options).figlets
170
+ end
171
+ def element options = {}
172
+ new(options).element
173
+ end
174
+ def form_tags options = {}
175
+ new(options).form_tags
176
+ end
177
+ def form options = {}
178
+ new(options).form
179
+ end
180
+
181
+ def latest_prototype_lib
182
+ 'http://www.prototypejs.org/assets/2007/6/20/prototype.js'
183
+ end
184
+ def require_prototype
185
+ %Q`
186
+ <script type="text/javascript">
187
+ var prototype = true;
188
+ try{ Prototype; } catch(e) { prototype = false };
189
+ if(!prototype){
190
+ var js = document.createElement('script');
191
+ js.type='text/javascript';
192
+ js.src='/javascripts/prototype.js';
193
+ document.getElementsByTagName('head')[0].appendChild(js);
194
+ }
195
+ </script>
196
+ <script type="text/javascript">
197
+ var prototype = true;
198
+ try{ Prototype; } catch(e) { prototype = false };
199
+ if(!prototype){
200
+ var js = document.createElement('script');
201
+ js.type='text/javascript';
202
+ js.src='#{ latest_prototype_lib }';
203
+ document.getElementsByTagName('head')[0].appendChild(js);
204
+ }
205
+ </script>
206
+ `
207
+ end
208
+ def javascript options = {}
209
+ id = options[:id] || options['id'] || 'flatulent'
210
+ url = options[:url] || options['url'] || '/flatulent/captcha'
211
+ %Q`
212
+ #{ require_prototype }
213
+ <script type="text/javascript">
214
+ new Ajax.Updater('#{ id }', '#{ url }', { method: 'get' });
215
+ </script>
216
+ `
217
+ end
218
+ def ajax options = {}
219
+ id = options[:id] || options['id'] || 'flatulent'
220
+ %Q`
221
+ <div id="#{ id }"></div>
222
+ #{ Flatulent.javascript }
223
+ `
224
+ end
225
+ end
226
+
227
+ singleton_class.attributes.each{|a| attribute(a){ self.class.send a}}
228
+
229
+ attribute 'string'
230
+ attribute 'size'
231
+ attribute 'font'
232
+ attribute 'noise'
233
+ attribute 'id'
234
+ attribute 'action'
235
+ attribute 'ttl'
236
+
237
+ attribute 'figlet'
238
+ attribute 'figlets'
239
+ attribute 'element'
240
+ attribute 'form_tags'
241
+ attribute 'form'
242
+
243
+ def initialize arg = {}
244
+ if Hash === arg
245
+ opt = getopts arg
246
+ @size = Integer opt[ 'size', 4 ]
247
+ @string = String opt[ 'string', generate_random_string ]
248
+ else
249
+ opt = getopts Hash.new
250
+ @string = String arg
251
+ @size = @string.size
252
+ end
253
+
254
+ @font = String opt[ 'font', 'big' ]
255
+ @noise = Float opt[ 'noise', 0.03 ]
256
+ @id = String opt[ 'id', 'flatulent' ]
257
+ @action = String opt[ 'action' ]
258
+ @ttl = Integer opt[ 'ttl', 256 ]
259
+
260
+ figlet!
261
+ element!
262
+ form_tags!
263
+ form!
264
+ end
265
+
266
+ def generate_random_string
267
+ chars = ('A' .. 'Z').to_a + ('1' .. '9').to_a ### zero is too much like o/O
268
+ Array.new(@size).map{ chars[rand(chars.size - 1)]}.join
269
+ end
270
+
271
+ def figlet!
272
+ spaced = @string.split(%r//).join #.join(' ')
273
+ fontfile = File.join fontdir, "#{ @font }.flf"
274
+ font = Text::Figlet::Font.new fontfile
275
+ typesetter = Text::Figlet::Typesetter.new font
276
+ @figlets = []
277
+ chars = spaced.split %r//
278
+ chars.each{|char| @figlets << typesetter[char]}
279
+ @figlet = typesetter[spaced]
280
+ end
281
+
282
+ def element!
283
+ rows = []
284
+ rows << (row = [])
285
+ chars = @figlet.split %r//
286
+ size = chars.size
287
+ last = size - 1
288
+
289
+ chars.each_with_index do |char, idx|
290
+ content =
291
+ case char
292
+ when %r/\n/o
293
+ "<br>"
294
+ when %r/\s/o
295
+ #rand > 0.42 ? "&nbsp;" : " "
296
+ "&nbsp;"
297
+ when %r/([^\s])/o
298
+ CGI.escapeHTML $1
299
+ end
300
+ Array.new(rand(42)){ content = "<span>#{ content }</span>"}
301
+ row << content
302
+ rows << (row = []) unless idx == last
303
+ end
304
+
305
+ noisy = %W` | / - _ ( ) \ `
306
+ (@noise * chars.size).ceil.times do
307
+ y = rand(rows.size - 1)
308
+ x = rand(rows.first.size - 1)
309
+ next if rows[y][x] =~ %r"<br>"
310
+ char = noisy[ rand(noisy.size) ]
311
+ rows[y][x] = char
312
+ end
313
+
314
+ content = rows.join
315
+ @element = "<pre id='#{ @id }_element' style='#{ css }'>#{ content }</pre>"
316
+ end
317
+
318
+ =begin
319
+
320
+ def element!
321
+ cells = []
322
+
323
+ @figlets.each do |figlet|
324
+ rows = []
325
+ rows << (row = [])
326
+
327
+ offset_t = Array.new(rand(4)).map{ "\n"}
328
+ offset_b = Array.new(rand(4)).map{ "\n"}
329
+
330
+ offset_l = Array.new(rand(4)).map{ " "}
331
+ offset_r = Array.new(rand(4)).map{ " "}
332
+
333
+ chars = offset_t + figlet.split(%r//) + offset_b
334
+ size = chars.size
335
+ last = size - 1
336
+ #drawn = chars.select{|char| char !~ %r/\s/}
337
+ drawn = %w` | / \ &lt; &gt; v ^ - _ ( ) `
338
+
339
+ chars.each_with_index do |char, idx|
340
+ content =
341
+ case char
342
+ when %r/\n/o
343
+ "<br>"
344
+ when %r/\s/o
345
+ #rand > 0.42 ? "&nbsp;" : " "
346
+ "&nbsp;"
347
+ when %r/([^\s])/o
348
+ CGI.escapeHTML $1
349
+ end
350
+ #rand(10).times{ content = "<span>#{ content }</span>" }
351
+ row << content
352
+ rows << (row = []) unless idx == last
353
+ end
354
+
355
+ noisy = %w` | / \ - _ ( ) `
356
+ (@noise * chars.size).ceil.times do
357
+ y = rand(rows.size - 1)
358
+ x = rand(rows.first.size - 1)
359
+ next if rows[y][x] == "<br>"
360
+ char = noisy[ rand(noisy.size) ]
361
+ rows[y][x] = char
362
+ end
363
+
364
+ content = rows.join
365
+ cells << content
366
+ end
367
+
368
+ formatted = lambda{|x| "<pre class='#{ @id }_figlet' style='#{ css }'>#{ x }</pre>"}
369
+
370
+ @element =
371
+ "<table id='#{ @id }_element' border='0' cellpadding='0' cellspacing='0' bgcolor='#{ style["background"] }'><tr>" <<
372
+ cells.map{|cell| "<td>#{ formatted[cell] }</td>"}.join <<
373
+ "</tr></table>"
374
+ end
375
+ =end
376
+
377
+ def css
378
+ css_for style
379
+ end
380
+ def noise_css
381
+ css_for noise_style
382
+ end
383
+
384
+ def css_for hash
385
+ hash.map{|kv| kv.join ':'}.join ';'
386
+ end
387
+
388
+ def form_tags!
389
+ n = @string.scan(%r/\w/).size
390
+ string = @string
391
+ timebomb = Time.now.utc.to_i + @ttl
392
+ @form_tags = <<-html
393
+ #{ element }
394
+ <p id='#{ @id }_instructions'>
395
+ Please enter the #{ n } large characters (A-Z, 1-9) shown.
396
+ </p>
397
+ <input type='textarea' name='#{ @id }[c]' id='#{ @id }_textarea' />
398
+ <input type='hidden' name='#{ @id }[s]' id='#{ @id }_e' value='#{ encrypt string }' />
399
+ <input type='hidden' name='#{ @id }[t]' id='#{ @id }_v' value='#{ encrypt timebomb }' />
400
+ html
401
+ end
402
+ alias_method 'to_html', 'form_tags'
403
+
404
+ def encrypt string
405
+ self.class.encrypt string.to_s
406
+ end
407
+
408
+ def encrypted
409
+ self.class.encrypt @string
410
+ end
411
+
412
+ def munge string
413
+ self.class.munge string
414
+ end
415
+
416
+ def form!
417
+ action = "action='#{ @action }'"
418
+ @form = <<-html
419
+ <form method='post' #{ action }>
420
+ #{ form_tags }
421
+ <input type='submit' name='#{ @id }[submit]' id='#{ @id }_submit' value='Submit' />
422
+ </form>
423
+ html
424
+ end
425
+
426
+ def to_html
427
+ element
428
+ end
429
+
430
+ def to_s
431
+ form
432
+ end
433
+
434
+ def getopts options
435
+ self.class.getopts options
436
+ end
437
+ end
438
+
439
+ def Flatulent(*a, &b) Flatulent.new(*a, &b) end
440
+
441
+ if $0 == __FILE__
442
+ #string = rand.to_s
443
+ #puts Flatulent(string)
444
+ #Flatulent.validate! :t => string, :e => Flatulent.encrypt(string), :v => (Time.now.utc.to_i + 60)
445
+ #e = Flatulent.encrypt('foobar')
446
+ #p e
447
+ #p Flatulent.decrypt(e)
448
+
449
+ puts Flatulent.figlet('foobar')
450
+ end