]> Untitled Git - lemmy-ui.git/blob - src/server/handlers/catch-all-handler.tsx
Merge branch 'main' into remove_markdown_it_emoji
[lemmy-ui.git] / src / server / handlers / catch-all-handler.tsx
1 import { initializeSite, isAuthPath } from "@utils/app";
2 import { ErrorPageData } from "@utils/types";
3 import type { Request, Response } from "express";
4 import { StaticRouter, matchPath } from "inferno-router";
5 import { renderToString } from "inferno-server";
6 import IsomorphicCookie from "isomorphic-cookie";
7 import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
8 import { App } from "../../shared/components/app/app";
9 import { getHttpBaseInternal } from "../../shared/env";
10 import {
11   InitialFetchRequest,
12   IsoDataOptionalSite,
13   RouteData,
14 } from "../../shared/interfaces";
15 import { routes } from "../../shared/routes";
16 import {
17   FailedRequestState,
18   wrapClient,
19 } from "../../shared/services/HttpService";
20 import { createSsrHtml } from "../utils/create-ssr-html";
21 import { getErrorPageData } from "../utils/get-error-page-data";
22 import { setForwardedHeaders } from "../utils/set-forwarded-headers";
23
24 export default async (req: Request, res: Response) => {
25   try {
26     const activeRoute = routes.find(route => matchPath(req.path, route));
27     let auth: string | undefined = IsomorphicCookie.load("jwt", req);
28
29     const getSiteForm: GetSite = { auth };
30
31     const headers = setForwardedHeaders(req.headers);
32     const client = wrapClient(
33       new LemmyHttp(getHttpBaseInternal(), { fetchFunction: fetch, headers })
34     );
35
36     const { path, url, query } = req;
37
38     // Get site data first
39     // This bypasses errors, so that the client can hit the error on its own,
40     // in order to remove the jwt on the browser. Necessary for wrong jwts
41     let site: GetSiteResponse | undefined = undefined;
42     let routeData: RouteData = {};
43     let errorPageData: ErrorPageData | undefined = undefined;
44     let try_site = await client.getSite(getSiteForm);
45     if (try_site.state === "failed" && try_site.msg == "not_logged_in") {
46       console.error(
47         "Incorrect JWT token, skipping auth so frontend can remove jwt cookie"
48       );
49       getSiteForm.auth = undefined;
50       auth = undefined;
51       try_site = await client.getSite(getSiteForm);
52     }
53
54     if (!auth && isAuthPath(path)) {
55       return res.redirect("/login");
56     }
57
58     if (try_site.state === "success") {
59       site = try_site.data;
60       initializeSite(site);
61
62       if (path !== "/setup" && !site.site_view.local_site.site_setup) {
63         return res.redirect("/setup");
64       }
65
66       if (site && activeRoute?.fetchInitialData) {
67         const initialFetchReq: InitialFetchRequest = {
68           client,
69           auth,
70           path,
71           query,
72           site,
73         };
74
75         routeData = await activeRoute.fetchInitialData(initialFetchReq);
76       }
77     } else if (try_site.state === "failed") {
78       errorPageData = getErrorPageData(new Error(try_site.msg), site);
79     }
80
81     const error = Object.values(routeData).find(
82       res => res.state === "failed"
83     ) as FailedRequestState | undefined;
84
85     // Redirect to the 404 if there's an API error
86     if (error) {
87       console.error(error.msg);
88       if (error.msg === "instance_is_private") {
89         return res.redirect(`/signup`);
90       } else {
91         errorPageData = getErrorPageData(new Error(error.msg), site);
92       }
93     }
94
95     const isoData: IsoDataOptionalSite = {
96       path,
97       site_res: site,
98       routeData,
99       errorPageData,
100     };
101
102     const wrapper = (
103       <StaticRouter location={url} context={isoData}>
104         <App />
105       </StaticRouter>
106     );
107
108     const root = renderToString(wrapper);
109
110     res.send(await createSsrHtml(root, isoData));
111   } catch (err) {
112     // If an error is caught here, the error page couldn't even be rendered
113     console.error(err);
114     res.statusCode = 500;
115     return res.send(
116       process.env.NODE_ENV === "development" ? err.message : "Server error"
117     );
118   }
119 };