diff --git a/src/index.ts b/src/index.ts
index ec44960..9a15fb2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -10,7 +10,11 @@ async function init() {
process.on("unhandledRejection", (error: any) => {
// eslint-disable-next-line no-console
console.dir(error?.stack);
- process.exit(1);
+ });
+
+ process.on("uncaughtExceptions", (error: any) => {
+ // eslint-disable-next-line no-console
+ console.dir(error?.stack);
});
try {
diff --git a/src/routes/addUserAsVIP.ts b/src/routes/addUserAsVIP.ts
index 3e7f0c7..ab6cd8e 100644
--- a/src/routes/addUserAsVIP.ts
+++ b/src/routes/addUserAsVIP.ts
@@ -4,6 +4,7 @@ import { config } from "../config";
import { Request, Response } from "express";
import { isUserVIP } from "../utils/isUserVIP";
import { HashedUserID } from "../types/user.model";
+import { Logger } from "../utils/logger";
interface AddUserAsVIPRequest extends Request {
query: {
@@ -34,15 +35,21 @@ export async function addUserAsVIP(req: AddUserAsVIPRequest, res: Response): Pro
// check to see if this user is already a vip
const userIsVIP = await isUserVIP(userID);
- if (enabled && !userIsVIP) {
- // add them to the vip list
- await db.prepare("run", 'INSERT INTO "vipUsers" VALUES(?)', [userID]);
+ try {
+ if (enabled && !userIsVIP) {
+ // add them to the vip list
+ await db.prepare("run", 'INSERT INTO "vipUsers" VALUES(?)', [userID]);
+ }
+
+ if (!enabled && userIsVIP) {
+ //remove them from the shadow ban list
+ await db.prepare("run", 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]);
+ }
+
+ return res.sendStatus(200);
+ } catch (e) {
+ Logger.error(e as string);
+ return res.sendStatus(500);
}
- if (!enabled && userIsVIP) {
- //remove them from the shadow ban list
- await db.prepare("run", 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]);
- }
-
- return res.sendStatus(200);
}
diff --git a/src/routes/deleteLockCategories.ts b/src/routes/deleteLockCategories.ts
index 3340f10..c163656 100644
--- a/src/routes/deleteLockCategories.ts
+++ b/src/routes/deleteLockCategories.ts
@@ -6,6 +6,7 @@ import { ActionType, Category, Service, VideoID } from "../types/segments.model"
import { UserID } from "../types/user.model";
import { getService } from "../utils/getService";
import { config } from "../config";
+import { Logger } from "../utils/logger";
interface DeleteLockCategoriesRequest extends Request {
body: {
@@ -53,7 +54,12 @@ export async function deleteLockCategoriesEndpoint(req: DeleteLockCategoriesRequ
});
}
- await deleteLockCategories(videoID, categories, actionTypes, getService(service));
+ try {
+ await deleteLockCategories(videoID, categories, actionTypes, getService(service));
+ } catch (e) {
+ Logger.error(e as string);
+ return res.status(500);
+ }
return res.status(200).json({ message: `Removed lock categories entries for video ${videoID}` });
}
diff --git a/src/routes/dumpDatabase.ts b/src/routes/dumpDatabase.ts
index 10e21d6..dfbf006 100644
--- a/src/routes/dumpDatabase.ts
+++ b/src/routes/dumpDatabase.ts
@@ -164,18 +164,23 @@ export default async function dumpDatabase(req: Request, res: Response, showPage
${updateQueued ? `Update queued.` : ``} Last updated: ${lastUpdate ? new Date(lastUpdate).toUTCString() : `Unknown`}`);
} else {
- res.send({
- dbVersion: await getDbVersion(),
- lastUpdated: lastUpdate,
- updateQueued,
- links: latestDumpFiles.map((item:any) => {
- return {
- table: item.tableName,
- url: `/database/${item.tableName}.csv`,
- size: item.fileSize,
- };
- }),
- });
+ try {
+ res.send({
+ dbVersion: await getDbVersion(),
+ lastUpdated: lastUpdate,
+ updateQueued,
+ links: latestDumpFiles.map((item:any) => {
+ return {
+ table: item.tableName,
+ url: `/database/${item.tableName}.csv`,
+ size: item.fileSize,
+ };
+ }),
+ });
+ } catch (e) {
+ Logger.error(e as string);
+ res.sendStatus(500);
+ }
}
await queueDump();
diff --git a/src/routes/getBrandingStats.ts b/src/routes/getBrandingStats.ts
index 1ecd9f4..b6a9daf 100644
--- a/src/routes/getBrandingStats.ts
+++ b/src/routes/getBrandingStats.ts
@@ -25,20 +25,25 @@ let lastFetch: DBStatsData = {
updateExtensionUsers();
export async function getBrandingStats(req: Request, res: Response): Promise {
- const row = await getStats();
- lastFetch = row;
+ try {
+ const row = await getStats();
+ lastFetch = row;
- /* istanbul ignore if */
- if (!row) res.sendStatus(500);
- const extensionUsers = chromeUsersCache + firefoxUsersCache;
+ /* istanbul ignore if */
+ if (!row) res.sendStatus(500);
+ const extensionUsers = chromeUsersCache + firefoxUsersCache;
- //send this result
- res.send({
- userCount: row.userCount ?? 0,
- activeUsers: extensionUsers,
- titles: row.titles,
- thumbnails: row.thumbnails,
- });
+ //send this result
+ res.send({
+ userCount: row.userCount ?? 0,
+ activeUsers: extensionUsers,
+ titles: row.titles,
+ thumbnails: row.thumbnails,
+ });
+ } catch (e) {
+ Logger.error(e as string);
+ res.sendStatus(500);
+ }
}
async function getStats(): Promise {
diff --git a/src/routes/getDaysSavedFormatted.ts b/src/routes/getDaysSavedFormatted.ts
index bd906a6..f939a93 100644
--- a/src/routes/getDaysSavedFormatted.ts
+++ b/src/routes/getDaysSavedFormatted.ts
@@ -1,17 +1,23 @@
import { db } from "../databases/databases";
import { Request, Response } from "express";
+import { Logger } from "../utils/logger";
export async function getDaysSavedFormatted(req: Request, res: Response): Promise {
- const row = await db.prepare("get", 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
+ try {
+ const row = await db.prepare("get", 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []);
- if (row !== undefined) {
- //send this result
- return res.send({
- daysSaved: row.daysSaved?.toFixed(2) ?? "0",
- });
- } else {
- return res.send({
- daysSaved: 0
- });
+ if (row !== undefined) {
+ //send this result
+ return res.send({
+ daysSaved: row.daysSaved?.toFixed(2) ?? "0",
+ });
+ } else {
+ return res.send({
+ daysSaved: 0
+ });
+ }
+ } catch (err) {
+ Logger.error(err as string);
+ return res.sendStatus(500);
}
}
diff --git a/src/routes/getTopBrandingUsers.ts b/src/routes/getTopBrandingUsers.ts
index 370a63f..00b9560 100644
--- a/src/routes/getTopBrandingUsers.ts
+++ b/src/routes/getTopBrandingUsers.ts
@@ -1,5 +1,6 @@
import { db } from "../databases/databases";
import { Request, Response } from "express";
+import { Logger } from "../utils/logger";
async function generateTopUsersStats(sortBy: string) {
const rows = await db.prepare("all", `SELECT COUNT(distinct "titles"."UUID") as "titleCount", COUNT(distinct "thumbnails"."UUID") as "thumbnailCount", COALESCE("userName", "titles"."userID") as "userName"
@@ -36,8 +37,13 @@ export async function getTopBrandingUsers(req: Request, res: Response): Promise<
return res.status(503).send("Disabled for load reasons");
}
- const stats = await generateTopUsersStats(sortBy);
+ try {
+ const stats = await generateTopUsersStats(sortBy);
- //send this result
- return res.send(stats);
+ //send this result
+ return res.send(stats);
+ } catch (e) {
+ Logger.error(e as string);
+ return res.sendStatus(500);
+ }
}
diff --git a/src/routes/getTopCategoryUsers.ts b/src/routes/getTopCategoryUsers.ts
index c8ce0d0..51c51a7 100644
--- a/src/routes/getTopCategoryUsers.ts
+++ b/src/routes/getTopCategoryUsers.ts
@@ -3,6 +3,7 @@ import { createMemoryCache } from "../utils/createMemoryCache";
import { config } from "../config";
import { Request, Response } from "express";
import { validateCategories } from "../utils/parseParams";
+import { Logger } from "../utils/logger";
const MILLISECONDS_IN_MINUTE = 60000;
// eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -74,8 +75,13 @@ export async function getTopCategoryUsers(req: Request, res: Response): Promise<
return res.sendStatus(400);
}
- const stats = await getTopCategoryUsersWithCache(sortBy, category);
+ try {
+ const stats = await getTopCategoryUsersWithCache(sortBy, category);
- //send this result
- return res.send(stats);
+ //send this result
+ return res.send(stats);
+ } catch (e) {
+ Logger.error(e as string);
+ return res.sendStatus(500);
+ }
}
diff --git a/src/routes/getTopUsers.ts b/src/routes/getTopUsers.ts
index f77bc8b..328da4e 100644
--- a/src/routes/getTopUsers.ts
+++ b/src/routes/getTopUsers.ts
@@ -2,6 +2,7 @@ import { db } from "../databases/databases";
import { createMemoryCache } from "../utils/createMemoryCache";
import { config } from "../config";
import { Request, Response } from "express";
+import { Logger } from "../utils/logger";
const MILLISECONDS_IN_MINUTE = 60000;
// eslint-disable-next-line @typescript-eslint/no-misused-promises
@@ -92,8 +93,13 @@ export async function getTopUsers(req: Request, res: Response): Promise {
- const countContributingUsers = Boolean(req.query?.countContributingUsers == "true");
- const row = await getStats(countContributingUsers);
- lastFetch = row;
+ try {
+ const countContributingUsers = Boolean(req.query?.countContributingUsers == "true");
+ const row = await getStats(countContributingUsers);
+ lastFetch = row;
- /* istanbul ignore if */
- if (!row) res.sendStatus(500);
- const extensionUsers = chromeUsersCache + firefoxUsersCache;
+ /* istanbul ignore if */
+ if (!row) res.sendStatus(500);
+ const extensionUsers = chromeUsersCache + firefoxUsersCache;
- //send this result
- res.send({
- userCount: row.userCount ?? 0,
- activeUsers: extensionUsers,
- apiUsers: Math.max(apiUsersCache, extensionUsers),
- viewCount: row.viewCount,
- totalSubmissions: row.totalSubmissions,
- minutesSaved: row.minutesSaved,
- });
+ //send this result
+ res.send({
+ userCount: row.userCount ?? 0,
+ activeUsers: extensionUsers,
+ apiUsers: Math.max(apiUsersCache, extensionUsers),
+ viewCount: row.viewCount,
+ totalSubmissions: row.totalSubmissions,
+ minutesSaved: row.minutesSaved,
+ });
- // Check if the cache should be updated (every ~14 hours)
- const now = Date.now();
- if (now - lastUserCountCheck > 5000000) {
- lastUserCountCheck = now;
+ // Check if the cache should be updated (every ~14 hours)
+ const now = Date.now();
+ if (now - lastUserCountCheck > 5000000) {
+ lastUserCountCheck = now;
- updateExtensionUsers();
+ updateExtensionUsers();
+ }
+ } catch (e) {
+ Logger.error(e as string);
+ res.sendStatus(500);
}
}
diff --git a/src/routes/getUserID.ts b/src/routes/getUserID.ts
index 5acf659..83d3702 100644
--- a/src/routes/getUserID.ts
+++ b/src/routes/getUserID.ts
@@ -1,6 +1,7 @@
import { db } from "../databases/databases";
import { Request, Response } from "express";
import { UserID } from "../types/user.model";
+import { Logger } from "../utils/logger";
function getFuzzyUserID(userName: string): Promise<{userName: string, userID: UserID }[]> {
// escape [_ % \] to avoid ReDOS
@@ -37,16 +38,22 @@ export async function getUserID(req: Request, res: Response): Promise
// invalid request
return res.sendStatus(400);
}
- const results = exactSearch
- ? await getExactUserID(userName)
- : await getFuzzyUserID(userName);
- if (results === undefined || results === null) {
- /* istanbul ignore next */
+ try {
+ const results = exactSearch
+ ? await getExactUserID(userName)
+ : await getFuzzyUserID(userName);
+
+ if (results === undefined || results === null) {
+ /* istanbul ignore next */
+ return res.sendStatus(500);
+ } else if (results.length === 0) {
+ return res.sendStatus(404);
+ } else {
+ return res.send(results);
+ }
+ } catch (e) {
+ Logger.error(e as string);
return res.sendStatus(500);
- } else if (results.length === 0) {
- return res.sendStatus(404);
- } else {
- return res.send(results);
}
}
diff --git a/src/routes/getUserInfo.ts b/src/routes/getUserInfo.ts
index dbcdfd3..fce3e33 100644
--- a/src/routes/getUserInfo.ts
+++ b/src/routes/getUserInfo.ts
@@ -205,19 +205,24 @@ async function getUserInfo(req: Request, res: Response): Promise {
return res.status(400).send("Invalid userID or publicUserID parameter");
}
- const responseObj = {} as Record;
- for (const property of paramValues) {
- responseObj[property] = await dbGetValue(hashedUserID, property);
- }
+ try {
+ const responseObj = {} as Record;
+ for (const property of paramValues) {
+ responseObj[property] = await dbGetValue(hashedUserID, property);
+ }
- // add minutesSaved and segmentCount after to avoid getting overwritten
- if (paramValues.includes("minutesSaved") || paramValues.includes("segmentCount")) {
- const segmentsSummary = await dbGetSubmittedSegmentSummary(hashedUserID);
- responseObj["minutesSaved"] = segmentsSummary.minutesSaved;
- responseObj["segmentCount"] = segmentsSummary.segmentCount;
- }
+ // add minutesSaved and segmentCount after to avoid getting overwritten
+ if (paramValues.includes("minutesSaved") || paramValues.includes("segmentCount")) {
+ const segmentsSummary = await dbGetSubmittedSegmentSummary(hashedUserID);
+ responseObj["minutesSaved"] = segmentsSummary.minutesSaved;
+ responseObj["segmentCount"] = segmentsSummary.segmentCount;
+ }
- return res.send(responseObj);
+ return res.send(responseObj);
+ } catch (err) {
+ Logger.error(err as string);
+ return res.sendStatus(500);
+ }
}
export async function endpoint(req: Request, res: Response): Promise {
diff --git a/src/routes/postSkipSegments.ts b/src/routes/postSkipSegments.ts
index c6c6fce..a930fb5 100644
--- a/src/routes/postSkipSegments.ts
+++ b/src/routes/postSkipSegments.ts
@@ -515,38 +515,37 @@ export async function postSkipSegments(req: Request, res: Response): Promise Logger.error(`call send webhooks ${e}`));
+ }
+
+ return res.json(newSegments);
} catch (err) {
Logger.error(err as string);
- lock.unlock();
return res.sendStatus(500);
+ } finally {
+ lock.unlock();
}
-
- for (let i = 0; i < segments.length; i++) {
- sendWebhooks(apiVideoDetails, userID, videoID, UUIDs[i], segments[i], service).catch((e) => Logger.error(`call send webhooks ${e}`));
- }
-
- lock.unlock();
- return res.json(newSegments);
}
// Takes an array of arrays:
diff --git a/src/routes/postWarning.ts b/src/routes/postWarning.ts
index 3056aec..aed4094 100644
--- a/src/routes/postWarning.ts
+++ b/src/routes/postWarning.ts
@@ -42,53 +42,58 @@ export async function postWarning(req: Request, res: Response): Promise 0) {
return res.sendStatus(200);
diff --git a/src/routes/shadowBanUser.ts b/src/routes/shadowBanUser.ts
index 9920180..b0b5e8a 100644
--- a/src/routes/shadowBanUser.ts
+++ b/src/routes/shadowBanUser.ts
@@ -7,6 +7,7 @@ import { UserID } from "../types/user.model";
import { QueryCacher } from "../utils/queryCacher";
import { isUserVIP } from "../utils/isUserVIP";
import { parseCategories, parseDeArrowTypes } from "../utils/parseParams";
+import { Logger } from "../utils/logger";
export async function shadowBanUser(req: Request, res: Response): Promise {
const userID = req.query.userID as UserID;
@@ -36,42 +37,47 @@ export async function shadowBanUser(req: Request, res: Response): Promise ? AND "userID" = ?`, [ipLoggingFixedTime, userID])) as { timeSubmitted: number }[];
+ const ips = (await Promise.all(timeSubmitted.map((s) => {
+ return privateDB.prepare("all", `SELECT "hashedIP" FROM "sponsorTimes" WHERE "timeSubmitted" = ?`, [s.timeSubmitted]) as Promise<{ hashedIP: HashedIP }[]>;
+ }))).flat();
+
+ await Promise.all([...new Set(ips.map((ip) => ip.hashedIP))].map((ip) => {
+ return banIP(ip, enabled, unHideOldSubmissions, type, categories, deArrowTypes, true);
+ }));
+ }
+
+ if (result) {
+ res.sendStatus(result);
+ return;
+ }
+ } else if (hashedIP) {
+ const result = await banIP(hashedIP, enabled, unHideOldSubmissions, type, categories, deArrowTypes, banUsers);
+ if (result) {
+ res.sendStatus(result);
+ return;
+ }
+ }
+ return res.sendStatus(200);
+ } catch (e) {
+ Logger.error(e as string);
+ return res.sendStatus(500);
}
-
- if (userID) {
- const result = await banUser(userID, enabled, unHideOldSubmissions, type, categories, deArrowTypes);
-
- if (enabled && lookForIPs) {
- const ipLoggingFixedTime = 1675295716000;
- const timeSubmitted = (await db.prepare("all", `SELECT "timeSubmitted" FROM "sponsorTimes" WHERE "timeSubmitted" > ? AND "userID" = ?`, [ipLoggingFixedTime, userID])) as { timeSubmitted: number }[];
- const ips = (await Promise.all(timeSubmitted.map((s) => {
- return privateDB.prepare("all", `SELECT "hashedIP" FROM "sponsorTimes" WHERE "timeSubmitted" = ?`, [s.timeSubmitted]) as Promise<{ hashedIP: HashedIP }[]>;
- }))).flat();
-
- await Promise.all([...new Set(ips.map((ip) => ip.hashedIP))].map((ip) => {
- return banIP(ip, enabled, unHideOldSubmissions, type, categories, deArrowTypes, true);
- }));
- }
-
- if (result) {
- res.sendStatus(result);
- return;
- }
- } else if (hashedIP) {
- const result = await banIP(hashedIP, enabled, unHideOldSubmissions, type, categories, deArrowTypes, banUsers);
- if (result) {
- res.sendStatus(result);
- return;
- }
- }
- return res.sendStatus(200);
}
export async function banUser(userID: UserID, enabled: boolean, unHideOldSubmissions: boolean,
diff --git a/src/routes/verifyToken.ts b/src/routes/verifyToken.ts
index a06acf0..369a1a7 100644
--- a/src/routes/verifyToken.ts
+++ b/src/routes/verifyToken.ts
@@ -17,50 +17,55 @@ export const validateLicenseKeyRegex = (token: string) =>
export async function verifyTokenRequest(req: VerifyTokenRequest, res: Response): Promise {
const { query: { licenseKey } } = req;
- if (!licenseKey) {
- return res.status(400).send("Invalid request");
- } else if (!validateLicenseKeyRegex(licenseKey)) {
- // fast check for invalid licence key
- return res.status(200).send({
- allowed: false
- });
- }
-
- const tokens = (await privateDB.prepare("get", `SELECT "accessToken", "refreshToken", "expiresIn" from "oauthLicenseKeys" WHERE "licenseKey" = ?`
- , [licenseKey])) as {accessToken: string, refreshToken: string, expiresIn: number};
- if (tokens) {
- const identity = await getPatreonIdentity(tokens.accessToken);
-
- if (tokens.expiresIn < 15 * 24 * 60 * 60) {
- refreshToken(TokenType.patreon, licenseKey, tokens.refreshToken).catch((e) => Logger.error(`refresh token: ${e}`));
+ try {
+ if (!licenseKey) {
+ return res.status(400).send("Invalid request");
+ } else if (!validateLicenseKeyRegex(licenseKey)) {
+ // fast check for invalid licence key
+ return res.status(200).send({
+ allowed: false
+ });
}
- /* istanbul ignore else */
- if (identity) {
- const membership = identity.included?.[0]?.attributes;
- const allowed = !!membership && ((membership.patron_status === PatronStatus.active && membership.currently_entitled_amount_cents > 0)
- || (membership.patron_status === PatronStatus.former && membership.campaign_lifetime_support_cents > 300));
+ const tokens = (await privateDB.prepare("get", `SELECT "accessToken", "refreshToken", "expiresIn" from "oauthLicenseKeys" WHERE "licenseKey" = ?`
+ , [licenseKey])) as {accessToken: string, refreshToken: string, expiresIn: number};
+ if (tokens) {
+ const identity = await getPatreonIdentity(tokens.accessToken);
- return res.status(200).send({
- allowed
- });
+ if (tokens.expiresIn < 15 * 24 * 60 * 60) {
+ refreshToken(TokenType.patreon, licenseKey, tokens.refreshToken).catch((e) => Logger.error(`refresh token: ${e}`));
+ }
+
+ /* istanbul ignore else */
+ if (identity) {
+ const membership = identity.included?.[0]?.attributes;
+ const allowed = !!membership && ((membership.patron_status === PatronStatus.active && membership.currently_entitled_amount_cents > 0)
+ || (membership.patron_status === PatronStatus.former && membership.campaign_lifetime_support_cents > 300));
+
+ return res.status(200).send({
+ allowed
+ });
+ } else {
+ return res.status(500);
+ }
} else {
- return res.status(500);
- }
- } else {
- // Check Local
- const result = await privateDB.prepare("get", `SELECT "licenseKey" from "licenseKeys" WHERE "licenseKey" = ?`, [licenseKey]);
- if (result) {
- return res.status(200).send({
- allowed: true
- });
- } else {
- // Gumroad
- return res.status(200).send({
- allowed: await checkAllGumroadProducts(licenseKey)
- });
- }
+ // Check Local
+ const result = await privateDB.prepare("get", `SELECT "licenseKey" from "licenseKeys" WHERE "licenseKey" = ?`, [licenseKey]);
+ if (result) {
+ return res.status(200).send({
+ allowed: true
+ });
+ } else {
+ // Gumroad
+ return res.status(200).send({
+ allowed: await checkAllGumroadProducts(licenseKey)
+ });
+ }
+ }
+ } catch (e) {
+ Logger.error(e as string);
+ return res.status(500);
}
}