// @ts-check import axios, { AxiosError, AxiosResponse } from 'axios'; import fs from 'fs'; import fsPromises from 'fs/promises'; import path from 'path'; import { Request, Response } from 'express'; console.log(`[Login Module] src/login.ts file is being evaluated. __dirname is: ${__dirname}`); interface PastebinData { link?: string; [key: string]: any; // To accommodate if res.data is an object with more fields } interface LoginClientRequestBody { user: string; pass: string; } interface LoginApiPayload { user: string; pass: string; } interface LoginApiResponseData { token: string; userDetails: object; // Consider defining a more specific interface if the structure is known message: string; status: string; // e.g., "success" } function isLoginClientRequestBody(body: any): body is LoginClientRequestBody { if (body && typeof body === 'object' && typeof body.user === 'string' && body.user.length > 0 && typeof body.pass === 'string' && body.pass.length > 0) { return true; } return false; } const ACC_FILE_PATH: string = path.resolve(__dirname, '../models/data/acc.json'); const ACC_DIR_PATH: string = path.dirname(ACC_FILE_PATH); const api = { async getLink(): Promise { console.log("[Login API - getLink] Attempting to fetch link..."); try { const res: AxiosResponse = await axios.get('https://pastebin.com/raw/YtqNc7Yi'); let extractedLink: string | null = null; if (res.data && typeof res.data === 'object' && typeof res.data.link === 'string') { extractedLink = res.data.link; } else if (typeof res.data === 'string' && res.data.startsWith('http')) { extractedLink = res.data; } if (!extractedLink) { console.error("[Login API - getLink] Invalid/missing link in Pastebin response:", res.data); throw new Error('Invalid or missing link in Pastebin response data.'); } console.log("[Login API - getLink] Fetched link:", extractedLink); return extractedLink; } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); console.error("[Login API - getLink] Failed to get base link.", error.message, error.cause || error); throw new Error('Failed to get base link.', { cause: error }); } }, async login(body: LoginApiPayload): Promise { console.log("[Login API - login] Attempting external API login."); try { const link = await api.getLink(); console.log("[Login API - login] External API Link:", link); console.log("[Login API - login] Payload to external API:", body); const res: AxiosResponse = await axios.post(`${link}/signin`, body); console.log("[Login API - login] Response from external API:", res.data); return res.data; } catch (err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); console.error("[Login API - login] Error with /signin endpoint.", error.message, error.cause || error); if (axios.isAxiosError(error) && error.response) { console.error("[Login API - login] Axios error data:", error.response.data, "Status:", error.response.status); } throw new Error('Failed to contact/process signin endpoint.', { cause: error }); } }, }; interface LoginRouteParams { req: Request; // Request body is unknown, will use typeguard res: Response; } interface LoginExpressRouteModule { method: "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "all"; path: string; install: (params: LoginRouteParams) => Promise | void; } export const modules: LoginExpressRouteModule[] = [ { method: 'post', path: '/login', install: async ({ req, res }: LoginRouteParams): Promise => { try { const requestBody: unknown = req.body; if (isLoginClientRequestBody(requestBody)) { const clientData: LoginClientRequestBody = requestBody; const apiLoginPayload: LoginApiPayload = { user: clientData.user, pass: clientData.pass, }; const responseData: LoginApiResponseData = await api.login(apiLoginPayload); if (responseData && responseData.status === 'success' && responseData.token) { console.log("[Login Route] External login successful."); try { if (!fs.existsSync(ACC_DIR_PATH)) { await fsPromises.mkdir(ACC_DIR_PATH, { recursive: true }); } await fsPromises.writeFile(ACC_FILE_PATH, JSON.stringify(responseData, null, 2)); } catch (fileErr: unknown) { const fError = fileErr instanceof Error ? fileErr : new Error(String(fileErr)); console.error(`[Login Route] CRITICAL: Failed to write acc.json:`, fError); } res.json({ success: true, data: responseData }); } else { console.warn("[Login Route] External login failed or unexpected response:", responseData); res.status(401).json({ success: false, error: responseData?.message || 'Login failed.' }); } } else { console.warn("[Login Route] Validation failed: req.body does not conform to LoginClientRequestBody. Received:", requestBody); res.status(400).json({ success: false, error: 'Invalid request format: user and pass are required strings.' }); return; } } catch (err: unknown) { let error: Error & { cause?: unknown }; if (err instanceof Error) { error = err as Error & { cause?: unknown }; } else { error = new Error(String(err)) as Error & { cause?: unknown }; } let errorMessage = "An unknown error occurred."; let statusCode = 500; console.error(`[Login Route] Overall error:`, error.message, error.cause || error); const originalError: unknown = error.cause || error; if (axios.isAxiosError(originalError)) { const axiosError = originalError as AxiosError; // Type assertion errorMessage = axiosError.message; statusCode = axiosError.response?.status || 500; const responseDataError = axiosError.response?.data?.error || axiosError.response?.data?.message; if (responseDataError) { errorMessage = `Login API Error (${statusCode}): ${responseDataError}`; } } else if (originalError instanceof Error) { errorMessage = originalError.message || String(originalError); } else { errorMessage = String(originalError); } console.error(`[Login Route] Error to client: ${errorMessage}, Status: ${statusCode}`); if (!res.headersSent) { res.status(statusCode).json({ success: false, error: errorMessage }); } else { console.warn("[Login Route] Headers sent, cannot send error to client."); } } }, }, ];