require 'rails_helper' RSpec.describe RemoteStorageAuthorization, type: :model do include ActiveJob::TestHelper let(:user) { create :user } before do allow_any_instance_of(AppCatalog::WebApp).to receive(:update_metadata).and_return(true) end describe "#create" do after(:each) { clear_enqueued_jobs } after(:all) { redis_rs_delete_keys("authorizations:*") } let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(documents photos contacts:rw videos:r tasks/work:r), client_id: "example.com", redirect_uri: "https://example.com" ) end it "generates a token" do expect(auth.token).to match(/[a-zA-Z0-9]+/) end it "stores a token in redis" do user_auth_keys = redis_rs.keys("authorizations:#{user.cn}:*") expect(user_auth_keys.length).to eq(1) authorizations = redis_rs.smembers(user_auth_keys.first) expect(authorizations.sort).to eq(%w(documents photos contacts:rw videos:r tasks/work:r).sort) end context "with expiry set" do it "enqueues an expiration job" do auth_with_expiry = user.remote_storage_authorizations.create!( permissions: %w(documents:rw), client_id: "example.com", redirect_uri: "https://example.com", expire_at: 1.month.from_now ) job = enqueued_jobs.select{|j| j['job_class'] == "RemoteStorageExpireAuthorizationJob"}.first expect(job['arguments'][0]).to eq(auth_with_expiry.id) end end end describe "#destroy" do after(:each) { clear_enqueued_jobs } after(:all) { redis_rs_delete_keys("authorizations:*") } it "removes the token from redis" do auth = user.remote_storage_authorizations.create!( permissions: %w(shares:rw documents pictures:r), client_id: "sharesome.5apps.com", redirect_uri: "https://sharesome.5apps.com" ) auth.destroy! expect(redis_rs.keys("authorizations:#{user.address}:*")).to be_empty end context "with expiry set" do it "removes the expiration job" do auth_with_expiry = user.remote_storage_authorizations.create!( permissions: %w(documents:rw), client_id: "example.com", redirect_uri: "https://example.com", expire_at: 1.month.from_now ) # Cannot test for removal from the actual Sidekiq::Queue, because it is # not used in specs, but the method directly removes jobs from there expect(auth_with_expiry).to receive(:remove_token_expiry_job) auth_with_expiry.destroy! end end end describe "#find_or_create_web_app" do context "with origin that looks hosted" do after(:all) { redis_rs_delete_keys("authorizations:*") } let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(documents:rw), client_id: "example.com", redirect_uri: "https://example.com" ) end it "generates a web_app" do expect(auth.web_app).to be_a(AppCatalog::WebApp) end end context "when creating two authorizations for the same app" do let(:user_2) { create :user, id: 23, cn: "michiel", email: "michiel@example.com" } let(:auth_1) do user.remote_storage_authorizations.create!( permissions: %w(documents photos contacts:rw videos:r tasks/work:r), client_id: "example.com", redirect_uri: "https://example.com" ) end let(:auth_2) do user_2.remote_storage_authorizations.create!( permissions: %w(documents photos contacts:rw videos:r tasks/work:r), client_id: "example.com", redirect_uri: "https://example.com" ) end after do auth_1.destroy auth_2.destroy user_2.destroy end it "uses the same web app for both authorizations" do expect(auth_1.web_app).to eq(auth_2.web_app) end end describe "non-production app origins" do context "when host is not an FQDN" do let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(recipes), client_id: "localhost:4200", redirect_uri: "http://localhost:4200" ) end it "does not create a web app" do expect(auth.web_app).to be_nil expect(auth.app_name).to eq("localhost:4200") end end context "when host is an IP address" do let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(recipes), client_id: "192.168.0.23:3000", redirect_uri: "http://192.168.0.23:3000" ) end it "does not create a web app" do expect(auth.web_app).to be_nil expect(auth.app_name).to eq("192.168.0.23:3000") end end context "when host is an extension URL" do let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(bookmarks), client_id: "123.addons.allizom.org", redirect_uri: "123.addons.allizom.org/foo" ) end it "does not create a web app" do expect(auth.web_app).to be_nil expect(auth.app_name).to eq("123.addons.allizom.org") end end end end describe "#launch_url" do after(:all) { redis_rs_delete_keys("authorizations:*") } context "without start URL" do before do AppCatalog::WebApp.create!( url: "https://webmarks.5apps.com", name: "Webmarks", metadata: { name: "Webmarks", start_url: nil, scope: nil } ) end let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(bookmarks:rw), client_id: "webmarks.5apps.com", redirect_uri: "https://webmarks.5apps.com/connect" ) end it "uses the base URL (from client ID)" do expect(auth.launch_url).to eq("https://webmarks.5apps.com") end end context "with start URL" do before do AppCatalog::WebApp.create!( url: "https://hyperdraft.rosano.ca", name: "Hyperdraft", metadata: { name: "Hyperdraft", scope: nil, start_url: "https://hyperdraft.rosano.ca/start" } ) end let(:auth) do user.remote_storage_authorizations.create!( permissions: %w(notes:rw), client_id: "hyperdraft.rosano.ca", redirect_uri: "https://hyperdraft.rosano.ca/write/foo" ) end describe "full URL" do it "respects the start URL" do expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca/start") end it "does not respect URLs outside of the client ID scope" do auth.web_app.metadata[:start_url] = "https://uberdraft.rosano.ca/write" expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca") end end describe "relative paths" do it "includes the path relative from the base URL" do auth.web_app.metadata[:start_url] = "start.html" expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca/start.html") auth.web_app.metadata[:start_url] = "./start.html" expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca/start.html") auth.web_app.metadata[:start_url] = "../start.html" expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca/start.html") end end describe "absolute path" do it "includes the path relative from the base URL" do auth.web_app.metadata[:start_url] = "/write" expect(auth.launch_url).to eq("https://hyperdraft.rosano.ca/write") end end end end # describe "auth notifications" do # context "with auth notifications enabled" do # before do # ResqueSpec.reset! # user.push(mailing_lists: "rs-auth-notifications-#{Rails.env}") # auth = user.remote_storage_authorizations.create!( # :permissions => %w(documents photos contacts:rw videos:r tasks/work:r), # :client_id => "example.com", # :redirect_uri => "https://example.com" # ) # end # # it "notifies the user via email" do # expect(enqueued_jobs.size).to eq(1) # job = enqueued_jobs.first # expect(job).to eq( # job: ActionMailer::DeliveryJob, # args: ['StorageAuthorizationMailer', 'authorized_rs_app', 'deliver_now', # auth.id.to_s], # queue: 'mailers' # ) # end # end # # context "with auth notifications disabled" do # before do # ResqueSpec.reset! # user.pull(mailing_lists: "rs-auth-notifications-#{Rails.env}") # auth = user.remote_storage_authorizations.create!( # :permissions => %w(documents photos contacts:rw videos:r tasks/work:r), # :client_id => "example.com", # :redirect_uri => "https://example.com" # ) # end # # it "does not notify the user via email about new RS app" do # expect(enqueued_jobs.size).to eq(0) # end # end # end end