Merge pull request 'Expire inactive sessions, optionally allow to stay signed in' (#82) from feature/8-session_timeouts into master
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			Reviewed-on: #82 Reviewed-by: galfert <garret.alfert@gmail.com>
This commit is contained in:
		
						commit
						324809f77e
					
				| @ -5,10 +5,4 @@ | ||||
|     &:visited { @apply text-indigo-600; } | ||||
|     &:active  { @apply text-red-600; } | ||||
|   } | ||||
| 
 | ||||
|   .devise-links { | ||||
|     a { | ||||
|       @apply ks-text-link; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <%= button_tag type: "button", name: "toggle", data: @data, | ||||
|       role: "switch", aria: { checked: @enabled.to_s }, | ||||
|       disabled: !@input_enabled, | ||||
|       tabindex: @tabindex, disabled: !@input_enabled, | ||||
|       class: "#{ @enabled ? 'bg-blue-600' : 'bg-gray-200' } | ||||
|               #{ @class_names.present? ? @class_names : '' } | ||||
|               relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer | ||||
|  | ||||
| @ -2,11 +2,12 @@ | ||||
| 
 | ||||
| module FormElements | ||||
|   class ToggleComponent < ViewComponent::Base | ||||
|     def initialize(enabled:, input_enabled: true, data: nil, class_names: nil) | ||||
|     def initialize(enabled:, input_enabled: true, data: nil, class_names: nil, tabindex: nil) | ||||
|       @enabled = !!enabled | ||||
|       @input_enabled = input_enabled | ||||
|       @data = data | ||||
|       @class_names = class_names | ||||
|       @tabindex = tabindex | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| @ -4,6 +4,10 @@ export default class extends Controller { | ||||
|   static targets = ["buttons", "countdown"] | ||||
| 
 | ||||
|   connect() { | ||||
|     // Devise timeoutable ends up adding a second flash message without content
 | ||||
|     // TODO investigate bug
 | ||||
|     if (this.element.textContent.trim() == "true") return; | ||||
| 
 | ||||
|     const timeoutSeconds = parseInt(this.data.get("timeout")); | ||||
| 
 | ||||
|     setTimeout(() => { | ||||
|  | ||||
| @ -38,7 +38,9 @@ class User < ApplicationRecord | ||||
|   devise :ldap_authenticatable, | ||||
|          :confirmable, | ||||
|          :recoverable, | ||||
|          :validatable | ||||
|          :validatable, | ||||
|          :timeoutable, | ||||
|          :rememberable | ||||
| 
 | ||||
|   def ldap_before_save | ||||
|     self.email = Devise::LDAP::Adapter.get_ldap_param(self.cn, "mail").first | ||||
|  | ||||
| @ -7,19 +7,43 @@ | ||||
|       <%= f.label :cn, 'User', class: 'block mb-2 font-bold' %> | ||||
|       <p class="flex gap-2 items-center"> | ||||
|         <%= f.text_field :cn, autofocus: true, autocomplete: "username", | ||||
|                               required: true, class: "relative grow"%> | ||||
|               required: true, class: "relative grow", tabindex: "1" %> | ||||
|         <span class="relative shrink-0 text-gray-500">@ kosmos.org</span> | ||||
|       </p> | ||||
|     </div> | ||||
|     <p> | ||||
|     <p class="mb-8"> | ||||
|       <%= f.label :password, class: 'block mb-2 font-bold' %> | ||||
|       <%= f.password_field :password, autocomplete: "current-password", | ||||
|                                       required: true, class: "w-full"%> | ||||
|             required: true, class: "w-full", tabindex: "2" %> | ||||
|     </p> | ||||
|     <p class="mt-8"> | ||||
|       <%= f.submit "Log in", class: 'btn-md btn-blue w-full' %> | ||||
| 
 | ||||
|     <%= tag.div class: "flex items-center mb-8 gap-x-3", data: { | ||||
|           controller: "settings--toggle", | ||||
|           :'settings--toggle-switch-enabled-value' => "false" | ||||
|         } do %> | ||||
|       <div class="relative inline-flex flex-shrink-0"> | ||||
|         <%= render FormElements::ToggleComponent.new( | ||||
|               enabled: false, input_enabled: true, class_names: "hidden", | ||||
|               tabindex: "3", data: { | ||||
|                 :'settings--toggle-target' => "button", | ||||
|                 action: "settings--toggle#toggleSwitch" | ||||
|               }) %> | ||||
|         <%= f.check_box :remember_me, { | ||||
|               checked: false, | ||||
|               data: { :'settings--toggle-target' => "checkbox" } | ||||
|             }, "true", "false" %> | ||||
|       </div> | ||||
|       <%= f.label :remember_me, | ||||
|             class: "text-gray-500 flex flex-col", | ||||
|             data: { action: "click->settings--toggle#toggleSwitch" } %> | ||||
|       <p class="grow text-sm text-right"> | ||||
|         <%= link_to "Forgot your password?", new_password_path(resource_name), | ||||
|               class: "text-gray-500 underline" %><br /> | ||||
|       </p> | ||||
|     <% end %> | ||||
| 
 | ||||
|     <p> | ||||
|       <%= f.submit "Log in", class: 'btn-md btn-blue w-full', tabindex: "4" %> | ||||
|     </p> | ||||
|   <% end %> | ||||
| 
 | ||||
|   <%= render "devise/shared/links" %> | ||||
| <% end %> | ||||
|  | ||||
| @ -1,25 +1,29 @@ | ||||
| <div class="devise-links mt-8 text-sm"> | ||||
|   <%- if controller_name != 'sessions' %> | ||||
|     <p class="mb-1.5"> | ||||
|       <%= link_to "Log in", new_session_path(resource_name) %><br /> | ||||
|     <p class="mb-2"> | ||||
|       <%= link_to "Log in", new_session_path(resource_name), | ||||
|             class: "text-gray-500 underline" %> | ||||
|     </p> | ||||
|   <% end %> | ||||
| 
 | ||||
|   <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> | ||||
|     <p class="mb-1.5"> | ||||
|       <%= link_to "Forgot your password?", new_password_path(resource_name) %><br /> | ||||
|     <p class="mb-2"> | ||||
|       <%= link_to "Forgot your password?", new_password_path(resource_name), | ||||
|             class: "text-gray-500 underline" %> | ||||
|     </p> | ||||
|   <% end %> | ||||
| 
 | ||||
|   <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> | ||||
|     <p class="mb-1.5"> | ||||
|       <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br /> | ||||
|   <%- if devise_mapping.confirmable? && !controller_name.match(/^(confirmations|sessions)$/) %> | ||||
|     <p class="mb-2"> | ||||
|       <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), | ||||
|             class: "text-gray-500 underline" %> | ||||
|     </p> | ||||
|   <% end %> | ||||
| 
 | ||||
|   <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> | ||||
|     <p class="mb-1.5"> | ||||
|       <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br /> | ||||
|     <p class="mb-2"> | ||||
|       <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), | ||||
|             class: "text-gray-500 underline" %> | ||||
|     </p> | ||||
|   <% end %> | ||||
| </div> | ||||
|  | ||||
| @ -186,13 +186,13 @@ Devise.setup do |config| | ||||
| 
 | ||||
|   # ==> Configuration for :rememberable | ||||
|   # The time the user will be remembered without asking for credentials again. | ||||
|   # config.remember_for = 2.weeks | ||||
|   config.remember_for = 2.weeks | ||||
| 
 | ||||
|   # Invalidates all the remember me tokens when the user signs out. | ||||
|   config.expire_all_remember_me_on_sign_out = true | ||||
| 
 | ||||
|   # If true, extends the user's remember period when remembered via cookie. | ||||
|   # config.extend_remember_period = false | ||||
|   config.extend_remember_period = true | ||||
| 
 | ||||
|   # Options to be passed to the created cookie. For instance, you can set | ||||
|   # secure: true in order to force SSL only cookies. | ||||
| @ -210,7 +210,7 @@ Devise.setup do |config| | ||||
|   # ==> Configuration for :timeoutable | ||||
|   # The time you want to timeout the user session without activity. After this | ||||
|   # time the user will be asked for credentials again. Default is 30 minutes. | ||||
|   # config.timeout_in = 30.minutes | ||||
|   config.timeout_in = 30.minutes | ||||
| 
 | ||||
|   # ==> Configuration for :lockable | ||||
|   # Defines which strategy will be used to lock an account. | ||||
|  | ||||
| @ -0,0 +1,6 @@ | ||||
| class AddRememberCreatedAtToUsers < ActiveRecord::Migration[7.0] | ||||
|   def change | ||||
|     add_column :users, :remember_created_at, :datetime | ||||
|     add_column :users, :remember_token, :string | ||||
|   end | ||||
| end | ||||
| @ -10,7 +10,7 @@ | ||||
| # | ||||
| # It's strongly recommended that you check this file into your version control system. | ||||
| 
 | ||||
| ActiveRecord::Schema[7.0].define(version: 2023_02_23_115536) do | ||||
| ActiveRecord::Schema[7.0].define(version: 2023_03_19_101128) do | ||||
|   create_table "donations", force: :cascade do |t| | ||||
|     t.integer "user_id" | ||||
|     t.integer "amount_sats" | ||||
| @ -57,6 +57,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_23_115536) do | ||||
|     t.text "ln_login_ciphertext" | ||||
|     t.text "ln_password_ciphertext" | ||||
|     t.string "ln_account" | ||||
|     t.datetime "remember_created_at" | ||||
|     t.string "remember_token" | ||||
|     t.index ["email"], name: "index_users_on_email", unique: true | ||||
|     t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true | ||||
|   end | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user