123 lines
3.7 KiB
Ruby
123 lines
3.7 KiB
Ruby
class RemoteStorageAuthorization < ApplicationRecord
|
|
belongs_to :user
|
|
belongs_to :web_app, class_name: "AppCatalog::WebApp", optional: true
|
|
|
|
serialize :permissions, coder: YAML unless Rails.env.production?
|
|
|
|
validates_presence_of :permissions
|
|
validates_presence_of :client_id
|
|
|
|
scope :valid, -> { where(expire_at: nil).or(where(expire_at: (DateTime.now)..)) }
|
|
scope :expired, -> { where(expire_at: ..(DateTime.now)) }
|
|
|
|
after_initialize do |a|
|
|
a.permissions = [] if a.permissions == nil
|
|
end
|
|
|
|
before_create :generate_token
|
|
before_create :store_token_in_redis
|
|
before_create :find_or_create_web_app
|
|
after_create :schedule_token_expiry
|
|
after_create :notify_user
|
|
before_destroy :delete_token_from_redis
|
|
after_destroy :remove_token_expiry_job
|
|
|
|
def url
|
|
uri = URI.parse self.redirect_uri
|
|
"#{uri.scheme}://#{client_id}"
|
|
end
|
|
|
|
def launch_url
|
|
return url unless web_app && web_app.metadata[:start_url].present?
|
|
|
|
start_url = web_app.metadata[:start_url]
|
|
|
|
if start_url.match("^https?:\/\/")
|
|
return start_url.start_with?(url) ? start_url : url
|
|
else
|
|
path = start_url.gsub(/^\.\.\//, "").gsub(/^\.\//, "").gsub(/^\//, "")
|
|
"#{url}/#{path}"
|
|
end
|
|
end
|
|
|
|
def delete_token_from_redis
|
|
key = "authorizations:#{user.cn}:#{token}"
|
|
redis.srem? key, redis.smembers(key)
|
|
rescue => e
|
|
Rails.logger.error e
|
|
Sentry.capture_exception(e) if Setting.sentry_enabled?
|
|
end
|
|
|
|
private
|
|
|
|
def redis
|
|
@redis ||= Redis.new(url: Setting.rs_redis_url)
|
|
end
|
|
|
|
def generate_token(length=16)
|
|
self.token = SecureRandom.hex(length) if self.token.blank?
|
|
end
|
|
|
|
def store_token_in_redis
|
|
redis.sadd "authorizations:#{user.cn}:#{token}", permissions
|
|
end
|
|
|
|
def schedule_token_expiry
|
|
return unless expire_at.present?
|
|
RemoteStorageExpireAuthorizationJob.set(wait_until: expire_at)
|
|
.perform_later(id)
|
|
end
|
|
|
|
def remove_token_expiry_job
|
|
job_class = RemoteStorageExpireAuthorizationJob
|
|
job_args = [id]
|
|
|
|
query = SolidQueue::Job.where(class_name: job_class.to_s)
|
|
|
|
case ActiveRecord::Base.connection.adapter_name.downcase
|
|
when /sqlite/
|
|
query.where("json_extract(arguments, '$.arguments') = ?", job_args.to_json)
|
|
when /postgres/
|
|
query.where("arguments->>'arguments' = ?", job_args.to_json)
|
|
else
|
|
raise "Unsupported database adapter"
|
|
end.destroy_all
|
|
end
|
|
|
|
def find_or_create_web_app
|
|
if looks_like_hosted_origin?
|
|
web_app = AppCatalog::WebApp.find_or_create_by!(url: self.url)
|
|
web_app.update_metadata unless web_app.name.present?
|
|
self.web_app = web_app
|
|
self.app_name = web_app.name.presence || client_id
|
|
else
|
|
self.app_name = client_id
|
|
end
|
|
end
|
|
|
|
def looks_like_hosted_origin?
|
|
uri = URI.parse self.redirect_uri
|
|
!!(uri.host =~ /(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9]\.)+[a-zA-Z]{2,63}$)/)
|
|
rescue URI::InvalidURIError
|
|
false
|
|
end
|
|
|
|
def notify_user
|
|
notify = user.preferences[:remotestorage_notify_auth_created]
|
|
|
|
case notify
|
|
when "xmpp"
|
|
router = Router.new
|
|
payload = {
|
|
type: "normal", to: user.address,
|
|
from: Setting.xmpp_notifications_from_address,
|
|
body: "You have just granted '#{self.client_id}' access to your Kosmos Storage. Visit your Storage dashboard to check on your connected apps and revoke permissions anytime: #{router.services_storage_url}"
|
|
}
|
|
XmppSendMessageJob.perform_later(payload)
|
|
when "email"
|
|
NotificationMailer.with(user: user, auth: self)
|
|
.remotestorage_auth_created.deliver_later
|
|
end
|
|
end
|
|
end
|