File size: 7,069 Bytes
6b825ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// @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<string> {
    console.log("[Login API - getLink] Attempting to fetch link...");
    try {
      const res: AxiosResponse<PastebinData | string> = 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<LoginApiResponseData> {
    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<LoginApiResponseData> = 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<any, any, unknown>; // 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> | void;
}

export const modules: LoginExpressRouteModule[] = [
  {
    method: 'post',
    path: '/login',
    install: async ({ req, res }: LoginRouteParams): Promise<void> => {
      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<any>; // 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.");
        }
      }
    },
  },
];