about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorSorin Davidoi <sorin.davidoi@gmail.com>2017-06-23 18:50:53 +0200
committerEugen Rochko <eugen@zeonfederated.com>2017-06-23 18:50:53 +0200
commit2211e8d1cd6eb97a8a04e24c1fea7031a201edb5 (patch)
treeb235a97b1c0f73475449c2313823dc6d599f31bb /app
parent3783cadf2d7a2b7ace078d1d337645f53c190c69 (diff)
Revocable sessions (#3616)
* feat: Revocable sessions

* fix: Tests using sign_in

* feat: Configuration entry for the maximum number of session activations
Diffstat (limited to 'app')
-rw-r--r--app/models/session_activation.rb38
-rw-r--r--app/models/user.rb14
2 files changed, 52 insertions, 0 deletions
diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb
new file mode 100644
index 000000000..71e9f023c
--- /dev/null
+++ b/app/models/session_activation.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+# == Schema Information
+#
+# Table name: session_activations
+#
+#  id         :integer          not null, primary key
+#  user_id    :integer          not null
+#  session_id :string           not null
+#  created_at :datetime         not null
+#  updated_at :datetime         not null
+#
+
+class SessionActivation < ApplicationRecord
+  LIMIT = Rails.configuration.x.max_session_activations
+
+  def self.active?(id)
+    id && where(session_id: id).exists?
+  end
+
+  def self.activate(id)
+    activation = create!(session_id: id)
+    purge_old
+    activation
+  end
+
+  def self.deactivate(id)
+    return unless id
+    where(session_id: id).destroy_all
+  end
+
+  def self.purge_old
+    order('created_at desc').offset(LIMIT).destroy_all
+  end
+
+  def self.exclusive(id)
+    where('session_id != ?', id).destroy_all
+  end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index ca11f2f5d..fccf1089b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -63,6 +63,8 @@ class User < ApplicationRecord
   # handle this itself, and this can be removed from our User class.
   attribute :otp_secret
 
+  has_many :session_activations, dependent: :destroy
+
   def confirmed?
     confirmed_at.present?
   end
@@ -89,6 +91,18 @@ class User < ApplicationRecord
     settings.auto_play_gif
   end
 
+  def activate_session
+    session_activations.activate(SecureRandom.hex).session_id
+  end
+
+  def exclusive_session(id)
+    session_activations.exclusive(id)
+  end
+
+  def session_active?(id)
+    session_activations.active? id
+  end
+
   protected
 
   def send_devise_notification(notification, *args)