jank-client-fork/src/utils.ts
2024-12-26 13:03:38 -06:00

128 lines
3 KiB
TypeScript

import {Request, Response} from "express";
import {instace} from "./index.js";
interface ApiUrls {
api: string;
gateway: string;
cdn: string;
wellknown: string;
}
interface Invite {
guild: {
name: string;
description?: string;
icon?: string;
id: string;
};
inviter?: {
username: string;
};
}
export async function getApiUrls(
url: string,
instances: instace[],
check = true,
): Promise<ApiUrls | null> {
if (!url.endsWith("/")) {
url += "/";
}
if (check) {
let valid = false;
for (const instace of instances) {
const urlstr = instace.url || instace.urls?.api;
if (!urlstr) {
continue;
}
try {
if (new URL(urlstr).host === new URL(url).host) {
valid = true;
break;
}
} catch (e) {
//console.log(e);
}
}
if (!valid) {
throw new Error("Invalid instance");
}
}
try {
const info: ApiUrls = await fetch(`${url}.well-known/spacebar`).then((res) => res.json());
const api = info.api;
const apiUrl = new URL(api);
const policies: any = await fetch(
`${api}${apiUrl.pathname.includes("api") ? "" : "api"}/policies/instance/domains`,
).then((res) => res.json());
return {
api: policies.apiEndpoint,
gateway: policies.gateway,
cdn: policies.cdn,
wellknown: url,
};
} catch (error) {
console.error("Error fetching API URLs:", error);
return null;
}
}
export async function inviteResponse(
req: Request,
res: Response,
instances: instace[],
): Promise<void> {
let url: URL;
try {
url = new URL(req.query.url as string);
} catch {
const scheme = req.secure ? "https" : "http";
const host = `${scheme}://${req.get("Host")}`;
url = new URL(host);
}
try {
if (!url.pathname.startsWith("invite") && !url.pathname.startsWith("/invite")) {
throw new Error("Invalid invite URL");
}
const code = url.pathname.split("/")[2];
const instance = url.searchParams.get("instance");
if (!instance) {
throw new Error("Instance not specified");
}
const urls = await getApiUrls(instance, instances);
if (!urls) {
throw new Error("Failed to get API URLs");
}
const invite = await fetch(`${urls.api}/invites/${code}`).then(
(json) => json.json() as Promise<Invite>,
);
const title = invite.guild.name;
const description = invite.inviter
? `${invite.inviter.username} has invited you to ${invite.guild.name}${invite.guild.description ? `\n${invite.guild.description}` : ""}`
: `You've been invited to ${invite.guild.name}${invite.guild.description ? `\n${invite.guild.description}` : ""}`;
const thumbnail = invite.guild.icon
? `${urls.cdn}/icons/${invite.guild.id}/${invite.guild.icon}.png`
: "";
res.json({
type: "link",
version: "1.0",
title,
thumbnail,
description,
});
} catch (error) {
//console.error("Error processing invite response:", error);
res.json({
type: "link",
version: "1.0",
title: "Jank Client",
thumbnail: "/logo.webp",
description: "A spacebar client that has DMs, replying and more",
url: url.toString(),
});
}
}