summaryrefslogtreecommitdiff
path: root/app/models/user.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/user.rb')
-rw-r--r--app/models/user.rb31
1 files changed, 31 insertions, 0 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index bf0f40ee..c3035a02 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -25,6 +25,7 @@ class User < ApplicationRecord
25 :message => Authentication.bad_email_message 25 :message => Authentication.bad_email_message
26 26
27 validate :roles_are_known 27 validate :roles_are_known
28 validate :admin_needs_second_factor
28 29
29 # Authenticates a user by their login name and unencrypted password. Returns the user or nil. 30 # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
30 def self.authenticate(login, password) 31 def self.authenticate(login, password)
@@ -136,6 +137,30 @@ class User < ApplicationRecord
136 true 137 true
137 end 138 end
138 139
140 def grant_redaktion!(actor:)
141 return :already if redaktion?
142 return :no_second_factor unless otp_enrolled?
143
144 transaction do
145 update_column(:roles, (roles | ["redaktion"]).sort)
146 NodeAction.record!(:participants => [self], :user => actor,
147 :action => "redaktion_grant", :target_login => login)
148 end
149 :granted
150 end
151
152 def revoke_redaktion!(actor:)
153 return :already unless redaktion?
154 return :self unless actor != self
155
156 transaction do
157 update_column(:roles, (roles - ["redaktion"]).sort)
158 NodeAction.record!(:participants => [self], :user => actor,
159 :action => "redaktion_revoke", :target_login => login)
160 end
161 :revoked
162 end
163
139 # otp_secret present == enrolled. otp_pending_secret holds the secret 164 # otp_secret present == enrolled. otp_pending_secret holds the secret
140 # between QR display and first-code confirmation. otp_consumed_timestep 165 # between QR display and first-code confirmation. otp_consumed_timestep
141 # makes every accepted code single-use (replay guard within the drift 166 # makes every accepted code single-use (replay guard within the drift
@@ -213,4 +238,10 @@ class User < ApplicationRecord
213 unknown = roles.to_a - ROLES 238 unknown = roles.to_a - ROLES
214 errors.add(:roles, :unknown, :list => unknown.join(", ")) if unknown.any? 239 errors.add(:roles, :unknown, :list => unknown.join(", ")) if unknown.any?
215 end 240 end
241
242 def admin_needs_second_factor
243 return unless roles.include?("admin")
244 return if otp_secret.present?
245 errors.add(:roles, :admin_needs_otp)
246 end
216end 247end