Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const app = http.createServer(async (req, res) => {
sendFile(filePath);
});

export type instace = {
export type instance = {
name: string;
description?: string;
descriptionLong?: string;
Expand All @@ -157,7 +157,7 @@ export type instace = {
};
const instances = JSON.parse(
readFileSync(process.env.JANK_INSTANCES_PATH || __dirname + "/webpage/instances.json").toString(),
) as instace[];
) as instance[];

const instanceNames = new Map<string, Instance>();

Expand Down
96 changes: 77 additions & 19 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {instace} from "./index.js";
import {instance} from "./index.js";

interface ApiUrls {
api: string;
gateway: string;
Expand All @@ -8,16 +9,17 @@ interface ApiUrls {

export async function getApiUrls(
url: string,
instances: instace[],
instances: instance[],
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;
for (const instance of instances) {
const urlstr = instance.url || instance.urls?.api;
if (!urlstr) {
continue;
}
Expand All @@ -34,21 +36,77 @@ export async function getApiUrls(
throw new Error("Invalid instance");
}
}

const hostName = new URL(url).hostname;
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;
return await getApiUrlsV2(url);
} catch (e) {
console.warn(
`[WARN] Failed to get V2 API URLs for ${hostName}, trying V1...`,
(e as Error).message,
);
try {
return await getApiUrlsV1(url);
} catch (e) {
console.error(`[ERROR] Failed to get V1 API URLs for ${hostName}:`, (e as Error).message);
throw e;
}
}
}

//region Well-Known V1 Interfaces

interface WellKnownV1 {
api: string;
}

export async function getApiUrlsV1(url: string): Promise<ApiUrls | null> {
const info: WellKnownV1 = 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,
};
}
//endregion

//region Well-Known V2 Interfaces
interface WellKnownV2BasicEndpoint {
baseUrl: string;
}

interface WellKnownV2ApiVersions {
default: string;
active: string[];
}

interface WellKnownV2GatewayOptions {
encoding: ("json" | "etf")[];
compression: ("zlib-stream" | "zstd-stream" | null)[];
}

interface WellKnownV2 {
admin?: WellKnownV2BasicEndpoint;
api: WellKnownV2BasicEndpoint & {apiVersions: WellKnownV2ApiVersions};
cdn: WellKnownV2BasicEndpoint;
gateway: WellKnownV2BasicEndpoint & WellKnownV2GatewayOptions;
}

export async function getApiUrlsV2(url: string): Promise<ApiUrls | null> {
const info: WellKnownV2 = await fetch(`${url}.well-known/spacebar/client`).then((res) =>
res.json(),
);
return {
api: info.api.baseUrl + "/api/v" + info.api.apiVersions.default,
gateway: info.gateway.baseUrl,
cdn: info.cdn.baseUrl,
wellknown: url,
};
}
//endregion
2 changes: 1 addition & 1 deletion src/webpage/instances.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"gateway": "wss://gateway-spacebar.greysilly7.xyz"
},
"contactInfo": {
"dicord": "greysilly7",
"discord": "greysilly7",
"github": "https://github.com/greysilly7",
"email": "greysilly7@gmail.com"
}
Expand Down
8 changes: 4 additions & 4 deletions src/webpage/localuser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4026,7 +4026,7 @@ class Localuser {
remove();
}
}
MDFindChannel(name: string, orginal: string, box: HTMLDivElement, typebox: MarkDown) {
MDFindChannel(name: string, original: string, box: HTMLDivElement, typebox: MarkDown) {
const maybe: [number, Channel][] = [];
if (this.lookingguild && this.lookingguild.id !== "@me") {
for (const channel of this.lookingguild.channels) {
Expand All @@ -4039,7 +4039,7 @@ class Localuser {
maybe.sort((a, b) => b[0] - a[0]);
this.MDSearchOptions(
maybe.map((a) => ["# " + a[1].name, `<#${a[1].id}> `, undefined]),
orginal,
original,
box,
typebox,
);
Expand Down Expand Up @@ -4113,7 +4113,7 @@ class Localuser {
}
}
}
findEmoji(search: string, orginal: string, box: HTMLDivElement, typebox: MarkDown) {
findEmoji(search: string, original: string, box: HTMLDivElement, typebox: MarkDown) {
const emj = Emoji.searchEmoji(search, this, 10);
const map = emj.map(([emoji]): [string, string, HTMLElement, () => void] => {
return [
Expand All @@ -4127,7 +4127,7 @@ class Localuser {
},
];
});
this.MDSearchOptions(map, orginal, box, typebox);
this.MDSearchOptions(map, original, box, typebox);
}
async findCommands(search: string, box: HTMLDivElement, md: MarkDown) {
const guild = this.lookingguild;
Expand Down
4 changes: 2 additions & 2 deletions src/webpage/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {instanceinfo, adduser, Specialuser} from "./utils/utils.js";
import {I18n} from "./i18n.js";
import {Dialog, FormError} from "./settings.js";
import {makeRegister} from "./register.js";
import {trimTrailingSlashes} from "./utils/netUtils";
function generateRecArea(recover = document.getElementById("recover")) {
if (!recover) return;
recover.innerHTML = "";
Expand Down Expand Up @@ -55,8 +56,7 @@ export async function makeLogin(
opt.addTitle(I18n.login.login());
const picker = opt.addInstancePicker(
(info) => {
const api = info.login + (info.login.startsWith("/") ? "/" : "");
form.fetchURL = api + "/auth/login";
form.fetchURL = trimTrailingSlashes(info.api) + "/auth/login";
recover(info, rec);
},
{
Expand Down
4 changes: 2 additions & 2 deletions src/webpage/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,8 +719,8 @@ class MarkDown {
}
if (URL.canParse(build) && txt[j] === ">") {
const url = new URL(build);
const allowedProticals = new Set(["https:", "http:"]);
if (allowedProticals.has(url.protocol)) {
const allowedprotocols = new Set(["https:", "http:"]);
if (allowedprotocols.has(url.protocol)) {
i = j;

if (keep) {
Expand Down
4 changes: 2 additions & 2 deletions src/webpage/register.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {adduser, Specialuser} from "./utils/utils.js";
import {makeLogin} from "./login.js";
import {MarkDown} from "./markdown.js";
import {Dialog, FormError} from "./settings.js";
import {trimTrailingSlashes} from "./utils/netUtils";
export async function makeRegister(
trasparentBg = false,
instance = "",
Expand All @@ -13,8 +14,7 @@ export async function makeRegister(
opt.addTitle(I18n.htmlPages.createAccount());
const picker = opt.addInstancePicker(
(info) => {
const api = info.login + (info.login.endsWith("/") ? "" : "/");
form.fetchURL = api + "auth/register";
form.fetchURL = trimTrailingSlashes(info.api) + "/auth/register";
tosLogic(md);
},
{instance},
Expand Down
16 changes: 8 additions & 8 deletions src/webpage/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,19 @@ let fails = 0;
async function getfile(req: Request): Promise<Response> {
checkCache();
if (!samedomain(req.url) || enabled === "false" || (enabled === "offlineOnly" && !offline)) {
const responce = await fetch(req.clone());
const response = await fetch(req.clone());
if (samedomain(req.url)) {
if (enabled === "offlineOnly" && responce.ok) {
putInCache(toPath(req.url), responce.clone());
if (enabled === "offlineOnly" && response.ok) {
putInCache(toPath(req.url), response.clone());
}
if (!responce.ok) {
if (!response.ok) {
fails++;
if (fails > 5) {
offline = true;
}
}
}
return responce;
return response;
}

let path = toPath(req.url);
Expand Down Expand Up @@ -228,12 +228,12 @@ self.addEventListener("fetch", async (e) => {

if (apiHosts?.has(host || "")) {
try {
const responce = await fetch(req.clone());
const response = await fetch(req.clone());
try {
event.respondWith(responce.clone());
event.respondWith(response.clone());
} catch {}

const json = await responce.json();
const json = await response.json();
if (json._trace) {
sendAll({
code: "trace",
Expand Down
18 changes: 9 additions & 9 deletions src/webpage/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
getInstances,
getStringURLMapPair,
instancefetch,
instanceinfo,
InstanceInfo,
removeAni,
} from "./utils/utils.js";
import {Emoji} from "./emoji.js";
Expand Down Expand Up @@ -890,13 +890,13 @@ class Dialog {
removeAni(background);
}
}
class InstancePicker implements OptionsElement<instanceinfo | null> {
value: instanceinfo | null = null;
class InstancePicker implements OptionsElement<InstanceInfo | null> {
value: InstanceInfo | null = null;
owner: Options | Form;
verify = document.createElement("p");
onchange = (_: instanceinfo) => {};
onchange = (_: InstanceInfo) => {};
instance?: string;
watchForChange(func: (arg1: instanceinfo) => void) {
watchForChange(func: (arg1: InstanceInfo) => void) {
this.onchange = func;
}
constructor(
Expand Down Expand Up @@ -1142,10 +1142,10 @@ class Options implements OptionsElement<void> {
onchange?: InstancePicker["onchange"],
{button, instance}: {button?: HTMLButtonElement; instance?: string} = {},
) {
const instacePicker = new InstancePicker(this, onchange, button, instance);
this.options.push(instacePicker);
this.generate(instacePicker);
return instacePicker;
const instancePicker = new InstancePicker(this, onchange, button, instance);
this.options.push(instancePicker);
this.generate(instancePicker);
return instancePicker;
}
returnFromSub() {
this.subOptions = undefined;
Expand Down
8 changes: 8 additions & 0 deletions src/webpage/utils/netUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function trimTrailingSlashes(uri: string) {
if (!uri) return uri;
return uri.replace(/\/+$/, "");
}

export function isLoopback(str: string) {
return str.includes("localhost") || str.includes("127.0.0.1");
}
Loading