Skip to content

Commit

Permalink
MAJOR CLEANING
Browse files Browse the repository at this point in the history
  • Loading branch information
jaspermayone committed Feb 26, 2025
1 parent 02867d1 commit 165bf48
Show file tree
Hide file tree
Showing 37 changed files with 281 additions and 322 deletions.
File renamed without changes.
13 changes: 13 additions & 0 deletions src/defs/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Interface for domain check response
*/
export interface DomainCheckResponse {
domain: string;
phishing: boolean;
times: {
createdAt: Date;
updatedAt: Date;
lastChecked: Date | null;
};
rawData?: any[]; // Optional property for extended data
}
2 changes: 1 addition & 1 deletion src/middleware/logRequest.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { NextFunction, Request, Response } from "express";
import requestIp from "request-ip";

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

let monitoringAgents = ["Checkly/", "Uptime-Kuma/"];
Expand Down
4 changes: 2 additions & 2 deletions src/routes/admin/router.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import express from "express";
import moment from "moment";
import { getPackageVersion, getVersion } from "../../functions/getVersion";
import { authenticateToken, getUserInfo } from "../../functions/jwt";
import { logRequest } from "../../middleware/logRequest";
import { prisma } from "../../prisma";
import { getPackageVersion, getVersion } from "../../utils/getVersion";
import { authenticateToken, getUserInfo } from "../../utils/jwt";
import domainRouter from "./routes/domain";
import userRouter from "./routes/user";

Expand Down
8 changes: 4 additions & 4 deletions src/routes/admin/routes/domain.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import axios from "axios";
import express, { Request, Response } from "express";

import { getDbDomain } from "../../../functions/db/getDbDomain";
import { domainReport } from "../../../functions/domain";
import { getUserInfo } from "../../../functions/jwt";
import { headersWithOTX } from "../../../defs/headers";
import { prisma } from "../../../prisma";
import { headersWithOTX } from "../../../utils/headers";
import { getDbDomain } from "../../../utils/db/getDbDomain";
import { domainReport } from "../../../utils/domain/domainReport";
import { getUserInfo } from "../../../utils/jwt";

/*
GET domain - Get all domains
Expand Down
2 changes: 1 addition & 1 deletion src/routes/admin/swaggerOptions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getVersion } from "../../functions/getVersion";
import { getVersion } from "../../utils/getVersion";

let filePattern;
if (process.env.NODE_ENV === "production") {
Expand Down
268 changes: 19 additions & 249 deletions src/routes/domain/check.ts
Original file line number Diff line number Diff line change
@@ -1,272 +1,42 @@
import axios from "axios";

import express from "express";
const router = express.Router();

import { domainCheck } from "../../functions/domain";
import { authenticateToken } from "../../functions/jwt";
import { parseData } from "../../functions/parseData";
import { userNeedsExtendedData } from "../../functions/userNeedsExtendedData";
import { prisma } from "../../prisma";

import { headersWithOTX } from "../../utils/headers";
import { findOrCreateDomain } from "../../utils/db/findOrCreateDomain";
import { prepareResponse } from "../../utils/domain/prepareResponse";
import { validateAndExtractParams } from "../../utils/domain/validateAndExtractDomainParams";
import { authenticateToken } from "../../utils/jwt";
import { ValidationError } from "../../utils/validationError";

/**
* GET /domain/check
* @summary Checks if a domain is phishing/malicious.
* @description This endpoint checks if a domain is phishing/malicious.
It will return a boolean value of true if it is phishing/malicious and false if it is not, and some other data.
Internally, this queries multiple sources to check if the domain is phishing/malicious, including but not limited to:
- Walshy's API
- IPQualityScore
- Google Safebrowsing
- Sinking Yahts
- PhishTank
- OpenPhish
- Lots more...
We also keep our own database of domains and their status, so we can return the status of the domain quickly if it has been checked before.
* It will return a boolean value of true if it is phishing/malicious and false if it is not, and some other data.
* @tags Domain - Endpoints for checking / reporting domains.
* @security BearerAuth
* @param {string} domain.query.required - Domain to check
* @param {boolean} extendData.query.optional - Optionally, request extra information about the domain (MAY HAVE LONGER RESPONSE TIME). You need special permissions to access this.
* @return {object} 200 - Success message
* @return {string} 400 - Error message
* @example response - 200 - Success message
* {
* "domain": "google.com",
* "phishing": false,
* "times": {
* "createdAt": "2024-08-14T00:00:00.000Z",
* "updatedAt": "2024-08-14T00:00:00.000Z",
* "lastChecked": "2024-08-14T00:00:00.000Z"
* }
* }
* @example response - 400 - Error: No domain parameter
* "No domain parameter found"
* @example response - 400 - Error: Invalid domain parameter
* "Invalid domain parameter, should be a top level domain. Ex: google.com, amazon.com"
*/
router.get("/", authenticateToken, async (req, res) => {

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
// metrics.increment("endpoint.domain.check");

// look for the query parameter
const query = req.query!;

let domain: string = query.domain! as string;
let extendData = await userNeedsExtendedData(req);

// check for domain parameter
if (!domain || domain === "" || domain === undefined || domain === null) {
return res.status(400).json("No domain parameter found");
}

// validate the domain (should be a top level domain
// and not a subdomain
// ex: google.com amazn.com
// not: mail.google.com, docs.google.com)

let regex = new RegExp("^(?!http://|https://)[a-zA-Z0-9-]+.[a-zA-Z]{2,}$");
if (!regex.test(domain)) {
return res
.status(400)
.json(
"Invalid domain parameter, should be a top level domain. Ex: google.com, amazon.com"
);
}

let dbDomain = await prisma.domain.findFirst({
where: {
domain: domain,
},
});

if (!dbDomain) {
dbDomain = await prisma.domain.create({
data: {
domain: domain,
},
});

let data = await domainCheck(domain);

let walshyData = data.walshyData;
let ipQualityScoreData = data.ipQualityScoreData;
let googleSafebrowsingData = data.googleSafebrowsingData;
let sinkingYahtsData = data.sinkingYahtsData;
let virusTotalData = data.virusTotalData;
let phishObserverData = data.phishObserverData;
let urlScanData = data.urlScanData;
let securitytrailsData = data.securitytrailsData;
let phishreportData = data.phishreportData;

let isPhish = await parseData(
walshyData,
ipQualityScoreData,
googleSafebrowsingData,
sinkingYahtsData,
virusTotalData,
phishObserverData,
urlScanData,
securitytrailsData,
phishreportData
);

if (isPhish) {
await prisma.domain.update({
where: {
id: dbDomain.id,
},
data: {
malicious: true,
lastChecked: new Date(),
},
});

await axios.patch(
"https://otx.alienvault.com/api/v1/pulses/6785dccb041b628fde283705",
{
indicators: {
add: [
{
indicator: `${domain}`,
type: "domain",
role: "phishing",
},
],
},
},
{
headers: headersWithOTX,
}
);

let response = {
domain: domain,
phishing: true,
times: {
createdAt: dbDomain.createdAt,
updatedAt: dbDomain.updatedAt,
lastChecked: dbDomain.lastChecked,
},
};

if (extendData) {
let rawAPIData = await prisma.rawAPIData.findMany({
where: {
domainId: dbDomain.id,
},
});

// push the raw data to the response
response["rawData"] = rawAPIData;
}

return res.status(200).json(response);
} else {
await prisma.domain.update({
where: {
id: dbDomain.id,
},
data: {
malicious: false,
lastChecked: new Date(),
},
});

let response = {
domain: domain,
phishing: false,
times: {
createdAt: dbDomain.createdAt,
updatedAt: dbDomain.updatedAt,
lastChecked: dbDomain.lastChecked,
},
};

if (extendData) {
let rawAPIData = await prisma.rawAPIData.findMany({
where: {
domainId: dbDomain.id,
},
});

// push the raw data to the response
response["rawData"] = rawAPIData;
}

return res.status(200).json(response);
}
} else {
domainCheck(domain);

if (dbDomain.malicious) {
await axios.patch(
"https://otx.alienvault.com/api/v1/pulses/6785dccb041b628fde283705",
{
indicators: {
add: [
{
indicator: `${domain}`,
type: "domain",
role: "phishing",
},
],
},
},
{
headers: headersWithOTX,
}
);

let response = {
domain: domain,
phishing: true,
times: {
createdAt: dbDomain.createdAt,
updatedAt: dbDomain.updatedAt,
lastChecked: dbDomain.lastChecked,
},
};

if (extendData) {
let rawAPIData = await prisma.rawAPIData.findMany({
where: {
domainId: dbDomain.id,
},
});

// push the raw data to the response
response["rawData"] = rawAPIData;
}

return res.status(200).json(response);
} else {
let response = {
domain: domain,
phishing: false,
times: {
createdAt: dbDomain.createdAt,
updatedAt: dbDomain.updatedAt,
lastChecked: dbDomain.lastChecked,
},
};
try {
// Validate and extract query parameters
const { domain, extendData } = await validateAndExtractParams(req);

if (extendData) {
let rawAPIData = await prisma.rawAPIData.findMany({
where: {
domainId: dbDomain.id,
},
});
// Check if domain exists in database
const dbDomain = await findOrCreateDomain(domain);

// push the raw data to the response
response["rawData"] = rawAPIData;
}
// Prepare and send response
const response = await prepareResponse(domain, dbDomain, extendData);

return res.status(200).json(response);
return res.status(200).json(response);
} catch (error) {
if (error instanceof ValidationError) {
return res.status(400).json(error.message);
}
console.error("Error in domain check:", error);
return res.status(500).json("Internal server error");
}
});

Expand Down
2 changes: 1 addition & 1 deletion src/routes/domain/classify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ const router = express.Router();

import { Classifications } from "@prisma/client";
import * as jwt from "jsonwebtoken";
import { authenticateToken } from "../../functions/jwt";
import { prisma } from "../../prisma";
import { authenticateToken } from "../../utils/jwt";

/**
* PUT /domain/classify
Expand Down
6 changes: 3 additions & 3 deletions src/routes/domain/report.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import express from "express";
const router = express.Router();

import { getDbDomain } from "../../functions/db/getDbDomain";
import { domainReport } from "../../functions/domain";
import { authenticateToken, getUserInfo } from "../../functions/jwt";
import { prisma } from "../../prisma";
import { getDbDomain } from "../../utils/db/getDbDomain";
import { domainReport } from "../../utils/domain/domainReport";
import { authenticateToken, getUserInfo } from "../../utils/jwt";

/**
* POST /domain/report
Expand Down
2 changes: 1 addition & 1 deletion src/routes/email.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as express from "express";
import { validateEmail } from "../functions/validateEmail";
import { logRequest } from "../middleware/logRequest";
import { ipQualityScoreService } from "../services/_index";
import { validateEmail } from "../utils/validateEmail";

const router = express.Router();
router.use(express.json());
Expand Down
2 changes: 1 addition & 1 deletion src/routes/misc.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as express from "express";
import moment from "moment";
import { getVersion } from "../functions/getVersion";
import { logRequest } from "../middleware/logRequest";
import { prisma } from "../prisma";
import { getVersion } from "../utils/getVersion";

const router = express.Router();
router.use(express.json());
Expand Down
Loading

0 comments on commit 165bf48

Please sign in to comment.