Nick: cleaner functions to handle authenticated requests that dont require ifs everywhere
This commit is contained in:
parent
aa89e2e8b5
commit
5cdbf3a0ac
@ -1,10 +1,15 @@
|
|||||||
import { parseApi } from "../../src/lib/parseApi";
|
import { parseApi } from "../../src/lib/parseApi";
|
||||||
import { getRateLimiter } from "../../src/services/rate-limiter";
|
import { getRateLimiter } from "../../src/services/rate-limiter";
|
||||||
import { RateLimiterMode } from "../../src/types";
|
import { AuthResponse, RateLimiterMode } from "../../src/types";
|
||||||
import { supabase_service } from "../../src/services/supabase";
|
import { supabase_service } from "../../src/services/supabase";
|
||||||
|
import { withAuth } from "../../src/lib/withAuth";
|
||||||
|
|
||||||
|
|
||||||
export async function authenticateUser(
|
export async function authenticateUser(req, res, mode?: RateLimiterMode) : Promise<AuthResponse> {
|
||||||
|
return withAuth(supaAuthenticateUser)(req, res, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function supaAuthenticateUser(
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
mode?: RateLimiterMode
|
mode?: RateLimiterMode
|
||||||
@ -15,15 +20,6 @@ export async function authenticateUser(
|
|||||||
status?: number;
|
status?: number;
|
||||||
}> {
|
}> {
|
||||||
|
|
||||||
console.log(process.env)
|
|
||||||
|
|
||||||
if(process.env.USE_DB_AUTHENTICATION === "false"){
|
|
||||||
console.log("WARNING - YOU'RE bypassing Authentication");
|
|
||||||
return { success: true};
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("USING SUPABASE AUTH");
|
|
||||||
|
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = req.headers.authorization;
|
||||||
if (!authHeader) {
|
if (!authHeader) {
|
||||||
return { success: false, error: "Unauthorized", status: 401 };
|
return { success: false, error: "Unauthorized", status: 401 };
|
||||||
|
@ -8,8 +8,7 @@ import { addWebScraperJob } from "../../src/services/queue-jobs";
|
|||||||
|
|
||||||
export async function crawlController(req: Request, res: Response) {
|
export async function crawlController(req: Request, res: Response) {
|
||||||
try {
|
try {
|
||||||
|
console.log("hello");
|
||||||
console.log("hello")
|
|
||||||
const { success, team_id, error, status } = await authenticateUser(
|
const { success, team_id, error, status } = await authenticateUser(
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
@ -19,12 +18,10 @@ export async function crawlController(req: Request, res: Response) {
|
|||||||
return res.status(status).json({ error });
|
return res.status(status).json({ error });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.USE_DB_AUTHENTICATION === "true") {
|
const { success: creditsCheckSuccess, message: creditsCheckMessage } =
|
||||||
const { success: creditsCheckSuccess, message: creditsCheckMessage } =
|
await checkTeamCredits(team_id, 1);
|
||||||
await checkTeamCredits(team_id, 1);
|
if (!creditsCheckSuccess) {
|
||||||
if (!creditsCheckSuccess) {
|
return res.status(402).json({ error: "Insufficient credits" });
|
||||||
return res.status(402).json({ error: "Insufficient credits" });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = req.body.url;
|
const url = req.body.url;
|
||||||
@ -45,7 +42,6 @@ export async function crawlController(req: Request, res: Response) {
|
|||||||
returnOnlyUrls: true,
|
returnOnlyUrls: true,
|
||||||
},
|
},
|
||||||
pageOptions: pageOptions,
|
pageOptions: pageOptions,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const docs = await a.getDocuments(false, (progress) => {
|
const docs = await a.getDocuments(false, (progress) => {
|
||||||
|
@ -41,7 +41,6 @@ export async function scrapeHelper(
|
|||||||
return { success: true, error: "No page found", returnCode: 200 };
|
return { success: true, error: "No page found", returnCode: 200 };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.USE_DB_AUTHENTICATION === "true") {
|
|
||||||
const { success, credit_usage } = await billTeam(
|
const { success, credit_usage } = await billTeam(
|
||||||
team_id,
|
team_id,
|
||||||
filteredDocs.length
|
filteredDocs.length
|
||||||
@ -54,7 +53,6 @@ export async function scrapeHelper(
|
|||||||
returnCode: 402,
|
returnCode: 402,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
19
apps/api/src/lib/withAuth.ts
Normal file
19
apps/api/src/lib/withAuth.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { AuthResponse } from "../../src/types";
|
||||||
|
|
||||||
|
export function withAuth<T extends AuthResponse, U extends any[]>(
|
||||||
|
originalFunction: (...args: U) => Promise<T>
|
||||||
|
) {
|
||||||
|
return async function (...args: U): Promise<T> {
|
||||||
|
if (process.env.USE_DB_AUTHENTICATION === "false") {
|
||||||
|
console.warn("WARNING - You're bypassing authentication");
|
||||||
|
return { success: true } as T;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return await originalFunction(...args);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in withAuth function: ", error);
|
||||||
|
return { success: false, error: error.message } as T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,7 +1,12 @@
|
|||||||
|
import { withAuth } from "../../lib/withAuth";
|
||||||
import { supabase_service } from "../supabase";
|
import { supabase_service } from "../supabase";
|
||||||
|
|
||||||
const FREE_CREDITS = 100;
|
const FREE_CREDITS = 100;
|
||||||
|
|
||||||
export async function billTeam(team_id: string, credits: number) {
|
export async function billTeam(team_id: string, credits: number) {
|
||||||
|
return withAuth(supaBillTeam)(team_id, credits);
|
||||||
|
}
|
||||||
|
export async function supaBillTeam(team_id: string, credits: number) {
|
||||||
if (team_id === "preview") {
|
if (team_id === "preview") {
|
||||||
return { success: true, message: "Preview team, no credits used" };
|
return { success: true, message: "Preview team, no credits used" };
|
||||||
}
|
}
|
||||||
@ -52,8 +57,11 @@ export async function billTeam(team_id: string, credits: number) {
|
|||||||
return { success: true, credit_usage };
|
return { success: true, credit_usage };
|
||||||
}
|
}
|
||||||
|
|
||||||
// if team has enough credits for the operation, return true, else return false
|
|
||||||
export async function checkTeamCredits(team_id: string, credits: number) {
|
export async function checkTeamCredits(team_id: string, credits: number) {
|
||||||
|
return withAuth(supaCheckTeamCredits)(team_id, credits);
|
||||||
|
}
|
||||||
|
// if team has enough credits for the operation, return true, else return false
|
||||||
|
export async function supaCheckTeamCredits(team_id: string, credits: number) {
|
||||||
if (team_id === "preview") {
|
if (team_id === "preview") {
|
||||||
return { success: true, message: "Preview team, no credits used" };
|
return { success: true, message: "Preview team, no credits used" };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
|
||||||
// SupabaseService class initializes the Supabase client conditionally based on environment variables.
|
// SupabaseService class initializes the Supabase client conditionally based on environment variables.
|
||||||
class SupabaseService {
|
class SupabaseService {
|
||||||
@ -7,15 +7,17 @@ class SupabaseService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
const supabaseUrl = process.env.SUPABASE_URL;
|
const supabaseUrl = process.env.SUPABASE_URL;
|
||||||
const supabaseServiceToken = process.env.SUPABASE_SERVICE_TOKEN;
|
const supabaseServiceToken = process.env.SUPABASE_SERVICE_TOKEN;
|
||||||
|
|
||||||
// Only initialize the Supabase client if both URL and Service Token are provided.
|
// Only initialize the Supabase client if both URL and Service Token are provided.
|
||||||
if (process.env.USE_DB_AUTHENTICATION === "false") {
|
if (process.env.USE_DB_AUTHENTICATION === "false") {
|
||||||
|
|
||||||
// Warn the user that Authentication is disabled by setting the client to null
|
// Warn the user that Authentication is disabled by setting the client to null
|
||||||
console.warn("\x1b[33mAuthentication is disabled. Supabase client will not be initialized.\x1b[0m");
|
console.warn(
|
||||||
|
"\x1b[33mAuthentication is disabled. Supabase client will not be initialized.\x1b[0m"
|
||||||
|
);
|
||||||
this.client = null;
|
this.client = null;
|
||||||
} else if (!supabaseUrl || !supabaseServiceToken) {
|
} else if (!supabaseUrl || !supabaseServiceToken) {
|
||||||
console.error("\x1b[31mSupabase environment variables aren't configured correctly. Supabase client will not be initialized. Fix ENV configuration or disable DB authentication with USE_DB_AUTHENTICATION env variable\x1b[0m");
|
console.error(
|
||||||
|
"\x1b[31mSupabase environment variables aren't configured correctly. Supabase client will not be initialized. Fix ENV configuration or disable DB authentication with USE_DB_AUTHENTICATION env variable\x1b[0m"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this.client = createClient(supabaseUrl, supabaseServiceToken);
|
this.client = createClient(supabaseUrl, supabaseServiceToken);
|
||||||
}
|
}
|
||||||
@ -29,21 +31,26 @@ class SupabaseService {
|
|||||||
|
|
||||||
// Using a Proxy to handle dynamic access to the Supabase client or service methods.
|
// Using a Proxy to handle dynamic access to the Supabase client or service methods.
|
||||||
// This approach ensures that if Supabase is not configured, any attempt to use it will result in a clear error.
|
// This approach ensures that if Supabase is not configured, any attempt to use it will result in a clear error.
|
||||||
export const supabase_service: SupabaseClient = new Proxy(new SupabaseService(), {
|
export const supabase_service: SupabaseClient = new Proxy(
|
||||||
get: function (target, prop, receiver) {
|
new SupabaseService(),
|
||||||
const client = target.getClient();
|
{
|
||||||
// If the Supabase client is not initialized, intercept property access to provide meaningful error feedback.
|
get: function (target, prop, receiver) {
|
||||||
if (client === null) {
|
const client = target.getClient();
|
||||||
console.error("Attempted to access Supabase client when it's not configured.");
|
// If the Supabase client is not initialized, intercept property access to provide meaningful error feedback.
|
||||||
return () => {
|
if (client === null) {
|
||||||
throw new Error("Supabase client is not configured.");
|
console.error(
|
||||||
};
|
"Attempted to access Supabase client when it's not configured."
|
||||||
}
|
);
|
||||||
// Direct access to SupabaseService properties takes precedence.
|
return () => {
|
||||||
if (prop in target) {
|
throw new Error("Supabase client is not configured.");
|
||||||
return Reflect.get(target, prop, receiver);
|
};
|
||||||
}
|
}
|
||||||
// Otherwise, delegate access to the Supabase client.
|
// Direct access to SupabaseService properties takes precedence.
|
||||||
return Reflect.get(client, prop, receiver);
|
if (prop in target) {
|
||||||
|
return Reflect.get(target, prop, receiver);
|
||||||
|
}
|
||||||
|
// Otherwise, delegate access to the Supabase client.
|
||||||
|
return Reflect.get(client, prop, receiver);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}) as unknown as SupabaseClient;
|
) as unknown as SupabaseClient;
|
||||||
|
@ -25,7 +25,6 @@ export interface WebScraperOptions {
|
|||||||
origin?: string;
|
origin?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface FirecrawlJob {
|
export interface FirecrawlJob {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
@ -40,8 +39,6 @@ export interface FirecrawlJob {
|
|||||||
origin: string;
|
origin: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export enum RateLimiterMode {
|
export enum RateLimiterMode {
|
||||||
Crawl = "crawl",
|
Crawl = "crawl",
|
||||||
CrawlStatus = "crawl-status",
|
CrawlStatus = "crawl-status",
|
||||||
@ -49,4 +46,9 @@ export enum RateLimiterMode {
|
|||||||
Preview = "preview",
|
Preview = "preview",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface AuthResponse {
|
||||||
|
success: boolean;
|
||||||
|
team_id?: string;
|
||||||
|
error?: string;
|
||||||
|
status?: number;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user