From c14eef0e445cea3458462f8c166c35680ce4199f Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Mon, 27 Mar 2023 00:31:50 +0200 Subject: [PATCH 1/2] Support auto-redirection by `` --- src/_locales/en/messages.json | 4 ++ src/background/modules/ActivityPubRedirect.js | 46 +++++++++++++++++++ src/background/modules/AutoRemoteFollow.js | 9 +++- src/common/modules/MastodonApi.js | 19 ++++++++ src/common/modules/data/DefaultSettings.js | 3 +- src/options/options.html | 4 ++ 6 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/background/modules/ActivityPubRedirect.js diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index cb2c872..63a56c8 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -163,6 +163,10 @@ "message": "Prevents the use of an extra tab and instead redirects the action on the main page.", "description": "This is an option shown in the add-on settings." }, + "optionRedirectImmediately": { + "message": "Redirect immediately on page load, instead of on action.", + "description": "This is an option shown in the add-on settings." + }, "translatorCredit": { "message": "This add-on has been translated into English by $TRANSLATORS$.", "description": "The credit text for the translator. See https://github.com/TinyWebEx/common/blob/master/CONTRIBUTING.md#translator-credit-inside-of-add-on for how to translate this.", diff --git a/src/background/modules/ActivityPubRedirect.js b/src/background/modules/ActivityPubRedirect.js new file mode 100644 index 0000000..1ac7f93 --- /dev/null +++ b/src/background/modules/ActivityPubRedirect.js @@ -0,0 +1,46 @@ +import * as NetworkTools from "/common/modules/NetworkTools.js"; +import * as AddonSettings from "/common/modules/AddonSettings/AddonSettings.js"; +import { resolveActivityPubId } from "/common/modules/MastodonApi.js"; + +/** + * Scrapes the ActivityPub destination from the HTML page, if needed and exists. + * + * @param {number} tabIdToModify + * @param {URL} url + * @returns {Promise} + */ +export async function redirectByActivityPubLink(tabIdToModify, url) { + if (!tabIdToModify || !url) { + throw new Error("Needs a tab id and a page URL"); + } + + const [objectId] = await browser.tabs.executeScript({ + code: `document.querySelector("link[rel=alternate][type='application/activity+json']")?.href`, + runAt: "document_end", + }); + if (!objectId) { + return; + } + + const ownMastodon = await AddonSettings.get("ownMastodon"); + if (ownMastodon.server === url.hostname) { + return; + } + + const body = await resolveActivityPubId(ownMastodon.server, objectId); + + const baseUrl = `https://${ownMastodon.server}`; + let homeUrl; + if (body.accounts[0]) { + homeUrl = new URL(`@${body.accounts[0].acct}`, baseUrl); + } else if (body.statuses[0]) { + homeUrl = new URL( + `@${body.statuses[0].account.acct}/${body.statuses[0].id}`, + baseUrl + ); + } else { + return; + } + + await NetworkTools.redirectToWebsite(homeUrl, tabIdToModify); +} diff --git a/src/background/modules/AutoRemoteFollow.js b/src/background/modules/AutoRemoteFollow.js index 73fd618..731b568 100644 --- a/src/background/modules/AutoRemoteFollow.js +++ b/src/background/modules/AutoRemoteFollow.js @@ -15,6 +15,7 @@ import * as MisskeyDetect from "./Detect/Misskey.js"; import * as NetworkTools from "/common/modules/NetworkTools.js"; import * as MastodonRedirect from "./MastodonRedirect.js"; +import { redirectByActivityPubLink } from "./ActivityPubRedirect.js"; import * as AddonSettings from "/common/modules/AddonSettings/AddonSettings.js"; import * as MastodonHandleCheck from "/common/modules/MastodonHandle/ConfigCheck.js"; @@ -149,12 +150,18 @@ function getInteractionType(url) { /** * Handles changes to the URL of a tab. - * + * * @param {string} tabId * @param {Object} changeInfo * @returns {void} */ async function onTabUpdate(tabId, changeInfo) { + // clear cache of settings + await AddonSettings.loadOptions(); + if (await AddonSettings.get("redirectImmediately")) { + redirectByActivityPubLink(tabId, changeInfo.url); + } + const ownMastodon = await AddonSettings.get("ownMastodon"); const currentURL = new URL(changeInfo.url); if (ownMastodon.server !== currentURL.hostname){ diff --git a/src/common/modules/MastodonApi.js b/src/common/modules/MastodonApi.js index b685c7d..6d599fd 100644 --- a/src/common/modules/MastodonApi.js +++ b/src/common/modules/MastodonApi.js @@ -99,3 +99,22 @@ export function getTootStatus(mastodonServer, localTootId) { return response.json(); }); } + +/** + * Resolves the ActivityPub object ID on a given server + * + * @param {string} mastodonServer + * @param {string} objectId + */ +export async function resolveActivityPubId(mastodonServer, objectId) { + const apiUrl = new URL("api/v2/search", `https://${mastodonServer}`); + apiUrl.searchParams.set("q", objectId); + apiUrl.searchParams.set("resolve", "true"); + + const response = await NetworkTools.fetch(apiUrl); + if (!response.ok) { + throw new MastodonApiError(mastodonServer, response, `Failed to resolve ${objectId}.`); + } + + return await response.json(); +} diff --git a/src/common/modules/data/DefaultSettings.js b/src/common/modules/data/DefaultSettings.js index 4aeb280..b774d8c 100644 --- a/src/common/modules/data/DefaultSettings.js +++ b/src/common/modules/data/DefaultSettings.js @@ -6,5 +6,6 @@ export const DEFAULT_SETTINGS = Object.freeze({ ownMastodon: null, - redirectInMainWindow: false + redirectInMainWindow: false, + redirectImmediately: false, }); diff --git a/src/options/options.html b/src/options/options.html index cffa210..1ca63a5 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -85,6 +85,10 @@ +
+ + +
From 255a9ca9740c57053c0a28cbc28883967bb469d1 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Mon, 27 Mar 2023 00:37:49 +0200 Subject: [PATCH 2/2] tabId --- src/background/modules/ActivityPubRedirect.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/background/modules/ActivityPubRedirect.js b/src/background/modules/ActivityPubRedirect.js index 1ac7f93..cd7e795 100644 --- a/src/background/modules/ActivityPubRedirect.js +++ b/src/background/modules/ActivityPubRedirect.js @@ -5,16 +5,16 @@ import { resolveActivityPubId } from "/common/modules/MastodonApi.js"; /** * Scrapes the ActivityPub destination from the HTML page, if needed and exists. * - * @param {number} tabIdToModify + * @param {number} tabId * @param {URL} url * @returns {Promise} */ -export async function redirectByActivityPubLink(tabIdToModify, url) { - if (!tabIdToModify || !url) { +export async function redirectByActivityPubLink(tabId, url) { + if (!tabId || !url) { throw new Error("Needs a tab id and a page URL"); } - const [objectId] = await browser.tabs.executeScript({ + const [objectId] = await browser.tabs.executeScript(tabId, { code: `document.querySelector("link[rel=alternate][type='application/activity+json']")?.href`, runAt: "document_end", }); @@ -42,5 +42,5 @@ export async function redirectByActivityPubLink(tabIdToModify, url) { return; } - await NetworkTools.redirectToWebsite(homeUrl, tabIdToModify); + await NetworkTools.redirectToWebsite(homeUrl, tabId); }