discourse/lib/common_passwords/common_passwords.rb
Sam Saffron 30990006a9 DEV: enable frozen string literal on all files
This reduces chances of errors where consumers of strings mutate inputs
and reduces memory usage of the app.

Test suite passes now, but there may be some stuff left, so we will run
a few sites on a branch prior to merging
2019-05-13 09:31:32 +08:00

57 lines
1.6 KiB
Ruby

# frozen_string_literal: true
# CommonPasswords will check a given password against a list of the most commonly used passwords.
# The list comes from https://github.com/danielmiessler/SecLists/tree/master/Passwords
# specifically the list of 10 million passwords, top 100k, filtered by length
#
# The list is stored in Redis at a key that is shared by all sites in a multisite config.
#
# If the password file is changed, you need to add a migration that deletes the list from redis
# so it gets re-populated:
#
# $redis.without_namespace.del CommonPasswords::LIST_KEY
class CommonPasswords
PASSWORD_FILE = File.join(Rails.root, 'lib', 'common_passwords', '10-char-common-passwords.txt')
LIST_KEY = 'discourse-common-passwords'
@mutex = Mutex.new
def self.common_password?(password)
return false unless password.present?
password_list.include?(password)
end
private
class RedisPasswordList
def include?(password)
CommonPasswords.redis.sismember CommonPasswords::LIST_KEY, password
end
end
def self.password_list
@mutex.synchronize do
load_passwords unless redis.scard(LIST_KEY) > 0
end
RedisPasswordList.new
end
def self.redis
$redis.without_namespace
end
def self.load_passwords
passwords = File.readlines(PASSWORD_FILE)
passwords.map!(&:chomp).each do |pwd|
# slower, but a tad more compatible
redis.sadd LIST_KEY, pwd
end
rescue Errno::ENOENT
# tolerate this so we don't block signups
Rails.logger.error "Common passwords file #{PASSWORD_FILE} is not found! Common password checking is skipped."
end
end