feat: add link creation and lookup
All checks were successful
Build and push Docker image / build (push) Successful in 2m50s
Release new version / release (push) Successful in 26s
Update changelog / changelog (push) Successful in 25s

finally has the bare minimum functionality to say that it works!
This commit is contained in:
2026-01-03 10:51:59 +01:00
parent c19a098b1c
commit d7f4006698
8 changed files with 477 additions and 34 deletions

View File

@@ -1,27 +1,33 @@
import * as dotenv from 'dotenv';
dotenv.config({ quiet: true });
import express from 'express';
import { version } from '../package.json';
import { AppDataSource } from './data-source'
import { Link } from './entities/Link';
import inferUser from './middleware/inferUser';
import miscRouter from './routes/miscRoutes';
import userRouter from './routes/userRoutes';
import linkRouter from './routes/linkRoutes';
import { getCorsConfig } from './tools/cors';
import { LinkService } from './services/linkService';
import * as env from './tools/env';
import * as z from 'zod';
AppDataSource.initialize().then(async () => {
await AppDataSource.runMigrations();
const app: express.Express = express();
const linkService = new LinkService();
const rs = env.getRewriteStrings();
const removedExpired = await linkService.removeAllExpired();
if (removedExpired !== 0) console.log(`[${Date.now() / 1_000}] (DB) Removed ${removedExpired} expired links.`);
app.use(express.json());
app.use(getCorsConfig());
app.use(inferUser);
app.use(miscRouter, userRouter, linkRouter);
if (process.env['DEBUG'] === 'true') {
if (env.getBool('debug', true)) {
const swaggerJsdocOpts = {
failOnErrors: true,
definition: {
@@ -67,16 +73,65 @@ AppDataSource.initialize().then(async () => {
// Handle 404s
// https://stackoverflow.com/a/9802006
app.use(function(req: express.Request, res: express.Response) {
res.status(404);
app.use(async function(req: express.Request, res: express.Response) {
if (req.accepts('json')) {
res.json({ status: 'error', error: 'Not found' });
return;
// Check if host header seems right
try {
z.string()
.includes(rs.fqdn)
.parse(req.headers.host);
} catch {
return res.status(400)
.json({
status: 'error',
error: 'Invalid host. Is your browser sending the host header?',
code: 'no_host'
});
}
// Retrieve url, subdomain from request.
let uri: string = req.url.slice(1); // discards / from /abc, /abc -> abc
let subdomain: string | null = req.headers.host!.replace(rs.fqdn, '') || null;
// Try to lookup the url in DB
const reversedLink: Link | null = await linkService.lookupUriWithExpiryValidation(uri, subdomain);
// Found something?
if (reversedLink !== null) {
// Count this as a visit
reversedLink.visits += 1;
linkService.save(reversedLink);
// Redirect the user.
return res.redirect(302, reversedLink.fullUrl);
}
res.type('txt').send('Not found');
// Nothing found? Return the standard 404.
res.status(404);
if (req.accepts('json')) {
return res.json({
status: 'error',
error: 'Not found',
code: 'uri_not_found'
});
}
return res.type('txt')
.send('Not found');
});
app.listen(6567, () => console.log('(HTTP Server) Listening on port 6567.'));
const errorHandler: express.ErrorRequestHandler = (err, req, res, next) => {
console.error(`[${Date.now() / 1_000}] (ErrorHandler) Server error! Error stack:`);
console.error(err?.stack);
return res.status(500)
.json({
status: 'error',
error: 'Server error! Something broke',
code: 'generic_server_error'
});
};
app.use(errorHandler);
app.listen(6567, () => console.log(`[${Date.now() / 1_000}] (HTTP Server) Listening on port 6567.`));
}).catch(error => console.log(error))