Merge branch 'feat/delegated-domains'

# Conflicts:
#	create-circle.js
#	image.js
This commit is contained in:
Natty 2023-09-01 17:32:18 +02:00
commit 1823230b64
No known key found for this signature in database
GPG key ID: BF6CB659ADEE60EC

View file

@ -12,6 +12,13 @@ async function apiRequest(url, options = null)
} }
return await fetch(url, options ?? {}) return await fetch(url, options ?? {})
.then(response => {
if (response.ok) {
return response;
}
throw new Error(`Error fetching ${url}: ${response.status} ${response.statusText}`);
})
.then(response => response.json()) .then(response => response.json())
.catch(error => { .catch(error => {
console.error(`Error fetching ${url}: ${error}`); console.error(`Error fetching ${url}: ${error}`);
@ -20,15 +27,88 @@ async function apiRequest(url, options = null)
} }
function Handle(name, instance) { function Handle(name, instance) {
let handle = Object.create(Handle.prototype); let handleObj = Object.create(Handle.prototype);
handle.name = name; handleObj.name = name;
handle.instance = instance; handleObj.instance = instance;
return handle; handleObj._baseInstance = null;
handleObj._apiInstance = null;
return handleObj;
} }
Handle.prototype.toString = function() { Object.defineProperty(Handle.prototype, "baseInstance", {
return `${this.name}@${this.instance}`; get: function () {
} return this._baseInstance || this.instance;
}
});
Object.defineProperty(Handle.prototype, "apiInstance", {
get: function () {
return this._apiInstance || this.instance;
}
});
Object.defineProperty(Handle.prototype, "baseHandle", {
get: function () {
return this.name + "@" + this.baseInstance;
}
});
Handle.prototype.toString = function () {
return this.name + "@" + this.instance;
};
/**
* @returns {Promise<Handle>} The handle WebFingered, or the original on fail
*/
Handle.prototype.webFinger = async function () {
if (this._baseInstance) {
return this;
}
let url = `https://${this.instance}/.well-known/webfinger?` + new URLSearchParams({
resource: `acct:${this}`
});
let webFinger = await apiRequest(url);
if (!webFinger)
return this;
let acct = webFinger["subject"];
if (typeof acct !== "string")
return this;
if (acct.startsWith("acct:")) {
acct = acct.substring("acct:".length);
}
let baseHandle = parseHandle(acct);
baseHandle._baseInstance = baseHandle.instance;
baseHandle.instance = this.instance;
const links = webFinger["links"];
if (!Array.isArray(links)) {
return baseHandle;
}
const selfLink = links.find(link => link["rel"] === "self");
if (!selfLink) {
return baseHandle;
}
try {
const url = new URL(selfLink["href"])
baseHandle._apiInstance = url.hostname;
} catch (e) {
console.error(`Error parsing WebFinger self link ${selfLink["href"]}: ${e}`);
}
return baseHandle;
};
/** /**
* @typedef {{ * @typedef {{
@ -197,8 +277,13 @@ class MastodonApiClient extends ApiClient {
} }
async getUserIdFromHandle(handle) { async getUserIdFromHandle(handle) {
const url = `https://${this._instance}/api/v1/accounts/lookup?acct=${handle.name}@${handle.instance}`; const url = `https://${this._instance}/api/v1/accounts/lookup?acct=${handle.baseHandle}`;
const response = await apiRequest(url, null); let response = await apiRequest(url, null);
if (!response) {
const url = `https://${this._instance}/api/v1/accounts/lookup?acct=${handle}`;
response = await apiRequest(url, null);
}
if (!response) { if (!response) {
return null; return null;
@ -381,8 +466,11 @@ class MisskeyApiClient extends ApiClient {
let id = null; let id = null;
for (const user of Array.isArray(lookup) ? lookup : []) { for (const user of Array.isArray(lookup) ? lookup : []) {
if ((user["host"] === handle.instance || this._instance === handle.instance && user["host"] === null) const isLocal = user?.["host"] === handle.instance ||
&& user["username"] === handle.name) { user?.["host"] === handle.baseInstance ||
this._instance === handle.apiInstance && user?.["host"] === null;
if (isLocal && user?.["username"] === handle.name && user["id"]) {
id = user["id"]; id = user["id"];
break; break;
} }
@ -565,7 +653,7 @@ async function circleMain() {
generateBtn.style.display = "none"; generateBtn.style.display = "none";
let fediHandle = document.getElementById("txt_mastodon_handle"); let fediHandle = document.getElementById("txt_mastodon_handle");
const selfUser = parseHandle(fediHandle.value); const selfUser = await parseHandle(fediHandle.value).webFinger();
let form = document.getElementById("generateForm"); let form = document.getElementById("generateForm");
let backend = form.backend; let backend = form.backend;
@ -578,17 +666,17 @@ async function circleMain() {
let client; let client;
switch (backend.value) { switch (backend.value) {
case "mastodon": case "mastodon":
client = new MastodonApiClient(selfUser.instance); client = new MastodonApiClient(selfUser.apiInstance);
break; break;
case "pleroma": case "pleroma":
client = new PleromaApiClient(selfUser.instance, true); client = new PleromaApiClient(selfUser.apiInstance, true);
break; break;
case "misskey": case "misskey":
client = new MisskeyApiClient(selfUser.instance); client = new MisskeyApiClient(selfUser.apiInstance);
break; break;
default: default:
progress.innerText = "Detecting instance..."; progress.innerText = "Detecting instance...";
client = await ApiClient.getClient(selfUser.instance); client = await ApiClient.getClient(selfUser.apiInstance);
backend.value = client.getClientName(); backend.value = client.getClientName();
break; break;
} }