From 9a9947f9ad5276fc329f1281a7f58c1eeb910035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 20 Nov 2023 13:30:23 +0100 Subject: [PATCH] Respect "start_url" from manifest when launching web apps --- .../services/rs_auths_controller.rb | 2 +- app/models/remote_storage_authorization.rb | 14 +++- .../remote_storage_authorization_spec.rb | 83 +++++++++++++++++-- 3 files changed, 91 insertions(+), 8 deletions(-) diff --git a/app/controllers/services/rs_auths_controller.rb b/app/controllers/services/rs_auths_controller.rb index 091ce7b..c0750e6 100644 --- a/app/controllers/services/rs_auths_controller.rb +++ b/app/controllers/services/rs_auths_controller.rb @@ -22,7 +22,7 @@ class Services::RsAuthsController < Services::BaseController def launch_app auth = current_user.remote_storage_authorizations.find(params[:id]) - launch_url = "#{auth.url}#remotestorage=#{current_user.address}&access_token=#{auth.token}" + launch_url = "#{auth.launch_url}#remotestorage=#{current_user.address}&access_token=#{auth.token}" redirect_to launch_url, allow_other_host: true end diff --git a/app/models/remote_storage_authorization.rb b/app/models/remote_storage_authorization.rb index e5f2ec0..53ca1b1 100644 --- a/app/models/remote_storage_authorization.rb +++ b/app/models/remote_storage_authorization.rb @@ -23,11 +23,23 @@ class RemoteStorageAuthorization < ApplicationRecord after_destroy :remove_token_expiry_job def url - # TODO use web app scope in addition to host/client_id 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) diff --git a/spec/models/remote_storage_authorization_spec.rb b/spec/models/remote_storage_authorization_spec.rb index c29308d..8fadd34 100644 --- a/spec/models/remote_storage_authorization_spec.rb +++ b/spec/models/remote_storage_authorization_spec.rb @@ -84,8 +84,7 @@ RSpec.describe RemoteStorageAuthorization, type: :model do user.remote_storage_authorizations.create!( permissions: %w(documents:rw), client_id: "example.com", - redirect_uri: "https://example.com", - expire_at: 1.month.from_now + redirect_uri: "https://example.com" ) end @@ -101,8 +100,7 @@ RSpec.describe RemoteStorageAuthorization, type: :model 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", - expire_at: 1.month.from_now + redirect_uri: "https://example.com" ) end @@ -110,8 +108,7 @@ RSpec.describe RemoteStorageAuthorization, type: :model 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", - expire_at: 1.month.from_now + redirect_uri: "https://example.com" ) end @@ -174,6 +171,80 @@ RSpec.describe RemoteStorageAuthorization, type: :model do 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