wwmd 0.2.20.3

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 (80) hide show
  1. data/History.txt +38 -0
  2. data/README.rdoc +87 -0
  3. data/Rakefile +33 -0
  4. data/examples/config_example.yaml +24 -0
  5. data/examples/wwmd_example.rb +73 -0
  6. data/lib/wwmd.rb +84 -0
  7. data/lib/wwmd/class_extensions.rb +4 -0
  8. data/lib/wwmd/class_extensions/extensions_base.rb +251 -0
  9. data/lib/wwmd/class_extensions/extensions_encoding.rb +79 -0
  10. data/lib/wwmd/class_extensions/extensions_external.rb +18 -0
  11. data/lib/wwmd/class_extensions/extensions_nilclass.rb +11 -0
  12. data/lib/wwmd/class_extensions/extensions_rbkb.rb +193 -0
  13. data/lib/wwmd/class_extensions/mixins_string_encoding.rb +40 -0
  14. data/lib/wwmd/guid.rb +155 -0
  15. data/lib/wwmd/page.rb +3 -0
  16. data/lib/wwmd/page/_fa.old +302 -0
  17. data/lib/wwmd/page/auth.rb +17 -0
  18. data/lib/wwmd/page/constants.rb +63 -0
  19. data/lib/wwmd/page/form.rb +99 -0
  20. data/lib/wwmd/page/form_array.rb +304 -0
  21. data/lib/wwmd/page/headers.rb +118 -0
  22. data/lib/wwmd/page/helpers.rb +41 -0
  23. data/lib/wwmd/page/html2text_hpricot.rb +76 -0
  24. data/lib/wwmd/page/html2text_nokogiri.rb +42 -0
  25. data/lib/wwmd/page/inputs.rb +47 -0
  26. data/lib/wwmd/page/irb_helpers.rb +114 -0
  27. data/lib/wwmd/page/page.rb +257 -0
  28. data/lib/wwmd/page/parsing_convenience.rb +98 -0
  29. data/lib/wwmd/page/reporting_helpers.rb +89 -0
  30. data/lib/wwmd/page/scrape.rb +196 -0
  31. data/lib/wwmd/page/spider.rb +127 -0
  32. data/lib/wwmd/urlparse.rb +125 -0
  33. data/lib/wwmd/viewstate.rb +17 -0
  34. data/lib/wwmd/viewstate/viewstate.rb +101 -0
  35. data/lib/wwmd/viewstate/viewstate_deserializer_methods.rb +217 -0
  36. data/lib/wwmd/viewstate/viewstate_from_xml.rb +129 -0
  37. data/lib/wwmd/viewstate/viewstate_types.rb +51 -0
  38. data/lib/wwmd/viewstate/viewstate_utils.rb +164 -0
  39. data/lib/wwmd/viewstate/viewstate_yaml.rb +25 -0
  40. data/lib/wwmd/viewstate/vs_stubs.rb +22 -0
  41. data/lib/wwmd/viewstate/vs_stubs/vs_array.rb +38 -0
  42. data/lib/wwmd/viewstate/vs_stubs/vs_binary_serialized.rb +30 -0
  43. data/lib/wwmd/viewstate/vs_stubs/vs_hashtable.rb +42 -0
  44. data/lib/wwmd/viewstate/vs_stubs/vs_hybrid_dict.rb +42 -0
  45. data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string.rb +6 -0
  46. data/lib/wwmd/viewstate/vs_stubs/vs_indexed_string_ref.rb +24 -0
  47. data/lib/wwmd/viewstate/vs_stubs/vs_int_enum.rb +27 -0
  48. data/lib/wwmd/viewstate/vs_stubs/vs_list.rb +34 -0
  49. data/lib/wwmd/viewstate/vs_stubs/vs_pair.rb +29 -0
  50. data/lib/wwmd/viewstate/vs_stubs/vs_read_types.rb +11 -0
  51. data/lib/wwmd/viewstate/vs_stubs/vs_read_value.rb +35 -0
  52. data/lib/wwmd/viewstate/vs_stubs/vs_sparse_array.rb +58 -0
  53. data/lib/wwmd/viewstate/vs_stubs/vs_string.rb +33 -0
  54. data/lib/wwmd/viewstate/vs_stubs/vs_string_array.rb +39 -0
  55. data/lib/wwmd/viewstate/vs_stubs/vs_string_formatted.rb +32 -0
  56. data/lib/wwmd/viewstate/vs_stubs/vs_stub_helpers.rb +37 -0
  57. data/lib/wwmd/viewstate/vs_stubs/vs_triplet.rb +31 -0
  58. data/lib/wwmd/viewstate/vs_stubs/vs_type.rb +23 -0
  59. data/lib/wwmd/viewstate/vs_stubs/vs_unit.rb +30 -0
  60. data/lib/wwmd/viewstate/vs_stubs/vs_value.rb +35 -0
  61. data/lib/wwmd/wwmd_config.rb +52 -0
  62. data/lib/wwmd/wwmd_puts.rb +9 -0
  63. data/lib/wwmd/wwmd_utils.rb +28 -0
  64. data/spec/README +3 -0
  65. data/spec/form_array.spec +49 -0
  66. data/spec/spider_csrf_test.spec +28 -0
  67. data/spec/urlparse_test.spec +101 -0
  68. data/tasks/ann.rake +80 -0
  69. data/tasks/bones.rake +20 -0
  70. data/tasks/gem.rake +201 -0
  71. data/tasks/git.rake +40 -0
  72. data/tasks/notes.rake +27 -0
  73. data/tasks/post_load.rake +34 -0
  74. data/tasks/rdoc.rake +51 -0
  75. data/tasks/rubyforge.rake +55 -0
  76. data/tasks/setup.rb +292 -0
  77. data/tasks/spec.rake +54 -0
  78. data/tasks/test.rake +40 -0
  79. data/tasks/zentest.rake +36 -0
  80. metadata +222 -0
@@ -0,0 +1,38 @@
1
+ == 0.2.20 / 2009-08-24
2
+
3
+ * convert ViewState to use StringIO
4
+ * include iZsh changes to fix some issues
5
+ * still lots to do and there's no time
6
+
7
+ == 0.2.19 /
8
+
9
+ * nothing to see here... move along quitely
10
+
11
+ == 0.2.18 /
12
+
13
+ * black hat special
14
+
15
+ == 0.2.17 / 2009-06-22
16
+
17
+ * lots happening between here and .9
18
+ * viewstate refactor complete
19
+ * clean up page/page.rb
20
+ * cleaning up page/headers.rb
21
+ * cleaning up page/scrape.rb
22
+ * FormArray refactor includes the form action (full URL)
23
+ * page.submit(page.get_form)
24
+ * still bugs in URLParse but hunting them down throw by throw
25
+ * remove broken NTLM (preserve auth header warnings)
26
+ * remove WWMDConfig in favor of WWMD module methods but preserve old class for back compat
27
+ * add some burp helpers
28
+ * Page#from_paste (take entire request into Page and turn off cookies)
29
+ * burp log parsing coming
30
+ * Curb includes http_put (with header munging bug so careful)
31
+ * internal monkey patch for Curb to do arbitrary verb tampering (not here yet)
32
+ * add String#pbcopy
33
+ * move lots of things around for clarity during refactor
34
+ * refactor progressing but still unstable (2.0.16 gem including viewstate is good to go)
35
+
36
+ == 0.2.9 / 2009-05-05
37
+
38
+ * bonesify
@@ -0,0 +1,87 @@
1
+ == PARDON OUR DUST
2
+
3
+ WWMD is currently in the throes of major cleanup and refactoring.
4
+
5
+ 0.2.17 should be stable.
6
+
7
+ The viewstate tools can be had by themselves by using:
8
+
9
+ require 'wwmd/viewstate'
10
+
11
+ We appreciate your patience.
12
+
13
+ <;'"}()[]>{ XSSFish says, "Swim wif me"
14
+
15
+ == DESCRIPTION:
16
+
17
+ WWMD was originally intended to provide a console helper tool for
18
+ conducting web application security assessments (which is something I
19
+ find myself doing alot of). I've spent alot of time and had alot of
20
+ success writing application specific fuzzers + scrapers to test with.
21
+ WWMD provides a base of useful code to help you work with web sites both
22
+ in IRB and by writing scripts that can be as generic or as application
23
+ specific as you choose.
24
+
25
+ There's alot of helpful stuff crammed in here and its usage has evolved
26
+ alot. It's not intended to replace, remove or be better than any of the
27
+ tools you currently use. In fact, WWMD works best *with* the tools you
28
+ currently use to get stuff done. You get convenience methods for
29
+ getting, scraping, spidering, decoding, decrypting and munging user
30
+ inputs, pages and web applications.
31
+
32
+ It doesn't try to be smart. That's up to you.
33
+
34
+ What's here is the basic framework for getting started. There's a raft
35
+ of cookbook scripts and examples that are coming soon so make sure you
36
+ check the wiki regularly.
37
+
38
+ == REQUIREMENTS:
39
+
40
+ * rubygems
41
+ * ruby-debug
42
+ * curb (taf2-curb located here on github)
43
+ * nokogiri >= 1.3.2
44
+ * hpricot (not used by default)
45
+ * htmlentities
46
+
47
+ == INSTALL
48
+
49
+ ==== gem installation
50
+
51
+ WWMD is available as a gem from github:
52
+
53
+ gem sources -a http://gems.github.com #(you only have to do this once)
54
+ gem install mtracy-wwmd
55
+
56
+ === manual installation
57
+
58
+ fetch the repository from github and add path/to/wwmd/lib to your RUBYLIB
59
+ environment variable
60
+
61
+ == LICENSE:
62
+
63
+ (The MIT License)
64
+
65
+ Copyright (c) 2008,2009 Michael Tracy <mtracy@matasano.com>
66
+
67
+ Permission is hereby granted, free of charge, to any person obtaining
68
+ a copy of this software and associated documentation files (the
69
+ 'Software'), to deal in the Software without restriction, including
70
+ without limitation the rights to use, copy, modify, merge, publish,
71
+ distribute, sublicense, and/or sell copies of the Software, and to
72
+ permit persons to whom the Software is furnished to do so, subject to
73
+ the following conditions:
74
+
75
+ The above copyright notice and this permission notice shall be
76
+ included in all copies or substantial portions of the Software.
77
+
78
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
79
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
80
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
81
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
82
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
83
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
84
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85
+
86
+ ## Blah blah blah
87
+
@@ -0,0 +1,33 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+ begin
5
+ require 'bones'
6
+ Bones.setup
7
+ rescue LoadError
8
+ begin
9
+ load 'tasks/setup.rb'
10
+ rescue LoadError
11
+ raise RuntimeError, '### please install the "bones" gem ###'
12
+ end
13
+ end
14
+
15
+ ensure_in_path 'lib'
16
+ require 'wwmd'
17
+
18
+ task :default => 'spec:run'
19
+
20
+ PROJ.name = 'wwmd'
21
+ PROJ.authors = 'Michael L. Tracy'
22
+ PROJ.email = 'mtracy@matasano.com'
23
+ PROJ.url = 'http://github.com/miketracy/wwmd/tree/master'
24
+ PROJ.version = WWMD::VERSION
25
+ #PROJ.rubyforge.name = 'wwmd'
26
+
27
+ PROJ.spec.opts << '--color'
28
+
29
+ depend_on 'ruby-debug'
30
+ depend_on 'curb'
31
+ depend_on 'nokogiri'
32
+
33
+ # EOF
@@ -0,0 +1,24 @@
1
+ #---
2
+ :base_url: "http://www.example.com"
3
+ :header_file: "./HEADERS.default" # argv
4
+ :username: "username" # argv
5
+ :password: "password" # argv
6
+
7
+ # opts for spider (only spider local urls)
8
+ :spider_local_only: true
9
+
10
+ # opts for curl object
11
+ # set max_redirects and follow_location (follows 302s)
12
+ :follow_location: true
13
+ :max_redirects: 20
14
+
15
+ # --use_proxy=host:port overrides both of these settings
16
+ # to use a proxy (I use burp and so should you)
17
+ :use_proxy: false
18
+ :proxy_url: "localhost:8080"
19
+
20
+ # cookies (where are we going to save our cookies?)
21
+ :enable_cookies: true
22
+ :cookiejar: "./__cookiejar"
23
+
24
+ #+++
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'wwmd'
4
+ include WWMD
5
+
6
+ $stop = lambda { Debugger.breakpoint; Debugger.catchpoint }
7
+
8
+ module WWMD
9
+ class Page
10
+ # here we add directly to Page.login instead of creating an outside
11
+ # helper class. Normally we create a mixin script for this.
12
+ def login
13
+ self.get(self.opts[:base_url]) ;# GET the main page redirects to /login
14
+ form = self.get_form ;# get the login form
15
+ if form.nil? then ;# did we actually get a form?
16
+ puts "WARN: No login form on base page"
17
+ return (self.logged_in = false)
18
+ end
19
+ form.set("name",self.opts[:username]) ;# set login form variables from config
20
+ form.set("password",self.opts[:password])
21
+ self.url = self.action ;# set the url to submit to to the form action
22
+ self.submit(form) ;# submit the form
23
+
24
+ # perform some check to make sure we aren't still on the login page
25
+ # (this naively checks to make sure we don't have any password fields on the current page
26
+ self.logged_in = (self.search("//input[@type='password']").size == 0)
27
+ end
28
+ end
29
+ end
30
+
31
+ # parse options and load configuration file
32
+ inopts = WWMDConfig.parse_opts(ARGV)
33
+ conf = ARGV[0] || "./config_example.yaml"
34
+ opts = WWMDConfig.load_config(conf)
35
+ inopts.each_pair { |k,v| opts[k] = v }
36
+ $opts = opts
37
+
38
+ # create our Page object and name it page
39
+ page = Page.new(opts)
40
+ page.scrape.warn = false ;# don't complain about not overwriting scrape
41
+
42
+ # move our spider object up here
43
+ spider = page.spider
44
+
45
+ # output current configuration
46
+ puts "current configuration:\n"
47
+ page.opts.each_pair { |k,v|
48
+ if k == :password then
49
+ puts "#{k} :: ********"
50
+ else
51
+ puts "#{k} :: #{v}"
52
+ end
53
+ }
54
+ puts "\n"
55
+
56
+ # use the Helper method to login to the application
57
+ if page.opts[:use_auth] then
58
+ page.login
59
+ if page.logged_in? then
60
+ puts "logged in as #{opts[:username]}"
61
+ else
62
+ puts "WARN: could not log in" if !page.logged_in?
63
+ end
64
+ else
65
+ page.get opts[:base_url]
66
+ end
67
+
68
+ # report our current location and let's drop to irb with
69
+ # our whole context complete
70
+ puts "current location: #{page.current}"
71
+ puts "enter \"irb\" to go to the console"
72
+
73
+ $stop.call
@@ -0,0 +1,84 @@
1
+ # third-party
2
+ require 'rubygems'
3
+ unless self.respond_to?(:java)
4
+ require 'ruby-debug'
5
+ require 'curb'
6
+ else
7
+ # I_KNOW_I_AM_USING_AN_OLD_AND_BUGGY_VERSION_OF_LIBXML2 = true
8
+ # require 'curb_ffi'
9
+ # include CurbFfi
10
+ end
11
+ require 'yaml'
12
+ require 'fileutils'
13
+ require 'base64'
14
+ require 'optparse'
15
+ require 'digest'
16
+ require 'uri'
17
+ require 'htmlentities'
18
+ require 'nkf'
19
+ require 'rexml/document'
20
+
21
+ module WWMD
22
+
23
+ # :stopdoc:
24
+ VERSION = "0.2.20.3"
25
+ PARSER = :nokogiri # :nokogiri || :hpricot
26
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
27
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
28
+ # :startdoc:
29
+
30
+ # Returns the version string for the library.
31
+ #
32
+ def self.version
33
+ VERSION
34
+ end
35
+
36
+ # Returns the library path for the module. If any arguments are given,
37
+ # they will be joined to the end of the libray path using
38
+ # <tt>File.join</tt>.
39
+ #
40
+ def self.libpath( *args )
41
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
42
+ end
43
+
44
+ # Returns the lpath for the module. If any arguments are given,
45
+ # they will be joined to the end of the path using
46
+ # <tt>File.join</tt>.
47
+ #
48
+ def self.path( *args )
49
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
50
+ end
51
+
52
+ # Utility method used to require all files ending in .rb that lie in the
53
+ # directory below this file that has the same name as the filename passed
54
+ # in. Optionally, a specific _directory_ name can be passed in such that
55
+ # the _filename_ does not have to be equivalent to the directory.
56
+ #
57
+ def self.require_all_libs_relative_to( fname, dir = nil )
58
+ dir ||= ::File.basename(fname, '.*')
59
+ search_me = ::File.expand_path(
60
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
61
+
62
+ Dir.glob(search_me).sort.each do |rb|
63
+ next if rb =~ /html2text_/
64
+ require rb
65
+ end
66
+ end
67
+
68
+ end # module WWMD
69
+
70
+ WWMD.require_all_libs_relative_to(__FILE__)
71
+
72
+ # special case parser
73
+
74
+ if WWMD::PARSER == :nokogiri
75
+ require 'nokogiri'
76
+ WWMD::HDOC = Nokogiri::HTML
77
+ require 'wwmd/page/html2text_nokogiri'
78
+ else
79
+ require 'hpricot'
80
+ WWMD::HDOC = Hpricot
81
+ require 'wwmd/page/html2text_hpricot'
82
+ end
83
+
84
+ # EOF
@@ -0,0 +1,4 @@
1
+ require 'rubygems'
2
+ require 'htmlentities'
3
+ Dir.glob(::File.join(::File.dirname(__FILE__),"class_extensions/","*.rb")).each { |rb| require rb }
4
+
@@ -0,0 +1,251 @@
1
+ require 'htmlentities'
2
+
3
+ =begin rdoc
4
+ let's re-open everything!
5
+ =end
6
+
7
+ require 'uri'
8
+
9
+ class Numeric
10
+ # return binary representation of <tt>length</tt> size padded with \x00
11
+ # length: length in bytes to return (padded with least signficant \x00
12
+ # reverse: reverse the byte order
13
+ def to_bin (len,rev = false)
14
+ str = ""
15
+ bignum = self
16
+ 1.upto(len) do |i|
17
+ str << (bignum & 0xFF).to_n8
18
+ bignum = bignum >> 8
19
+ end
20
+ return str.reverse if rev
21
+ return str
22
+ end
23
+
24
+ # integer to ip address
25
+ def int_to_ip
26
+ [24, 16, 8, 0].map { |b| (self >> b) & 255 }.join('.')
27
+ end
28
+
29
+ # integer to mac address [uses ':' as delimiter]
30
+ def int_to_mac
31
+ [40,32,24,16,8,0].map { |b| ((self >> b) & 255).to_s(16).rjust(2,"0") }.join(":")
32
+ end
33
+ end
34
+
35
+ class String
36
+
37
+ def hexify
38
+ self.unpack("H*").first.upcase
39
+ end
40
+
41
+ def unhexify
42
+ [self].pack("H*")
43
+ end
44
+ alias_method :dehexify,:unhexify
45
+
46
+ def strip_up
47
+ self.gsub(/[^\x20-\x7e,\n]/,"").gsub(/^\n/,"")
48
+ end
49
+
50
+ # ip address to int
51
+ def ip_to_int
52
+ self.split('.').inject(0) { |a,e| (a << 8) + e.to_i }
53
+ end
54
+
55
+ # mac address to int [uses ':' as delimiter]
56
+ def mac_to_int
57
+ self.split(':').inject(0) { |a,e| (a << 8) + e.to_i(16) }
58
+ end
59
+
60
+ # return true or false for <tt>string.match</tt>
61
+ def contains?(rexp)
62
+ return !self.match(rexp).nil?
63
+ end
64
+
65
+ # strip the string and return true if empty
66
+ def empty?
67
+ return self.strip == ''
68
+ end
69
+
70
+ # return everything in the string (url) before the first get param
71
+ ## "http://foo.bar.com/page.asp?somearg=foo&otherarg=bar".clip
72
+ ## => "http://foo.bar.com/page.asp"
73
+ def clip(pref="?")
74
+ if (v = self.index(pref))
75
+ return self[0..(v-1)]
76
+ end
77
+ return self
78
+ end
79
+
80
+ # return everything in the string (url) after the first get parameter
81
+ # without the leading '?'
82
+ #
83
+ # pass true as the second param to also get back the ?
84
+ ## "http://foo.bar.com/page.asp?somearg=foo&otherarg=bar".clop
85
+ ## => "somearg=foo&otherarg=bar"
86
+ def clop(pref="?",preftoo=false)
87
+ (preftoo == false) ? add = "" : add = pref
88
+ if (v = self.index(pref))
89
+ return add + self[(v+1)..-1]
90
+ end
91
+ return nil
92
+ end
93
+
94
+ def clopp; self.clop("?",true); end #:nodoc:
95
+
96
+ def clopa
97
+ return [self.clip,self.clop]
98
+ end
99
+
100
+ alias_method :clipa, :clopa
101
+
102
+ # File.dirname with a trailing slash
103
+ def dirname
104
+ return self if self.match(/\/$/)
105
+ File.dirname(self) + "/"
106
+ end
107
+
108
+ # File.basename
109
+ def basename(ext=nil)
110
+ if ext
111
+ File.basename(self,ext)
112
+ else
113
+ File.basename(self)
114
+ end
115
+ end
116
+
117
+ def extname
118
+ self.split('.').last
119
+ end
120
+
121
+ # write string to passed filename
122
+ # if filename is nil? will raise an error
123
+ def write(fname=nil)
124
+ raise "filename required" unless fname
125
+ File.write(fname,self)
126
+ self
127
+ end
128
+
129
+ # parse passed GET param string into a form and return the FormArray object
130
+ def to_form(action=nil)
131
+ if self.split("\n").size > 1
132
+ return self.to_form_from_show
133
+ end
134
+ ret = FormArray.new
135
+ self.split("&").each do |x|
136
+ y = x.split("=",2)
137
+ ret[y[0].to_s] = y[1].to_s
138
+ # ret.extend!(y[0].to_s,y[1].to_s)
139
+ end
140
+ ret.action = action if action
141
+ return ret
142
+ end
143
+
144
+ def to_form_from_show
145
+ self.split("\n").map { |a|
146
+ key,val = a.split("=",2)
147
+ key = key.split(" ")[-1]
148
+ val = val.strip if val
149
+ ["#{key}=#{val}"]
150
+ }.join("&").to_form.squeeze_keys!
151
+ end
152
+
153
+ def mform
154
+ return self.gsub("\n","").to_form
155
+ end
156
+
157
+ def to_form_from_req
158
+ # self.split("\x0d\x0a\x0d\x0a")[1].to_form
159
+ self.split("\n\n")[1].to_form
160
+ end
161
+ alias_method :to_ffr, :to_form_from_req
162
+
163
+ # create filename from url changing "/" to "_"
164
+ def to_fn(ext=nil)
165
+ ret = self.clip.split("/")[3..-1].join("_")
166
+ ret += ".#{ext}" if not ext.nil?
167
+ return ret
168
+ end
169
+
170
+ # strip html tags from string
171
+ def strip_html
172
+ self.gsub(/<\/?[^>]*>/, "")
173
+ end
174
+
175
+ # range or int
176
+ def head(c=5)
177
+ if c.kind_of?(Range) then
178
+ range = c
179
+ else
180
+ range = (0..(c - 1))
181
+ end
182
+ self.split("\n")[range].join("\n")
183
+ end
184
+
185
+ # return a literal regexp object for this string
186
+ #
187
+ # escape regexp operators
188
+ def to_regexp
189
+ return Regexp.new(self.gsub(/([\[\]\{\}\(\)\*\$\?])/) { |x| '\\' + x })
190
+ end
191
+
192
+ # check if this string is a guid
193
+ def is_guid?
194
+ begin
195
+ Guid.from_s(self)
196
+ rescue => e
197
+ return false
198
+ end
199
+ return true
200
+ end
201
+
202
+ def md5
203
+ Digest::MD5.digest(self).hexify
204
+ end
205
+
206
+ def sha1
207
+ Digest::SHA1.digest(self).hexify
208
+ end
209
+
210
+ def sha256
211
+ Digest::SHA256.digest(self).hexify
212
+ end
213
+
214
+ def sha512
215
+ Digest::SHA512.digest(self).hexify
216
+ end
217
+
218
+ def pbcopy
219
+ IO.popen('pbcopy', 'r+') { |c| c.print self }
220
+ end
221
+ end
222
+
223
+ class Array
224
+ # grep each element of an array for the passed regular expression
225
+ # and return an Array of matches
226
+ # (only works one deep)
227
+ def each_grep(regex)
228
+ ret = []
229
+ self.each { |e| ret << e.grep(regex) }
230
+ return ret
231
+ end
232
+
233
+ # join the array with "\n" and write to a file
234
+ def to_file(filename)
235
+ File.write(filename,self.join("\n"))
236
+ end
237
+ end
238
+
239
+ class File
240
+ # write string to file
241
+ def self.write(filename,contents)
242
+ fout = File.open(filename,"w")
243
+ fout.print contents
244
+ fout.close
245
+ end
246
+ end
247
+
248
+ def pbpaste
249
+ %x[pbpaste]
250
+ end
251
+