tool_pouch 0.0.34

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,43 @@
1
+ require 'base64'
2
+ require 'cgi'
3
+ require 'digest/sha1'
4
+ require 'digest/md5'
5
+ require 'find'
6
+ require 'net/http'
7
+ require 'openssl'
8
+ require 'yaml'
9
+ require 'uri'
10
+ # HashTree
11
+
12
+ module ToolPouch
13
+ DATA_PATH = File.expand_path("../../data", __FILE__) + '/'
14
+
15
+ def self.get_data(name, extension='yml')
16
+ set_data_cache(name, YAML.load_file("#{DATA_PATH}#{name}.#{extension}")['data']) if not data_cached?(name)
17
+
18
+ return get_data_cache(name)
19
+ end
20
+
21
+ def self.get_data_cache(name)
22
+ @data_cache[name]
23
+ end
24
+
25
+ def self.set_data_cache(name, data)
26
+ @data_cache = {} if not @data_cache
27
+
28
+ @data_cache[name] = data
29
+
30
+ return @data_cache[name]
31
+ end
32
+
33
+ def self.data_cached?(name)
34
+ @data_cache and @data_cache[name]
35
+ end
36
+ end
37
+
38
+ require 'tool_pouch/babel'
39
+ require 'tool_pouch/krono'
40
+ require 'tool_pouch/locksmith'
41
+ require 'tool_pouch/mathema'
42
+ require 'tool_pouch/trail'
43
+ require 'tool_pouch/transistor'
@@ -0,0 +1,225 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module ToolPouch::Babel
3
+ def self.bytes_to(size, options={})
4
+ options.reverse_merge!(:unit => nil, :show_unit => true)
5
+
6
+ unit = options[:unit]
7
+
8
+ divider = 1
9
+
10
+ unless options[:unit]
11
+ if size < 1000
12
+ unit = :b
13
+ elsif size < 1000000
14
+ unit = :kb
15
+ elsif size < 1000000000
16
+ unit = :mb
17
+ else
18
+ unit = :gb
19
+ end
20
+ end
21
+
22
+ case unit
23
+ when :kb then divider = 1000
24
+ when :mb then divider = 1000000
25
+ when :gb then divider = 1000000000
26
+ end
27
+
28
+ sprintf("%0.02f", (size.to_f / divider)) + (options[:show_unit] ? ' ' + unit.to_s.upcase_utf8 : '')
29
+ end
30
+
31
+ def self.convert_accents(str)
32
+ str_to_convert = String.new(str)
33
+ table = {'Á' => 'A', 'Â' => 'A', 'Ä' => 'A', 'À' => 'A', 'Å' => 'A', 'Ç' => 'C', 'É' => 'E', 'Ê' => 'E', 'Ë' => 'E', 'È' => 'E', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ì' => 'I', 'Ñ' => 'N', 'Œ' => 'O', 'Ó' => 'O', 'Ô' => 'O', 'Ö' => 'O', 'Ò' => 'O', 'Õ' => 'O', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ù' => 'U', 'Ý' => 'Y', 'Ÿ' => 'Y', 'Ž' => 'Z', 'á' => 'a', 'â' => 'a', 'ä' => 'a', 'æ' => 'a', 'à' => 'a', 'å' => 'a', 'ã' => 'a', 'ç' => 'c', 'é' => 'e', 'ê' => 'e', 'ë' => 'e', 'è' => 'e', 'ð' => 'o', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ì' => 'i', 'ñ' => 'n', 'ó' => 'o', 'ô' => 'o', 'ö' => 'o', 'œ' => 'o', 'ò' => 'o', 'õ' => 'o', 'ú' => 'u', 'û' => 'u', 'ü' => 'u', 'ù' => 'u', 'ý' => 'y', 'ÿ' => 'y', 'ž' => 'z'}
34
+
35
+ table.each { |k, v| str_to_convert.gsub!(k, v) }
36
+
37
+ return str_to_convert
38
+ end
39
+
40
+ def self.currency_for_country(country)
41
+ case country
42
+ when 'fra', 'ita', 'lux', 'bel', 'deu' then 'eur'
43
+ when 'can' then 'cad'
44
+ when 'usa' then 'usd'
45
+ when 'che' then 'chf'
46
+ end
47
+ end
48
+
49
+ def self.currency_for_region(region)
50
+ return case region
51
+ when 'europe' then 'eur'
52
+ when 'quebec' then 'cad'
53
+ when 'usa' then 'usd'
54
+ when 'suisse' then 'chf'
55
+ else ''
56
+ end
57
+ end
58
+
59
+ def self.enumerate(terms)
60
+ last_element = terms.pop;
61
+
62
+ if terms.length == 0
63
+ return last_element;
64
+ else
65
+ return terms.join(', ') + ' ' + I18n.t('and') + ' ' + last_element;
66
+ end
67
+ end
68
+
69
+ def self.extract_first_quotes(value)
70
+ value.index('"') ? value.split('"')[1] : ''
71
+ end
72
+
73
+ def self.extract_first_tag(value)
74
+ if value.index('<') and value.index('>')
75
+ return value[value.index('<') + 2, value.rindex('>') - value.index('<')-2]
76
+ else
77
+ return ''
78
+ end
79
+ end
80
+
81
+ def self.random_string(size, options={})
82
+ options.reverse_merge!(:force_array => false, :quantity => 1, :reject => [])
83
+
84
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
85
+ strings = []
86
+ try = 0
87
+
88
+ options[:quantity].times do
89
+ new_random = ''
90
+ while new_random.empty? do
91
+ 1.upto(size) { |i| new_random << chars[rand(chars.size)] }
92
+
93
+ new_random = '' if options[:reject].include?(new_random)
94
+ try += 1
95
+
96
+ return nil if try > 500
97
+ end
98
+ options[:reject] << new_random
99
+ strings << new_random
100
+ end
101
+
102
+ (options[:quantity] == 1 and not options[:force_array]) ? strings.first : strings
103
+ end
104
+
105
+ def self.region_for_country(country)
106
+ return case country.downcase
107
+ when 'ita', 'fra', 'lux', 'bel', 'deu' then 'europe'
108
+ when 'che' then 'suisse'
109
+ when 'can' then 'quebec'
110
+ when 'usa' then 'usa'
111
+ end
112
+ end
113
+
114
+ def self.strip_html(value)
115
+ (value) ? value.to_s.gsub(/<\/?[^>]*>/, "") : value
116
+ end
117
+
118
+ def self.to_currency_symbol(unit)
119
+ return case unit.downcase
120
+ when 'cad', 'usd' then '$'
121
+ when 'eur' then '€'
122
+ when 'chf' then 'CHF'
123
+ else ''
124
+ end
125
+ end
126
+
127
+ # TODO : Finish the method
128
+ def self.to_iso3166_1(country_code, options={})
129
+ options.reverse_merge!(:to_alpha => '3')
130
+
131
+ from_2_to_3 = { "be" => "bel", "ca" => "can", "ch" => "che", "de" => "deu", "fr" => "fra", "it" => "ita", "lx" => "lux", "us" => "usa" }
132
+ from_3_to_2 = from_2_to_3.invert
133
+
134
+ if options[:to_alpha].to_s == '3'
135
+ return from_2_to_3[country_code.to_s.downcase]
136
+ elsif options[:to_alpha].to_s == '2'
137
+ return from_3_to_2[country_code.to_s.downcase]
138
+ else
139
+ return nil
140
+ end
141
+ end
142
+
143
+ def self.to_iso639(language, options={})
144
+ options.reverse_merge!(:from => nil, :to => '2b')
145
+
146
+ options[:from] = options[:from] ? [options[:from]].flatten : ['1', '2b', '2t', '3']
147
+
148
+ options[:from].each do |from|
149
+ table = ToolPouch.get_data('iso639')['iso639_convert']["#{from}_to_#{options[:to]}"]
150
+
151
+ return table[language] if table and not table[language].to_s.empty?
152
+ end
153
+
154
+ return language
155
+ end
156
+
157
+ def self.to_latin_encoded(value)
158
+ latin_table = { 'Æ' => '306', 'Á' => '301', 'Â' => '302', 'Ä' => '304', 'À' => '300', 'Å' => '305', 'Ã' => '303', 'Ç' => '307', 'É' => '311', 'Ê' => '312', 'Ë' => '313', 'È' => '310', 'Ð' => '320', '€' => '240', 'Í' => '315', 'Î' => '316', 'Ï' => '317', 'Ì' => '314', 'Ł' => '225', 'Ñ' => '321', 'Œ' => '226', 'Ó' => '323', 'Ô' => '324', 'Ö' => '326', 'Ò' => '322', 'Ø' => '330', 'Õ' => '325', 'Š' => '227', 'Þ' => '336', 'Ú' => '332', 'Û' => '333', 'Ü' => '334', 'Ù' => '331', 'Ý' => '335', 'Ÿ' => '230', 'Ž' => '231', 'á' => '341', 'â' => '342', '´' => '264', 'ä' => '344', 'æ' => '346', 'à' => '340', 'å' => '345', '^' => '136', '~' => '176', '*' => '052', 'ã' => '343', '˘' => '030', '¦' => '246', '•' => '200', 'ˇ' => '031', 'ç' => '347', '¸' => '270', '¢' => '242', 'ˆ' => '032', '©' => '251', '¤' => '244', '†' => '201', '‡' => '202', '°' => '260', '÷' => '367', 'ı' => '232', 'é' => '351', 'ê' => '352', 'ë' => '353', 'è' => '350', 'ð' => '360', '¡' => '241', 'fi' => '223', 'fl' => '224', 'ƒ' => '206', 'ß' => '337', '«' => '253', '»' => '273', 'í' => '355', 'î' => '356', 'ï' => '357', 'ì' => '354', 'ł' => '233', 'µ' => '265', '×' => '327', 'ñ' => '361', '#' => '043', 'ó' => '363', 'ô' => '364', 'ö' => '366', 'œ' => '234', 'ò' => '362', 'ª' => '252', 'º' => '272', 'ø' => '370', 'õ' => '365', '¶' => '266', '¿' => '277', '„' => '214', '“' => '215', '”' => '216', '®' => '256', 'š' => '235', '§' => '247', '£' => '243', 'þ' => '376', '™' => '222', 'ú' => '372', 'û' => '373', 'ü' => '374', 'ù' => '371', 'ý' => '375', 'ÿ' => '377', '¥' => '245', 'ž' => '236' }
159
+ value_encoded = ''
160
+
161
+ value.each_char { |c| value_encoded << (latin_table[c] ? "\\" + latin_table[c] : c) }
162
+
163
+ value_encoded
164
+ end
165
+
166
+ def self.to_price(amount, options={})
167
+ options.reverse_merge!(:separator => ',', :format => '%n%u', :unit => 'cad')
168
+
169
+ price = amount.to_s.rjust(3,'0')
170
+ price = price[0..-3] + options[:separator] + price[-2..-1]
171
+
172
+ if options[:unit]
173
+ unit_symbol = to_currency_symbol(options[:unit])
174
+ price = options[:format].gsub('%u', unit_symbol).gsub('%n', price)
175
+ end
176
+
177
+ return price
178
+ end
179
+
180
+ def self.to_roman(numeric)
181
+ numerals = [
182
+ { :roman => 'M', :arab => 1000 },
183
+ { :roman => 'CM', :arab => 900 },
184
+ { :roman => 'D', :arab => 500 },
185
+ { :roman => 'CD', :arab => 400 },
186
+ { :roman => 'C', :arab => 100 },
187
+ { :roman => 'XC', :arab => 90 },
188
+ { :roman => 'L', :arab => 50 },
189
+ { :roman => 'XL', :arab => 40 },
190
+ { :roman => 'X', :arab => 10 },
191
+ { :roman => 'IX', :arab => 9 },
192
+ { :roman => 'V', :arab => 5 },
193
+ { :roman => 'IV', :arab => 4 },
194
+ { :roman => 'I', :arab => 1 }
195
+ ]
196
+
197
+ roman = '';
198
+ numerals.each do |num|
199
+ while numeric >= num[:arab]
200
+ roman += num[:roman]
201
+ numeric -= num[:arab]
202
+ end
203
+ end
204
+
205
+ return roman
206
+ end
207
+
208
+ def self.to_slug(value)
209
+ value.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^[:alnum:]]/,'-')
210
+ end
211
+
212
+ def self.to_slug_advanced(value)
213
+ to_slug(value).gsub(/-{2,}/,'-').gsub(/-\Z/, '')
214
+ end
215
+
216
+ def self.validate_email?(email, options={})
217
+ options.reverse_merge!(:allow_blank => false)
218
+
219
+ if options[:allow_blank] and email.blank?
220
+ return true
221
+ else
222
+ return (email.match(/^\S+@\S+\.\S+$/) ? true : false)
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,153 @@
1
+ module ToolPouch::Krono
2
+ def self.datestamp(date=nil)
3
+ date = Time.now unless date
4
+
5
+ return date.strftime("%Y%m%d")
6
+ end
7
+
8
+ def self.floor(datetime, seconds=60)
9
+ return Time.at((datetime.to_f / seconds).floor * seconds)
10
+ end
11
+
12
+ def self.format_in_time(number)
13
+ minutes = (number >= 1) ? number.modulo(number.floor) : number
14
+ minutes = (minutes * 60).to_i.to_s
15
+
16
+ return number.floor.to_s.rjust(2, '0') + ':' + minutes.rjust(2, '0')
17
+ end
18
+
19
+ def self.is_iso8601?(date)
20
+ date.is_a? String and date =~ /^\d{4}-(0\d|1[0-2])-([0-2]\d|3[0-1])T([0-1]\d|2[0-4]):([0-5]\d):([0-5]\d)([zZ]|([+-](0\d|1[0-4]):[0-5]\d))/
21
+ end
22
+
23
+ def self.is_valid?(strtime, options={})
24
+ options.reverse_merge!(:blank_is_valid => true)
25
+
26
+ if strtime.blank?
27
+ return options[:blank_is_valid]
28
+ else
29
+ begin
30
+ return (Time.zone.parse(strtime) ? true : false)
31
+ rescue
32
+ return false
33
+ end
34
+ end
35
+ end
36
+
37
+ def self.parse_in_utc(date_string)
38
+ last_time_zone = Time.zone.name
39
+
40
+ Time.zone = 'UTC'
41
+ utc_time = Time.zone.parse(date_string)
42
+ Time.zone = last_time_zone
43
+
44
+ return utc_time
45
+ end
46
+
47
+ def self.parse_timestamp(raw_timestamp, options={})
48
+ options.reverse_merge!(:time_only => false)
49
+
50
+ timestamp = Time.zone.parse(raw_timestamp)
51
+
52
+ return options[:time_only] ? timestamp.strftime("%H:%M:%S") : timestamp
53
+ end
54
+
55
+ def self.round(datetime, seconds=60)
56
+ return Time.at((datetime.to_f / seconds).round * seconds)
57
+ end
58
+
59
+ def self.seconds_to_unit(seconds, options={})
60
+ options.reverse_merge!(:force => nil, :format => :time, :show_unit => true)
61
+ seconds = seconds.to_f
62
+
63
+ result = seconds
64
+ time_table = {'year' => 31536000, 'day' => 86400, 'hour' => 3600, 'minute' => 60, 'second' => 1}
65
+ unit_selected = 'second'
66
+
67
+ time_table.each do |unit, value|
68
+ if (seconds >= value and not options[:force]) or (unit == options[:force])
69
+ unit_selected = unit
70
+ result = seconds / value
71
+ break
72
+ end
73
+ end
74
+
75
+ formatted_result = (options[:format] == :time) ? format_in_time(result) : sprintf("%0.02f", result)
76
+
77
+ if options[:show_unit]
78
+ return formatted_result + " " + I18n.t("datetime.short.#{unit_selected}")
79
+ else
80
+ return formatted_result.to_i
81
+ end
82
+ end
83
+
84
+ def self.start_timer
85
+ @timer = Time.now
86
+ end
87
+
88
+ def self.stop_timer
89
+ Time.now - @timer
90
+ end
91
+
92
+ def self.time_format
93
+ {
94
+ :basic => "%Y%m%dT%H%M%S",
95
+ :shortdate => "%Y-%m-%d",
96
+ :shorttime => "%H:%M:%S",
97
+ :shortdatetime => "%Y-%m-%dT%H:%M:%S"
98
+ }
99
+ end
100
+
101
+ def self.time_process_in_seconds(time)
102
+ time = time.split('.')[0]
103
+ new_time = time.split(':')
104
+
105
+ return (new_time[new_time.length-2].to_i * 60).to_i + new_time.last.to_i
106
+ end
107
+
108
+ def self.datetime_standard
109
+ [ :iso8601 ]
110
+ end
111
+
112
+ def self.timestamp(date=nil)
113
+ date = Time.now.getgm unless date
114
+
115
+ return date.strftime("%Y%m%d%H%M%S")
116
+ end
117
+
118
+ def self.timestamp_db(date=nil)
119
+ date = Time.now unless date
120
+
121
+ return date.strftime("%Y-%m-%d %H:%M:%S")
122
+ end
123
+
124
+ def self.timezone(date, options={})
125
+ options.reverse_merge!(:standard => :iso8601)
126
+ send("timezone_" + options[:standard].to_s, date) if datetime_standard.include?(options[:standard])
127
+ end
128
+
129
+ def self.timezone_iso8601(date)
130
+ if date.utc?
131
+ 'Z'
132
+ else
133
+ off = date.utc_offset
134
+ sign = off < 0 ? '-' : '+'
135
+ sprintf('%s%02d:%02d', sign, *(off.abs / 60).divmod(60))
136
+ end
137
+ end
138
+
139
+ def self.to_iso8601(date, options={})
140
+ options.reverse_merge!(:format => :basic, :utc => false, :timezone => false)
141
+
142
+ date = date.utc if options[:utc]
143
+
144
+ if time_format[options[:format]]
145
+ iso8601_date = date.strftime(time_format[options[:format]])
146
+ iso8601_date = iso8601_date + timezone(date, :standard => :iso8601) if options[:timezone] and options[:format] != :shortdate
147
+ else
148
+ iso8601_date = date.iso8601
149
+ end
150
+
151
+ return iso8601_date
152
+ end
153
+ end
@@ -0,0 +1,111 @@
1
+ require 'active_support/time'
2
+ require 'active_support/core_ext/object'
3
+ require 'tool_pouch/trail'
4
+
5
+ module ToolPouch::Locksmith
6
+ include ToolPouch
7
+
8
+ def self.build_digest_request(url, password, lifespan = 2.minutes)
9
+ if url.blank? || password.blank?
10
+ nil
11
+ else
12
+ nonce = Babel.random_string(15)
13
+ timestamp = (Time.now + lifespan).utc.strftime('%Y-%m-%dT%H:%M:%SZ')
14
+ escaped_timestamp = CGI.escape(timestamp)
15
+
16
+ uri = Addressable::URI.parse url
17
+ params = uri.query_values || {}
18
+ params.merge!({'timestamp' => timestamp, 'nonce' => nonce})
19
+
20
+ digested_url = digest_uri(uri, params).to_s
21
+ params.merge!({
22
+ token: hexdigest([password, nonce, escaped_timestamp].join, digested_url)
23
+ })
24
+ uri.query_values = params
25
+ uri.to_s
26
+ end
27
+ end
28
+
29
+ def self.check_digest_request(url, password)
30
+ if url.blank? || password.blank?
31
+ false
32
+ else
33
+ uri = Addressable::URI.parse url
34
+ params = uri.query_values || {}
35
+
36
+ unescaped_timestamp = CGI.unescape(params['timestamp'].to_s)
37
+ escaped_timestamp = CGI.escape(unescaped_timestamp)
38
+ token_key = [password, params['nonce'].to_s, escaped_timestamp].join
39
+
40
+ digested_url = digest_uri(uri, params).to_s
41
+
42
+ expire_at = Krono.parse_in_utc(unescaped_timestamp)
43
+ compare_hexdigest(token_key, digested_url, params['token']) && expire_at.future?
44
+ end
45
+ end
46
+
47
+ # Harmonize generated URL and request URL so they can be compared.
48
+ # Digest params are added to the query
49
+ # Scheme is ignored (harmonized to http)
50
+ # Note that the gem Adressable do order the query string by key values
51
+ def self.digest_uri(original_uri, params = nil)
52
+ uri = original_uri.dup
53
+ if params
54
+ p = params.dup
55
+ p.delete 'token'
56
+ uri.query_values = p
57
+ end
58
+ uri.scheme = nil
59
+ uri.port = nil
60
+ uri.to_s
61
+ end
62
+
63
+ def self.compare_hexdigest(password, value, target_key)
64
+ password and value and OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), password, value.to_s) == target_key
65
+ end
66
+
67
+ def self.decrypt(value, password)
68
+ decrypted_value = nil
69
+
70
+ if value and password
71
+ c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
72
+ c.decrypt
73
+ c.key = Digest::SHA1.hexdigest(password)
74
+ begin
75
+ decrypted_value = c.update(Base64.decode64(value))
76
+ decrypted_value << c.final
77
+ rescue
78
+ decrypted_value = nil
79
+ end
80
+ end
81
+
82
+ return decrypted_value
83
+ end
84
+
85
+ def self.encrypt(value, password)
86
+ encrypt = nil
87
+
88
+ if value and password
89
+ begin
90
+ c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
91
+ c.encrypt
92
+ c.key = Digest::SHA1.hexdigest(password)
93
+ e = c.update(value)
94
+ e << c.final
95
+ encrypt = Base64.encode64(e).strip
96
+ rescue
97
+ encrypt = nil
98
+ end
99
+ end
100
+
101
+ return encrypt
102
+ end
103
+
104
+ def self.generate_file_checksum(file)
105
+ File.exist?(file) ? Digest::MD5.hexdigest(File.read(file)) : nil
106
+ end
107
+
108
+ def self.hexdigest(password, value)
109
+ (password and value) ? OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), password, value) : nil
110
+ end
111
+ end