7ab06d1dbd
#sample uses PRNG under the hood which is pseudo random, which means that given enough magic link codes you can predict which code would come next. To fix that we have to switch to CSPRNG - SecureRandom.random_number - which isn't easy to predict based on previous results.
32 lines
813 B
Ruby
32 lines
813 B
Ruby
module MagicLink::Code
|
|
CODE_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ".chars.freeze
|
|
CODE_SUBSTITUTIONS = { "O" => "0", "I" => "1", "L" => "1" }.freeze
|
|
|
|
class << self
|
|
def generate(length)
|
|
Array.new(length) { CODE_ALPHABET[SecureRandom.random_number(CODE_ALPHABET.length)] }.join
|
|
end
|
|
|
|
def sanitize(code)
|
|
return nil if code.blank?
|
|
|
|
normalize_code(code)
|
|
.then { apply_substitutions(_1) }
|
|
.then { remove_invalid_characters(_1) }
|
|
end
|
|
|
|
private
|
|
def normalize_code(code)
|
|
code.to_s.upcase
|
|
end
|
|
|
|
def apply_substitutions(code)
|
|
CODE_SUBSTITUTIONS.reduce(code) { |result, (from, to)| result.gsub(from, to) }
|
|
end
|
|
|
|
def remove_invalid_characters(code)
|
|
code.gsub(/[^#{CODE_ALPHABET.join}]/, "")
|
|
end
|
|
end
|
|
end
|