Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move to bun natively #84

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NextFunction, Request, Response } from "express";
import requestIp from "request-ip";

import { log } from "../../src/utils/logger";
import { prisma } from "../prisma";
import { getUserInfo } from "../utils/jwt";
import { log } from "../utils/logger";

let monitoringAgents = ["Checkly/", "Uptime-Kuma/"];

Expand Down Expand Up @@ -49,12 +49,21 @@ export const logRequest = async (

if (req.headers.authorization) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];

if (token !== null && token !== undefined) {
userinfo = await getUserInfo(req);
if (userinfo) {
usr = userinfo.uuid;
// Check if it's a Bearer token with proper JWT format
if (authHeader && authHeader.startsWith("Bearer ")) {
const token = authHeader.split(" ")[1];
// Basic validation that it looks like a JWT (has two dots)
if (token && token.split(".").length === 3) {
try {
userinfo = await getUserInfo(req);
// Only set usr if userinfo exists AND has a valid uuid
if (userinfo && userinfo.uuid) {
usr = userinfo.uuid;
}
} catch (error) {
// Just log error but continue processing request without setting user values
console.error("Error validating JWT:", error);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/router.ts → OLD-SRC/router.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import responseTime from "response-time";
// import metrics from "./metrics";
import { logRequest } from "./middleware/logRequest";
// import defaultRateLimiter from "./middleware/rateLimit";
import * as logger from "../src/utils/logger";
import { prisma } from "./prisma";
import adminRouter from "./routes/admin/router";
import domainRouter from "./routes/domain";
import emailRouter from "./routes/email";
import miscRouter from "./routes/misc";
import userRouter from "./routes/user";
import * as logger from "./utils/logger";

const router = express.Router();

Expand Down
8 changes: 1 addition & 7 deletions src/utils/jwt.ts → OLD-SRC/utils/jwt.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import jwt, { JwtPayload } from "jsonwebtoken";

// import metrics from "../metrics";
import * as logger from "../../src/utils/logger";
import { prisma } from "../prisma";
import * as logger from "../utils/logger";

/**
* Function to authenticate the token
Expand Down Expand Up @@ -77,12 +77,6 @@ export async function generateAccessToken(user: any) {
export async function getUserInfo(req: any) {
const tsStart = Date.now();

// FIXME:
// for some reson, even when we have headers, we still get a error, so this is the temp solution
if (!req.headers) {
return logger.debug("No headers found, but not actually an error");
}

const authHeader = req.headers.authorization;
const token = authHeader && authHeader.split(" ")[1];
if (token == null) return console.error("No token provided");
Expand Down
116 changes: 34 additions & 82 deletions bun.lock

Large diffs are not rendered by default.

File renamed without changes.
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "phish.directory",
"version": "3.0.0",
"version": "4.0.0",
"description": "API for phish.directory, a community-driven anti-phishing tool. Helping catch, prevent, and catalog phishing links & attempts.",
"maintainers": [
{
Expand All @@ -18,13 +18,17 @@
"keywords": [],
"author": "Jasper Mayone <[email protected]>",
"dependencies": {
"@elysiajs/bearer": "^1.2.0",
"@elysiajs/cors": "^1.2.0",
"@elysiajs/cron": "^1.2.0",
"@elysiajs/jwt": "^1.2.0",
"@playwright/test": "^1.49.1",
"@prisma/client": "6.4.1",
"axios": "^1.7.9",
"bcrypt": "^5.1.1",
"body-parser": "^1.20.3",
"colors": "^1.4.0",
"dotenv": "^16.4.7",
"elysia-ip": "^1.0.8",
"express": "^4.21.2",
"express-jsdoc-swagger": "^1.8.0",
"express-rate-limit": "^7.5.0",
Expand All @@ -37,15 +41,15 @@
"ts-node": "^10.9.2"
},
"devDependencies": {
"bun-types": "latest",
"@flydotio/dockerfile": "^0.6.1",
"@types/bcrypt": "^5.0.2",
"@types/bun": "^1.2.3",
"@types/express": "^4.17.21",
"@types/jsonwebtoken": "^9.0.7",
"@types/node": "^20.17.10",
"@types/node-statsd": "^0.1.6",
"@types/request-ip": "^0.0.41",
"@types/response-time": "^2.3.8",
"bun-types": "latest",
"nodemon": "^3.1.9",
"prisma": "^6.4.1",
"typescript": "^5.7.2"
Expand Down
2 changes: 0 additions & 2 deletions src/app.ts

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { prisma } from "../../prisma";
import { prisma } from "../../utils/prisma";
import { checkAndUpdateDomainStatus } from "../domain/checkAndUpdateDomainStatus";
import { domainCheck } from "../domain/domain";

Expand Down
4 changes: 2 additions & 2 deletions src/utils/db/getDbDomain.ts → src/func/db/getDbDomain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { prisma } from "../../prisma";
import { sanitizeDomain } from "../../utils/sanitizeDomain";
import { prisma } from "../../utils/prisma";
import { sanitizeDomain } from "../domain/sanitizeDomain";

export async function getDbDomain(domain: string) {
let sanitizedDomain = sanitizeDomain(domain);
Expand Down
2 changes: 1 addition & 1 deletion src/utils/db/getDbUser.ts → src/func/db/getDbUser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { prisma } from "../../prisma";
import { prisma } from "../../utils/prisma";

export async function getDbUser(id: number) {
const dbUser = await prisma.user.findUnique({
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from "axios";
import { axios } from "../../utils/axios";

import { headersWithOTX } from "../../defs/headers";
import { headersWithOTX } from "../../../src/defs/headers";
import { virusTotalService, walshyService } from "../../services/_index";

/**
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DomainCheckResponse } from "../../defs/interfaces";
import { DomainCheckResponse } from "../../../src/defs/interfaces";
import { prisma } from "../../prisma";
import { reportToAlienVault } from "./reportToAlienVault";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios from "axios";
import { headersWithOTX } from "../../defs/headers";
import { headersWithOTX } from "../../../src/defs/headers";
import { axios } from "../../utils/axios";

/**
* Reports a malicious domain to AlienVault OTX
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ValidationError } from "../../../src/defs/validationError";
import { userNeedsExtendedData } from "../userNeedsExtendedData";
import { ValidationError } from "../validationError";

/**
* Validates the domain parameter and extracts query parameters
Expand Down
File renamed without changes.
185 changes: 111 additions & 74 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,84 +1,125 @@
import axios from "axios";
import * as dotenv from "dotenv";
import expressJSDocSwagger from "express-jsdoc-swagger";
import helmet from "helmet";
import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { Elysia } from "elysia";
// import { cron } from "@elysiajs/cron";
// bun add @elysiajs/jwt
// import { randomUUIDv7 } from "bun";
import { ip } from "elysia-ip";

import { app } from "./app";
import router from "./router";
import { server } from "./server";
// import metrics from "./metrics";
import { swaggerOptions as adminSwagOptions } from "./routes/admin/swaggerOptions";
import { swaggerOptions as mainSwagOptions } from "./swaggerOptions";
import { getVersion } from "./utils/getVersion";
// import { prisma } from "./utils/prisma";
import * as logger from "./utils/logger";

dotenv.config();
let version = getVersion();

const port: number = Number(process.env.PORT) || 3000;

expressJSDocSwagger(app)(mainSwagOptions);
expressJSDocSwagger(app)(adminSwagOptions);
new Elysia()
.use(
cors({
maxAge: 86400,
})
)
.use(ip())
// .use(
// cron({
// name: "updateState",
// pattern: "*/10 * * * * *",
// run() {

app.disable("x-powered-by");

app.use(
helmet({
xFrameOptions: { action: "deny" },
xContentTypeOptions: true,
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
baseUri: ["'self'"],
fontSrc: ["'self'", "https:", "data:"],
formAction: ["'self'"],
frameAncestors: ["'self'"],
imgSrc: ["'self'", "data:"],
objectSrc: ["'none'"],
scriptSrc: ["'self'"],
scriptSrcAttr: ["'none'"],
styleSrc: ["'self'", "https:", "'unsafe-inline'"],
upgradeInsecureRequests: [],
// },
// })
// )
.use(
swagger({
exclude: ["/"],
documentation: {
info: {
title: "phish.directory API",
version: version,
description:
"API for phish.directory, a community-driven anti-phishing tool. Helping catch, prevent, and catalog phishing links & attempts",
contact: {
name: "phish.directory",
url: "mailto:[email protected]",
email: "[email protected]",
},
// license: {
// name: "AGPL 3.0",
// url: "",
// },
},
tags: [
{ name: "Domain", description: "Domain-related operations" },
{ name: "Email", description: "Email-related operations" },
{ name: "User", description: "User management operations" },
{ name: "Admin", description: "[RESTRICTED] Admin operations" },
],
components: {
securitySchemes: {
BearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
},
},
security: [
{
BearerAuth: [],
},
],
},
// Scalar-specific configuration
provider: "scalar",
scalarConfig: {
hideDownloadButton: false,
hideTestRequestButton: false,
servers: [
{
url: "https://api.phish.directory",
description: "Production server",
},
{
url: "http://localhost:3000",
description: "Local server",
},
],
forceDarkModeState: "dark",
hideDarkModeToggle: true,
// defaultOpenAllTags: true,
metaData: {
title: "phish.directory API",
description:
"API for phish.directory, a community-driven anti-phishing tool. Helping catch, prevent, and catalog phishing links & attempts",
ogDescription:
"API for phish.directory, a community-driven anti-phishing tool. Helping catch, prevent, and catalog phishing links & attempts",
ogTitle: "phish.directory API",
},
},
},
referrerPolicy: { policy: "strict-origin" },
strictTransportSecurity: {
maxAge: 63072000,
preload: true,
},
xPoweredBy: false,
path: "/docs",
})
)
.get("/", async ({ set }) => {
// redirect to docs
set.status = 302;
set.headers = {
Location: "/docs",
};
return "Redirecting to /docs";
})
);

// Add metric interceptors for axios
axios.interceptors.request.use((config: any) => {
config.metadata = { startTs: performance.now() };
return config;
});

axios.interceptors.response.use((res: any) => {
const stat = (res.config.method + "/" + res.config.url?.split("/")[1])
.toLowerCase()
.replace(/[:.]/g, "")
.replace(/\//g, "_");

const httpCode = res.status;
const timingStatKey = `http.request.${stat}`;
const codeStatKey = `http.request.${stat}.${httpCode}`;
// metrics.timing(
// timingStatKey,
// performance.now() - res.config.metadata.startTs
// );
// metrics.increment(codeStatKey, 1);

return res;
});

app.use("/", router);
.get("/up", async ({}) => {
return {
status: "up",
};
})
.listen(port);

// Heartbeat
// new CronJob(
// "0 * * * * *",
// async function () {
// logger.log("Thump Thump");
// console.log("Thump Thump");
// // metrics.increment("heartbeat");
// },
// null,
Expand All @@ -87,10 +128,6 @@ app.use("/", router);
// );
//

server
.listen(Number(port), "0.0.0.0", () => {
logger.info(`Server is running on port ${port}`);
})
.on("error", (err) => {
logger.error(`Failed to start server: ${err.message}`);
});
logger.log(`Server started on port ${port}`, "ready");
logger.log("Press Ctrl+C to stop the server", "ready");
logger.log("----\n", "plain");
Empty file.
Loading