flatulent 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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