7 Commits

Author SHA1 Message Date
429613c67e chore: bump version
All checks were successful
Build and push Docker image / build (push) Successful in 2m49s
Release new version / release (push) Successful in 30s
Update changelog / changelog (push) Successful in 25s
2026-01-08 13:22:27 +01:00
681555fef8 fix: fix subdomain retrieval
All checks were successful
Update changelog / changelog (push) Successful in 25s
2026-01-08 13:20:32 +01:00
066b9884c2 docs: minor markdown rendering fixes to readme
All checks were successful
Update changelog / changelog (push) Successful in 24s
2026-01-07 23:11:18 +01:00
9311cd3c96 chore: release v0.0.2
All checks were successful
Build and push Docker image / build (push) Successful in 2m46s
Release new version / release (push) Successful in 26s
Update changelog / changelog (push) Successful in 24s
2026-01-07 23:06:21 +01:00
89e6832e73 Merge remote-tracking branch 'origin/master' 2026-01-07 23:04:42 +01:00
109f22c231 docs: add note to link shortening endpoint swagger doc 2026-01-07 23:04:35 +01:00
355338e397 docs: add requireAdmin and docs for requireUser 2026-01-03 18:29:14 +01:00
7 changed files with 66 additions and 9 deletions

View File

@@ -26,10 +26,14 @@ Running the back-end is as simple as:
npm ci
```
- Copying the .env.default file to .env, and customizing it to own preferences.
**Example:** Say, you want to add a domain to the trusted CORS origins list. To do so, your .env file in your editor of choice and append a comma (`,`) with the origin you want to add (say, `http://example.com`). Your .env file might then look as follows: `TRUSTED_ORIGINS=http://localhost:6568,http://example.com`.
**Important:** Make sure to change the `ACCESS_TOKEN_PRIVATE_KEY` variable to something secure, as this secret value will be used to generate user sessions. **Setting a weak key will allow attackers to potentially bruteforce your secret and forge user tokens!**
- Pasting your wordlist file into `src/tools/wordlist.ts`.
No wordlist file exists by default in `src/tools/wordlist.ts`. This is because wordlists were meant to be as modular as possible (with the philosophy of "bring your own wordlist"). If you leave that as-is, you'll run into runtime errors.
However, if you don't want to provide your own wordlist, and just want to get up and running as fast as possible, you're free to use the provided sample `wordlist.example-large.ts` file. Just copy it into `src/tools/wordlist.ts`:
```sh
cp wordlist.example-large.ts src/tools/wordlist.ts

View File

@@ -1,6 +1,6 @@
{
"name": "kittyBE",
"version": "0.0.1",
"version": "0.0.3",
"description": "Your go-to place for short and memorable URLs.",
"type": "commonjs",
"devDependencies": {

View File

@@ -91,7 +91,7 @@ AppDataSource.initialize().then(async () => {
// 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;
let subdomain: string | null = req.headers.host!.replace(rs.fqdn, '').slice(0, -1) || null; // slice() to remove trailing dot
// Try to lookup the url in DB
const reversedLink: Link | null = await linkService.lookupUriWithExpiryValidation(uri, subdomain);

View File

@@ -15,5 +15,5 @@ export const AppDataSource = new DataSource({
entities: [__dirname + '/entities/*.ts'],
migrations: [__dirname + '/migrations/*.ts'],
subscribers: [],
parseInt8: true
parseInt8: true // https://github.com/typeorm/typeorm/issues/9341#issuecomment-1268986627
})

View File

@@ -0,0 +1,38 @@
import { Request, Response, NextFunction } from 'express';
import { ErrorDTO } from '../schemas/miscSchema';
import * as jwt from '../tools/jwt';
/**
* Checks if user has administrative privileges.
*
* This needs to happen AFTER ensuring this is not a guest session.
* So: use requireUser first, and after that requireAdmin to enforce
* admin privilege requirement.
*
* @param {Request} req The request
* @param {Response} res The resource
* @param {(Function|NextFunction)} next The next
* @return {any} Next function on success, unauthorized error otherwise
*/
const requireAdmin = (req: Request, res: Response, next: NextFunction) => {
const user: jwt.JwtStatus = res.locals.user;
let error: ErrorDTO | null = null;
// Check if role is set to 1 (1 = admin, 0 = standard user).
if (user.decoded?.role !== 1)
error = {
status: 'error',
error: 'Unauthorized, admin access required',
code: 'unauthorized_non_admin'
};
// It is? Send 401 unauthorized.
if (error !== null)
return res.status(401)
.send(error);
// Otherwise jump to next endpoint.
return next();
};
export default requireAdmin;

View File

@@ -1,7 +1,20 @@
import { Request, Response, NextFunction } from "express";
import { ErrorDTO } from "../schemas/miscSchema";
import * as jwt from "../tools/jwt";
import { Request, Response, NextFunction } from 'express';
import { ErrorDTO } from '../schemas/miscSchema';
import * as jwt from '../tools/jwt';
/**
* Checks if user is singed in.
* Returns 401 when user is unauthorized.
*
* To check if user is an admin, chain requireUser and requireAdmin together.
* So: use requireUser first, and after that requireAdmin to enforce
* admin privilege requirement.
*
* @param {Request} req The request
* @param {Response} res The resource
* @param {(Function|NextFunction)} next The next
* @return {any} Next function on success, unauthorized error otherwise
*/
const requireUser = (req: Request, res: Response, next: NextFunction) => {
const user: jwt.JwtStatus = res.locals.user;
let error: ErrorDTO | null = null;

View File

@@ -104,9 +104,11 @@ linkRouter.get('/api/v1/link/fromWordlist', validateSchema(ls.sentenceLinkReques
* post:
* description:
* Register a new shortened URL. <br/>
* See linkSchema.ts for constraints.
* See linkSchema.ts for constraints. <br/>
* <b>Note:</b> This endpoint's functionality differs depending on the user info,
* which means guests will be treated differently from authenticated users.
* tags: [Link]
* summary: Shorten a link
* summary: "[AUTHED?] Shorten a link"
* requestBody:
* required: true
* content: