tool_pouch 0.0.34
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/README +22 -0
- data/Rakefile +3 -0
- data/data/iso639.yml +412 -0
- data/lib/tool_pouch.rb +43 -0
- data/lib/tool_pouch/babel.rb +225 -0
- data/lib/tool_pouch/krono.rb +153 -0
- data/lib/tool_pouch/locksmith.rb +111 -0
- data/lib/tool_pouch/mathema.rb +27 -0
- data/lib/tool_pouch/trail.rb +279 -0
- data/lib/tool_pouch/transistor.rb +98 -0
- data/lib/tool_pouch/version.rb +3 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/tool_pouch/krono_spec.rb +12 -0
- data/spec/tool_pouch/locksmith/digest_spec.rb +105 -0
- metadata +88 -0
data/lib/tool_pouch.rb
ADDED
@@ -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
|