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