Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Vrite v0.3 (#45)
- Replace wrapper with element;
- Add XML-like syntax for elements;
- Redesign editor block menus;
- Add MDX extension;
- Allow CORS API access;
- Restructure @vrite/backend;
  • Loading branch information
areknawo committed Oct 10, 2023
1 parent 09b1832 commit 1877683
Show file tree
Hide file tree
Showing 224 changed files with 8,327 additions and 5,720 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -26,6 +26,7 @@ yarn-error.log*
.pnpm-debug.log*

# local env files
docker.env
.env
.env.local
.env.development.local
Expand Down
50 changes: 26 additions & 24 deletions apps/backend/api/src/api.ts
Expand Up @@ -4,7 +4,7 @@ import {
createOpenApiNodeHttpHandler,
CreateOpenApiNodeHttpHandlerOptions
} from "trpc-openapi/dist/adapters/node-http/core";
import corsPlugin from "@fastify/cors";
import corsPlugin, { OriginFunction } from "@fastify/cors";
import { OpenApiRouter } from "trpc-openapi";
import { AnyRouter } from "@trpc/server";
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
Expand Down Expand Up @@ -55,36 +55,38 @@ const fastifyTRPCOpenApiPlugin = <TRouter extends AnyRouter>(
done();
};
const apiService = publicPlugin(async (fastify) => {
const originCallback: OriginFunction = (origin, callback) => {
if (!origin || origin === "null") {
callback(null, true);

return;
}

const { hostname } = new URL(origin);
const appHostname = new URL(fastify.config.PUBLIC_APP_URL).hostname;

if (
hostname === "localhost" ||
hostname.endsWith(appHostname) ||
(fastify.config.VRITE_CLOUD && hostname.endsWith("swagger.io"))
) {
callback(null, true);

return;
}

callback(new Error("Not allowed"), false);
};

await fastify.register(rateLimitPlugin, {
max: 500,
timeWindow: "1 minute",
redis: fastify.redis
});
await fastify.register(corsPlugin, {
origin: true,
credentials: true,
methods: ["GET", "DELETE", "PUT", "POST"],
origin(origin, callback) {
if (!origin || origin === "null") {
callback(null, true);

return;
}

const { hostname } = new URL(origin);
const appHostname = new URL(fastify.config.PUBLIC_APP_URL).hostname;

if (
hostname === "localhost" ||
hostname.endsWith(appHostname) ||
(fastify.config.VRITE_CLOUD && hostname.endsWith("swagger.io"))
) {
callback(null, true);

return;
}

callback(new Error("Not allowed"), false);
}
methods: ["GET", "DELETE", "PUT", "POST"]
});
await fastify.register(fastifyTRPCOpenApiPlugin, {
basePath: "/",
Expand Down
11 changes: 9 additions & 2 deletions apps/backend/api/src/index.ts
Expand Up @@ -3,15 +3,22 @@ import { generateOpenApiDocument } from "trpc-openapi";
import { createServer, appRouter } from "@vrite/backend";

(async () => {
const server = await createServer();
const server = await createServer({
database: true,
pubSub: true,
auth: true,
email: true,
gitSync: true,
search: true
});

await server.register(apiService);
server.get("/swagger.json", (req, res) => {
res.send(
generateOpenApiDocument(appRouter, {
baseUrl: server.config.PUBLIC_API_URL,
title: "Vrite API",
version: "0.2.0"
version: "0.3.0"
})
);
});
Expand Down
56 changes: 2 additions & 54 deletions apps/backend/app/src/app.ts
@@ -1,11 +1,10 @@
import { appRouter, errors, publicPlugin, trpcPlugin } from "@vrite/backend";
import { errors, publicPlugin, trpcPlugin, processAuth } from "@vrite/backend";
import staticPlugin from "@fastify/static";
import websocketPlugin from "@fastify/websocket";
import axios from "axios";
import viewPlugin from "@fastify/view";
import handlebars from "handlebars";
import { FastifyReply } from "fastify";
import { processAuth } from "@vrite/backend/src/lib/auth";
import { nanoid } from "nanoid";
import multipartPlugin from "@fastify/multipart";
import mime from "mime-types";
Expand All @@ -15,7 +14,7 @@ import path from "path";

const appService = publicPlugin(async (fastify) => {
const renderPage = async (reply: FastifyReply): Promise<void> => {
return reply.view("index.html", {
return reply.header("X-Frame-Options", "SAMEORIGIN").view("index.html", {
PUBLIC_APP_URL: fastify.config.PUBLIC_APP_URL,
PUBLIC_API_URL: fastify.config.PUBLIC_API_URL,
PUBLIC_COLLAB_URL: fastify.config.PUBLIC_COLLAB_URL,
Expand Down Expand Up @@ -51,57 +50,6 @@ const appService = publicPlugin(async (fastify) => {
fastify.setNotFoundHandler(async (_request, reply) => {
return renderPage(reply);
});
fastify.get<{ Querystring: { url: string } }>("/proxy*", async (request, reply) => {
const filterOutRegex =
/(localhost|\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)(?::\d{0,4})?\b)/;

if (request.headers.origin) {
reply.header("Access-Control-Allow-Origin", fastify.config.PUBLIC_APP_URL);
reply.header("Access-Control-Allow-Methods", "GET");
reply.header(
"Access-Control-Allow-Headers",
request.headers["access-control-request-headers"]
);
} else if (
fastify.config.NODE_ENV !== "development" &&
!fastify.config.PUBLIC_APP_URL.includes("localhost")
) {
// Prevent proxy abuse in production
return reply.status(400).send("Invalid Origin");
}

if (
filterOutRegex.test(request.query.url) &&
!request.query.url.includes(fastify.config.PUBLIC_ASSETS_URL)
) {
return reply.status(400).send("Invalid URL");
}

if (request.method === "OPTIONS") {
// CORS Preflight
reply.send();
} else {
const targetURL = request.query.url;

try {
const response = await axios.get(targetURL, {
responseType: "arraybuffer"
});

if (!`${response.headers["content-type"]}`.includes("image")) {
return reply.status(400).send("Invalid Content-Type");
}

reply.header("content-type", response.headers["content-type"]);
reply.send(Buffer.from(response.data, "binary"));
} catch (error) {
// eslint-disable-next-line no-console
console.error(error);

return reply.status(500).send("Could not fetch");
}
}
});
fastify.post<{
Body: Buffer;
}>("/upload", async (req, res) => {
Expand Down
10 changes: 9 additions & 1 deletion apps/backend/app/src/index.ts