diff options
Diffstat (limited to 'app/models')
| -rw-r--r-- | app/models/user.rb | 31 |
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 | ||
| 216 | end | 247 | end |
