summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-21 15:21:26 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-10-21 15:21:26 +0000
commitb867882a1c2a358bb7a46f84365c86a959d35240 (patch)
tree041ca5d0e77d08e53cd8a6c965f8ce3277fff65e
parentcd381d8acca042d969c72da64ecd2088a6000a0d (diff)
SecureRandom.alphanumeric implemented.
[ruby-core:68098] [Feature #10849] proposed by Andrew Butterfield. SecureRandom.choose and SecureRandom.graph is not included. (The implementation has SecureRandom.choose but it is private.) I feel the method name, SecureRandom.choose, doesn't represent the behavior well. The actual use cases of SecureRandom.graph is not obvious. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60297 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--NEWS4
-rw-r--r--lib/securerandom.rb44
-rw-r--r--test/test_securerandom.rb7
3 files changed, 53 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index e340872df6..18cd045ddc 100644
--- a/NEWS
+++ b/NEWS
@@ -191,6 +191,10 @@ with all sufficient information, see the ChangeLog file or Redmine
* http://blog.rubygems.org/2017/08/27/2.6.13-released.html
* http://blog.rubygems.org/2017/10/09/unsafe-object-deserialization-vulnerability.html
+* SecureRandom
+ * New methods:
+ * SecureRandom.alphanumeric
+
* Set
* Add Set#to_s as alias to #inspect [Feature #13676]
* Add Set#=== as alias to #include? [Feature #13801]
diff --git a/lib/securerandom.rb b/lib/securerandom.rb
index 2140a7e1fc..3ee5cbd4d6 100644
--- a/lib/securerandom.rb
+++ b/lib/securerandom.rb
@@ -222,10 +222,50 @@ module Random::Formatter
"%08x-%04x-%04x-%04x-%04x%08x" % ary
end
- private
- def gen_random(n)
+ private def gen_random(n)
self.bytes(n)
end
+
+ # SecureRandom.choose generates a string that randomly draws from a
+ # source array of characters.
+ #
+ # The argument _source_ specifies the array of characters from which
+ # to generate the string.
+ # The argument _n_ specifies the length, in characters, of the string to be
+ # generated.
+ #
+ # The result may contain whatever characters are in the source array.
+ #
+ # p SecureRandom.choose([*'l'..'r']) #=> "lmrqpoonmmlqlron"
+ # p SecureRandom.choose([*'0'..'9'], 5) #=> "27309"
+ #
+ # If a secure random number generator is not available,
+ # +NotImplementedError+ is raised.
+ private def choose(source, n)
+ size = source.size
+ n.times.map {source[random_number(size)]}.join('')
+ end
+
+ ALPHANUMERIC = [*'A'..'Z', *'a'..'z', *'0'..'9']
+ # SecureRandom.alphanumeric generates a random alphanumeric string.
+ #
+ # The argument _n_ specifies the length, in characters, of the alphanumeric
+ # string to be generated.
+ #
+ # If _n_ is not specified or is nil, 16 is assumed.
+ # It may be larger in the future.
+ #
+ # The result may contain A-Z, a-z and 0-9.
+ #
+ # p SecureRandom.alphanumeric #=> "2BuBuLf3WfSKyQbR"
+ # p SecureRandom.alphanumeric(10) #=> "i6K93NdqiH"
+ #
+ # If a secure random number generator is not available,
+ # +NotImplementedError+ is raised.
+ def alphanumeric(n=nil)
+ n = 16 if n.nil?
+ choose(ALPHANUMERIC, n)
+ end
end
SecureRandom.extend(Random::Formatter)
diff --git a/test/test_securerandom.rb b/test/test_securerandom.rb
index f2cc7f553b..9b2c8a5e67 100644
--- a/test/test_securerandom.rb
+++ b/test/test_securerandom.rb
@@ -143,6 +143,13 @@ end
assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid)
end
+ def test_alphanumeric
+ 65.times do |idx|
+ an = @it.alphanumeric
+ assert_match(/^[0-9a-zA-Z]+$/, an)
+ end
+ end
+
def protect
begin
yield