mischacks 0.1.1 → 0.2.0
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.
- data/.gitignore +2 -0
- data/History.txt +5 -0
- data/README.txt +9 -0
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/lib/mischacks.rb +4 -1
- data/lib/mischacks/password.rb +57 -0
- data/lib/mischacks/random.rb +66 -0
- data/spec/mischacks/password_spec.rb +136 -0
- data/spec/mischacks/random_spec.rb +114 -0
- data/spec/spec_helper.rb +15 -0
- metadata +10 -3
data/.gitignore
ADDED
data/History.txt
CHANGED
data/README.txt
CHANGED
@@ -31,6 +31,15 @@ dump an uncaught exception.
|
|
31
31
|
|
32
32
|
IO#best_datasync:: Try fdatasync, falling back to fsync, falling back to flush.
|
33
33
|
|
34
|
+
Random#exp:: Return a random integer 0 ≤ n < 2^argument (using SecureRandom).
|
35
|
+
|
36
|
+
Random#float:: Return a random float 0.0 ≤ n < argument (using SecureRandom).
|
37
|
+
|
38
|
+
Random#int:: Return a random integer 0 ≤ n < argument (using SecureRandom).
|
39
|
+
|
40
|
+
Password:: A small wrapper for String#crypt that does secure salt generation
|
41
|
+
and easy password verification.
|
42
|
+
|
34
43
|
== FEATURES/PROBLEMS:
|
35
44
|
|
36
45
|
The sh method is only safe if your sh script is safe. If unsure, add double
|
data/Rakefile
CHANGED
@@ -28,7 +28,12 @@ begin
|
|
28
28
|
Jeweler::Tasks.new do |gemspec|
|
29
29
|
gemspec.name = "mischacks"
|
30
30
|
gemspec.summary = "Miscellaneous methods that may or may not be useful"
|
31
|
-
gemspec.description =
|
31
|
+
gemspec.description = \
|
32
|
+
"sh: Safely pass untrusted parameters to sh scripts. " \
|
33
|
+
"overwrite: Safely replace a file. " \
|
34
|
+
"Exception#to_formatted_string: Return a string that looks like how Ruby would dump an uncaught exception. " \
|
35
|
+
"Random: Generate various types of random numbers using SecureRandom. " \
|
36
|
+
"Password: A small wrapper for String#crypt that does secure salt generation and easy password verification."
|
32
37
|
gemspec.email = "devel@johan.kiviniemi.name"
|
33
38
|
gemspec.homepage = "http://johan.kiviniemi.name/software/mischacks/"
|
34
39
|
gemspec.authors = ["Johan Kiviniemi"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/mischacks.rb
CHANGED
@@ -13,8 +13,11 @@
|
|
13
13
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
14
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
15
|
|
16
|
+
require 'mischacks/password'
|
17
|
+
require 'mischacks/random'
|
18
|
+
|
16
19
|
module MiscHacks
|
17
|
-
VERSION =
|
20
|
+
VERSION = File.read(File.dirname(__FILE__)+'/../VERSION').chomp
|
18
21
|
|
19
22
|
class ChildError < RuntimeError
|
20
23
|
attr_reader :status
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# mischacks – Miscellaneous methods that may or may not be useful
|
2
|
+
# Copyright © 2010 Johan Kiviniemi
|
3
|
+
#
|
4
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
5
|
+
# purpose with or without fee is hereby granted, provided that the above
|
6
|
+
# copyright notice and this permission notice appear in all copies.
|
7
|
+
#
|
8
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
|
16
|
+
require 'mischacks/random'
|
17
|
+
|
18
|
+
module MiscHacks
|
19
|
+
class Password
|
20
|
+
SALT_SET = ['a'..'z', 'A'..'Z', '0'..'9', %w{ . / }].map(&:to_a).flatten
|
21
|
+
SALT_SET.freeze
|
22
|
+
if SALT_SET.length != 64
|
23
|
+
raise RuntimeError, "SALT_SET.length = #{SALT_SET.length}, expected 64"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.random_salt
|
27
|
+
length = 9 + RANDOM.exp(3) # Up to 9+(2³−1)=16
|
28
|
+
(0...length).map { SALT_SET[RANDOM.exp(6)] }.join
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.new_from_password password
|
32
|
+
new password.crypt('$6$%s$' % random_salt)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize encrypted
|
36
|
+
@salt, @encrypted = encrypted.scan(/\A(\$[^$]+\$[^$]+\$)(.+)\z/).first
|
37
|
+
if @salt.nil? or @encrypted.nil?
|
38
|
+
raise ArgumentError, "Failed to parse #{encrypted.inspect}", caller
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def match? password
|
43
|
+
to_s == password.crypt(@salt)
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
[@salt, @encrypted].join
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
'#<%s: %s>' % [self.class, to_s.inspect]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# vim:set et sw=2 sts=2:
|
57
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# mischacks – Miscellaneous methods that may or may not be useful
|
2
|
+
# Copyright © 2010 Johan Kiviniemi
|
3
|
+
#
|
4
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
5
|
+
# purpose with or without fee is hereby granted, provided that the above
|
6
|
+
# copyright notice and this permission notice appear in all copies.
|
7
|
+
#
|
8
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
|
16
|
+
require 'securerandom'
|
17
|
+
require 'singleton'
|
18
|
+
require 'thread'
|
19
|
+
|
20
|
+
module MiscHacks
|
21
|
+
class Random
|
22
|
+
include Singleton
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
@mutex = Mutex.new
|
26
|
+
@pool = 0
|
27
|
+
@pool_size = 0
|
28
|
+
end
|
29
|
+
|
30
|
+
# 0 ≤ return_value < 2^size_bits
|
31
|
+
def exp size_bits
|
32
|
+
@mutex.synchronize do
|
33
|
+
while @pool_size < size_bits
|
34
|
+
# Push 32×8 bits to the pool.
|
35
|
+
SecureRandom.random_bytes(32).unpack('Q*').each do |byte|
|
36
|
+
@pool = (@pool << 64) | byte
|
37
|
+
@pool_size += 64
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Unshift size_bits bits from the pool.
|
42
|
+
@pool_size -= size_bits
|
43
|
+
bits = @pool >> @pool_size
|
44
|
+
@pool ^= bits << @pool_size
|
45
|
+
|
46
|
+
bits
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def float n=1
|
51
|
+
n*Math.ldexp(exp(Float::MANT_DIG), -Float::MANT_DIG)
|
52
|
+
end
|
53
|
+
|
54
|
+
def int n
|
55
|
+
float(n).floor
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect
|
59
|
+
"#<#{self.class}: pool_size=#{@pool_size}>"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
RANDOM = Random.instance
|
64
|
+
end
|
65
|
+
|
66
|
+
# vim:set et sw=2 sts=2:
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# mischacks – Miscellaneous methods that may or may not be useful
|
2
|
+
# Copyright © 2010 Johan Kiviniemi
|
3
|
+
#
|
4
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
5
|
+
# purpose with or without fee is hereby granted, provided that the above
|
6
|
+
# copyright notice and this permission notice appear in all copies.
|
7
|
+
#
|
8
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
|
16
|
+
require File.expand_path(File.dirname(__FILE__)+'/../spec_helper.rb')
|
17
|
+
require 'mischacks/password'
|
18
|
+
|
19
|
+
require 'set'
|
20
|
+
|
21
|
+
describe MiscHacks::Password do
|
22
|
+
def match expected
|
23
|
+
simple_matcher("match #{expected.inspect}") do |given, matcher|
|
24
|
+
matcher.failure_message = "expected #{given.inspect} to match #{expected.inspect}"
|
25
|
+
matcher.negative_failure_message = "expected #{given.inspect} not to match #{expected.inspect}"
|
26
|
+
given.match? expected
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
before :all do
|
31
|
+
@many = 1000
|
32
|
+
|
33
|
+
@password = 'foo'
|
34
|
+
@salt = 'bar'
|
35
|
+
@encrypted = @password.crypt('$6$%s$' % @salt)
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'SALT_SET' do
|
39
|
+
salt_set = MiscHacks::Password::SALT_SET
|
40
|
+
|
41
|
+
it 'should be an array' do
|
42
|
+
salt_set.should be_an Array
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should contain 64 unique values' do
|
46
|
+
salt_set.length.should == 64
|
47
|
+
salt_set.to_set.length.should == 64
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should have characters as values' do
|
51
|
+
salt_set.each do |char|
|
52
|
+
char.should be_a String
|
53
|
+
char.bytesize.should == 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'random_salt' do
|
59
|
+
it 'should return strings of random length between 9 and 16' do
|
60
|
+
range = 9..16
|
61
|
+
counts = Array.new(range.max - range.min + 1) { 0 }
|
62
|
+
|
63
|
+
@many.times do
|
64
|
+
size = MiscHacks::Password.random_salt.bytesize
|
65
|
+
range.should include size
|
66
|
+
counts[size - range.min] += 1
|
67
|
+
end
|
68
|
+
|
69
|
+
probabilities = counts.map {|c| counts.length * c / @many.to_f }
|
70
|
+
|
71
|
+
probabilities.stddev.should be_close 0.0, 0.15
|
72
|
+
(probabilities.min - probabilities.mean).should be_close 0.0, 0.30
|
73
|
+
(probabilities.max - probabilities.mean).should be_close 0.0, 0.30
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should use SALT_SET with a sane distribution' do
|
77
|
+
salt_set = MiscHacks::Password::SALT_SET
|
78
|
+
|
79
|
+
counts = Array.new(salt_set.length) { 0 }
|
80
|
+
num_chars = 0
|
81
|
+
@many.times do
|
82
|
+
MiscHacks::Password.random_salt.each_char do |char|
|
83
|
+
MiscHacks::Password::SALT_SET.should include char
|
84
|
+
|
85
|
+
counts[salt_set.index(char)] += 1
|
86
|
+
num_chars += 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
probabilities = counts.map {|c| salt_set.length * c / num_chars.to_f }
|
91
|
+
|
92
|
+
probabilities.stddev.should be_close 0.0, 0.15
|
93
|
+
(probabilities.min - probabilities.mean).should be_close 0.0, 0.30
|
94
|
+
(probabilities.max - probabilities.mean).should be_close 0.0, 0.30
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'new_from_password' do
|
99
|
+
it 'should return a new instance with the parameter encrypted with random_salt' do
|
100
|
+
MiscHacks::Password.should_receive(:random_salt).once.and_return(@salt)
|
101
|
+
|
102
|
+
pw = MiscHacks::Password.new_from_password @password
|
103
|
+
pw.should be_a MiscHacks::Password
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe 'initialize' do
|
108
|
+
it 'should verify the format of the parameter' do
|
109
|
+
['', 'foo', 'foo$$$', '$foo$$', '$$foo$', '$$$foo'].each do |str|
|
110
|
+
lambda { MiscHacks::Password.new str }.
|
111
|
+
should raise_exception ArgumentError
|
112
|
+
end
|
113
|
+
|
114
|
+
['$foo$foo$foo', @encrypted].each do |str|
|
115
|
+
lambda { MiscHacks::Password.new str }.should_not raise_exception
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'match?' do
|
121
|
+
it 'should verify whether the cleartext parameter matches the encrypted password' do
|
122
|
+
%w{foo bar baz}.each do |password|
|
123
|
+
pw = MiscHacks::Password.new_from_password password
|
124
|
+
pw.should match password
|
125
|
+
pw.should_not match "#{password}x"
|
126
|
+
pw.should_not match ''
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'to_s' do
|
132
|
+
it 'should return the encrypted password' do
|
133
|
+
MiscHacks::Password.new(@encrypted).to_s.should == @encrypted
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# mischacks – Miscellaneous methods that may or may not be useful
|
2
|
+
# Copyright © 2010 Johan Kiviniemi
|
3
|
+
#
|
4
|
+
# Permission to use, copy, modify, and/or distribute this software for any
|
5
|
+
# purpose with or without fee is hereby granted, provided that the above
|
6
|
+
# copyright notice and this permission notice appear in all copies.
|
7
|
+
#
|
8
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
|
16
|
+
require File.expand_path(File.dirname(__FILE__)+'/../spec_helper.rb')
|
17
|
+
require 'mischacks/random'
|
18
|
+
|
19
|
+
require 'ostruct'
|
20
|
+
|
21
|
+
describe MiscHacks::Random do
|
22
|
+
before :all do
|
23
|
+
@many = 1000
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should define MiscHacks::RANDOM as an instance' do
|
27
|
+
MiscHacks::RANDOM.should == MiscHacks::Random.instance
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.spec_method meth, params, &block
|
31
|
+
params = OpenStruct.new params
|
32
|
+
|
33
|
+
describe meth do
|
34
|
+
it "should return #{params.return_type} values" do
|
35
|
+
params.args.each do |arg|
|
36
|
+
MiscHacks::RANDOM.send(meth, arg).should be_a params.return_type
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return #{params.range_str}" do
|
41
|
+
params.args.each do |arg|
|
42
|
+
range = params.range_for_arg.call arg
|
43
|
+
@many.times do
|
44
|
+
range.should include MiscHacks::RANDOM.send(meth, arg)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should have a sane distribution' do
|
50
|
+
params.args.each do |arg|
|
51
|
+
quarter = params.quarter_for_arg.call arg
|
52
|
+
|
53
|
+
counts = (0...@many).inject [0, 0, 0] do |c, i|
|
54
|
+
n = MiscHacks::RANDOM.send(meth, arg)
|
55
|
+
[
|
56
|
+
c[0] + if n < quarter then 1 else 0 end,
|
57
|
+
c[1] + if n < quarter*2 then 1 else 0 end,
|
58
|
+
c[2] + if n < quarter*3 then 1 else 0 end,
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
counts.each_with_index do |count, i|
|
63
|
+
count.should be_close @many*0.25*(i+1), 50
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
instance_eval &block if block
|
68
|
+
end
|
69
|
+
|
70
|
+
if params.default_arg
|
71
|
+
it "should have #{params.default_arg} as the default argument" do
|
72
|
+
MiscHacks::RANDOM.method(meth).arity.should == -1
|
73
|
+
|
74
|
+
half = params.default_arg * 0.5
|
75
|
+
|
76
|
+
n = (0...@many).inject 0.0 do |sum, i|
|
77
|
+
sum + if MiscHacks::RANDOM.send(meth) < half then 1 else 0 end
|
78
|
+
end
|
79
|
+
|
80
|
+
n.should be_close @many*0.5, 50
|
81
|
+
end
|
82
|
+
|
83
|
+
else
|
84
|
+
it 'should have no default argument' do
|
85
|
+
MiscHacks::RANDOM.method(meth).arity.should == 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
spec_method :exp,
|
92
|
+
:return_type => Integer,
|
93
|
+
:range_str => '0 <= n < 2**size_bits',
|
94
|
+
:range_for_arg => lambda {|arg| 0...2**arg },
|
95
|
+
:quarter_for_arg => lambda {|arg| 2**(arg-2) },
|
96
|
+
:args => [2, 42, 99, 2345]
|
97
|
+
|
98
|
+
spec_method :float,
|
99
|
+
:return_type => Float,
|
100
|
+
:range_str => '0.0 <= n < max',
|
101
|
+
:range_for_arg => lambda {|arg| 0.0...arg },
|
102
|
+
:quarter_for_arg => lambda {|arg| arg*0.25 },
|
103
|
+
:args => [0.5, 1.5, 99.0, 1234567.8],
|
104
|
+
:default_arg => 1.0
|
105
|
+
|
106
|
+
spec_method :int,
|
107
|
+
:return_type => Integer,
|
108
|
+
:range_str => '0 <= n < max',
|
109
|
+
:range_for_arg => lambda {|arg| 0...arg },
|
110
|
+
:quarter_for_arg => lambda {|arg| arg/4 },
|
111
|
+
:args => [1, 2, 42, 99, 1234567].map {|n| n*4 }
|
112
|
+
end
|
113
|
+
|
114
|
+
# vim:set et sw=2 sts=2:
|
data/spec/spec_helper.rb
CHANGED
@@ -23,6 +23,21 @@ class Object
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
module Enumerable
|
27
|
+
def mean
|
28
|
+
inject(:+) / length.to_f
|
29
|
+
end
|
30
|
+
|
31
|
+
def stddev
|
32
|
+
Math.sqrt variance
|
33
|
+
end
|
34
|
+
|
35
|
+
def variance
|
36
|
+
mean_ = mean
|
37
|
+
inject(0) {|sum, e| sum + (e - mean_)**2} / length.to_f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
26
41
|
Spec::Matchers.define :exit_with do |expected|
|
27
42
|
match do |block|
|
28
43
|
@status = 0
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mischacks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johan Kiviniemi
|
@@ -9,11 +9,11 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-08-
|
12
|
+
date: 2010-08-29 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
16
|
-
description: "sh: Safely pass untrusted parameters to sh scripts. overwrite: Safely replace a file. Exception#to_formatted_string: Return a string that looks like how Ruby would dump an uncaught exception."
|
16
|
+
description: "sh: Safely pass untrusted parameters to sh scripts. overwrite: Safely replace a file. Exception#to_formatted_string: Return a string that looks like how Ruby would dump an uncaught exception. Random: Generate various types of random numbers using SecureRandom. Password: A small wrapper for String#crypt that does secure salt generation and easy password verification."
|
17
17
|
email: devel@johan.kiviniemi.name
|
18
18
|
executables: []
|
19
19
|
|
@@ -22,6 +22,7 @@ extensions: []
|
|
22
22
|
extra_rdoc_files:
|
23
23
|
- README.txt
|
24
24
|
files:
|
25
|
+
- .gitignore
|
25
26
|
- COPYING
|
26
27
|
- History.txt
|
27
28
|
- Manifest.txt
|
@@ -29,6 +30,10 @@ files:
|
|
29
30
|
- Rakefile
|
30
31
|
- VERSION
|
31
32
|
- lib/mischacks.rb
|
33
|
+
- lib/mischacks/password.rb
|
34
|
+
- lib/mischacks/random.rb
|
35
|
+
- spec/mischacks/password_spec.rb
|
36
|
+
- spec/mischacks/random_spec.rb
|
32
37
|
- spec/mischacks_spec.rb
|
33
38
|
- spec/spec_helper.rb
|
34
39
|
has_rdoc: true
|
@@ -60,5 +65,7 @@ signing_key:
|
|
60
65
|
specification_version: 3
|
61
66
|
summary: Miscellaneous methods that may or may not be useful
|
62
67
|
test_files:
|
68
|
+
- spec/mischacks/random_spec.rb
|
69
|
+
- spec/mischacks/password_spec.rb
|
63
70
|
- spec/spec_helper.rb
|
64
71
|
- spec/mischacks_spec.rb
|