Merged pull request #50.
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -17,6 +17,7 @@ gem 'kaminari', github: 'jomo/kaminari', branch: 'patch-2' # pagination
|
|||||||
gem 'jquery-textcomplete-rails' # @mentions
|
gem 'jquery-textcomplete-rails' # @mentions
|
||||||
gem 'actionpack-action_caching', github: 'antulik/actionpack-action_caching', ref: '8c6e52c69315d67437f480da5dce4b7c8737fb32'
|
gem 'actionpack-action_caching', github: 'antulik/actionpack-action_caching', ref: '8c6e52c69315d67437f480da5dce4b7c8737fb32'
|
||||||
gem 'mail-gpg', github: 'jomo/mail-gpg', ref: 'a666b48ee866dfa3eaa700f9c5edf4d195d0f8c9'
|
gem 'mail-gpg', github: 'jomo/mail-gpg', ref: 'a666b48ee866dfa3eaa700f9c5edf4d195d0f8c9'
|
||||||
|
gem 'totp'
|
||||||
|
|
||||||
# Gems used only for assets and not required
|
# Gems used only for assets and not required
|
||||||
# in production environments by default.
|
# in production environments by default.
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ GEM
|
|||||||
airbrussh (1.3.0)
|
airbrussh (1.3.0)
|
||||||
sshkit (>= 1.6.1, != 1.7.0)
|
sshkit (>= 1.6.1, != 1.7.0)
|
||||||
arel (6.0.4)
|
arel (6.0.4)
|
||||||
|
base32 (0.3.2)
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
better_errors (2.4.0)
|
better_errors (2.4.0)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
@@ -237,6 +238,8 @@ GEM
|
|||||||
thor (0.20.0)
|
thor (0.20.0)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.8)
|
tilt (2.0.8)
|
||||||
|
totp (1.0.0)
|
||||||
|
base32
|
||||||
tzinfo (1.2.5)
|
tzinfo (1.2.5)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (4.1.8)
|
uglifier (4.1.8)
|
||||||
@@ -277,10 +280,11 @@ DEPENDENCIES
|
|||||||
sass-rails
|
sass-rails
|
||||||
sqlite3
|
sqlite3
|
||||||
strip_attributes
|
strip_attributes
|
||||||
|
totp
|
||||||
tzinfo-data
|
tzinfo-data
|
||||||
uglifier
|
uglifier
|
||||||
unicorn
|
unicorn
|
||||||
webrick
|
webrick
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.16.1
|
1.16.2
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
protect_from_forgery
|
protect_from_forgery
|
||||||
before_filter :update_ip, :update_seen, :check_banned
|
before_filter :update_ip, :update_seen, :check_banned, :check_2fa
|
||||||
# TODO: use SSL
|
# TODO: use SSL
|
||||||
|
|
||||||
|
|
||||||
@@ -41,6 +41,14 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_2fa
|
||||||
|
# Over complicated way of asking if the user is logged in as a mod without TOTP enabled while they are not on their login settings screen, logging out, or updating their login settings.
|
||||||
|
if current_user && current_user.mod? && !current_user.totp_enabled? && !(controller_name == "users" && action_name == "edit_login") && !(controller_name == "sessions" && action_name == "destroy") && !(controller_name == "users" && action_name == "update_login")
|
||||||
|
flash[:alert] = "Due to your staff rank, you are required to enable 2FA."
|
||||||
|
redirect_to :controller => "users", :action => "edit_login", :id => current_user.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
#roles
|
#roles
|
||||||
def disabled?
|
def disabled?
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ class SessionsController < ApplicationController
|
|||||||
flash[:alert] = "Your account has been disabled!"
|
flash[:alert] = "Your account has been disabled!"
|
||||||
elsif user.banned?
|
elsif user.banned?
|
||||||
flash[:alert] = "You are banned!"
|
flash[:alert] = "You are banned!"
|
||||||
|
elsif user.totp_enabled && !TOTP.valid?(user.totp_secret, params[:totp_code].to_i)
|
||||||
|
flash[:alert] = "You're doing it wrong!"
|
||||||
|
render action: 'new'
|
||||||
|
return
|
||||||
else
|
else
|
||||||
session[:user_id] = user.id
|
session[:user_id] = user.id
|
||||||
flash[:notice] = "Logged in!"
|
flash[:notice] = "Logged in!"
|
||||||
@@ -110,4 +114,4 @@ class SessionsController < ApplicationController
|
|||||||
redirect_to login_path
|
redirect_to login_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -241,6 +241,11 @@ class UsersController < ApplicationController
|
|||||||
unless @user.is?(current_user) || admin? && current_user.role > @user.role || superadmin?
|
unless @user.is?(current_user) || admin? && current_user.role > @user.role || superadmin?
|
||||||
flash[:alert] = "You are not allowed to edit this user's login details!"
|
flash[:alert] = "You are not allowed to edit this user's login details!"
|
||||||
redirect_to @user
|
redirect_to @user
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if !@user.totp_enabled
|
||||||
|
@user.update(totp_secret: TOTP.secret)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -263,6 +268,18 @@ class UsersController < ApplicationController
|
|||||||
@user.email_token = SecureRandom.hex(16) if mail_changed
|
@user.email_token = SecureRandom.hex(16) if mail_changed
|
||||||
@user.confirmed = !mail_changed
|
@user.confirmed = !mail_changed
|
||||||
|
|
||||||
|
if params[:user][:totp_enabled] == "1" && !@user.totp_enabled
|
||||||
|
if TOTP.valid?(@user.totp_secret, params[:totp_code].to_i)
|
||||||
|
@user.totp_enabled = true
|
||||||
|
else
|
||||||
|
flash[:alert] = "Wrong TOTP code!"
|
||||||
|
render action: "edit_login"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
elsif params[:user][:totp_enabled] == "0" && @user.totp_enabled
|
||||||
|
@user.totp_enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
# checking here for password so we can send back changes to the view
|
# checking here for password so we can send back changes to the view
|
||||||
if authenticated
|
if authenticated
|
||||||
if @user.save
|
if @user.save
|
||||||
@@ -370,7 +387,7 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_params(add = [])
|
def user_params(add = [])
|
||||||
a = [:ign, :email, :password, :password_confirmation, :mail_own_thread_reply, :mail_other_thread_reply, :mail_own_blogpost_comment, :mail_other_blogpost_comment, :mail_mention, :public_key] + add
|
a = [:ign, :email, :password, :password_confirmation, :mail_own_thread_reply, :mail_other_thread_reply, :mail_own_blogpost_comment, :mail_other_blogpost_comment, :mail_mention, :public_key, :totp_code] + add
|
||||||
params.require(:user).permit(a)
|
params.require(:user).permit(a)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,6 +16,14 @@
|
|||||||
<td></td>
|
<td></td>
|
||||||
<td><%= link_to "Lost your password?", lost_password_users_path %></td>
|
<td><%= link_to "Lost your password?", lost_password_users_path %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><%= label_tag :totp_code %></td>
|
||||||
|
<td><%= text_field_tag :totp_code, nil, placeholder: "123456", required: false %></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>Leave this field blank if you do not have 2FA enabled.</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<p><%= submit_tag "Log in", class: "btn blue" %></p>
|
<p><%= submit_tag "Log in", class: "btn blue" %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
<p><%= f.submit "Save Profile", class: "btn variable-size left", disabled: (!@user.confirmed? && @user.is?(current_user)) %></p>
|
<p><%= f.submit "Save Profile", class: "btn variable-size left", disabled: (!@user.confirmed? && @user.is?(current_user)) %></p>
|
||||||
<p>
|
<p>
|
||||||
<%= link_to "Edit Login Details", edit_login_user_path(@user), class: "btn variable-size right" %>
|
<%= link_to "Login Settings", edit_login_user_path(@user), class: "btn variable-size right" %>
|
||||||
<%= link_to "Notification Settings", edit_notifications_user_path(@user), class: "btn variable-size right" %>
|
<%= link_to "Notification Settings", edit_notifications_user_path(@user), class: "btn variable-size right" %>
|
||||||
<%= link_to "Website Settings", edit_website_settings_user_path(@user), class: "btn variable-size right" %>
|
<%= link_to "Website Settings", edit_website_settings_user_path(@user), class: "btn variable-size right" %>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<% title "Edit Login Credentials: #{@user.name}" %>
|
<% title "Edit Login Credentials: #{@user.name}" %>
|
||||||
|
|
||||||
<%= link_to @user.name, @user %> → Edit Login credentials
|
<%= link_to @user.name, @user %> → Edit Login settings
|
||||||
<h1>Edit Login Credentials</h1>
|
<h1>Edit Login Settings</h1>
|
||||||
|
|
||||||
|
|
||||||
<%= form_for @user, url: update_login_user_path(@user), method: :put do |f| %>
|
<%= form_for @user, url: update_login_user_path(@user), method: :put do |f| %>
|
||||||
@@ -25,12 +25,49 @@
|
|||||||
<%= f.password_field :password_confirmation %>
|
<%= f.password_field :password_confirmation %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>2FA Enabled</td>
|
||||||
|
<td>
|
||||||
|
<%= f.check_box :totp_enabled %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>TOTP Secret</td>
|
||||||
|
<td>
|
||||||
|
<% if !@user.totp_enabled? %>
|
||||||
|
<%= f.text_field :totp_secret, :readonly => true %>
|
||||||
|
<% else %>
|
||||||
|
<i>2FA is currently enabled. Disable 2FA to generate a new secret.</i>
|
||||||
|
<% end %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Current password</td>
|
<td>Current password</td>
|
||||||
<td>
|
<td>
|
||||||
<%= password_field_tag :current_password, nil, disabled: !@user.is?(current_user) %>
|
<%= password_field_tag :current_password, nil, disabled: !@user.is?(current_user) %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<% if !@user.totp_enabled? %>
|
||||||
|
<tr>
|
||||||
|
<td>TOTP Code</td>
|
||||||
|
<td>
|
||||||
|
<%= text_field_tag :totp_code, nil, disabled: !@user.is?(current_user) %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td><i>Leave this field blank if you are not enabling 2FA.</i></td>
|
||||||
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p><%= f.submit "Save Changes", class: "btn blue left" %></p>
|
<p><%= f.submit "Save Changes", class: "btn blue left" %></p>
|
||||||
|
|||||||
6
db/migrate/20180606223258_add_totp_to_users.rb
Normal file
6
db/migrate/20180606223258_add_totp_to_users.rb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
class AddTotpToUsers < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :users, :totp_secret, :string
|
||||||
|
add_column :users, :totp_enabled, :boolean, default: false
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,7 +11,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: 20171013001146) do
|
ActiveRecord::Schema.define(version: 20180606223258) do
|
||||||
|
|
||||||
create_table "badges", force: :cascade do |t|
|
create_table "badges", force: :cascade do |t|
|
||||||
t.string "name", limit: 191
|
t.string "name", limit: 191
|
||||||
@@ -154,6 +154,8 @@ ActiveRecord::Schema.define(version: 20171013001146) do
|
|||||||
t.boolean "header_scroll", default: false
|
t.boolean "header_scroll", default: false
|
||||||
t.boolean "dark", default: false
|
t.boolean "dark", default: false
|
||||||
t.text "public_key", limit: 65535
|
t.text "public_key", limit: 65535
|
||||||
|
t.string "totp_secret", limit: 255
|
||||||
|
t.boolean "totp_enabled", default: false
|
||||||
end
|
end
|
||||||
|
|
||||||
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
|
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
|
||||||
|
|||||||
Reference in New Issue
Block a user