Generate recovery keys on TOTP setup
This commit is contained in:
parent
ab03fadaef
commit
b4f479a00f
|
@ -190,13 +190,14 @@ class UserController < ApplicationController
|
||||||
current_user.otp_module = :enabled
|
current_user.otp_module = :enabled
|
||||||
|
|
||||||
if current_user.authenticate_otp(req_params[:otp_validation], drift: APP_CONFIG.fetch(:otp_drift_period, 30).to_i)
|
if current_user.authenticate_otp(req_params[:otp_validation], drift: APP_CONFIG.fetch(:otp_drift_period, 30).to_i)
|
||||||
flash[:success] = t('views.auth.2fa.setup.success')
|
@recovery_keys = TotpRecoveryCode.create!(Array.new(10) { {user: current_user, code: SecureRandom.base58(8).downcase} })
|
||||||
current_user.save!
|
current_user.save!
|
||||||
|
|
||||||
|
render 'settings/security/recovery_keys'
|
||||||
else
|
else
|
||||||
flash[:error] = t('views.auth.2fa.errors.invalid_code')
|
flash[:error] = t('views.auth.2fa.errors.invalid_code')
|
||||||
|
redirect_to edit_user_security_path
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to edit_user_security_path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy_2fa
|
def destroy_2fa
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
class TotpRecoveryCode < ApplicationRecord
|
||||||
|
belongs_to :user
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
%p= t('views.auth.2fa.setup.success')
|
||||||
|
|
||||||
|
%ul
|
||||||
|
- @recovery_keys.each do |key|
|
||||||
|
%li
|
||||||
|
%code= key.code
|
|
@ -0,0 +1,9 @@
|
||||||
|
class CreateTotpRecoveryCodes < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :totp_recovery_codes do |t|
|
||||||
|
t.bigint :user_id
|
||||||
|
t.string :code, limit: 8
|
||||||
|
end
|
||||||
|
add_index :totp_recovery_codes, [:user_id, :code]
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_10_18_090453) do
|
ActiveRecord::Schema.define(version: 2020_11_01_155648) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -219,6 +219,12 @@ ActiveRecord::Schema.define(version: 2020_10_18_090453) do
|
||||||
t.index ["user_id", "created_at"], name: "index_themes_on_user_id_and_created_at"
|
t.index ["user_id", "created_at"], name: "index_themes_on_user_id_and_created_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "totp_recovery_codes", force: :cascade do |t|
|
||||||
|
t.bigint "user_id"
|
||||||
|
t.string "code", limit: 8
|
||||||
|
t.index ["user_id", "code"], name: "index_totp_recovery_codes_on_user_id_and_code"
|
||||||
|
end
|
||||||
|
|
||||||
create_table "users", id: :bigint, default: -> { "gen_timestamp_id('users'::text)" }, force: :cascade do |t|
|
create_table "users", id: :bigint, default: -> { "gen_timestamp_id('users'::text)" }, force: :cascade do |t|
|
||||||
t.string "email", default: "", null: false
|
t.string "email", default: "", null: false
|
||||||
t.string "encrypted_password", default: "", null: false
|
t.string "encrypted_password", default: "", null: false
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# From Rails 6
|
||||||
|
# Remove once upgraded
|
||||||
|
module SecureRandom
|
||||||
|
BASE36_ALPHABET = ("0".."9").to_a + ("a".."z").to_a
|
||||||
|
# SecureRandom.base36 generates a random base36 string in lowercase.
|
||||||
|
#
|
||||||
|
# The argument _n_ specifies the length of the random string to be generated.
|
||||||
|
#
|
||||||
|
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
||||||
|
# This method can be used over +base58+ if a deterministic case key is necessary.
|
||||||
|
#
|
||||||
|
# The result will contain alphanumeric characters in lowercase.
|
||||||
|
#
|
||||||
|
# p SecureRandom.base36 # => "4kugl2pdqmscqtje"
|
||||||
|
# p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
|
||||||
|
def self.base36(n = 16)
|
||||||
|
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
||||||
|
idx = byte % 64
|
||||||
|
idx = SecureRandom.random_number(36) if idx >= 36
|
||||||
|
BASE36_ALPHABET[idx]
|
||||||
|
end.join
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe TotpRecoveryCode, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
Loading…
Reference in New Issue