Save username & server separately instead of one "insertHandle"

Upgrade routine for this has been implemented. (new data is now v0.8)
This commit is contained in:
rugk 2018-11-11 18:34:06 +01:00
parent 474194c00b
commit 83410a4040
No known key found for this signature in database
GPG key ID: 05D40A636AFAB34D
12 changed files with 390 additions and 18 deletions

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_extensionName__",
"short_name": "__MSG_extensionNameShort__",
"version": "0.7",
"version": "0.8",
"author": "rugk",
"description": "__MSG_extensionDescription__",

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_extensionName__",
"short_name": "__MSG_extensionNameShort__",
"version": "0.7",
"version": "0.8",
"author": "rugk",
"description": "__MSG_extensionDescription__",

View file

@ -6,7 +6,8 @@ See also https://discourse.mozilla.org/t/using-es6-modules-in-background-scripts
<html lang="en">
<head>
<meta charset="utf-8">
<script async src="background.js" type="module" charset="utf-8"></script>
<!-- async currently disabled, because of https://bugzilla.mozilla.org/show_bug.cgi?id=1506464 -->
<script src="background.js" type="module" charset="utf-8"></script>
</head>
<body>
</body>

View file

@ -1 +1,2 @@
import "./modules/InstallUpgrade.js";
import "./modules/AutoRemoteFollow.js";

View file

@ -57,9 +57,8 @@ export function getTootUrl(url) {
// if this is your local server, you can obviously directly redirect and
// use the local toot ID/URL
const fromStaticOwnServer = browser.storage.sync.get("insertHandle").then((handleObject) => {
const ownMastodon = Mastodon.splitUserHandle(handleObject.insertHandle);
if (mastodonServer !== ownMastodon.server) {
const fromStaticOwnServer = browser.storage.sync.get("mastodonServer").then((handleObject) => {
if (mastodonServer !== handleObject.mastodonServer.server) {
return Promise.reject(new Error("is not own server URL"));
}

View file

@ -0,0 +1,60 @@
/**
* Upgrades user data on installation of new updates.
*
* Attention: Currently you must not include this script asyncronously. See
* https://bugzilla.mozilla.org/show_bug.cgi?id=1506464 for details.
*
* @module InstallUpgrade
*/
import * as Mastodon from "/common/modules/Mastodon.js";
/**
* Checks whether an upgrade is needed.
*
* @see {@link https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onInstalled}
* @private
* @param {Object} details
* @returns {void}
*/
async function handleInstalled(details) {
// only trigger for usual addon updates
if (details.reason !== "update") {
return;
}
switch (details.previousVersion) {
case "0.7": {
console.log(`Doing upgrade from ${details.previousVersion}.`, details);
const ownMastodonSplit = await browser.storage.sync.get("insertHandle").then((handleObject) => {
return Mastodon.splitUserHandle(handleObject.insertHandle);
});
await browser.storage.sync.set({
mastodonUsername: ownMastodonSplit.username,
mastodonServer: ownMastodonSplit.server,
});
await browser.storage.sync.remove("insertHandle");
console.log("Data upgrade successful.", await browser.storage.sync.get());
break;
}
default:
console.log(`Addon upgrade from ${details.previousVersion}. No data upgrade needed.`, details);
}
}
/**
* Inits module.
*
* @private
* @returns {void}
*/
function init() {
browser.runtime.onInstalled.addListener(handleInstalled);
}
init()

View file

@ -16,9 +16,12 @@ import * as NetworkTools from "./NetworkTools.js";
* @returns {Promise}
*/
async function triggerRemoteAction(uri) {
const handleObject = await browser.storage.sync.get("insertHandle");
const ownMastodon = Mastodon.splitUserHandle(handleObject.insertHandle);
// get and assemble Mastodon object
const handleObject = await browser.storage.sync.get(["mastodonUsername", "mastodonServer"]);
const ownMastodon = {
username: handleObject.mastodonUsername,
server: handleObject.mastodonServer,
};
// skip the subscribe/interact API if it is not needed, because it is your
// own server

View file

@ -1,3 +1,9 @@
/**
* Provides small wrapper functions around browser APIs for listening to web requests.
*
* @module NetworkTools
*/
/**
* Listen to a web request of this URL.
*

View file

@ -4,8 +4,8 @@
* @module common/modules/Mastodon
*/
// https://regex101.com/r/dlnnSq/1
const MASTODON_HANDLE_SPLIT = /^@?(.+)@(.+)$/;
// https://regex101.com/r/dlnnSq/2
const MASTODON_HANDLE_SPLIT = /^@?([^@ ]+)@([^@ ]+)$/;
/**
* Do a webfinger request for Mastodon account at server.
@ -26,7 +26,7 @@ function getWebfinger(mastodonServer, mastodonHandle) {
/**
* Splits a Mastodon handle to return the username and server URL.
*
* @function
* @public
* @param {string} mastodonHandle
* @throws {TypeError}
* @returns {{username: string, server: string}} username/server
@ -44,6 +44,42 @@ export function splitUserHandle(mastodonHandle) {
};
}
/**
* Concatenates a Mastodon username and server to return the full user handle.
*
* In this definition a Mastodon handle is not prefixed with '@', i.e. not
* '@user@example.com', but just 'user@example.com'. The function will remove
* the 'at' char if it is prepended to the username.
*
* @public
* @param {string} username
* @param {string} server
* @throws {TypeError} if the format is invalid
* @returns {string}
*/
export function concatUserHandle(username, server) {
// remove prefixed @ if needed
if (username && username.startsWith("@")) {
username = username.substring(1);
}
// sanity checks
if (!server) {
throw new TypeError("Server must not be empty.");
}
if (!username) {
throw new TypeError("Username must not be empty.");
}
const mastodonHandle = `${username}@${server}`;
if (!MASTODON_HANDLE_SPLIT.test(mastodonHandle)) {
throw new TypeError("Username or server has invalid format.");
}
return mastodonHandle;
}
/**
* Return the API endpoint (path) that handles these remote follows/interactions.
*

View file

@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_extensionName__",
"short_name": "__MSG_extensionNameShort__",
"version": "0.7",
"version": "0.8",
"author": "rugk",
"description": "__MSG_extensionDescription__",

View file

@ -1,13 +1,17 @@
"use strict";
import * as Mastodon from "/common/modules/Mastodon.js";
const insertHandle = document.getElementById("insertHandle");
insertHandle.addEventListener("input", () => {
browser.storage.sync.set({
"insertHandle": insertHandle.value
const ownMastodonSplit = Mastodon.splitUserHandle(insertHandle.value);
return browser.storage.sync.set({
mastodonUsername: ownMastodonSplit.username,
mastodonServer: ownMastodonSplit.server,
});
});
browser.storage.sync.get("insertHandle").then((handleObject) => {
insertHandle.value = handleObject.insertHandle;
browser.storage.sync.get(["mastodonUsername", "mastodonServer"]).then((handleObject) => {
const mastodonHandle = Mastodon.concatUserHandle(handleObject.mastodonUsername, handleObject.mastodonServer);
insertHandle.value = mastodonHandle;
});

View file

@ -36,6 +36,26 @@ describe("common module: Mastodon", function () {
}, 'does not handle correctly: "FakeUser123Name@fake.example"');
});
it("correctly splits servers without TLD (LAN adresses, IPs, etc.)", function () {
chai.assert.deepEqual(Mastodon.splitUserHandle("username@tldFreeServer"), {
username: "username",
server: "tldFreeServer"
}, 'does not handle correctly: "username@tldFreeServer"');
chai.assert.deepEqual(Mastodon.splitUserHandle("@username@tldFreeServer"), {
username: "username",
server: "tldFreeServer"
}, 'does not handle correctly: "@username@tldFreeServer"');
chai.assert.deepEqual(Mastodon.splitUserHandle("username@127.0.0.1"), {
username: "username",
server: "127.0.0.1"
}, 'does not handle correctly: "username@127.0.0.1"');
chai.assert.deepEqual(Mastodon.splitUserHandle("@username@127.0.0.1"), {
username: "username",
server: "127.0.0.1"
}, 'does not handle correctly: "@username@127.0.0.1"');
});
it("correctly splits handles with Emoji", function () {
chai.assert.deepEqual(Mastodon.splitUserHandle("thinking🤔user@whatis🤔.great.app"), {
username: "thinking🤔user",
@ -69,6 +89,248 @@ describe("common module: Mastodon", function () {
});
});
describe("concatUserHandle()", function () {
it('correctly concatenates user handle', function () {
chai.assert.strictEqual(
Mastodon.concatUserHandle("rugk_testing", "mastodon.social"),
"rugk_testing@mastodon.social",
'does not handle correctly: "rugk_testing@mastodon.social"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("rugk", "social.wiuwiu.de"),
"rugk@social.wiuwiu.de",
'does not handle correctly: "rugk@social.wiuwiu.de"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("FakeUser123Name", "fake.example"),
"FakeUser123Name@fake.example",
'does not handle correctly: "FakeUser123Name@fake.example"'
);
});
it("correctly concatenates handles with @-prefix", function () {
chai.assert.strictEqual(
Mastodon.concatUserHandle("@rugk_testing", "mastodon.social"),
"rugk_testing@mastodon.social",
'does not handle correctly: "rugk_testing@mastodon.social"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("@rugk", "social.wiuwiu.de"),
"rugk@social.wiuwiu.de",
'does not handle correctly: "rugk@social.wiuwiu.de"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("@FakeUser123Name", "fake.example"),
"FakeUser123Name@fake.example",
'does not handle correctly: "FakeUser123Name@fake.example"'
);
});
it("correctly concatenates servers without TLD (LAN adresses, IPs, etc.)", function () {
chai.assert.strictEqual(
Mastodon.concatUserHandle("username", "tldFreeServer"),
"username@tldFreeServer",
'does not handle correctly: "username@tldFreeServer"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("@username", "tldFreeServer"),
"username@tldFreeServer",
'does not handle correctly: "@username@tldFreeServer"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("username", "127.0.0.1"),
"username@127.0.0.1",
'does not handle correctly: "username@127.0.0.1"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("@username", "127.0.0.1"),
"username@127.0.0.1",
'does not handle correctly: "@username@127.0.0.1"'
);
});
it("correctly concatenates handles with Emoji", function () {
chai.assert.strictEqual(
Mastodon.concatUserHandle("thinking🤔user", "whatis🤔.great.app"),
"thinking🤔user@whatis🤔.great.app",
'does not handle correctly: "thinking🤔user@whatis🤔.great.app"'
);
chai.assert.strictEqual(
Mastodon.concatUserHandle("@thinking🤔user", "whatis🤔.great.app"),
"thinking🤔user@whatis🤔.great.app",
'does not handle correctly: "@thinking🤔user@whatis🤔.great.app"'
);
});
it("correctly rejects empty variables", function () {
// empty string
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "rugk_testing@mastodon.social", ""),
TypeError,
"Server must not be empty.",
'does not handle correctly: concatUserHandle("rugk_testing@mastodon.social", "")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "", "rugk_testing@mastodon.social"),
TypeError,
"Username must not be empty.",
'does not handle correctly: concatUserHandle("", "rugk_testing@mastodon.social")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@rugk_testing@mastodon.social", ""),
TypeError,
"Server must not be empty.",
'does not handle correctly: concatUserHandle("@rugk_testing@mastodon.social", "")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "", "@rugk_testing@mastodon.social"),
TypeError,
"Username must not be empty.",
'does not handle correctly: concatUserHandle("", "@rugk_testing@mastodon.social")'
);
// null
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "rugk_testing@mastodon.social", null),
TypeError,
"Server must not be empty.",
'does not handle correctly: concatUserHandle("rugk_testing@mastodon.social", null)'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, null, "rugk_testing@mastodon.social"),
TypeError,
"Username must not be empty.",
'does not handle correctly: concatUserHandle(null, "rugk_testing@mastodon.social")'
);
// undefined
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "rugk_testing@mastodon.social", undefined),
TypeError,
"Server must not be empty.",
'does not handle correctly: concatUserHandle("rugk_testing@mastodon.social", undefined)'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, undefined, "rugk_testing@mastodon.social"),
TypeError,
"Username must not be empty.",
'does not handle correctly: concatUserHandle(undefined, "rugk_testing@mastodon.social")'
);
});
it("correctly rejects @ (ats) in usernames and servers", function () {
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "usernameWith@InIt", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("usernameWith@InIt", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@usernameWith@InIt", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@usernameWith@InIt", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "usernameWithAtAtEnd@", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("usernameWithAtAtEnd@", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@usernameWithAtAtEnd@", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@usernameWithAtAtEnd@", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "username", "@mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("username", "@mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@username", "@mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@username", "@mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "username", "mastodon@example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("username@", "mastodon@example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@username", "mastodon@example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@username", "mastodon@example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@ats@Everywhere@", "@mastodon@example@"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@ats@Everywhere@", "@mastodon@example@")'
);
});
it("correctly rejects spaces in usernames and servers", function () {
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "usernameWith InIt", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("usernameWith InIt", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@usernameWith InIt", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@usernameWith InIt", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "usernameWithSpaceAtEnd ", "mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("usernameWithSpaceAtEnd ", "mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "username", " mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("username", " mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "@username", " mastodon.example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("@username", " mastodon.example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, "username", "mastodon example"),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle("username ", "mastodon example")'
);
chai.assert.throws(
Mastodon.concatUserHandle.bind(null, " ats Everywhere ", " mastodon example "),
TypeError,
"Username or server has invalid format.",
'does not handle correctly: concatUserHandle(" ats Everywhere ", " mastodon example ")'
);
});
});
describe("getSubscribeApiUrl()", function () {
beforeEach(function() {
// TODO: mock settings API to prevent savings