slate/server.js

395 lines
9.7 KiB
JavaScript
Raw Normal View History

import * as Environment from "~/node_common/environment";
import * as Data from "~/node_common/data";
import * as Utilities from "~/node_common/utilities";
import * as Serializers from "~/node_common/serializers";
import * as ViewerManager from "~/node_common/managers/viewer";
import * as AnalyticsManager from "~/node_common/managers/analytics";
import * as Websocket from "~/node_common/nodejs-websocket";
import * as Validations from "~/common/validations";
import * as Window from "~/common/window";
import * as Strings from "~/common/strings";
2020-06-17 21:05:13 +03:00
import ApiV1GetSlateObjects from "~/pages/api/v1/get-slate-objects";
2020-10-29 10:05:57 +03:00
import limit from "express-rate-limit";
2020-07-09 06:19:08 +03:00
import express from "express";
import next from "next";
import compression from "compression";
import cors from "cors";
2020-10-08 03:51:49 +03:00
import morgan from "morgan";
2020-07-21 21:01:12 +03:00
const app = next({
dev: !Environment.IS_PRODUCTION,
dir: __dirname,
quiet: false,
});
2020-10-29 10:05:57 +03:00
const createLimiter = limit({
windowMs: 10 * 60 * 1000, // 10 minutes
max: 5,
message: {
decorator: "SIGN_UP_RATE_LIMITED",
error: true,
message: "You have made too many requests.",
},
2020-10-29 10:05:57 +03:00
});
const loginLimiter = limit({
windowMs: 10 * 60 * 1000, // 10 minutes
max: 5,
message: {
decorator: "SIGN_IN_RATE_LIMITED",
error: true,
message: "You have made too many requests.",
},
2020-10-29 10:05:57 +03:00
});
const handler = app.getRequestHandler();
const EXTERNAL_RESOURCES = {
storageDealUpload: Strings.isEmpty(Environment.RESOURCE_URI_STORAGE_UPLOAD)
2020-10-24 20:04:01 +03:00
? null
: Environment.RESOURCE_URI_STORAGE_UPLOAD,
upload: Strings.isEmpty(Environment.RESOURCE_URI_UPLOAD)
2020-10-24 20:04:01 +03:00
? null
: Environment.RESOURCE_URI_STORAGE_UPLOAD,
2020-11-14 16:27:45 +03:00
uploadZip: Strings.isEmpty(Environment.RESOURCE_URI_UPLOAD)
? null
: Environment.RESOURCE_URI_STORAGE_UPLOAD,
pubsub: Strings.isEmpty(Environment.RESOURCE_URI_PUBSUB) ? null : Environment.RESOURCE_URI_PUBSUB,
2020-11-11 05:38:22 +03:00
search: Strings.isEmpty(Environment.RESOURCE_URI_SEARCH) ? null : Environment.RESOURCE_URI_SEARCH,
};
app.prepare().then(async () => {
2020-02-19 09:30:47 +03:00
const server = express();
2020-08-18 01:11:08 +03:00
server.use(cors());
2020-10-22 08:38:37 +03:00
server.use(morgan(":method :url :status :res[content-length] - :response-time ms"));
2020-10-23 23:28:08 +03:00
if (Environment.IS_PRODUCTION) {
server.use(compression());
}
2020-07-09 06:19:08 +03:00
server.use("/public", express.static("public"));
server.get("/system", async (r, s) => s.redirect("/_/system"));
server.get("/experiences", async (r, s) => s.redirect("/_/system"));
server.get("/_/experiences", async (r, s) => s.redirect("/_/system"));
2020-10-22 08:38:37 +03:00
server.get("/system/:c", async (r, s) => s.redirect(`/_/system/${r.params.c}`));
server.get("/experiences/:m", async (r, s) => s.redirect(`/_/experiences/${r.params.m}`));
// NOTE(jim): Example of simple query to query slates by CID.
server.get("/api/v1/cid::cid", async (r, s) => {
return await ApiV1GetSlateObjects(r, s);
});
2020-10-29 10:05:57 +03:00
server.all("/api/users/create", createLimiter, async (r, s, next) => {
return handler(r, s, r.url);
});
server.all("/api/sign-in", loginLimiter, async (r, s, next) => {
return handler(r, s, r.url);
});
server.all("/api/:a", async (r, s, next) => {
return handler(r, s, r.url);
});
server.all("/api/:a/:b", async (r, s, next) => {
return handler(r, s, r.url);
});
2020-09-14 10:28:09 +03:00
server.get("/", async (req, res) => {
return app.render(req, res, "/", {});
});
server.get("/_", async (req, res) => {
2020-10-22 08:38:37 +03:00
let mobile = Window.isMobileBrowser(req.headers["user-agent"]);
2020-10-05 00:30:28 +03:00
const isBucketsAvailable = await Utilities.checkTextile();
2020-09-17 23:00:07 +03:00
if (!isBucketsAvailable) {
return res.redirect("/maintenance");
}
const id = Utilities.getIdFromCookie(req);
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
let analytics = await AnalyticsManager.get();
return app.render(req, res, "/_", {
viewer,
analytics,
2020-10-05 00:30:28 +03:00
mobile,
resources: EXTERNAL_RESOURCES,
2020-06-17 21:05:13 +03:00
});
2020-02-19 09:30:47 +03:00
});
server.get("/_/integration-page", async (req, res) => {
const id = Utilities.getIdFromCookie(req);
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
return app.render(req, res, "/_/integration-page", {
viewer,
});
});
server.all("/_/:a", async (r, s) => handler(r, s, r.url));
server.all("/_/:a/:b", async (r, s) => handler(r, s, r.url));
server.get("/[$]/:id", async (req, res) => {
let mobile = Window.isMobileBrowser(req.headers["user-agent"]);
const slate = await Data.getSlateById({
id: req.params.id,
});
if (!slate) {
return res.redirect("/404");
}
if (slate.error) {
return res.redirect("/404");
}
if (!slate.data.public) {
return res.redirect("/403");
}
const creator = await Data.getUserById({ id: slate.data.ownerId });
if (!creator) {
return res.redirect("/404");
}
if (creator.error) {
return res.redirect("/404");
}
const id = Utilities.getIdFromCookie(req);
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
return app.render(req, res, "/_/slate", {
viewer,
creator: Serializers.user(creator),
slate,
mobile,
resources: EXTERNAL_RESOURCES,
});
});
server.get("/:username", async (req, res) => {
2020-10-22 08:38:37 +03:00
let mobile = Window.isMobileBrowser(req.headers["user-agent"]);
2020-10-05 00:30:28 +03:00
2020-08-07 02:28:54 +03:00
// TODO(jim): Temporary workaround
if (!Validations.userRoute(req.params.username)) {
return handler(req, res, req.url, {
mobile,
resources: EXTERNAL_RESOURCES,
});
2020-08-07 02:28:54 +03:00
}
const id = Utilities.getIdFromCookie(req);
2020-11-17 23:36:36 +03:00
const shouldViewerRedirect = ViewerManager.shouldRedirect({ id });
if (shouldViewerRedirect) {
return res.redirect(
`/_${Strings.createQueryParams({
scene: "V1_NAVIGATION_PROFILE",
user: req.params.username,
})}`
);
}
2020-11-17 23:36:36 +03:00
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
const creator = await Data.getUserByUsername({
username: req.params.username,
});
if (!creator) {
return res.redirect("/404");
}
if (creator.error) {
return res.redirect("/404");
}
2020-08-06 23:59:06 +03:00
const slates = await Data.getSlatesByUserId({
userId: creator.id,
publicOnly: true,
});
2020-07-27 12:50:25 +03:00
return app.render(req, res, "/_/profile", {
viewer,
creator: Serializers.user({ ...creator, slates }),
2020-10-05 00:30:28 +03:00
mobile,
resources: EXTERNAL_RESOURCES,
});
});
server.get("/:username/:slatename", async (req, res) => {
2020-10-22 08:38:37 +03:00
let mobile = Window.isMobileBrowser(req.headers["user-agent"]);
2020-08-07 02:28:54 +03:00
// TODO(jim): Temporary workaround
if (!Validations.userRoute(req.params.username)) {
return handler(req, res, req.url, {
mobile,
resources: EXTERNAL_RESOURCES,
});
2020-08-07 02:28:54 +03:00
}
const id = Utilities.getIdFromCookie(req);
2020-11-17 23:36:36 +03:00
const shouldViewerRedirect = ViewerManager.shouldRedirect({ id });
if (shouldViewerRedirect) {
return res.redirect(
`/_${Strings.createQueryParams({
scene: "V1_NAVIGATION_SLATE",
user: req.params.username,
slate: req.params.slatename,
})}`
);
}
2020-07-27 12:50:25 +03:00
const slate = await Data.getSlateByName({
slatename: req.params.slatename,
2020-09-29 07:50:11 +03:00
username: req.params.username,
2020-07-27 12:50:25 +03:00
});
if (!slate) {
return res.redirect("/404");
2020-07-27 12:50:25 +03:00
}
if (slate.error) {
return res.redirect("/404");
}
if (!slate.data.public) {
return res.redirect("/403");
}
const creator = await Data.getUserById({ id: slate.data.ownerId });
if (!creator) {
return res.redirect("/404");
}
if (creator.error) {
return res.redirect("/404");
}
if (req.params.username !== creator.username) {
return res.redirect("/403");
}
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
return app.render(req, res, "/_/slate", {
viewer,
creator: Serializers.user(creator),
slate,
2020-10-05 00:30:28 +03:00
mobile,
resources: EXTERNAL_RESOURCES,
});
});
server.get("/:username/:slatename/cid::cid", async (req, res) => {
// TODO(jim): Temporary workaround
if (!Validations.userRoute(req.params.username)) {
return handler(req, res, req.url);
}
const id = Utilities.getIdFromCookie(req);
2020-11-17 23:36:36 +03:00
const shouldViewerRedirect = await ViewerManager.shouldRedirect({ id });
if (shouldViewerRedirect) {
return res.redirect(
`/_${Strings.createQueryParams({
scene: "V1_NAVIGATION_SLATE",
user: req.params.username,
slate: req.params.slatename,
cid: req.params.cid,
})}`
);
}
const slate = await Data.getSlateByName({
slatename: req.params.slatename,
2020-09-29 07:50:11 +03:00
username: req.params.username,
});
if (!slate) {
return res.redirect("/404");
}
if (slate.error) {
return res.redirect("/404");
}
if (!slate.data.public) {
2020-08-06 23:59:06 +03:00
return res.redirect("/403");
}
const creator = await Data.getUserById({ id: slate.data.ownerId });
if (!creator) {
return res.redirect("/404");
}
if (creator.error) {
return res.redirect("/404");
}
if (req.params.username !== creator.username) {
return res.redirect("/403");
}
let viewer = null;
if (id) {
viewer = await ViewerManager.getById({
id,
});
}
return app.render(req, res, "/_/slate", {
viewer,
creator: Serializers.user(creator),
slate,
cid: req.params.cid,
2020-07-27 12:50:25 +03:00
});
});
server.all("*", async (r, s) => handler(r, s, r.url));
2020-02-19 09:30:47 +03:00
2020-10-05 08:39:02 +03:00
const listenServer = server.listen(Environment.PORT, (e) => {
if (e) throw e;
2020-07-21 22:53:49 +03:00
console.log(`[ slate ] client: http://localhost:${Environment.PORT}`);
2020-02-19 09:30:47 +03:00
});
});