Home>

I am writing an application with rails and implementing a test user login function.
I'd like to generate a password randomly, but it's not working, so please help me.

Development environment

Ruby 2.6.5
Rails 6.0.3.3

Current code
class Users :: SessionsController<Devise :: SessionsController
  def new_guest
    user = User.find_or_create_by! (nickname:'guest user', email:'[email protected]') do | user |
      user.password = SecureRandom.alphanumeric
    end
    sign_in user
    redirect_to root_path, notice:'You have logged in as a guest user. '
  end
end

The following validations are set for the model

PASSWORD_REGEX =/\ A (? =. *? [A-z]) (? =. *? [\ D]) [a-z \ d] + \ z/i.freeze
  validates_format_of: password, with: PASSWORD_REGEX, on:: create, message:'Please include both half-width alphabetic characters and half-width numbers'

Because you have specified mixed alphanumeric validationSecureRandom.alphanumericMay cause an error.
Therefore, when I investigated other methodsSecureRandom.hexI thought it would be good to use, but I don't understand the hex string well.

Therefore, I would like to know the following two points.

1.SecureRandom.hexIs a mixed alphanumeric character string always generated when (A 32-digit password is generated without specifying an argument)?
2. I would like to know if there is a way to generate a random password (mixed alphanumeric characters) other than SecureRandom.

  • Answer # 1

    This is a brute force, but it is a case of generating a 32-character password.
    Generate 30 characters with SecureRandom.alphanumeric. (And convert to lowercase)
    Add one random alphabet and one number to the remaining two digits.
    At worst, one letter contains alphabets and numbers.
    If you want to increase the number of digits or the number of digits of the alphabet, please adjust the number of digits appropriately.
    If you want to use 2 letters of the alphabet and 3 letters of the number
    addw = [*'a' ..'z'] .sample (2) .join + [* '0' .. '9'] .sample (3) .join
    To do. Reduce the number of digits in SecureRandom.alphanumeric accordingly.

    require'securerandom'
    #Lowercase password
    pass = SecureRandom.alphanumeric (30) .downcase
    #Add one random alphabet and one number just in case
    addw = [*'a' ..'z'] .sample (1) .join + [* '0' .. '9'] .sample (1) .join
    pw = pass + addw
    p pass
    p addw
    p p w
    #Shuffle because the end is always a number
    pw = pw.scan (/./). shuffle.join
    p p w


    Execution result
    "8c4xnagoqc6mqzsk01e2y6jbrho0lp"
    "u3"
    "8c4xnagoqc6mqzsk01e2y6jbrho0lpu3"
    "lbz46uch8ro06g3oykqpe2nq1cs0jmxa"

  • Answer # 2

    If I use SecureRandom.hex (a 32-digit password is generated without specifying an argument), is a mixed alphanumeric character string always generated?

    There is no guarantee that this will happen.Completely randomIf so, it would be strange if there is no probability that "only numbers" or "only letters" will appear.

    I would like to know if there is a way to generate a random password (mixed alphanumeric characters) other than SecureRandom.

    If you want to exclude the method of reducing randomness, "until the conditions are met"SecureRandomI think it's easiest to keep pulling.

  • Answer # 3

    How about using mkpasswd or pwgen? (It cannot be used unless it is installed in the OS)

    Below, I have never used ruby ​​and just installed and tried it now, so there is a possibility that it is not recommended.

    require'open3'
    stdin, stdout, stderr, wait_thr = Open3.popen3 ('pwgen -s 32 -n 1 -c 1 1')
    pw = stdout.gets (nil)
    #unconfirmed
    require'open3'
    stdin, stdout, stderr, wait_thr = Open3.popen3 ('mkpasswd -l 32 -c 1 -C 1 -d 1 -s 0')
    pw = stdout.gets (nil)


    ubuntu has confirmed the operation, but I can't answer the question because I have already deleted ruby.

    Postscript

    There seems to be a library that has similar options, so only an introduction.
    https://www.rubydoc.info/gems/pwgen/1.0.2
    * As mentioned above, ruby ​​has been deleted, so we have not confirmed it.