refactor: use fastify vite for the dev server (#284)
* refactor: use fastify vite for the server by doing this we do not need to have local hacks for the routes. No local proxy needed. Everything just works. * fix: update the dockerfile build path * fix: update package.json * fix: fonts path
This commit is contained in:
parent
b20c472b94
commit
0c86efd56c
3
.gitignore
vendored
3
.gitignore
vendored
@ -122,4 +122,5 @@ prisma_test.js
|
|||||||
database/
|
database/
|
||||||
data/
|
data/
|
||||||
.vscode
|
.vscode
|
||||||
hemmelig.backup.db
|
hemmelig.backup.db
|
||||||
|
client/build/
|
||||||
|
@ -25,8 +25,7 @@ FROM node:20-alpine
|
|||||||
|
|
||||||
WORKDIR /home/node/hemmelig
|
WORKDIR /home/node/hemmelig
|
||||||
|
|
||||||
RUN mkdir build
|
COPY --from=0 /usr/src/app/client/build client/build
|
||||||
COPY --from=0 /usr/src/app/build build/
|
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
|
||||||
|
2
cli.js
2
cli.js
@ -3,7 +3,7 @@
|
|||||||
import meow from 'meow';
|
import meow from 'meow';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import YAML from 'yaml';
|
import YAML from 'yaml';
|
||||||
import { generateKey, encrypt } from './src/shared/helpers/crypto.js';
|
import { encrypt, generateKey } from './shared/helpers/crypto.js';
|
||||||
|
|
||||||
// Adding this hack to make it work for pkg
|
// Adding this hack to make it work for pkg
|
||||||
// https://github.com/vercel/pkg/issues/1291#issuecomment-1360586986
|
// https://github.com/vercel/pkg/issues/1291#issuecomment-1360586986
|
||||||
|
@ -3,7 +3,7 @@ import LanguageDetector from 'i18next-browser-languagedetector';
|
|||||||
import HttpApi from 'i18next-http-backend';
|
import HttpApi from 'i18next-http-backend';
|
||||||
import { initReactI18next } from 'react-i18next';
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
|
||||||
import config from './client/config';
|
import config from './config';
|
||||||
|
|
||||||
function getLanguage() {
|
function getLanguage() {
|
||||||
const language = config.get('settings.forcedLanguage');
|
const language = config.get('settings.forcedLanguage');
|
@ -3,14 +3,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Thin.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Thin.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-ThinItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-ThinItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -18,14 +18,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-ExtraLight.woff2') format('woff2');
|
src: url('/static/fonts/Inter-ExtraLight.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 200;
|
font-weight: 200;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-ExtraLightItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-ExtraLightItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -33,14 +33,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Light.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Light.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-LightItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-LightItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -48,14 +48,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Regular.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Regular.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Italic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Italic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -63,14 +63,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Medium.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Medium.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-MediumItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-MediumItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -78,14 +78,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-SemiBold.woff2') format('woff2');
|
src: url('/static/fonts/Inter-SemiBold.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-SemiBoldItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-SemiBoldItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -93,14 +93,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Bold.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Bold.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-BoldItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-BoldItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -108,14 +108,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-ExtraBold.woff2') format('woff2');
|
src: url('/static/fonts/Inter-ExtraBold.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-ExtraBoldItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-ExtraBoldItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
@ -123,14 +123,14 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-Black.woff2') format('woff2');
|
src: url('/static/fonts/Inter-Black.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Inter';
|
font-family: 'Inter';
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
src: url('/fonts/Inter-BlackItalic.woff2') format('woff2');
|
src: url('/static/fonts/Inter-BlackItalic.woff2') format('woff2');
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
@ -5,9 +5,9 @@ import { Provider } from 'react-redux';
|
|||||||
import { LoadingOverlay } from '@mantine/core';
|
import { LoadingOverlay } from '@mantine/core';
|
||||||
import './i18n';
|
import './i18n';
|
||||||
|
|
||||||
import HemmeligApplication from './client/app';
|
import HemmeligApplication from './app';
|
||||||
import configureStore from './client/helpers/configureStore';
|
import configureStore from './helpers/configureStore';
|
||||||
import './client/index.css';
|
import './index.css';
|
||||||
|
|
||||||
const store = configureStore();
|
const store = configureStore();
|
||||||
|
|
@ -40,7 +40,7 @@ const SignOut = () => {
|
|||||||
<Image
|
<Image
|
||||||
maw={240}
|
maw={240}
|
||||||
radius="md"
|
radius="md"
|
||||||
src="./secret_cat.png"
|
src="./static/secret_cat.png"
|
||||||
alt="Secret Cat"
|
alt="Secret Cat"
|
||||||
className={styles.image}
|
className={styles.image}
|
||||||
/>
|
/>
|
16
html.js
16
html.js
@ -5,10 +5,10 @@ export default `<!DOCTYPE html>
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Hemmelig.app - Paste a password, confidential message, or private data.</title>
|
<title>Hemmelig.app - Paste a password, confidential message, or private data.</title>
|
||||||
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/static/favicon.ico" />
|
||||||
<link rel="shortcut icon" href="/favicon.ico" />
|
<link rel="shortcut icon" href="/static/favicon.ico" />
|
||||||
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/static/manifest.json" />
|
||||||
<!-- Primary Meta Tags -->
|
<!-- Primary Meta Tags -->
|
||||||
<meta name="title" content="Paste a password, confidential message, or private data." />
|
<meta name="title" content="Paste a password, confidential message, or private data." />
|
||||||
<meta
|
<meta
|
||||||
@ -27,10 +27,10 @@ export default `<!DOCTYPE html>
|
|||||||
property="og:description"
|
property="og:description"
|
||||||
content="Ensure your sensitive data remains encrypted, secure, and confidential."
|
content="Ensure your sensitive data remains encrypted, secure, and confidential."
|
||||||
/>
|
/>
|
||||||
<meta property="og:image" content="/icons/icon-512x512.png" />
|
<meta property="og:image" content="/static/icons/icon-512x512.png" />
|
||||||
|
|
||||||
<!-- Twitter -->
|
<!-- Twitter -->
|
||||||
<meta property="twitter:card" content="summary_large_image" />
|
<meta property="twitter:card" content="/static/summary_large_image" />
|
||||||
<meta property="twitter:url" content="https://www.hemmelig.app/" />
|
<meta property="twitter:url" content="https://www.hemmelig.app/" />
|
||||||
<meta
|
<meta
|
||||||
property="twitter:title"
|
property="twitter:title"
|
||||||
@ -40,14 +40,14 @@ export default `<!DOCTYPE html>
|
|||||||
property="twitter:description"
|
property="twitter:description"
|
||||||
content="Ensure your sensitive data remains encrypted, secure, and confidential."
|
content="Ensure your sensitive data remains encrypted, secure, and confidential."
|
||||||
/>
|
/>
|
||||||
<meta property="twitter:image" content="/icons/icon-512x512.png" />
|
<meta property="twitter:image" content="/static/icons/icon-512x512.png" />
|
||||||
|
|
||||||
<meta name="theme-color" content="#231e23" />
|
<meta name="theme-color" content="#231e23" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<meta name="mobile-web-app-capable" content="yes" />
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
<link rel="apple-touch-icon" href="/icons/maskable-icon-192x192.png" />
|
<link rel="apple-touch-icon" href="/static/icons/maskable-icon-192x192.png" />
|
||||||
<script id="__secret_config">
|
<script id="__secret_config">
|
||||||
try {
|
try {
|
||||||
window.__SECRET_CONFIG = {{config}}
|
window.__SECRET_CONFIG = {{config}}
|
||||||
@ -61,7 +61,7 @@ export default `<!DOCTYPE html>
|
|||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
<script type="module" src="/src/index.jsx"></script>
|
<script type="module" src="/index.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
|
1737
package-lock.json
generated
1737
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@ -9,14 +9,13 @@
|
|||||||
"test": "mocha tests/**/*.test.js --reporter nyan",
|
"test": "mocha tests/**/*.test.js --reporter nyan",
|
||||||
"test-watch": "mocha --watch tests/**/*.test.js --reporter nyan",
|
"test-watch": "mocha --watch tests/**/*.test.js --reporter nyan",
|
||||||
"build": "node pre.js && vite build",
|
"build": "node pre.js && vite build",
|
||||||
"dev": "concurrently \"npm run server-dev\" \"npm run client-dev\"",
|
"dev": "npm run server-dev",
|
||||||
"server-dev": "prisma migrate dev && NODE_ENV=development node pre.js && NODE_ENV=development nodemon server.js",
|
"server-dev": "prisma migrate dev && NODE_ENV=development node pre.js && NODE_ENV=development node server.js --dev",
|
||||||
"client-dev": "NODE_ENV=development vite",
|
|
||||||
"docker-build": "docker build -t hemmelig .",
|
"docker-build": "docker build -t hemmelig .",
|
||||||
"docker-run": "docker run -p 3000:3000 -d --name=hemmelig -v ./data/hemmelig/:/var/tmp/hemmelig/upload/files -v ./database/:/home/node/hemmelig/database/ hemmelig",
|
"docker-run": "docker run -p 3000:3000 -d --name=hemmelig -v ./data/hemmelig/:/var/tmp/hemmelig/upload/files -v ./database/:/home/node/hemmelig/database/ hemmelig",
|
||||||
"production-test": "npm run docker-build && npm run docker-run",
|
"production-test": "npm run docker-build && npm run docker-run",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"prettier": "prettier --write --ignore-unknown src/ prisma/",
|
"prettier": "prettier --write --ignore-unknown server/ client/ shared/ prisma/",
|
||||||
"publish-cli": "rm -rf dist/ && npx microbundle build --target node -i cli.js -o dist/ && npm publish",
|
"publish-cli": "rm -rf dist/ && npx microbundle build --target node -i cli.js -o dist/ && npm publish",
|
||||||
"pkg": "rm -rf dist/ bin/ && npx esbuild cli.js --bundle --platform=node --outfile=dist/cli.cjs --define:import.meta.url=__dirname && npx pkg dist/cli.cjs --targets=node18-linux-arm64 --output=bin/hemmelig"
|
"pkg": "rm -rf dist/ bin/ && npx esbuild cli.js --bundle --platform=node --outfile=dist/cli.cjs --define:import.meta.url=__dirname && npx pkg dist/cli.cjs --targets=node18-linux-arm64 --output=bin/hemmelig"
|
||||||
},
|
},
|
||||||
@ -41,7 +40,8 @@
|
|||||||
"@fastify/helmet": "^9.1.0",
|
"@fastify/helmet": "^9.1.0",
|
||||||
"@fastify/jwt": "^7.2.3",
|
"@fastify/jwt": "^7.2.3",
|
||||||
"@fastify/multipart": "^7.1.1",
|
"@fastify/multipart": "^7.1.1",
|
||||||
"@fastify/static": "^6.5.0",
|
"@fastify/static": "^6.12.0",
|
||||||
|
"@fastify/vite": "^6.0.6",
|
||||||
"@mantine/core": "^6.0.6",
|
"@mantine/core": "^6.0.6",
|
||||||
"@mantine/form": "^6.0.6",
|
"@mantine/form": "^6.0.6",
|
||||||
"@mantine/hooks": "^6.0.6",
|
"@mantine/hooks": "^6.0.6",
|
||||||
@ -75,7 +75,6 @@
|
|||||||
"@vitejs/plugin-react": "^3.1.0",
|
"@vitejs/plugin-react": "^3.1.0",
|
||||||
"buffer": "^6.0.3",
|
"buffer": "^6.0.3",
|
||||||
"classcat": "^5.0.3",
|
"classcat": "^5.0.3",
|
||||||
"concurrently": "^7.4.0",
|
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"deepmerge": "^4.2.2",
|
"deepmerge": "^4.2.2",
|
||||||
"dlv": "^1.1.3",
|
"dlv": "^1.1.3",
|
||||||
|
4
pre.js
4
pre.js
@ -1,11 +1,11 @@
|
|||||||
import fs from 'fs';
|
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
|
import fs from 'fs';
|
||||||
import template from 'y8';
|
import template from 'y8';
|
||||||
import html from './html.js';
|
import html from './html.js';
|
||||||
|
|
||||||
// This is scripts that has to be run before the
|
// This is scripts that has to be run before the
|
||||||
// frontend build process
|
// frontend build process
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
'index.html',
|
'client/index.html',
|
||||||
template(html, { config: `'${JSON.stringify(config.get('__client_config'))}';` })
|
template(html, { config: `'${JSON.stringify(config.get('__client_config'))}';` })
|
||||||
);
|
);
|
||||||
|
154
server.js
154
server.js
@ -1,51 +1,94 @@
|
|||||||
// Boot scripts
|
// Boot scripts
|
||||||
import('./src/server/bootstrap.js');
|
import('./server/bootstrap.js');
|
||||||
|
|
||||||
import cookie from '@fastify/cookie';
|
import cookie from '@fastify/cookie';
|
||||||
import cors from '@fastify/cors';
|
import cors from '@fastify/cors';
|
||||||
import helmet from '@fastify/helmet';
|
import helmet from '@fastify/helmet';
|
||||||
import jwt from '@fastify/jwt';
|
import jwt from '@fastify/jwt';
|
||||||
import fstatic from '@fastify/static';
|
import fastifyStatic from '@fastify/static';
|
||||||
|
import FastifyVite from '@fastify/vite';
|
||||||
import config from 'config';
|
import config from 'config';
|
||||||
import importFastify from 'fastify';
|
import importFastify from 'fastify';
|
||||||
import fs from 'fs';
|
|
||||||
import { JSDOM } from 'jsdom';
|
import { JSDOM } from 'jsdom';
|
||||||
import path from 'path';
|
import fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'url';
|
import path from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
import template from 'y8';
|
import template from 'y8';
|
||||||
|
|
||||||
import rateLimit from './src/server/plugins/rate-limit.js';
|
import rateLimit from './server/plugins/rate-limit.js';
|
||||||
|
|
||||||
import adminDecorator from './src/server/decorators/admin.js';
|
import adminDecorator from './server/decorators/admin.js';
|
||||||
import allowedIp from './src/server/decorators/allowed-ip.js';
|
import allowedIp from './server/decorators/allowed-ip.js';
|
||||||
import attachment from './src/server/decorators/attachment-upload.js';
|
import attachment from './server/decorators/attachment-upload.js';
|
||||||
import jwtDecorator from './src/server/decorators/jwt.js';
|
import jwtDecorator from './server/decorators/jwt.js';
|
||||||
import userFeatures from './src/server/decorators/user-features.js';
|
import userFeatures from './server/decorators/user-features.js';
|
||||||
|
|
||||||
import readCookieAllRoutesHandler from './src/server/prehandlers/cookie-all-routes.js';
|
import readCookieAllRoutesHandler from './server/prehandlers/cookie-all-routes.js';
|
||||||
import disableUserAccountCreationHandler from './src/server/prehandlers/disable-user-account-creation.js';
|
import disableUserAccountCreationHandler from './server/prehandlers/disable-user-account-creation.js';
|
||||||
import disableUserHandler from './src/server/prehandlers/disable-users.js';
|
import disableUserHandler from './server/prehandlers/disable-users.js';
|
||||||
import readOnlyHandler from './src/server/prehandlers/read-only.js';
|
import readOnlyHandler from './server/prehandlers/read-only.js';
|
||||||
import restrictOrganizationEmailHandler from './src/server/prehandlers/restrict-organization-email.js';
|
import restrictOrganizationEmailHandler from './server/prehandlers/restrict-organization-email.js';
|
||||||
|
|
||||||
import accountRoute from './src/server/controllers/account.js';
|
import accountRoute from './server/controllers/account.js';
|
||||||
import adminSettingsRoute from './src/server/controllers/admin/settings.js';
|
import adminSettingsRoute from './server/controllers/admin/settings.js';
|
||||||
import usersRoute from './src/server/controllers/admin/users.js';
|
import usersRoute from './server/controllers/admin/users.js';
|
||||||
import authenticationRoute from './src/server/controllers/authentication.js';
|
import authenticationRoute from './server/controllers/authentication.js';
|
||||||
import downloadRoute from './src/server/controllers/download.js';
|
import downloadRoute from './server/controllers/download.js';
|
||||||
import healthzRoute from './src/server/controllers/healthz.js';
|
import healthzRoute from './server/controllers/healthz.js';
|
||||||
import secretRoute from './src/server/controllers/secret.js';
|
import secretRoute from './server/controllers/secret.js';
|
||||||
import statsRoute from './src/server/controllers/stats.js';
|
import statsRoute from './server/controllers/stats.js';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === 'development';
|
const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
|
||||||
const MAX_FILE_BYTES = 1024 * config.get('file.size') * 1000; // Example: 1024 * 2 * 1000 = 2 024 000 bytes
|
const MAX_FILE_BYTES = 1024 * config.get('file.size') * 1000; // Example: 1024 * 2 * 1000 = 2 024 000 bytes
|
||||||
|
|
||||||
|
const staticPath = path.join(__dirname, !isDev ? 'client/build' : 'client');
|
||||||
|
|
||||||
const fastify = importFastify({
|
const fastify = importFastify({
|
||||||
logger: config.get('logger'),
|
logger: config.get('logger'),
|
||||||
bodyLimit: MAX_FILE_BYTES,
|
bodyLimit: MAX_FILE_BYTES,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await fastify.register(FastifyVite, {
|
||||||
|
root: import.meta.url,
|
||||||
|
dev: process.argv.includes('--dev'),
|
||||||
|
spa: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.register(fastifyStatic, {
|
||||||
|
root: path.join(__dirname, 'public'),
|
||||||
|
prefix: '/static/',
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.register(fastifyStatic, {
|
||||||
|
root: path.join(__dirname, 'public', 'locales'),
|
||||||
|
prefix: '/locales/',
|
||||||
|
decorateReply: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isDev) {
|
||||||
|
const script = template(
|
||||||
|
`
|
||||||
|
try {
|
||||||
|
window.__SECRET_CONFIG = {{config}}
|
||||||
|
} catch (e) {
|
||||||
|
window.__SECRET_CONFIG = '';
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{ config: `'${JSON.stringify(config.get('__client_config'))}';` }
|
||||||
|
);
|
||||||
|
|
||||||
|
const index = staticPath + '/index.html';
|
||||||
|
|
||||||
|
const dom = new JSDOM(fs.readFileSync(index));
|
||||||
|
dom.window.document.querySelector('#__secret_config').textContent = script;
|
||||||
|
|
||||||
|
fs.writeFileSync(index, dom.serialize());
|
||||||
|
}
|
||||||
|
|
||||||
fastify.register(rateLimit, {
|
fastify.register(rateLimit, {
|
||||||
prefix: '/api/',
|
prefix: '/api/',
|
||||||
max: config.get('rateLimit.max'),
|
max: config.get('rateLimit.max'),
|
||||||
@ -91,7 +134,21 @@ fastify.addHook('preHandler', disableUserAccountCreationHandler);
|
|||||||
fastify.addHook('preHandler', readOnlyHandler);
|
fastify.addHook('preHandler', readOnlyHandler);
|
||||||
fastify.addHook('preHandler', restrictOrganizationEmailHandler);
|
fastify.addHook('preHandler', restrictOrganizationEmailHandler);
|
||||||
|
|
||||||
// Register our routes before the static content
|
function serveIndex(_, reply) {
|
||||||
|
return reply.html();
|
||||||
|
}
|
||||||
|
|
||||||
|
fastify.get('/', serveIndex);
|
||||||
|
fastify.get('/secret/*', serveIndex);
|
||||||
|
fastify.get('/about', serveIndex);
|
||||||
|
fastify.get('/privacy', serveIndex);
|
||||||
|
fastify.get('/api-docs', serveIndex);
|
||||||
|
fastify.get('/signin', serveIndex);
|
||||||
|
fastify.get('/signup', serveIndex);
|
||||||
|
fastify.get('/signout', serveIndex);
|
||||||
|
fastify.get('/account*', serveIndex);
|
||||||
|
fastify.get('/terms', serveIndex);
|
||||||
|
fastify.get('/public*', serveIndex);
|
||||||
|
|
||||||
fastify.register(authenticationRoute, {
|
fastify.register(authenticationRoute, {
|
||||||
prefix: '/api/authentication',
|
prefix: '/api/authentication',
|
||||||
@ -115,54 +172,9 @@ fastify.register(statsRoute, { prefix: '/api/stats' });
|
|||||||
fastify.register(healthzRoute, { prefix: '/api/healthz' });
|
fastify.register(healthzRoute, { prefix: '/api/healthz' });
|
||||||
fastify.register(healthzRoute, { prefix: '/healthz' });
|
fastify.register(healthzRoute, { prefix: '/healthz' });
|
||||||
|
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
|
|
||||||
const staticPath = path.join(__dirname, !isDev ? 'build' : '');
|
|
||||||
|
|
||||||
// Static frontend for the production build
|
|
||||||
if (!isDev) {
|
|
||||||
fastify.register(fstatic, {
|
|
||||||
root: staticPath,
|
|
||||||
route: '/*',
|
|
||||||
});
|
|
||||||
|
|
||||||
const script = template(
|
|
||||||
`
|
|
||||||
try {
|
|
||||||
window.__SECRET_CONFIG = {{config}}
|
|
||||||
} catch (e) {
|
|
||||||
window.__SECRET_CONFIG = '';
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
{ config: `'${JSON.stringify(config.get('__client_config'))}';` }
|
|
||||||
);
|
|
||||||
|
|
||||||
const index = staticPath + '/index.html';
|
|
||||||
|
|
||||||
const dom = new JSDOM(fs.readFileSync(index));
|
|
||||||
dom.window.document.querySelector('#__secret_config').textContent = script;
|
|
||||||
|
|
||||||
fs.writeFileSync(index, dom.serialize());
|
|
||||||
|
|
||||||
function serveIndex(_, res) {
|
|
||||||
return res.sendFile('index.html');
|
|
||||||
}
|
|
||||||
|
|
||||||
fastify.get('/secret/*', serveIndex);
|
|
||||||
fastify.get('/about', serveIndex);
|
|
||||||
fastify.get('/privacy', serveIndex);
|
|
||||||
fastify.get('/api-docs', serveIndex);
|
|
||||||
fastify.get('/signin', serveIndex);
|
|
||||||
fastify.get('/signup', serveIndex);
|
|
||||||
fastify.get('/signout', serveIndex);
|
|
||||||
fastify.get('/account*', serveIndex);
|
|
||||||
fastify.get('/terms', serveIndex);
|
|
||||||
fastify.get('/public*', serveIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
const startServer = async () => {
|
const startServer = async () => {
|
||||||
try {
|
try {
|
||||||
|
await fastify.vite.ready();
|
||||||
await fastify.listen({ port: config.get('port'), host: config.get('localHostname') });
|
await fastify.listen({ port: config.get('port'), host: config.get('localHostname') });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
fastify.log.error(err);
|
fastify.log.error(err);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
import { encrypt, decrypt, generateKey } from '../../../src/shared/helpers/crypto.js';
|
import { decrypt, encrypt, generateKey } from '../../../shared/helpers/crypto.js';
|
||||||
|
|
||||||
const SECRET = 'MASTER_KEY=1337-super-secret';
|
const SECRET = 'MASTER_KEY=1337-super-secret';
|
||||||
|
|
||||||
@ -9,8 +9,8 @@ const RANDOM_KEY = generateKey();
|
|||||||
describe('Crypto', () => {
|
describe('Crypto', () => {
|
||||||
describe('#encrypt(string)', () => {
|
describe('#encrypt(string)', () => {
|
||||||
it('should encrypt, and decrypt a secret', async () => {
|
it('should encrypt, and decrypt a secret', async () => {
|
||||||
const encrypted = await encrypt(SECRET, RANDOM_KEY);
|
const encrypted = encrypt(SECRET, RANDOM_KEY);
|
||||||
const decrypted = await decrypt(encrypted, RANDOM_KEY);
|
const decrypted = decrypt(encrypted, RANDOM_KEY);
|
||||||
|
|
||||||
assert.equal(decrypted, SECRET);
|
assert.equal(decrypted, SECRET);
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
import { hash, compare } from '../../../src/server/helpers/password.js';
|
import { compare, hash } from '../../../server/helpers/password.js';
|
||||||
|
|
||||||
const PASSWORD = 'suP3rL0ng!PssWrd';
|
const PASSWORD = 'suP3rL0ng!PssWrd';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
|
||||||
import isValidTTL from '../../../src/server/helpers/validate-ttl.js';
|
import isValidTTL from '../../../server/helpers/validate-ttl.js';
|
||||||
|
|
||||||
describe('Validate TTL', () => {
|
describe('Validate TTL', () => {
|
||||||
describe('#isValidTTL(ttl)', () => {
|
describe('#isValidTTL(ttl)', () => {
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import { defineConfig } from 'vite';
|
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
const path = fileURLToPath(import.meta.url);
|
||||||
|
const root = resolve(dirname(path), 'client');
|
||||||
|
|
||||||
export default defineConfig(() => {
|
export default defineConfig(() => {
|
||||||
return {
|
return {
|
||||||
|
root,
|
||||||
build: {
|
build: {
|
||||||
outDir: 'build',
|
outDir: 'build',
|
||||||
},
|
},
|
||||||
plugins: [react()],
|
publicDir: 'public',
|
||||||
server: {
|
plugins: [react({ jsxRuntime: 'classic' })],
|
||||||
port: 3001,
|
|
||||||
proxy: {
|
|
||||||
'/api': 'http://0.0.0.0:3000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user