Migrate to rAuth v1.

This commit is contained in:
Paul 2021-09-11 17:36:23 +01:00
parent a4138b52b0
commit 5b422b89e3
15 changed files with 116 additions and 87 deletions

2
external/lang vendored

@ -1 +1 @@
Subproject commit 3da029dff71f5657d6fd152d3391de8f85840d95 Subproject commit ad350d64633ead4c636d3cf1be5597c98f4ad006

View file

@ -120,8 +120,8 @@
"react-virtualized-auto-sizer": "^1.0.5", "react-virtualized-auto-sizer": "^1.0.5",
"react-virtuoso": "^1.10.4", "react-virtuoso": "^1.10.4",
"redux": "^4.1.0", "redux": "^4.1.0",
"revolt-api": "0.5.2-alpha.3", "revolt-api": "0.5.3-alpha.0-patch.0",
"revolt.js": "5.0.1-alpha.6-patch.2", "revolt.js": "5.1.0-alpha.0-patch.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"sass": "^1.35.1", "sass": "^1.35.1",
"shade-blend-color": "^1.0.0", "shade-blend-color": "^1.0.0",

View file

@ -39,15 +39,15 @@ export function ModifyAccountModal({ onClose, field }: Props) {
}) => { }) => {
try { try {
if (field === "email") { if (field === "email") {
await client.req("POST", "/auth/change/email", { await client.req("POST", "/auth/account/change/email", {
password, current_password: password,
new_email, email: new_email,
}); });
onClose(); onClose();
} else if (field === "password") { } else if (field === "password") {
await client.req("POST", "/auth/change/password", { await client.req("POST", "/auth/account/change/password", {
password, current_password: password,
new_password, password: new_password,
}); });
onClose(); onClose();
} else if (field === "username") { } else if (field === "username") {

View file

@ -1,4 +1,5 @@
/* eslint-disable react-hooks/rules-of-hooks */ /* eslint-disable react-hooks/rules-of-hooks */
import { Session } from "revolt-api/types/Auth";
import { Client } from "revolt.js"; import { Client } from "revolt.js";
import { Route } from "revolt.js/dist/api/routes"; import { Route } from "revolt.js/dist/api/routes";
@ -15,7 +16,6 @@ import { Children } from "../../types/Preact";
import { useIntermediate } from "../intermediate/Intermediate"; import { useIntermediate } from "../intermediate/Intermediate";
import { registerEvents, setReconnectDisallowed } from "./events"; import { registerEvents, setReconnectDisallowed } from "./events";
import { takeError } from "./util"; import { takeError } from "./util";
import { Session } from "revolt-api/types/Auth";
export enum ClientStatus { export enum ClientStatus {
INIT, INIT,
@ -29,7 +29,9 @@ export enum ClientStatus {
} }
export interface ClientOperations { export interface ClientOperations {
login: (data: Route<"POST", "/auth/login">["data"]) => Promise<void>; login: (
data: Route<"POST", "/auth/session/login">["data"],
) => Promise<void>;
logout: (shouldRequest?: boolean) => Promise<void>; logout: (shouldRequest?: boolean) => Promise<void>;
loggedIn: () => boolean; loggedIn: () => boolean;
ready: () => boolean; ready: () => boolean;

View file

@ -9,7 +9,10 @@ export function takeError(error: any): string {
const type = error?.response?.data?.type; const type = error?.response?.data?.type;
const id = type; const id = type;
if (!type) { if (!type) {
if (error?.response?.status === 403) { if (
error?.response?.status === 401 ||
error?.response?.status === 403
) {
return "Unauthorized"; return "Unauthorized";
} else if (error && !!error.isAxiosError && !error.response) { } else if (error && !!error.isAxiosError && !error.response) {
return "NetworkError"; return "NetworkError";

3
src/env.d.ts vendored
View file

@ -1,8 +1,9 @@
interface ImportMetaEnv { interface ImportMetaEnv {
DEV: boolean;
VITE_API_URL: string; VITE_API_URL: string;
VITE_THEMES_URL: string; VITE_THEMES_URL: string;
} }
interface ImportMeta { interface ImportMeta {
env: ImportMetaEnv env: ImportMetaEnv;
} }

View file

@ -16,8 +16,8 @@ import { APP_VERSION } from "../../version";
import background from "./background.jpg"; import background from "./background.jpg";
import { FormCreate } from "./forms/FormCreate"; import { FormCreate } from "./forms/FormCreate";
import { FormLogin } from "./forms/FormLogin"; import { FormLogin } from "./forms/FormLogin";
import { FormResend } from "./forms/FormResend";
import { FormReset, FormSendReset } from "./forms/FormReset"; import { FormReset, FormSendReset } from "./forms/FormReset";
import { FormResend, FormVerify } from "./forms/FormVerify";
export default function Login() { export default function Login() {
const theme = useContext(ThemeContext); const theme = useContext(ThemeContext);
@ -52,6 +52,9 @@ export default function Login() {
<Route path="/login/resend"> <Route path="/login/resend">
<FormResend /> <FormResend />
</Route> </Route>
<Route path="/login/verify/:token">
<FormVerify />
</Route>
<Route path="/login/reset/:token"> <Route path="/login/reset/:token">
<FormReset /> <FormReset />
</Route> </Route>

View file

@ -6,13 +6,5 @@ import { Form } from "./Form";
export function FormCreate() { export function FormCreate() {
const client = useContext(AppContext); const client = useContext(AppContext);
return <Form page="create" callback={(data) => client.register(data)} />;
return (
<Form
page="create"
callback={async (data) => {
await client.register(import.meta.env.VITE_API_URL, data);
}}
/>
);
} }

View file

@ -16,25 +16,25 @@ export function FormLogin() {
page="login" page="login"
callback={async (data) => { callback={async (data) => {
const browser = detect(); const browser = detect();
let device_name; let friendly_name;
if (browser) { if (browser) {
let { name } = browser; let { name } = browser;
const { os } = browser; const { os } = browser;
if (window.isNative) { if (window.isNative) {
device_name = `Revolt Desktop on ${os}`; friendly_name = `Revolt Desktop on ${os}`;
} else { } else {
if (name === "ios") { if (name === "ios") {
name = "safari"; name = "safari";
} else if (name === "fxios") { } else if (name === "fxios") {
name = "firefox"; name = "firefox";
} }
device_name = `${name} on ${os}`; friendly_name = `${name} on ${os}`;
} }
} else { } else {
device_name = "Unknown Device"; friendly_name = "Unknown Device";
} }
await login({ ...data, device_name }); await login({ ...data, friendly_name });
history.push("/"); history.push("/");
}} }}
/> />

View file

@ -1,18 +0,0 @@
import { useContext } from "preact/hooks";
import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { Form } from "./Form";
export function FormResend() {
const client = useContext(AppContext);
return (
<Form
page="resend"
callback={async (data) => {
await client.req("POST", "/auth/resend", data);
}}
/>
);
}

View file

@ -13,7 +13,7 @@ export function FormSendReset() {
<Form <Form
page="send_reset" page="send_reset"
callback={async (data) => { callback={async (data) => {
await client.req("POST", "/auth/send_reset", data); await client.req("POST", "/auth/account/reset_password", data);
}} }}
/> />
); );
@ -28,7 +28,7 @@ export function FormReset() {
<Form <Form
page="reset" page="reset"
callback={async (data) => { callback={async (data) => {
await client.req("POST", "/auth/reset", { await client.req("PATCH", "/auth/account/reset_password", {
token, token,
...data, ...data,
}); });

View file

@ -0,0 +1,48 @@
import { useHistory, useParams } from "react-router-dom";
import { useContext, useEffect, useState } from "preact/hooks";
import { AppContext } from "../../../context/revoltjs/RevoltClient";
import { takeError } from "../../../context/revoltjs/util";
import Overline from "../../../components/ui/Overline";
import Preloader from "../../../components/ui/Preloader";
import { Form } from "./Form";
export function FormResend() {
const client = useContext(AppContext);
return (
<Form
page="resend"
callback={async (data) => {
await client.req("POST", "/auth/account/reverify", data);
}}
/>
);
}
export function FormVerify() {
const [error, setError] = useState<undefined | string>(undefined);
const { token } = useParams<{ token: string }>();
const client = useContext(AppContext);
const history = useHistory();
useEffect(() => {
client
.req(
"POST",
`/auth/account/verify/${token}` as "/auth/account/verify/:code",
)
.then(() => history.push("/login"))
.catch((err) => setError(takeError(err)));
// eslint-disable-next-line
}, []);
return error ? (
<Overline type="error" error={error} />
) : (
<Preloader type="ring" />
);
}

View file

@ -46,7 +46,7 @@ export const Account = observer(() => {
useEffect(() => { useEffect(() => {
if (email === "..." && status === ClientStatus.ONLINE) { if (email === "..." && status === ClientStatus.ONLINE) {
client client
.req("GET", "/auth/user") .req("GET", "/auth/account")
.then((account) => setEmail(account.email)); .then((account) => setEmail(account.email));
} }

View file

@ -11,6 +11,7 @@ import {
} from "@styled-icons/simple-icons"; } from "@styled-icons/simple-icons";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import { SessionInfo } from "revolt-api/types/Auth";
import { decodeTime } from "ulid"; import { decodeTime } from "ulid";
import styles from "./Panes.module.scss"; import styles from "./Panes.module.scss";
@ -26,17 +27,14 @@ import Tip from "../../../components/ui/Tip";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
interface Session {
id: string;
friendly_name: string;
}
export function Sessions() { export function Sessions() {
const client = useContext(AppContext); const client = useContext(AppContext);
const deviceId = const deviceId =
typeof client.session === "object" ? client.session.id : undefined; typeof client.session === "object" ? client.session._id : undefined;
const [sessions, setSessions] = useState<Session[] | undefined>(undefined); const [sessions, setSessions] = useState<SessionInfo[] | undefined>(
undefined,
);
const [attemptingDelete, setDelete] = useState<string[]>([]); const [attemptingDelete, setDelete] = useState<string[]>([]);
const history = useHistory(); const history = useHistory();
@ -45,10 +43,10 @@ export function Sessions() {
} }
useEffect(() => { useEffect(() => {
client.req("GET", "/auth/sessions").then((data) => { client.req("GET", "/auth/session/all").then((data) => {
data.sort( data.sort(
(a, b) => (a, b) =>
(b.id === deviceId ? 1 : 0) - (a.id === deviceId ? 1 : 0), (b._id === deviceId ? 1 : 0) - (a._id === deviceId ? 1 : 0),
); );
setSessions(data); setSessions(data);
}); });
@ -62,8 +60,8 @@ export function Sessions() {
); );
} }
function getIcon(session: Session) { function getIcon(session: SessionInfo) {
const name = session.friendly_name; const name = session.name;
switch (true) { switch (true) {
case /firefox/i.test(name): case /firefox/i.test(name):
return <Firefoxbrowser size={32} />; return <Firefoxbrowser size={32} />;
@ -84,8 +82,8 @@ export function Sessions() {
} }
} }
function getSystemIcon(session: Session) { function getSystemIcon(session: SessionInfo) {
const name = session.friendly_name; const name = session.name;
switch (true) { switch (true) {
case /linux/i.test(name): case /linux/i.test(name):
return <Linux size={14} />; return <Linux size={14} />;
@ -105,12 +103,12 @@ export function Sessions() {
const mapped = sessions.map((session) => { const mapped = sessions.map((session) => {
return { return {
...session, ...session,
timestamp: decodeTime(session.id), timestamp: decodeTime(session._id),
}; };
}); });
mapped.sort((a, b) => b.timestamp - a.timestamp); mapped.sort((a, b) => b.timestamp - a.timestamp);
const id = mapped.findIndex((x) => x.id === deviceId); const id = mapped.findIndex((x) => x._id === deviceId);
const render = [ const render = [
mapped[id], mapped[id],
@ -127,13 +125,13 @@ export function Sessions() {
const systemIcon = getSystemIcon(session); const systemIcon = getSystemIcon(session);
return ( return (
<div <div
key={session.id} key={session._id}
className={styles.entry} className={styles.entry}
data-active={session.id === deviceId} data-active={session._id === deviceId}
data-deleting={ data-deleting={
attemptingDelete.indexOf(session.id) > -1 attemptingDelete.indexOf(session._id) > -1
}> }>
{deviceId === session.id && ( {deviceId === session._id && (
<span className={styles.label}> <span className={styles.label}>
<Text id="app.settings.pages.sessions.this_device" />{" "} <Text id="app.settings.pages.sessions.this_device" />{" "}
</span> </span>
@ -165,7 +163,7 @@ export function Sessions() {
<input <input
type="text" type="text"
className={styles.name} className={styles.name}
value={session.friendly_name} value={session.name}
autocomplete="off" autocomplete="off"
style={{ pointerEvents: "none" }} style={{ pointerEvents: "none" }}
/> />
@ -181,25 +179,25 @@ export function Sessions() {
</span> </span>
</div> </div>
</div> </div>
{deviceId !== session.id && ( {deviceId !== session._id && (
<Button <Button
onClick={async () => { onClick={async () => {
setDelete([ setDelete([
...attemptingDelete, ...attemptingDelete,
session.id, session._id,
]); ]);
await client.req( await client.req(
"DELETE", "DELETE",
`/auth/sessions/${session.id}` as "/auth/sessions", `/auth/session/${session._id}` as "/auth/session/id",
); );
setSessions( setSessions(
sessions?.filter( sessions?.filter(
(x) => x.id !== session.id, (x) => x._id !== session._id,
), ),
); );
}} }}
disabled={ disabled={
attemptingDelete.indexOf(session.id) > attemptingDelete.indexOf(session._id) >
-1 -1
}> }>
<Text id="app.settings.pages.logOut" /> <Text id="app.settings.pages.logOut" />
@ -215,8 +213,8 @@ export function Sessions() {
// ! FIXME: add to rAuth // ! FIXME: add to rAuth
const del: string[] = []; const del: string[] = [];
render.forEach((session) => { render.forEach((session) => {
if (deviceId !== session.id) { if (deviceId !== session._id) {
del.push(session.id); del.push(session._id);
} }
}); });
@ -225,11 +223,11 @@ export function Sessions() {
for (const id of del) { for (const id of del) {
await client.req( await client.req(
"DELETE", "DELETE",
`/auth/sessions/${id}` as "/auth/sessions", `/auth/session/${id}` as "/auth/session/id",
); );
} }
setSessions(sessions.filter((x) => x.id === deviceId)); setSessions(sessions.filter((x) => x._id === deviceId));
}}> }}>
<Text id="app.settings.pages.sessions.logout" /> <Text id="app.settings.pages.sessions.logout" />
</Button> </Button>

View file

@ -3654,15 +3654,15 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
revolt-api@0.5.2-alpha.3: revolt-api@0.5.3-alpha.0-patch.0:
version "0.5.2-alpha.3" version "0.5.3-alpha.0-patch.0"
resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.2-alpha.3.tgz#f980014f6cd1bef4fb3605fe56af0e829e43c6d9" resolved "https://registry.yarnpkg.com/revolt-api/-/revolt-api-0.5.3-alpha.0-patch.0.tgz#158556832843bb06cb06a4df50ffca24ab64be3b"
integrity sha512-eIjJtUGkm83mbm1i6OxhWav2m/Xf9FJAFEA2e8YhpC1kd8vXwm/mWbPbuyTX5LNxPT9EEW0Fgx+7xt9zl5lzAw== integrity sha512-76l+kGyrUy6uGMSIziyAHE27r9gD97OEh5gSzb2OJRsQM55TN0NurAsfFIEiB9hUzDDlwsXchtJiqdS4UVAwQw==
revolt.js@5.0.1-alpha.6-patch.2: revolt.js@5.1.0-alpha.0-patch.0:
version "5.0.1-alpha.6-patch.2" version "5.1.0-alpha.0-patch.0"
resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.0.1-alpha.6-patch.2.tgz#4a9c99f9422fdadbe2ca84a012e018d827c8f2cf" resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-5.1.0-alpha.0-patch.0.tgz#3d62f32d657ee1f44381018251a6682c81cf21d8"
integrity sha512-FfvNFS0noGjLlxsNTUaxIHREW2z7pPu0ZFayI5MUwDqDvdaKyicyZ63zmi14UGATPkCpNiJ4ufYhcLX8ArsGTg== integrity sha512-om61mNeVWiGc6+XFPpK2YM6i6QSOT3f5prhVyM78BcZZ5U2L39SWBN3S7ycAsr8g4Q9pPLv50qYwnsMjxe4P/A==
dependencies: dependencies:
axios "^0.19.2" axios "^0.19.2"
eventemitter3 "^4.0.7" eventemitter3 "^4.0.7"