convertified

This commit is contained in:
bootunloader
2025-12-31 08:08:55 +02:00
parent 2a122e1551
commit 9fa4a0c113
5 changed files with 637 additions and 676 deletions

7
pyapi/start.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
# FastAPI Proxy Server Startup Script
# This script starts the FastAPI proxy server that bypasses Cloudflare
echo "Starting FastAPI Proxy Server on port 3070..."
uv run python -m fastapi dev --port=3070 main.py

View File

@@ -1,4 +1,4 @@
import { getRandomUserAgent, getULID, sleep } from "$lib/utils"; import { getULID, sleep } from "$lib/utils";
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import type { BookingEntry, Draw, LooseApiUser } from "$lib/utils/data.types"; import type { BookingEntry, Draw, LooseApiUser } from "$lib/utils/data.types";
import { rng } from "$lib/utils/rng"; import { rng } from "$lib/utils/rng";
@@ -13,317 +13,300 @@ import { rng } from "$lib/utils/rng";
// } // }
export const testIfSessionIsValid = async (jwt: string) => { export const testIfSessionIsValid = async (jwt: string) => {
try { try {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/get-balance?userId=6339`, `${constants.PROXY_API_URL}/v1/user/get-balance?userId=6339&authorization=${encodeURIComponent(jwt)}`,
{ {
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
Authorization: jwt, },
"User-Agent": getRandomUserAgent(), },
}, );
}, if (res.status !== 200) {
); return false;
if (res.status !== 200) {
return false;
}
const rj = (await res.json()) as {
code: number;
success: boolean;
message: string;
data: any;
time: string;
};
return rj.code == 200 && rj.success;
} catch (err) {
console.log(err);
return false;
} }
const rj = (await res.json()) as {
code: number;
success: boolean;
message: string;
data: any;
time: string;
};
return rj.code == 200 && rj.success;
} catch (err) {
console.log(err);
return false;
}
}; };
export const getSessionToken = async (payload: { export const getSessionToken = async (payload: {
userId: string; userId: string;
password: string; password: string;
verifyToken: string; verifyToken: string;
code: string; code: string;
userType: number; userType: number;
}): Promise<{ ok: boolean; message: string }> => { }): Promise<{ ok: boolean; message: string }> => {
console.log("Requesting..."); console.log("Requesting...");
const res = await fetch(`${constants.SCRAP_API_URL}/v1/auth/login`, { const res = await fetch(`${constants.PROXY_API_URL}/v1/auth/login`, {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), },
"Content-Type": "application/json", body: JSON.stringify(payload),
}, });
body: JSON.stringify(payload), const out = await res.json();
}); if (out.code !== 200) {
const out = await res.json(); return { ok: false, message: out.message };
if (out.code !== 200) { }
return { ok: false, message: out.message }; return { ok: true, message: out.data.token };
}
return { ok: true, message: out.data.token };
}; };
export async function getUsersBalance(userId: number, jwt: string) { export async function getUsersBalance(userId: number, jwt: string) {
try { try {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/get-balance?userId=${userId}`, `${constants.PROXY_API_URL}/v1/user/get-balance?userId=${userId}&authorization=${encodeURIComponent(jwt)}`,
{ {
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
Authorization: jwt, },
"User-Agent": getRandomUserAgent(), },
}, );
}, const rj = (await res.json()) as {
); code: number;
const rj = (await res.json()) as { success: boolean;
code: number; message: string;
success: boolean; data: { allowedBalance: number; balance: number };
message: string; time: string;
data: { allowedBalance: number; balance: number }; };
time: string; if (res.status !== 200 || rj.code !== 200 || !rj.success) {
}; console.log(`[!] Error getting balance for ${userId} :: ${JSON.stringify(rj)}`);
if (res.status !== 200 || rj.code !== 200 || !rj.success) { return false;
console.log(
`[!] Error getting balance for ${userId} :: ${JSON.stringify(rj)}`,
);
return false;
}
return rj.data.balance;
} catch (err) {
console.log(err);
return false;
} }
return rj.data.balance;
} catch (err) {
console.log(err);
return false;
}
} }
export const getDealers = async (jwt: string, distributor_ids: string[]) => { export const getDealers = async (jwt: string, distributor_ids: string[]) => {
try { try {
// // Create an array of promises for each fetch request // // Create an array of promises for each fetch request
const requests = distributor_ids.map(async (did) => { const requests = distributor_ids.map(async (did) => {
await sleep(rng(100, 10000)); await sleep(rng(100, 10000));
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/dealer-list`, `${constants.PROXY_API_URL}/v1/user/dealer-list?authorization=${encodeURIComponent(jwt)}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
"Content-Type": "application/json", },
"User-Agent": getRandomUserAgent(), body: JSON.stringify({
Authorization: jwt, page: 1,
}, pageSize: 999999,
body: JSON.stringify({ parentDistributor: parseInt(did),
page: 1, }),
pageSize: 999999, },
parentDistributor: parseInt(did), );
}), const data = (await res.json()) as {
}, code: number;
); success: boolean;
const data = (await res.json()) as { message: string;
code: number; data: {
success: boolean; items: any[];
message: string; total: number;
data: {
items: any[];
total: number;
};
};
if (data.code !== 200 || !data.success) {
return {
dealers: [],
ok: false,
code: data.code,
message: data.message,
};
}
const dealers = data.data.items.map((item) => item.dealer);
// dumpDealers(dealers);
return {
dealers,
ok: res.status === 200 && data.success,
code: data.code,
message: data.message,
};
});
// // Wait for all promises to resolve
const responses = await Promise.all(requests);
const dealers: LooseApiUser[] = [];
const errors: { message: string }[] = [];
for (const res of responses) {
if (res.code !== 200 || !res.ok) {
errors.push({ message: res.message });
continue;
}
for (const dealer of res.dealers) {
dealers.push(dealer);
}
}
// fs.writeFileSync("dealers.json", JSON.stringify(dealers, null, 2));
return { dealers, errors };
} catch (err) {
console.error(err);
return {
dealers: [],
errors: [{ message: "An error occured during fetching dealers" }],
}; };
};
if (data.code !== 200 || !data.success) {
return {
dealers: [],
ok: false,
code: data.code,
message: data.message,
};
}
const dealers = data.data.items.map((item) => item.dealer);
// dumpDealers(dealers);
return {
dealers,
ok: res.status === 200 && data.success,
code: data.code,
message: data.message,
};
});
// // Wait for all promises to resolve
const responses = await Promise.all(requests);
const dealers: LooseApiUser[] = [];
const errors: { message: string }[] = [];
for (const res of responses) {
if (res.code !== 200 || !res.ok) {
errors.push({ message: res.message });
continue;
}
for (const dealer of res.dealers) {
dealers.push(dealer);
}
} }
// fs.writeFileSync("dealers.json", JSON.stringify(dealers, null, 2));
return { dealers, errors };
} catch (err) {
console.error(err);
return {
dealers: [],
errors: [{ message: "An error occured during fetching dealers" }],
};
}
}; };
export const getDistributors = async (jwt: string) => { export const getDistributors = async (jwt: string) => {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/distributor-list`, `${constants.PROXY_API_URL}/v1/user/distributor-list?authorization=${encodeURIComponent(jwt)}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
Authorization: jwt, },
"Content-Type": "application/json", body: JSON.stringify({
"User-Agent": getRandomUserAgent(), page: 1,
}, pageSize: 999999,
body: JSON.stringify({ parentDistributor: 15,
page: 1, }),
pageSize: 999999, },
parentDistributor: 15, );
}), const json = (await res.json()) as {
}, code: number;
); success: boolean;
const json = (await res.json()) as { message: string;
code: number; data: { total: number; items: any[] };
success: boolean; };
message: string;
data: { total: number; items: any[] };
};
if (!json.data.items || json.code !== 200 || !json.success) { if (!json.data.items || json.code !== 200 || !json.success) {
return { ok: false, message: json.message, data: [] }; return { ok: false, message: json.message, data: [] };
} }
// fs.writeFileSync( // fs.writeFileSync(
// "distributors.json", // "distributors.json",
// JSON.stringify(json.data.items, null, 2), // JSON.stringify(json.data.items, null, 2),
// ); // );
// dumpDistributors(json.data.items.map((item) => item.distributor)); // dumpDistributors(json.data.items.map((item) => item.distributor));
return { return {
ok: true, ok: true,
message: "", message: "",
data: json.data.items.map((item) => item.distributor), data: json.data.items.map((item) => item.distributor),
}; };
}; };
export const getDraws = async (jwt: string) => { export const getDraws = async (jwt: string) => {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/draw/list-my?userId=15`, `${constants.PROXY_API_URL}/v1/draw/list-my?userId=15&authorization=${encodeURIComponent(jwt)}`,
{ {
method: "GET", method: "GET",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, "Content-Type": "application/json",
Authorization: jwt, },
"Content-Type": "application/json", },
"User-Agent": getRandomUserAgent(), );
}, type J = {
}, code: number;
); success: boolean;
type J = { message: string;
code: number; data: { draw: Draw }[];
success: boolean; };
message: string; let decoded = (await res.json()) as { data: J };
data: { draw: Draw }[]; const json = (decoded.data.success ? decoded.data : decoded) as any as J;
}; if (json.code !== 200 || !json.success || !json.data) {
let decoded = (await res.json()) as { data: J }; return { ok: false, message: json.message, data: [] };
const json = (decoded.data.success ? decoded.data : decoded) as any as J; }
if (json.code !== 200 || !json.success || !json.data) { return {
return { ok: false, message: json.message, data: [] }; ok: true,
} message: "",
return { data: json.data.map((item) => item.draw),
ok: true, };
message: "",
data: json.data.map((item) => item.draw),
};
}; };
export const getData = async ( export const getData = async (
jwt: string, jwt: string,
userIds: number[], userIds: number[],
drawId: number, drawId: number,
chosenDate: string, chosenDate: string,
) => { ) => {
const res = await fetch(`${constants.SCRAP_API_URL}/v1/book/list2`, { const res = await fetch(
method: "POST", `${constants.PROXY_API_URL}/v1/book/list2?authorization=${encodeURIComponent(jwt)}`,
headers: { {
...constants.SCRAP_API_BASE_HEADERS, method: "POST",
Authorization: jwt, headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), },
}, body: JSON.stringify({
body: JSON.stringify({ userType: 3,
userType: 3, userIds,
userIds, drawId: drawId,
drawId: drawId, startDate: chosenDate,
startDate: chosenDate, endDate: chosenDate,
endDate: chosenDate, beAdmin: false,
beAdmin: false, containImported: false,
containImported: false, keyword: "",
keyword: "", }),
}), },
}); );
type J = { type J = {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { book: BookingEntry; user: any }[]; data: { book: BookingEntry; user: any }[];
}; };
let decoded = (await res.json()) as { data: J }; let decoded = (await res.json()) as { data: J };
const json = (decoded.data.success ? decoded.data : decoded) as any as J; const json = (decoded.data.success ? decoded.data : decoded) as any as J;
if (json.code !== 200 || !json.success || !json.data) { if (json.code !== 200 || !json.success || !json.data) {
return { ok: false, message: json.message, data: [] }; return { ok: false, message: json.message, data: [] };
} }
return { ok: true, message: "", data: json.data.map((e) => e.book) }; return { ok: true, message: "", data: json.data.map((e) => e.book) };
}; };
export const mockGetUserData = async ( export const mockGetUserData = async (
jwt: string, jwt: string,
userIds: number[], userIds: number[],
drawId: number, drawId: number,
chosenDate: string, chosenDate: string,
) => { ) => {
const entries = [] as BookingEntry[]; const entries = [] as BookingEntry[];
const rng = (min: number, max: number) => { const rng = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
}; };
const randomCeil = rng(10_000, 200_000); const randomCeil = rng(10_000, 200_000);
await sleep(rng(100, 1000)); await sleep(rng(100, 1000));
for (let i = 0; i < randomCeil; i++) { for (let i = 0; i < randomCeil; i++) {
const _f = rng(5, 50); const _f = rng(5, 50);
const _s = rng(5, 50); const _s = rng(5, 50);
const f = _f - (_f % 5); const f = _f - (_f % 5);
const s = _s - (_s % 5); const s = _s - (_s % 5);
entries.push({ entries.push({
id: getULID(), id: getULID(),
bookDate: chosenDate, bookDate: chosenDate,
changedBalance: f + s, changedBalance: f + s,
first: f, first: f,
second: s, second: s,
dealerId: userIds[rng(0, userIds.length - 1)], dealerId: userIds[rng(0, userIds.length - 1)],
distributorId: 6339, distributorId: 6339,
drawId: drawId, drawId: drawId,
number: rng(0, 9999).toString(), number: rng(0, 9999).toString(),
requestId: new Date().getTime().toString(), requestId: new Date().getTime().toString(),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
sheetId: "0", sheetId: "0",
sheetName: "", sheetName: "",
}); });
} }
return { ok: true, message: "", data: entries }; return { ok: true, message: "", data: entries };
}; };

View File

@@ -1,334 +1,312 @@
import { getRandomUserAgent, getULID, sleep } from "$lib/utils"; import { getULID, sleep } from "$lib/utils";
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import type { import type {
ApiPostUserWithParent, ApiPostUserWithParent,
APISession, APISession,
Draw, Draw,
PostDataEntry, PostDataEntry,
ServerError, ServerError,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import Fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent";
export type APIResponse<T> = { export type APIResponse<T> = {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: T; data: T;
time: string; time: string;
}; };
export function buildMessageString( export function buildMessageString(
ptr: number, ptr: number,
rows: PostDataEntry[], rows: PostDataEntry[],
distributorId: number, distributorId: number,
dealerId: number, dealerId: number,
drawId: number, drawId: number,
date: string, date: string,
) { ) {
let message = ""; let message = "";
let jumpSize = Math.floor(Math.random() * 490) + 10; let jumpSize = Math.floor(Math.random() * 490) + 10;
let total = 0; let total = 0;
let startReqId = new Date().getTime(); let startReqId = new Date().getTime();
let x = 0; let x = 0;
for (let j = ptr; j < ptr + jumpSize; j++) { for (let j = ptr; j < ptr + jumpSize; j++) {
if (j >= rows.length) { if (j >= rows.length) {
break; break;
}
const row = rows[j];
const reqId = startReqId + x++;
const no = row.number.trim();
const f = row.first;
const s = row.second;
const mTotal = f + s;
if (mTotal <= 0) {
continue;
}
total += mTotal;
message += `${reqId},${distributorId},${dealerId},${drawId},${date},${no},${f},${s},${mTotal};`;
} }
message = message.slice(0, -1); const row = rows[j];
return { message, total, jumped: ptr + jumpSize }; const reqId = startReqId + x++;
const no = row.number.trim();
const f = row.first;
const s = row.second;
const mTotal = f + s;
if (mTotal <= 0) {
continue;
}
total += mTotal;
message += `${reqId},${distributorId},${dealerId},${drawId},${date},${no},${f},${s},${mTotal};`;
}
message = message.slice(0, -1);
return { message, total, jumped: ptr + jumpSize };
} }
export async function postDataToApi(payload: { export async function postDataToApi(payload: {
sessions: Record<string, APISession>; sessions: Record<string, APISession>;
draw: Draw; draw: Draw;
data: PostDataEntry[]; data: PostDataEntry[];
users: ApiPostUserWithParent[]; users: ApiPostUserWithParent[];
}) { }) {
const responses = [] as APIResponse<[]>[]; const responses = [] as APIResponse<[]>[];
const responsesIds = [] as { requestId: number; bookId: string }[]; const responsesIds = [] as { requestId: number; bookId: string }[];
let failedResponses = 0; let failedResponses = 0;
let successResponses = 0; let successResponses = 0;
console.log(`[+] Sending ${payload.data.length} requests...`); console.log(`[+] Sending ${payload.data.length} requests...`);
const dataByUser = {} as Record<string, PostDataEntry[]>; const dataByUser = {} as Record<string, PostDataEntry[]>;
for (const row of payload.data) { for (const row of payload.data) {
const userId = row.userId ?? ""; const userId = row.userId ?? "";
if (userId.length < 1) { if (userId.length < 1) {
console.log(`[!] User not found for request ${row.userId}`); console.log(`[!] User not found for request ${row.userId}`);
return { return {
ok: false, ok: false,
detail: "User not found to post data with", detail: "User not found to post data with",
errors: [ errors: [{ message: "User not found for request" }] as ServerError,
{ message: "User not found for request" }, };
] as ServerError,
};
}
if (!dataByUser[userId]) {
dataByUser[userId] = [];
}
dataByUser[userId].push(row);
} }
if (!dataByUser[userId]) {
dataByUser[userId] = [];
}
dataByUser[userId].push(row);
}
try { try {
const userPromises = Object.entries(dataByUser).map( const userPromises = Object.entries(dataByUser).map(async ([userId, userData]) => {
async ([userId, userData]) => { const session = payload.sessions[userId];
const session = payload.sessions[userId]; const usr = payload.users.find((u) => u.userId === userId);
const usr = payload.users.find((u) => u.userId === userId); if (!usr) {
if (!usr) { throw new Error(`User ${userId} not found for posting to api`);
throw new Error( }
`User ${userId} not found for posting to api`,
);
}
const distId = usr.parentDistributor ?? 0; const distId = usr.parentDistributor ?? 0;
const dealerId = Number(session.userId.split(":")[1]); const dealerId = Number(session.userId.split(":")[1]);
const drawId = Number(payload.draw.id.split(":")[1]); const drawId = Number(payload.draw.id.split(":")[1]);
const date = new Date().toISOString().split("T")[0]; const date = new Date().toISOString().split("T")[0];
let ptr = 0; let ptr = 0;
const userResponseIds = [] as { const userResponseIds = [] as {
requestId: number; requestId: number;
bookId: string; bookId: string;
}[];
while (ptr < userData.length) {
let tries = 0;
while (tries < 3) {
let { message, total, jumped } = buildMessageString(
ptr,
userData,
distId,
dealerId,
drawId,
date,
);
const res = await sendBatchRequest(session, dealerId, payload.draw, total, message);
let rj:
| APIResponse<{
bookDtos: {
bookId: string;
requestId: number;
}[]; }[];
}>
while (ptr < userData.length) { | undefined = undefined;
let tries = 0; try {
while (tries < 3) { rj = (await res.json()) as any;
let { message, total, jumped } = buildMessageString( } catch (err) {
ptr, console.log("Encountered error while parsing post response");
userData, console.log(res.status, err);
distId, }
dealerId, if (rj && rj.code === 200 && res.status === 200) {
drawId, ptr = jumped;
date, userResponseIds.push(
); ...rj.data.bookDtos.map((b) => ({
const res = await sendBatchRequest( requestId: b.requestId as number,
session, bookId: b.bookId as string,
dealerId, })),
payload.draw, );
total, successResponses++;
message, break;
); }
let rj: console.log("Failed to send send post request");
| APIResponse<{ console.log(res.status, rj);
bookDtos: { failedResponses++;
bookId: string; tries++;
requestId: number;
}[];
}>
| undefined = undefined;
try {
rj = (await res.json()) as any;
} catch (err) {
console.log(
"Encountered error while parsing post response",
);
console.log(res.status, err);
}
if (rj && rj.code === 200 && res.status === 200) {
ptr = jumped;
userResponseIds.push(
...rj.data.bookDtos.map((b) => ({
requestId: b.requestId as number,
bookId: b.bookId as string,
})),
);
successResponses++;
break;
}
console.log("Failed to send send post request");
console.log(res.status, rj);
failedResponses++;
tries++;
}
if (tries >= 3) {
if (userResponseIds.length > 0) {
const out = await deleteAllBookedEntries({
data: userResponseIds,
closeTime: payload.draw.closeTime,
dealerId,
drawId,
session,
});
console.log(await out.text());
}
throw new Error(
`Failed to send data to api for user ${userId}`,
);
}
}
return userResponseIds;
},
);
// Wait for all user processes to complete
const results = await Promise.allSettled(userPromises);
// Process results
let hasErrors = false;
results.forEach((result) => {
if (result.status === "fulfilled") {
responsesIds.push(...result.value);
} else {
hasErrors = true;
console.log(`[!] Error processing user`);
console.log(result.reason);
}
});
if (hasErrors) {
return {
ok: false,
detail: "Failed to post data to API for some users",
errors: [
{ message: "Failed to post data to API for some users" },
] as ServerError,
};
} }
console.log(`[+] Finished sending ${payload.data.length} requests`); if (tries >= 3) {
console.log(`[?] Failed responses: ${failedResponses}`); if (userResponseIds.length > 0) {
console.log(`[?] Success responses: ${successResponses}`); const out = await deleteAllBookedEntries({
return { data: userResponseIds,
ok: true, closeTime: payload.draw.closeTime,
detail: "Successfully sent data to api", dealerId,
data: responses, drawId,
}; session,
} catch (err) { });
console.log(err); console.log(await out.text());
return { }
ok: false, throw new Error(`Failed to send data to api for user ${userId}`);
detail: "Failed to send data to api", }
}; }
return userResponseIds;
});
// Wait for all user processes to complete
const results = await Promise.allSettled(userPromises);
// Process results
let hasErrors = false;
results.forEach((result) => {
if (result.status === "fulfilled") {
responsesIds.push(...result.value);
} else {
hasErrors = true;
console.log(`[!] Error processing user`);
console.log(result.reason);
}
});
if (hasErrors) {
return {
ok: false,
detail: "Failed to post data to API for some users",
errors: [{ message: "Failed to post data to API for some users" }] as ServerError,
};
} }
console.log(`[+] Finished sending ${payload.data.length} requests`);
console.log(`[?] Failed responses: ${failedResponses}`);
console.log(`[?] Success responses: ${successResponses}`);
return {
ok: true,
detail: "Successfully sent data to api",
data: responses,
};
} catch (err) {
console.log(err);
return {
ok: false,
detail: "Failed to send data to api",
};
}
} }
async function sendBatchRequest( async function sendBatchRequest(
session: APISession, session: APISession,
dealerId: number, dealerId: number,
draw: Draw, draw: Draw,
changedBalance: number, changedBalance: number,
body: string, body: string,
) { ) {
return Fetch(`${constants.SCRAP_API_URL}/v1/book/add-multiple`, { return fetch(
agent: new HttpsProxyAgent(`http://${session.ip}`), `${constants.PROXY_API_URL}/v1/book/add-multiple?authorization=${encodeURIComponent(session.sessionToken)}`,
method: "POST", {
headers: { method: "POST",
...constants.SCRAP_API_BASE_HEADERS, headers: {
"Content-Type": "application/json;charset=UTF-8", "Content-Type": "application/json",
Authorization: session.sessionToken, },
"User-Agent": getRandomUserAgent(), body: JSON.stringify({
}, dealerId,
body: JSON.stringify({ drawId: Number(draw.id.split(":")[1]),
dealerId, closeTime: draw.closeTime,
drawId: Number(draw.id.split(":")[1]), date: new Date().toISOString().split("T")[0],
closeTime: draw.closeTime, changedBalance,
date: new Date().toISOString().split("T")[0], insertData: body,
changedBalance, }),
insertData: body, },
}), );
});
} }
async function mockSendBatchRequest( async function mockSendBatchRequest(
session: APISession, session: APISession,
dealerId: number, dealerId: number,
draw: Draw, draw: Draw,
changedBalance: number, changedBalance: number,
body: string, body: string,
) { ) {
console.log("----- Sending batch request ------"); console.log("----- Sending batch request ------");
console.log(session); console.log(session);
console.log(dealerId); console.log(dealerId);
console.log(draw); console.log(draw);
console.log(changedBalance); console.log(changedBalance);
console.log(body); console.log(body);
console.log("----------------------------------"); console.log("----------------------------------");
// between 5 to 20 ms // between 5 to 20 ms
await sleep(Math.floor(Math.random() * 1000) + 50); await sleep(Math.floor(Math.random() * 1000) + 50);
// if (Math.random() < 0.005) { // if (Math.random() < 0.005) {
// return new Response( // return new Response(
// JSON.stringify({ // JSON.stringify({
// code: 500, // code: 500,
// success: false, // success: false,
// message: "Failed", // message: "Failed",
// data: {}, // data: {},
// time: new Date().toISOString(), // time: new Date().toISOString(),
// }), // }),
// { // {
// status: 500, // status: 500,
// headers: { "Content-Type": "application/json" }, // headers: { "Content-Type": "application/json" },
// statusText: "Failed", // statusText: "Failed",
// }, // },
// ); // );
// } // }
return new Response( return new Response(
JSON.stringify({ JSON.stringify({
code: 200, code: 200,
success: true, success: true,
message: "Success", message: "Success",
data: { data: {
bookDtos: body.split(";").map((e) => { bookDtos: body.split(";").map((e) => {
return { return {
bookId: getULID(), bookId: getULID(),
requestId: +e.split(",")[0], requestId: +e.split(",")[0],
}; };
}),
},
time: new Date().toISOString(),
}), }),
{ },
status: 200, time: new Date().toISOString(),
headers: { "Content-Type": "application/json" }, }),
statusText: "OK", {
}, status: 200,
); headers: { "Content-Type": "application/json" },
statusText: "OK",
},
);
} }
async function deleteAllBookedEntries({ async function deleteAllBookedEntries({
session, session,
data, data,
dealerId, dealerId,
drawId, drawId,
closeTime, closeTime,
}: { }: {
session: APISession; session: APISession;
data: { bookId: string; requestId: number }[]; data: { bookId: string; requestId: number }[];
dealerId: number; dealerId: number;
drawId: number; drawId: number;
closeTime: string; closeTime: string;
}) { }) {
return Fetch(`${constants.SCRAP_API_URL}/v1/book/delete-multiple`, { return fetch(
agent: new HttpsProxyAgent(`http://${session.ip}`), `${constants.PROXY_API_URL}/v1/book/delete-multiple?authorization=${encodeURIComponent(session.sessionToken)}`,
method: "POST", {
headers: { method: "POST",
...constants.SCRAP_API_BASE_HEADERS, headers: {
"Content-Type": "application/json;charset=UTF-8", "Content-Type": "application/json",
Authorization: session.sessionToken, },
"User-Agent": getRandomUserAgent(), body: JSON.stringify({
}, bookIds: data.map((e) => e.bookId),
body: JSON.stringify({ closeTime,
bookIds: data.map((e) => e.bookId), dealerId,
closeTime, drawId,
dealerId, }),
drawId, },
}), );
});
} }
// export async function postDataToApi(payload: { // export async function postDataToApi(payload: {

View File

@@ -1,116 +1,108 @@
import { getSessionToken } from "$lib/server/external/api.scraping.helpers";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "../t";
import { constants } from "$lib/utils/constants";
import { getUUID } from "$lib/utils";
import { z } from "zod";
import { dbApiUser } from "$lib/server/db/apiuser.db"; import { dbApiUser } from "$lib/server/db/apiuser.db";
import type { ServerError } from "$lib/utils/data.types"; import { getSessionToken } from "$lib/server/external/api.scraping.helpers";
import { import {
isSessionValidInStore, isSessionValidInStore,
removeSessionFromStore, removeSessionFromStore,
setSessionToRedis, setSessionToRedis,
} from "$lib/server/utils/session.service"; } from "$lib/server/utils/session.service";
import { getUUID } from "$lib/utils";
import { constants } from "$lib/utils/constants";
import type { ServerError } from "$lib/utils/data.types";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import { createTRPCRouter, protectedProcedure } from "../t";
export const apiAuthRouter = createTRPCRouter({ export const apiAuthRouter = createTRPCRouter({
getCaptcha: protectedProcedure.mutation(async () => { getCaptcha: protectedProcedure.mutation(async () => {
try { try {
const uuid = getUUID(); const uuid = getUUID();
const res = await fetch( const res = await fetch(`${constants.PROXY_API_URL}/verify/image?uuid=${uuid}`, {
`${constants.SCRAP_API_URL}/verify/image?uuid=${uuid}`, headers: {
{ "Content-Type": "application/json",
headers: { },
...constants.SCRAP_API_BASE_HEADERS, });
Accept: "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", const bloob = await res.blob();
}, const imageBuffer = Buffer.from(await bloob.arrayBuffer());
}, const base64String = imageBuffer.toString("base64");
); return { id: uuid, image: base64String };
const bloob = await res.blob(); } catch (err) {
const imageBuffer = Buffer.from(await bloob.arrayBuffer()); console.log(err);
const base64String = imageBuffer.toString("base64"); throw new TRPCError({
return { id: uuid, image: base64String }; code: "INTERNAL_SERVER_ERROR",
} catch (err) { message: "Error getting captcha image.",
console.log(err); });
throw new TRPCError({ }
code: "INTERNAL_SERVER_ERROR", }),
message: "Error getting captcha image.",
}); getNewSession: protectedProcedure
.input(
z.object({
captchaId: z.string().min(1),
captchaAnswer: z.string().min(1),
userId: z.string().optional(),
}),
)
.mutation(async ({ input }) => {
console.log("[=] Getting new session... ", input);
try {
const { captchaId, captchaAnswer } = input;
let { userId, userType, password } = await dbApiUser.getRandomDistributor();
if (input.userId) {
let _user = await dbApiUser.getUserById(input.userId);
console.log("[=] User :: ", _user?.userId);
if (!_user) {
return {
success: false,
errors: [{ message: "User not found." }],
};
}
userId = _user.userId;
userType = _user.userType;
password = _user.password;
} }
console.log(`[=] Getting session token for user ${userId}...`);
const token = await getSessionToken({
code: captchaAnswer,
verifyToken: captchaId,
userId: userId,
userType: userType,
password: password,
});
console.log("[=] Token Response :: ", JSON.stringify(token, null, 2));
if (!token.ok) {
return {
success: false,
errors: [{ message: token.message }],
};
}
await setSessionToRedis(token.message, input.userId ?? "");
return { success: true, errors: [] as ServerError };
} catch (err) {
console.log(err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Error getting new session.",
});
}
}), }),
getNewSession: protectedProcedure isApiSessionValid: protectedProcedure
.input( .input(
z.object({ z.object({
captchaId: z.string().min(1), checkingUserSession: z.boolean(),
captchaAnswer: z.string().min(1), userId: z.string().optional(),
userId: z.string().optional(), }),
}), )
) .query(async ({ input }) => {
.mutation(async ({ input }) => { return { valid: await isSessionValidInStore(input.userId) };
console.log("[=] Getting new session... ", input); }),
try {
const { captchaId, captchaAnswer } = input;
let { userId, userType, password } =
await dbApiUser.getRandomDistributor();
if (input.userId) { logoutUser: protectedProcedure
let _user = await dbApiUser.getUserById(input.userId); .input(z.object({ userId: z.string().optional() }))
console.log("[=] User :: ", _user?.userId); .mutation(async ({ input }) => {
if (!_user) { const { userId } = input;
return { await removeSessionFromStore(userId);
success: false, return { success: true, errors: [] as ServerError };
errors: [{ message: "User not found." }], }),
};
}
userId = _user.userId;
userType = _user.userType;
password = _user.password;
}
console.log(`[=] Getting session token for user ${userId}...`);
const token = await getSessionToken({
code: captchaAnswer,
verifyToken: captchaId,
userId: userId,
userType: userType,
password: password,
});
console.log(
"[=] Token Response :: ",
JSON.stringify(token, null, 2),
);
if (!token.ok) {
return {
success: false,
errors: [{ message: token.message }],
};
}
await setSessionToRedis(token.message, input.userId ?? "");
return { success: true, errors: [] as ServerError };
} catch (err) {
console.log(err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Error getting new session.",
});
}
}),
isApiSessionValid: protectedProcedure
.input(
z.object({
checkingUserSession: z.boolean(),
userId: z.string().optional(),
}),
)
.query(async ({ input }) => {
return { valid: await isSessionValidInStore(input.userId) };
}),
logoutUser: protectedProcedure
.input(z.object({ userId: z.string().optional() }))
.mutation(async ({ input }) => {
const { userId } = input;
await removeSessionFromStore(userId);
return { success: true, errors: [] as ServerError };
}),
}); });

View File

@@ -4,6 +4,7 @@ export const constants = {
POST_SESSION_KEY: "postsession", POST_SESSION_KEY: "postsession",
LAST_FETCHED_KEY: "LAST_FETCHED", LAST_FETCHED_KEY: "LAST_FETCHED",
SCRAP_API_URL: "https://gamebooking24.com/lottery-api", SCRAP_API_URL: "https://gamebooking24.com/lottery-api",
PROXY_API_URL: "http://localhost:3070",
SCRAP_API_SESSION_KEY: "SRAJWT", SCRAP_API_SESSION_KEY: "SRAJWT",
SCRAP_API_BASE_HEADERS: { SCRAP_API_BASE_HEADERS: {
Host: "gamebooking24.com", Host: "gamebooking24.com",