Skip to content

Commit

Permalink
Merge pull request #144 from spacebarchat/feat/instancepicker
Browse files Browse the repository at this point in the history
Instance picker
  • Loading branch information
Puyodead1 committed Aug 9, 2023
2 parents f91b940 + c27a94a commit f181632
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 3 deletions.
67 changes: 66 additions & 1 deletion src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import HCaptcha, { HeaderContainer } from "../components/HCaptcha";
import MFA from "../components/MFA";
import ForgotPasswordModal from "../components/modals/ForgotPasswordModal";
import { AUTH_NO_BRANDING, useAppStore } from "../stores/AppStore";
import { Globals } from "../utils/Globals";
import REST from "../utils/REST";
import {
IAPILoginRequest,
IAPILoginResponse,
Expand All @@ -38,6 +40,7 @@ import { messageFromFieldError } from "../utils/messageFromFieldError";
type FormValues = {
login: string;
password: string;
instance: string;
captcha_key?: string;
};

Expand All @@ -49,6 +52,7 @@ function LoginPage() {
const [mfaData, setMfaData] =
React.useState<IAPILoginResponseMFARequired>();
const captchaRef = React.useRef<HCaptchaLib>(null);
const [debounce, setDebounce] = React.useState<NodeJS.Timeout | null>(null);
const { openModal } = useModals();

const {
Expand All @@ -57,21 +61,31 @@ function LoginPage() {
formState: { errors },
setError,
setValue,
clearErrors,
} = useForm<FormValues>();

const resetCaptcha = () => {
captchaRef.current?.resetCaptcha();
setValue("captcha_key", undefined);
};

const getValidURL = (url: string) => {
try {
return new URL(url);
} catch (e) {
return undefined;
}
};

const onSubmit = handleSubmit((data) => {
setLoading(true);
setCaptchaSiteKey(undefined);
setMfaData(undefined);

app.rest
.post<IAPILoginRequest, IAPILoginResponse>(Routes.login(), {
...data,
login: data.login,
password: data.password,
undelete: false,
})
.then((r) => {
Expand Down Expand Up @@ -157,6 +171,30 @@ function LoginPage() {
onSubmit();
};

const handleInstanceChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// set as validating
if (debounce) clearTimeout(debounce);

const doRequest = async () => {
const url = getValidURL(e.target.value);
if (!url) return;

const endpoints = await REST.getEndpointsFromDomain(url);
if (!endpoints)
return setError("instance", {
type: "manual",
message: "Instance could not be resolved",
});

console.debug(`Instance lookup has set routes to`, endpoints);
Globals.routeSettings = endpoints; // hmm
Globals.save();
clearErrors("instance");
};

setDebounce(setTimeout(doRequest, 500));
};

const forgotPassword = () => {
openModal(ForgotPasswordModal);
};
Expand Down Expand Up @@ -196,6 +234,33 @@ function LoginPage() {
marginBottom={true}
style={{ marginTop: 0 }}
>
<LabelWrapper error={!!errors.instance}>
<InputLabel>Instance</InputLabel>
{errors.instance && (
<InputErrorText>
<>
<Divider>-</Divider>
{errors.instance.message}
</>
</InputErrorText>
)}
</LabelWrapper>
<InputWrapper>
<Input
type="url"
{...register("instance", {
required: true,
value: Globals.routeSettings.wellknown,
})}
placeholder="Instance Root URL"
onChange={handleInstanceChange}
error={!!errors.instance}
disabled={loading}
/>
</InputWrapper>
</InputContainer>

<InputContainer marginBottom={false}>
<LabelWrapper error={!!errors.login}>
<InputLabel>Email</InputLabel>
{errors.login && (
Expand Down
4 changes: 3 additions & 1 deletion src/utils/Globals.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
interface RouteSettings {
export interface RouteSettings {
api: string;
cdn: string;
gateway: string;
wellknown: string;
}

export const DefaultRouteSettings: RouteSettings = {
api: "https://api.old.server.spacebar.chat/api",
cdn: "https://cdn.old.server.spacebar.chat",
gateway: "wss://gateway.old.server.spacebar.chat",
wellknown: "https://spacebar.chat",
};

export const Globals: {
Expand Down
43 changes: 42 additions & 1 deletion src/utils/REST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// import {DomainStore} from '../stores/DomainStore';

import AppStore from "../stores/AppStore";
import { Globals } from "./Globals";
import { Globals, RouteSettings } from "./Globals";

export default class REST {
private app: AppStore;
Expand All @@ -27,6 +27,47 @@ export default class REST {
}
}

public static async getEndpointsFromDomain(
url: URL,
): Promise<RouteSettings | null> {
let endpoints = await this.getInstanceDomains(url);
if (endpoints) return { ...endpoints, wellknown: url.toString() };

// get endpoints from .well-known
let wellKnown;
try {
wellKnown = await fetch(`${url.origin}/.well-known/spacebar`)
.then((x) => x.json())
.then((x) => new URL(x.api));
} catch (e) {
return null;
}

// well-known was found
endpoints = await this.getInstanceDomains(wellKnown);
if (!endpoints) return null;
return { ...endpoints, wellknown: url.toString() };
}

static async getInstanceDomains(
url: URL,
): Promise<Omit<RouteSettings, "wellknown"> | null> {
try {
const endpoints = await fetch(
`${url.toString()}${
url.pathname.includes("api") ? "" : "api"
}/policies/instance/domains`,
).then((x) => x.json());
return {
api: endpoints.apiEndpoint,
gateway: endpoints.gateway,
cdn: endpoints.cdn,
};
} catch (e) {
return null;
}
}

public static makeAPIUrl(
path: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down

0 comments on commit f181632

Please sign in to comment.