Class: GrimReaper::OtpModule
- Inherits:
-
Object
- Object
- GrimReaper::OtpModule
- Defined in:
- lib/grim_reaper/otp_module.rb
Overview
OTP (One-Time Password) authentication module
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#config_file ⇒ Object
readonly
Returns the value of attribute config_file.
-
#grim_root ⇒ Object
readonly
Returns the value of attribute grim_root.
-
#secret_file ⇒ Object
readonly
Returns the value of attribute secret_file.
Instance Method Summary collapse
-
#disable_otp ⇒ Object
Disable OTP authentication.
-
#execute(command, *args) ⇒ Object
Execute OTP-related commands.
-
#initialize(config = {}, grim_root = nil) ⇒ OtpModule
constructor
A new instance of OtpModule.
-
#regenerate_backup_codes ⇒ Object
Regenerate backup codes.
-
#setup_otp ⇒ Object
Setup OTP authentication.
-
#status ⇒ Object
Check OTP status.
-
#verify_otp(code) ⇒ Object
Verify OTP code.
Constructor Details
#initialize(config = {}, grim_root = nil) ⇒ OtpModule
Returns a new instance of OtpModule.
14 15 16 17 18 19 |
# File 'lib/grim_reaper/otp_module.rb', line 14 def initialize(config = {}, grim_root = nil) @config = config @grim_root = grim_root || Dir.pwd @secret_file = File.join(@grim_root, ".grim_otp_secret") @config_file = File.join(@grim_root, ".grim_otp_config") end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
12 13 14 |
# File 'lib/grim_reaper/otp_module.rb', line 12 def config @config end |
#config_file ⇒ Object (readonly)
Returns the value of attribute config_file.
12 13 14 |
# File 'lib/grim_reaper/otp_module.rb', line 12 def config_file @config_file end |
#grim_root ⇒ Object (readonly)
Returns the value of attribute grim_root.
12 13 14 |
# File 'lib/grim_reaper/otp_module.rb', line 12 def grim_root @grim_root end |
#secret_file ⇒ Object (readonly)
Returns the value of attribute secret_file.
12 13 14 |
# File 'lib/grim_reaper/otp_module.rb', line 12 def secret_file @secret_file end |
Instance Method Details
#disable_otp ⇒ Object
Disable OTP authentication
136 137 138 139 140 141 142 143 144 |
# File 'lib/grim_reaper/otp_module.rb', line 136 def disable_otp File.delete(@secret_file) if File.exist?(@secret_file) File.delete(@config_file) if File.exist?(@config_file) puts "🔓 OTP authentication disabled".colorize(:yellow) true rescue => e puts "Error disabling OTP: #{e.message}".colorize(:red) false end |
#execute(command, *args) ⇒ Object
Execute OTP-related commands
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/grim_reaper/otp_module.rb', line 118 def execute(command, *args) case command when 'setup' setup_otp when 'verify' verify_otp(args.first) when 'status' status when 'disable' disable_otp when 'regenerate-backup-codes' regenerate_backup_codes else { error: "Unknown OTP command: #{command}" } end end |
#regenerate_backup_codes ⇒ Object
Regenerate backup codes
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/grim_reaper/otp_module.rb', line 147 def regenerate_backup_codes return false unless otp_enabled? config_data = load_config backup_codes = generate_backup_codes config_data['backup_codes'] = backup_codes.map { |code| { code: code, used: false } } File.write(@config_file, JSON.pretty_generate(config_data)) puts "💾 New Backup Codes:".colorize(:yellow) backup_codes.each_with_index do |code, index| puts " #{index + 1}. #{code}".colorize(:cyan) end true rescue => e puts "Error regenerating backup codes: #{e.message}".colorize(:red) false end |
#setup_otp ⇒ Object
Setup OTP authentication
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/grim_reaper/otp_module.rb', line 22 def setup_otp secret = generate_secret # Save secret securely File.write(@secret_file, secret) File.chmod(0o600, @secret_file) # Generate QR code URL qr_url = generate_qr_url(secret) # Generate backup codes backup_codes = generate_backup_codes # Save configuration otp_config = { enabled: true, created_at: Time.now.iso8601, backup_codes: backup_codes.map { |code| { code: code, used: false } }, failed_attempts: 0, last_auth: nil } File.write(@config_file, JSON.pretty_generate(otp_config)) File.chmod(0o600, @config_file) puts "🔑 OTP Secret: #{secret}".colorize(:green) puts "📱 QR Code URL: #{qr_url}".colorize(:blue) puts "💾 Backup Codes:".colorize(:yellow) backup_codes.each_with_index do |code, index| puts " #{index + 1}. #{code}".colorize(:cyan) end puts "⚠️ Save these backup codes in a secure location!".colorize(:red) true rescue => e puts "Error setting up OTP: #{e.message}".colorize(:red) false end |
#status ⇒ Object
Check OTP status
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/grim_reaper/otp_module.rb', line 96 def status if otp_enabled? config_data = load_config { enabled: true, last_auth: config_data['last_auth'], failed_attempts: config_data['failed_attempts'] || 0, backup_codes_remaining: count_unused_backup_codes(config_data) } else { enabled: false, last_auth: nil, failed_attempts: 0, backup_codes_remaining: 0 } end rescue => e { error: e. } end |
#verify_otp(code) ⇒ Object
Verify OTP code
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/grim_reaper/otp_module.rb', line 62 def verify_otp(code) return false unless otp_enabled? config_data = load_config secret = load_secret # Check if it's a backup code if verify_backup_code(code, config_data) mark_backup_code_used(code, config_data) update_last_auth(config_data) return true end # Verify TOTP code current_time = Time.now.to_i / 30 # Check current and previous time windows (to handle clock skew) [-1, 0, 1].each do |offset| if generate_totp(secret, current_time + offset) == code.to_s.rjust(6, '0') update_last_auth(config_data) reset_failed_attempts(config_data) return true end end # Increment failed attempts increment_failed_attempts(config_data) false rescue => e puts "Error verifying OTP: #{e.message}".colorize(:red) false end |