mirror of
https://github.com/diced/zipline.git
synced 2025-12-06 04:41:12 -08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00eb6aef41 | ||
|
|
39f2773703 | ||
|
|
a0360269b8 | ||
|
|
6270c725dc | ||
|
|
b82a50ae4e |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "zipline-next",
|
||||
"version": "2.5.7",
|
||||
"version": "2.6.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@dicedtomato/colors": "^1.0.3",
|
||||
|
||||
265
src/index.ts
265
src/index.ts
@@ -1,37 +1,25 @@
|
||||
import next from 'next';
|
||||
import { textSync as text } from 'figlet';
|
||||
import fastify, { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import fastifyTypeorm from 'fastify-typeorm-plugin';
|
||||
import fastifyCookies from 'fastify-cookie';
|
||||
import fastifyMultipart from 'fastify-multipart';
|
||||
import fastifyRateLimit from 'fastify-rate-limit';
|
||||
import fastify from 'fastify';
|
||||
import fastifyStatic from 'fastify-static';
|
||||
import fastifyFavicon from 'fastify-favicon';
|
||||
import { bootstrap } from 'fastify-decorators';
|
||||
import fastifyTypeorm from 'fastify-typeorm-plugin';
|
||||
import { Console } from './lib/logger';
|
||||
import { AddressInfo } from 'net';
|
||||
import { magenta, bold, green, reset, blue, red } from '@dicedtomato/colors';
|
||||
import { bold, green, reset } from '@dicedtomato/colors';
|
||||
import { Configuration } from './lib/Config';
|
||||
import { UserController } from './lib/controllers/UserController';
|
||||
import { RootController } from './lib/controllers/RootController';
|
||||
import { join } from 'path';
|
||||
import { ImagesController } from './lib/controllers/ImagesController';
|
||||
import { URLSController } from './lib/controllers/URLSController';
|
||||
import { checkVersion } from './lib/Util';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { Image } from './lib/entities/Image';
|
||||
import { User } from './lib/entities/User';
|
||||
import { Zipline } from './lib/entities/Zipline';
|
||||
import { URL } from './lib/entities/URL';
|
||||
import { MultiFactorController } from './lib/controllers/MultiFactorController';
|
||||
import { PluginLoader } from './lib/plugin';
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production';
|
||||
const server = fastify({});
|
||||
const app = next({
|
||||
dev,
|
||||
quiet: dev
|
||||
});
|
||||
|
||||
(async () => {
|
||||
if (await checkVersion()) Console.logger('Zipline').info(
|
||||
'running an outdated version of zipline, please update soon!'
|
||||
);
|
||||
})();
|
||||
app.prepare();
|
||||
|
||||
const pluginLoader = new PluginLoader(server, process.cwd(), dev ? './src/plugins' : './dist/plugins');
|
||||
Console.logger(Configuration).verbose('searching for config...');
|
||||
const config = Configuration.readConfig();
|
||||
|
||||
@@ -42,188 +30,71 @@ if (!config) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!config.core || !config.database) {
|
||||
Console.logger('Zipline').error(
|
||||
'configuration seems to be invalid, did you generate a config? https://zipline.diced.wtf/docs/auto'
|
||||
);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (config.core.log) console.log(`
|
||||
${magenta(text('Zipline'))}
|
||||
|
||||
Version : ${blue(
|
||||
process.env.npm_package_version ||
|
||||
JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
|
||||
.version
|
||||
)}
|
||||
GitHub : ${blue('https://github.com/ZiplineProject/zipline')}
|
||||
Issues : ${blue('https://github.com/ZiplineProject/zipline/issues')}
|
||||
Docs : ${blue('https://zipline.diced.wtf/')}
|
||||
Mode : ${bold(dev ? red('dev') : green('production'))}
|
||||
Verbose : ${bold(process.env.VERBOSE ? red('yes') : green('no'))}
|
||||
`);
|
||||
|
||||
const dir = config.uploader.directory ? config.uploader.directory : 'uploads';
|
||||
const path = dir.charAt(0) == '/' ? dir : join(process.cwd(), dir);
|
||||
|
||||
const server = fastify({});
|
||||
const app = next({
|
||||
dev,
|
||||
quiet: dev
|
||||
});
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
Console.logger(next).info('Preparing app...');
|
||||
app.prepare();
|
||||
Console.logger(next).verbose('Prepared app');
|
||||
|
||||
server.register(fastifyRateLimit, {
|
||||
timeWindow: 5000,
|
||||
max: 1,
|
||||
global: false
|
||||
});
|
||||
|
||||
if (dev) server.get('/_next/*', async (req, reply) => {
|
||||
await handle(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.all('/*', async (req, reply) => {
|
||||
await handle(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.setNotFoundHandler(async (req, reply) => {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.get(`${config.urls.route}/:id`, async function (
|
||||
req: FastifyRequest<{ Params: { id: string } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
const urls = this.orm.getRepository(URL);
|
||||
|
||||
const urlId = await urls.findOne({
|
||||
where: {
|
||||
id: req.params.id
|
||||
(async () => {
|
||||
const builtInPlugins = await pluginLoader.loadPlugins(true);
|
||||
for (const plugin of builtInPlugins) {
|
||||
try {
|
||||
plugin.onLoad(server, null, app, config);
|
||||
} catch (e) {
|
||||
Console.logger(PluginLoader).error(`failed to load built-in plugin: ${plugin.name}, ${e.message}`);
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
const urlVanity = await urls.findOne({
|
||||
where: {
|
||||
vanity: req.params.id
|
||||
}
|
||||
});
|
||||
|
||||
if (config.urls.vanity && urlVanity) return reply.redirect(urlVanity.url);
|
||||
if (!urlId) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
return reply.redirect(urlId.url);
|
||||
});
|
||||
|
||||
server.get(`${config.uploader.rich_content_route || '/a'}/:id`, async function (
|
||||
req: FastifyRequest<{ Params: { id: string } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
if (!existsSync(join(config.uploader.directory, req.params.id))) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
|
||||
return reply.type('text/html').send(`
|
||||
<html>
|
||||
<head>
|
||||
<meta property="theme-color" content="${config.meta.color}">
|
||||
<meta property="og:title" content="${req.params.id}">
|
||||
<meta property="og:url" content="${config.uploader.route}/${req.params.id}">
|
||||
<meta property="og:image" content="${config.uploader.route}/${req.params.id}">
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
</head>
|
||||
<body>
|
||||
<div style="text-align:center;vertical-align:middle;">
|
||||
<img src="${config.uploader.route}/${req.params.id}" >
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
const dir = config.uploader.directory ? config.uploader.directory : 'uploads';
|
||||
const path = dir.charAt(0) == '/' ? dir : join(process.cwd(), dir);
|
||||
const handle = app.getRequestHandler();
|
||||
|
||||
server.register(fastifyMultipart);
|
||||
if (dev) server.get('/_next/*', async (req, reply) => {
|
||||
await handle(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.register(fastifyTypeorm, {
|
||||
...config.database,
|
||||
entities: [Image, URL, User, Zipline],
|
||||
synchronize: true,
|
||||
logging: false
|
||||
});
|
||||
server.all('/*', async (req, reply) => {
|
||||
await handle(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.register(bootstrap, {
|
||||
controllers: [
|
||||
UserController,
|
||||
RootController,
|
||||
ImagesController,
|
||||
URLSController,
|
||||
MultiFactorController
|
||||
]
|
||||
});
|
||||
server.setNotFoundHandler(async (req, reply) => {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
});
|
||||
|
||||
server.register(fastifyCookies, {
|
||||
secret: config.core.secret
|
||||
});
|
||||
server.register(fastifyStatic, {
|
||||
root: path,
|
||||
prefix: config.uploader.route
|
||||
});
|
||||
|
||||
server.register(fastifyStatic, {
|
||||
root: path,
|
||||
prefix: config.uploader.route
|
||||
});
|
||||
|
||||
server.register(fastifyStatic, {
|
||||
root: join(process.cwd(), 'public'),
|
||||
prefix: '/public',
|
||||
decorateReply: false
|
||||
});
|
||||
// done after everything so plugins can overwrite routes, etc.
|
||||
server.register(async () => {
|
||||
const plugins = await pluginLoader.loadPlugins();
|
||||
for (const plugin of plugins) {
|
||||
try {
|
||||
plugin.onLoad(server, server.orm, app, config);
|
||||
Console.logger(PluginLoader).info(`loaded plugin: ${plugin.name}`);
|
||||
} catch (e) {
|
||||
Console.logger(PluginLoader).error(`failed to load plugin: ${plugin.name}, ${e.message}`)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
server.register(fastifyFavicon);
|
||||
server.listen(
|
||||
{
|
||||
port: config.core.port,
|
||||
host: config.core.host
|
||||
},
|
||||
async err => {
|
||||
if (err) throw err;
|
||||
const info = server.server.address() as AddressInfo;
|
||||
|
||||
server.listen(
|
||||
{
|
||||
port: config.core.port,
|
||||
host: config.core.host
|
||||
},
|
||||
err => {
|
||||
if (err) throw err;
|
||||
const info = server.server.address() as AddressInfo;
|
||||
|
||||
Console.logger('Server').info(
|
||||
`server listening on ${bold(
|
||||
`${green(info.address)}${reset(':')}${bold(
|
||||
green(info.port.toString())
|
||||
Console.logger('Server').info(
|
||||
`server listening on ${bold(
|
||||
`${green(info.address)}${reset(':')}${bold(
|
||||
green(info.port.toString())
|
||||
)}`
|
||||
)}`
|
||||
)}`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
server.addHook('preHandler', async (req, reply) => {
|
||||
if (
|
||||
config.core.blacklisted_ips &&
|
||||
config.core.blacklisted_ips.includes(req.ip)
|
||||
) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
});
|
||||
|
||||
server.addHook('onResponse', (req, res, done) => {
|
||||
if (!req.url.startsWith('/_next') && config.core.log) {
|
||||
const status =
|
||||
res.statusCode !== 200
|
||||
? bold(red(res.statusCode.toString()))
|
||||
: bold(green(res.statusCode.toString()));
|
||||
Console.logger('server').info(`${status} ${req.url} was accessed`);
|
||||
}
|
||||
done();
|
||||
});
|
||||
);
|
||||
}
|
||||
);
|
||||
})();
|
||||
@@ -127,4 +127,30 @@ export class MultiFactorController {
|
||||
|
||||
return reply.send({ user, passed });
|
||||
}
|
||||
|
||||
@GET('/verify')
|
||||
async verifyOn(
|
||||
req: FastifyRequest<{
|
||||
Querystring: { token: string };
|
||||
}>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
if (!req.cookies.zipline) return sendError(reply, 'Not logged in.');
|
||||
|
||||
const user = await this.users.findOne({
|
||||
where: {
|
||||
id: readBaseCookie(req.cookies.zipline)
|
||||
}
|
||||
});
|
||||
|
||||
if (!user) return sendError(reply, `User that was signed in was not found, and guess what you should probably clear your cookies.`);
|
||||
|
||||
const passed = totp.verify({
|
||||
encoding: 'base32',
|
||||
token: req.query.token,
|
||||
secret: user.secretMfaKey
|
||||
});
|
||||
|
||||
return reply.send(passed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ export class RootController {
|
||||
if (config.uploader.blacklisted.includes(ext)) return sendError(reply, 'Blacklisted file extension!');
|
||||
|
||||
const fileName = config.uploader.original
|
||||
? data.filename.split('.')[0]
|
||||
? data.filename.split('.').pop()
|
||||
: createRandomId(config.uploader.length);
|
||||
const path = join(config.uploader.directory, `${fileName}.${ext}`);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ConsoleLevel } from '.';
|
||||
import { blue, red, reset, white, yellow } from '@dicedtomato/colors';
|
||||
import { blue, green, red, reset, white, yellow } from '@dicedtomato/colors';
|
||||
|
||||
export interface Formatter {
|
||||
format(
|
||||
@@ -27,7 +27,7 @@ export class DefaultFormatter implements Formatter {
|
||||
level: ConsoleLevel,
|
||||
time: Date
|
||||
): string {
|
||||
return `[${time.toLocaleString().replace(',', '')}] ${this.formatLevel(
|
||||
return `[${time.toLocaleString().replace(',', '')}] [${green(origin.toLowerCase())}] ${this.formatLevel(
|
||||
level
|
||||
)} ${reset(message)}`;
|
||||
}
|
||||
|
||||
11
src/lib/plugin/Plugin.ts
Normal file
11
src/lib/plugin/Plugin.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import Server from "next/dist/next-server/server/next-server";
|
||||
import { Connection } from "typeorm";
|
||||
import { Config } from "../Config";
|
||||
|
||||
export interface Plugin {
|
||||
name: string;
|
||||
priority?: number;
|
||||
|
||||
onLoad(server: FastifyInstance, orm: Connection, app: Server, config: Config): any;
|
||||
}
|
||||
45
src/lib/plugin/PluginLoader.ts
Normal file
45
src/lib/plugin/PluginLoader.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { readdirSync, statSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { Plugin } from "./Plugin";
|
||||
|
||||
export class PluginLoader {
|
||||
public directory: string;
|
||||
public files: string[];
|
||||
public plugins: Plugin[] = [];
|
||||
public builtIns: Plugin[] = [];
|
||||
public fastify: FastifyInstance;
|
||||
|
||||
constructor(fastify: FastifyInstance, ...directory: string[]) {
|
||||
this.directory = join(...directory);
|
||||
this.fastify = fastify;
|
||||
}
|
||||
|
||||
public getAllFiles(builtIn: boolean = false): string[] {
|
||||
const result = [];
|
||||
|
||||
const r = (dir: string) => {
|
||||
for (const file of readdirSync(dir)) {
|
||||
const p = join(dir, file);
|
||||
const s = statSync(p);
|
||||
if (s.isDirectory()) r(p);
|
||||
else result.push(p);
|
||||
}
|
||||
};
|
||||
|
||||
r(builtIn ? join(process.cwd(), process.env.NODE_ENV == 'development' ? 'dist/src' : 'src', 'lib', 'plugin', 'builtins') : this.directory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public async loadPlugins(builtIn: boolean = false): Promise<Plugin[]> {
|
||||
const files = this.getAllFiles(builtIn);
|
||||
|
||||
for (const pluginFile of files) {
|
||||
const im = await import(pluginFile);
|
||||
builtIn ? this.builtIns.push(new im.default()) : this.plugins.push(new im.default());
|
||||
}
|
||||
|
||||
return builtIn ? this.builtIns.sort((a, b) => a.priority - b.priority) : this.plugins.sort((a, b) => a.priority - b.priority);
|
||||
}
|
||||
}
|
||||
59
src/lib/plugin/builtins/FastifyPlugin.ts
Normal file
59
src/lib/plugin/builtins/FastifyPlugin.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import Server from 'next/dist/next-server/server/next-server';
|
||||
import { Connection } from 'typeorm';
|
||||
import { Config } from '../../Config';
|
||||
import { Plugin } from '../Plugin';
|
||||
import fastifyTypeorm from 'fastify-typeorm-plugin';
|
||||
import fastifyCookies from 'fastify-cookie';
|
||||
import fastifyMultipart from 'fastify-multipart';
|
||||
import fastifyRateLimit from 'fastify-rate-limit';
|
||||
import fastifyStatic from 'fastify-static';
|
||||
import fastifyFavicon from 'fastify-favicon';
|
||||
import { bootstrap } from 'fastify-decorators';
|
||||
import { User } from '../../entities/User';
|
||||
import { Zipline } from '../../entities/Zipline';
|
||||
import { Image } from '../../entities/Image';
|
||||
import { URL } from '../../entities/URL';
|
||||
import { UserController } from '../../controllers/UserController';
|
||||
import path, { join } from 'path';
|
||||
import { ImagesController } from '../../controllers/ImagesController';
|
||||
import { MultiFactorController } from '../../controllers/MultiFactorController';
|
||||
import { RootController } from '../../controllers/RootController';
|
||||
import { URLSController } from '../../controllers/URLSController';
|
||||
|
||||
export default class implements Plugin {
|
||||
public name: string = "assets";
|
||||
|
||||
public onLoad(server: FastifyInstance, orm: Connection, app: Server, config: Config) {
|
||||
server.register(fastifyMultipart);
|
||||
|
||||
server.register(fastifyTypeorm, {
|
||||
...config.database,
|
||||
entities: [Image, URL, User, Zipline],
|
||||
synchronize: true,
|
||||
logging: false
|
||||
});
|
||||
|
||||
server.register(bootstrap, {
|
||||
controllers: [
|
||||
UserController,
|
||||
RootController,
|
||||
ImagesController,
|
||||
URLSController,
|
||||
MultiFactorController
|
||||
]
|
||||
});
|
||||
|
||||
server.register(fastifyCookies, {
|
||||
secret: config.core.secret
|
||||
});
|
||||
|
||||
server.register(fastifyStatic, {
|
||||
root: join(process.cwd(), 'public'),
|
||||
prefix: '/public',
|
||||
decorateReply: false
|
||||
});
|
||||
|
||||
server.register(fastifyFavicon);
|
||||
}
|
||||
}
|
||||
29
src/lib/plugin/builtins/LogPlugin.ts
Normal file
29
src/lib/plugin/builtins/LogPlugin.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import Server from 'next/dist/next-server/server/next-server';
|
||||
import { Connection } from 'typeorm';
|
||||
import { Config } from '../../Config';
|
||||
import { Plugin } from '../Plugin';
|
||||
import { textSync } from 'figlet';
|
||||
import { magenta, blue, bold, red, green } from '@dicedtomato/colors';
|
||||
import { readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
export default class implements Plugin {
|
||||
public name: string = "assets";
|
||||
|
||||
public onLoad(server: FastifyInstance, orm: Connection, app: Server, config: Config) {
|
||||
if (config.core.log) console.log(`
|
||||
${magenta(textSync('Zipline'))}
|
||||
Version : ${blue(
|
||||
process.env.npm_package_version ||
|
||||
JSON.parse(readFileSync(join(process.cwd(), 'package.json'), 'utf8'))
|
||||
.version
|
||||
)}
|
||||
GitHub : ${blue('https://github.com/ZiplineProject/zipline')}
|
||||
Issues : ${blue('https://github.com/ZiplineProject/zipline/issues')}
|
||||
Docs : ${blue('https://zipline.diced.wtf/')}
|
||||
Mode : ${bold(process.env.NODE_ENV !== 'production' ? red('dev') : green('production'))}
|
||||
Verbose : ${bold(process.env.VERBOSE ? red('yes') : green('no'))}
|
||||
`);
|
||||
}
|
||||
}
|
||||
2
src/lib/plugin/index.ts
Normal file
2
src/lib/plugin/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './Plugin';
|
||||
export * from './PluginLoader';
|
||||
@@ -34,7 +34,7 @@ export default function Dashboard({ config }) {
|
||||
const router = useRouter();
|
||||
const state = store.getState();
|
||||
const [loading, setLoading] = React.useState(true);
|
||||
const [stats, setStats] = React.useState<{totalViews:number, averageViews:number, images: number}>(null);
|
||||
const [stats, setStats] = React.useState<{ totalViews: number, averageViews: number, images: number }>(null);
|
||||
const [recentImages, setRecentImages] = React.useState([]);
|
||||
|
||||
if (typeof window === 'undefined') return <UIPlaceholder />;
|
||||
@@ -61,7 +61,7 @@ export default function Dashboard({ config }) {
|
||||
{!loading ? (
|
||||
<Paper elevation={3} className={classes.padding}>
|
||||
<Typography variant='h4'>
|
||||
Welcome back, {state.user.username}
|
||||
Welcome back, {state.user.username}
|
||||
</Typography>
|
||||
<Typography color='textSecondary'>
|
||||
You have <b>{stats.images}</b> images, with <b>{stats.totalViews}</b> ({Math.round(stats.averageViews)}) collectively.
|
||||
|
||||
67
src/plugins/AssetsPlugin.ts
Normal file
67
src/plugins/AssetsPlugin.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { Config } from '../lib/Config';
|
||||
import { Plugin } from '../lib/plugin';
|
||||
import { URL } from '../lib/entities/URL';
|
||||
import Server from 'next/dist/next-server/server/next-server';
|
||||
import { Connection } from 'typeorm';
|
||||
import { existsSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
export default class implements Plugin {
|
||||
public name: string = "assets";
|
||||
|
||||
public onLoad(server: FastifyInstance, orm: Connection, app: Server, config: Config) {
|
||||
server.get(`${config.urls.route}/:id`, async function (
|
||||
req: FastifyRequest<{ Params: { id: string } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
const urls = orm.getRepository(URL);
|
||||
|
||||
const urlId = await urls.findOne({
|
||||
where: {
|
||||
id: req.params.id
|
||||
}
|
||||
});
|
||||
|
||||
const urlVanity = await urls.findOne({
|
||||
where: {
|
||||
vanity: req.params.id
|
||||
}
|
||||
});
|
||||
|
||||
if (config.urls.vanity && urlVanity) return reply.redirect(urlVanity.url);
|
||||
if (!urlId) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
return reply.redirect(urlId.url);
|
||||
});
|
||||
|
||||
server.get(`${config.uploader.rich_content_route || '/a'}/:id`, async function (
|
||||
req: FastifyRequest<{ Params: { id: string } }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
if (!existsSync(join(config.uploader.directory, req.params.id))) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
|
||||
return reply.type('text/html').send(`
|
||||
<html>
|
||||
<head>
|
||||
<meta property="theme-color" content="${config.meta.color}">
|
||||
<meta property="og:title" content="${req.params.id}">
|
||||
<meta property="og:url" content="${config.uploader.route}/${req.params.id}">
|
||||
<meta property="og:image" content="${config.uploader.route}/${req.params.id}">
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
</head>
|
||||
<body>
|
||||
<div style="text-align:center;vertical-align:middle;">
|
||||
<img src="${config.uploader.route}/${req.params.id}" >
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
}
|
||||
}
|
||||
34
src/plugins/HooksPlugin.ts
Normal file
34
src/plugins/HooksPlugin.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { Config } from '../lib/Config';
|
||||
import { Plugin } from '../lib/plugin';
|
||||
import { Console } from '../lib/logger';
|
||||
import Server from 'next/dist/next-server/server/next-server';
|
||||
import { Connection } from 'typeorm';
|
||||
import { bold, green, red } from '@dicedtomato/colors';
|
||||
|
||||
export default class implements Plugin {
|
||||
public name: string = "fastify_hooks";
|
||||
|
||||
public onLoad(server: FastifyInstance, orm: Connection, app: Server, config: Config) {
|
||||
server.addHook('preHandler', async (req, reply) => {
|
||||
if (
|
||||
config.core.blacklisted_ips &&
|
||||
config.core.blacklisted_ips.includes(req.ip)
|
||||
) {
|
||||
await app.render404(req.raw, reply.raw);
|
||||
return (reply.sent = true);
|
||||
}
|
||||
});
|
||||
|
||||
server.addHook('onResponse', (req, res, done) => {
|
||||
if (!req.url.startsWith('/_next') && config.core.log) {
|
||||
const status =
|
||||
res.statusCode !== 200
|
||||
? bold(red(res.statusCode.toString()))
|
||||
: bold(green(res.statusCode.toString()));
|
||||
Console.logger('server').info(`${status} ${req.url} was accessed`);
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"outDir": "./dist",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
@@ -16,6 +20,13 @@
|
||||
"experimentalDecorators": true,
|
||||
"noEmit": false
|
||||
},
|
||||
"include": ["next-env.d.ts", "src"],
|
||||
"exclude": ["node_modules", ".next"]
|
||||
}
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"src",
|
||||
"Zipline.toml"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".next"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user