diff --git a/package-lock.json b/package-lock.json index 466fb13..d43e10a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "auto-launch": "^5.0.5", - "axios": "^1.7.9", + "axios": "^1.13.6", "chalk": "^4.1.2", "console-table-printer": "^2.10.0", "electron-updater": "^6.3.9", @@ -21,7 +21,7 @@ "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.26.3", "cross-env": "^7.0.3", - "electron": "^34.2.0", + "electron": "^41.0.3", "electron-builder": "^25.1.8", "eslint": "^8.17.0", "eslint-config-prettier": "^10.0.1", @@ -1750,13 +1750,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.17.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", - "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", + "version": "24.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "node_modules/@types/parse-json": { @@ -2325,13 +2325,13 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -2813,6 +2813,19 @@ "node": ">=8" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3827,6 +3840,20 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3851,15 +3878,15 @@ } }, "node_modules/electron": { - "version": "34.2.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-34.2.0.tgz", - "integrity": "sha512-SYwBJNeXBTm1q/ErybQMUBZAYqEreBUqBwTrNkw1rV4YatDZk5Aittpcus3PPeC4UoI/tqmJ946uG8AKHTd6CA==", + "version": "41.0.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-41.0.3.tgz", + "integrity": "sha512-IDjx8liW1q+r7+MOip5W1Eo1eMwJzVObmYrd9yz2dPCkS7XlgLq3qPVMR80TpiROFp73iY30kTzMdpA6fEVs3A==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@electron/get": "^2.0.0", - "@types/node": "^20.9.0", + "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { @@ -4218,9 +4245,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">= 0.4" } @@ -4229,9 +4254,34 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", - "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { "node": ">= 0.4" } @@ -4910,9 +4960,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", @@ -4960,12 +5010,15 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -5029,10 +5082,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/functional-red-black-tree": { "version": "1.0.1", @@ -5079,6 +5135,30 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -5088,6 +5168,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -5202,9 +5295,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">= 0.4" }, @@ -5277,6 +5368,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -5284,6 +5402,18 @@ "dev": true, "license": "ISC" }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -7133,6 +7263,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9018,9 +9157,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index e41dd5a..79df1da 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "devDependencies": { "@babel/plugin-transform-modules-commonjs": "^7.26.3", "cross-env": "^7.0.3", - "electron": "^34.2.0", + "electron": "^41.0.3", "electron-builder": "^25.1.8", "eslint": "^8.17.0", "eslint-config-prettier": "^10.0.1", @@ -40,7 +40,7 @@ }, "dependencies": { "auto-launch": "^5.0.5", - "axios": "^1.7.9", + "axios": "^1.13.6", "chalk": "^4.1.2", "console-table-printer": "^2.10.0", "electron-updater": "^6.3.9", diff --git a/src/cli/main.js b/src/cli/main.js index 20d99e9..45b83c8 100644 --- a/src/cli/main.js +++ b/src/cli/main.js @@ -12,7 +12,7 @@ storage.setDataPath(config.storageDataPath); (async () => { const settings = await Settings.build("cli", config.defaultSettings); - translation.init(settings, config.websiteUrl).then(async () => { + translation.init(settings).then(async () => { await session.init(settings); if (!session.current()) { diff --git a/src/config.js b/src/config.js index 1805d40..51a71df 100644 --- a/src/config.js +++ b/src/config.js @@ -10,7 +10,7 @@ const storageDataPath = env.isPortable ? portableStorage : installationStorage; module.exports = { appName, - websiteUrl: "https://giftseeker.ru/", + steamUrl: "https://steamcommunity.com/", storageDataPath, defaultSettings: { translation: "en_US", diff --git a/src/core/services/follx.js b/src/core/services/follx.js deleted file mode 100644 index 44e3247..0000000 --- a/src/core/services/follx.js +++ /dev/null @@ -1,98 +0,0 @@ -const { parse } = require("node-html-parser"); - -const BaseService = require("./base-service"); -const translation = require("../../modules/translation"); - -class Follx extends BaseService { - constructor(settingsStorage) { - super(settingsStorage, { - websiteUrl: "https://follx.com", - authPageUrl: "https://follx.com/logIn", - winsPageUrl: "https://follx.com/giveaways/won", - authContent: "/account", - }); - } - - async getUserInfo() { - return this.http.get(this.websiteUrl).then(response => { - const document = parse(response.data); - - return { - avatar: document - .querySelector("span.avatar") - .toString() - .match(/http.*jpg/)[0], - username: document.querySelector(".username").structuredText, - value: document.querySelector(".energy span").structuredText, - }; - }); - } - - async seekService() { - let currentPage = 1; - const processPages = this.getConfig("pages", 1); - - do { - await this.enterOnPage(currentPage); - currentPage++; - } while (currentPage <= processPages); - } - - async enterOnPage(page) { - const document = await this.http - .get(`${this.websiteUrl}/giveaways`, { - page, - }) - .then(response => parse(response.data)); - - const csrfToken = document - .querySelectorAll("meta") - .filter(node => node.getAttribute("name") === "csrf-token")[0] - .getAttribute("content"); - - const giveaways = document - .querySelectorAll(".giveaway_card") - .map(card => ({ - url: card.querySelector(".head_info a").getAttribute("href"), - name: card.querySelector(".head_info").getAttribute("title"), - have: !!card.querySelector("span.have"), - entered: !!card.querySelector(".entered"), - entries: card.querySelector(".entries").structuredText, - })) - .filter(ga => !ga.have && !ga.entered); - - for (const giveaway of giveaways) { - if (!this.isStarted()) { - break; - } - - const entered = await this.enterGiveaway(giveaway, csrfToken); - - if (entered) { - this.log({ - text: `${translation.get("service.entered_in")} #link#`, - anchor: giveaway.name, - url: giveaway.url, - }); - } - await this.entryInterval(); - } - } - - async enterGiveaway(giveaway, csrfToken) { - return this.http({ - url: `${giveaway.url}/action`, - method: "post", - data: "action=enter", - responseType: "json", - headers: { - "X-Requested-With": "XMLHttpRequest", - "X-CSRF-TOKEN": csrfToken, - }, - }) - .then(res => res.data.entries > giveaway.entries) - .catch(() => false); - } -} - -module.exports = Follx; diff --git a/src/electron/main.js b/src/electron/main.js index 3c95834..dad840b 100644 --- a/src/electron/main.js +++ b/src/electron/main.js @@ -68,17 +68,17 @@ app.disableHardwareAcceleration(); } }); - const logout = () => { - session.flush(); + const logout = async () => { + await session.flush(); windows.main().hide(); windows.auth().show(); - windows.auth().webContents.executeJavaScript("setLogoutState()"); + windows.auth().webContents.send("user-logout"); }; // prevent the tray icon from being destroyed by the GC // eslint-disable-next-line no-unused-vars - const trayIcon = createTrayIcon(browser); + const trayIcon = createTrayIcon(); startApp(authWindow, settings); @@ -127,7 +127,7 @@ app.disableHardwareAcceleration(); ipcMain.on("window-loaded", ({ sender }, windowName) => { sender.send("window-initial-data", { - websiteUrl: config.websiteUrl, + steamUrl: config.steamUrl, userAgent: { default: config.defaultSettings.user_agent, initial: session.getSessionInstance().getUserAgent(), @@ -304,7 +304,7 @@ const checkSessionIsAlive = async (session, ipcRenderer) => { const startApp = (authWindow, settings) => { translation - .init(settings, config.websiteUrl) + .init(settings) .then(() => { authWindow.loadFile("./src/electron/web/auth.html"); @@ -335,18 +335,9 @@ const startApp = (authWindow, settings) => { }); }; -const createTrayIcon = browser => { +const createTrayIcon = () => { const trayIcon = new Tray(nativeImage.createFromPath(config.appIcon)); - const trayMenu = Menu.buildFromTemplate([ - { - label: "Open Website", - click: () => { - browser.openUrl(config.websiteUrl); - }, - }, - { type: "separator" }, - { role: "quit" }, - ]); + const trayMenu = Menu.buildFromTemplate([{ role: "quit" }]); trayIcon.setToolTip(`${config.appName} ${currentBuild}`); trayIcon.setContextMenu(trayMenu); diff --git a/src/electron/session.js b/src/electron/session.js index 69e1233..37f13c8 100644 --- a/src/electron/session.js +++ b/src/electron/session.js @@ -1,6 +1,6 @@ const { session } = require("electron"); const axios = require("axios"); -const { websiteUrl } = require("../config"); +const { steamUrl } = require("../config"); const create = (settings, sessionName) => { let accountInfo = { loggedIn: false }; @@ -11,33 +11,37 @@ const create = (settings, sessionName) => { _session.setUserAgent(newUserAgent); }); - const extractCookiesByDomain = url => { + const extractCookiesByUrl = async url => { const domain = new URL(url).hostname.replace("www.", ""); - return _session.cookies - .get({ domain }) + return _session.cookies.get({ domain }); + }; + + const extractCookiesStringByUrl = url => { + return extractCookiesByUrl(url) .then(cookies => cookies.map(cookie => cookie.name + "=" + cookie.value).join("; "), ) .catch(() => ""); }; - const checkUserIsLoggedIn = async currentBuild => { - const cookies = await extractCookiesByDomain(websiteUrl); + const checkUserIsLoggedIn = async () => { + const cookieString = await extractCookiesStringByUrl(steamUrl); + accountInfo = await axios - .get(`${websiteUrl}api/userData?ver=${currentBuild}`, { - headers: { Cookie: cookies }, + .get(steamUrl, { + headers: { Cookie: cookieString }, }) .then(({ data }) => { - if (data.response) { + if (!checkSteamLoggedIn(data)) { return { - loggedIn: true, - userData: data.response, + loggedIn: false, }; } return { - loggedIn: false, + loggedIn: true, + userData: extractSteamData(data), }; }) .catch(() => ({ @@ -48,20 +52,29 @@ const create = (settings, sessionName) => { return accountInfo; }; - const flush = async () => { - accountInfo = { loggedIn: false }; - const cookies = await extractCookiesByDomain(websiteUrl); + const checkSteamLoggedIn = html => html.indexOf("login/home/?goto=") === -1; - return axios.get(`${websiteUrl}logout`, { - headers: { Cookie: cookies }, - }); + const extractSteamData = html => { + const [, avatar, username] = html.match( + /(https:\/\/avatars.*jpg).*alt=.(.*)"/, + ); + + return { + avatar, + username, + }; + }; + + const flush = async () => { + await _session.clearStorageData(); }; return { flush, getSessionInstance: () => _session, checkUserIsLoggedIn, - extractCookiesByDomain, + extractCookiesByUrl, + extractCookiesStringByUrl, getAccountInfo: () => accountInfo, }; }; diff --git a/src/electron/web/auth.html b/src/electron/web/auth.html index e5f7d46..a92511f 100644 --- a/src/electron/web/auth.html +++ b/src/electron/web/auth.html @@ -1,4 +1,4 @@ - + @@ -56,10 +56,11 @@ onclick="document.querySelector('#choice-lang').classList.remove('visible')" > - + diff --git a/src/electron/web/main.html b/src/electron/web/main.html index 30fe222..0848576 100644 --- a/src/electron/web/main.html +++ b/src/electron/web/main.html @@ -1,4 +1,4 @@ - + @@ -123,8 +123,11 @@ ); ipcRenderer.on("window-initial-data", async (event, { translations }) => { + console.log(translations); updatePagePhrases(translations.phrases); }); + + ipcRenderer.send("window-loaded", "main-window"); diff --git a/src/electron/web/scripts/windows/auth.js b/src/electron/web/scripts/windows/auth.js index 5747dda..9c8dc7a 100644 --- a/src/electron/web/scripts/windows/auth.js +++ b/src/electron/web/scripts/windows/auth.js @@ -15,15 +15,13 @@ const setAuthStatus = (phraseKey, suffix) => { (suffix ?? ""); }; -const setLogoutState = () => { +ipcRenderer.on("user-logout", () => { authButton.classList.remove("disabled"); setAuthStatus("auth.ses_not_found"); -}; - -ipcRenderer.send("window-loaded", "auth-window"); +}); ipcRenderer.on("window-initial-data", async (event, data) => { - const { websiteUrl, translations } = data; + const { steamUrl, translations } = data; updatePagePhrases(translations.phrases); initTranslationSelector(translations); @@ -36,9 +34,9 @@ ipcRenderer.on("window-initial-data", async (event, data) => { setAuthStatus("auth.check"); await browser.authorizationWindow( - websiteUrl, - `${websiteUrl}logIn`, - "/account", + steamUrl, + `${steamUrl}login/home`, + "account_name", ); ipcRenderer.send("authorization-window-closed"); @@ -61,5 +59,3 @@ ipcRenderer.on("authorization-check-result", (event, authCheckResult) => { ipcRenderer.on("translation-changed", async (event, translations) => { updatePagePhrases(translations.phrases); }); - -export { setLogoutState }; diff --git a/src/electron/web/scripts/windows/main.js b/src/electron/web/scripts/windows/main.js index 35a28a4..60de3ab 100644 --- a/src/electron/web/scripts/windows/main.js +++ b/src/electron/web/scripts/windows/main.js @@ -3,15 +3,15 @@ const { ipcRenderer } = require("electron"); const logoutButton = document.querySelector(".logout-button"); -const renderUserInfo = userInfo => { +const renderUserInfo = userData => { document.querySelector("#head .user-bar .avatar").style.backgroundImage = - `url("${userInfo.avatar}")`; + `url("${userData.avatar}")`; document.querySelector("#head .user-bar .username").innerText = - userInfo.username; + userData.username; }; const initSettingsSection = initialData => { - const { currentBuild, websiteUrl, translations, settings } = initialData; + const { currentBuild, translations, settings } = initialData; initTranslationSelector(translations); @@ -30,10 +30,13 @@ const initSettingsSection = initialData => { const infoLinks = document.querySelector(".content-item .info-links"); - const websiteLink = document.createElement("button"); - websiteLink.classList.add("open-website"); - websiteLink.dataset.link = websiteUrl; - websiteLink.innerText = "GiftSeeker.RU"; + const githubLink = document.createElement("button"); + githubLink.classList.add("open-website"); + githubLink.dataset.link = "https://github.com/codesprut/giftseeker"; + githubLink.dataset.lang = "settings.source_code"; + githubLink.style.marginLeft = "7px"; + + infoLinks.appendChild(githubLink); const steamLink = document.createElement("button"); steamLink.classList.add("open-website"); @@ -41,15 +44,7 @@ const initSettingsSection = initialData => { steamLink.dataset.lang = "settings.steam_group"; steamLink.style.marginLeft = "7px"; - const donationLink = document.createElement("button"); - donationLink.classList.add("open-website"); - donationLink.dataset.link = new URL("/donation", websiteUrl).href; - donationLink.dataset.lang = "settings.donation"; - donationLink.style.marginLeft = "7px"; - - infoLinks.appendChild(websiteLink); infoLinks.appendChild(steamLink); - infoLinks.appendChild(donationLink); document .querySelectorAll("[data-menu-id=settings] .setter:not(select)") @@ -128,8 +123,6 @@ const initServicesSwitcher = settings => { servicesSwitcherScroll(ev.wheelDelta > 0 ? 20 : -20); }; -ipcRenderer.send("window-loaded", "main-window"); - setInterval(() => { ipcRenderer.send("check-session-is-alive"); }, 300000); diff --git a/src/electron/windows/browser.js b/src/electron/windows/browser.js index adb10ac..4b855f0 100644 --- a/src/electron/windows/browser.js +++ b/src/electron/windows/browser.js @@ -65,7 +65,7 @@ const create = (session, parentWindow, onClose) => { window.once("close", () => { window.webContents.removeAllListeners("did-finish-load"); - const cookies = session.extractCookiesByDomain(websiteUrl); + const cookies = session.extractCookiesStringByUrl(websiteUrl); resolve(cookies); }); diff --git a/src/modules/translation.js b/src/modules/translation.js index e9c9f28..2ff46c1 100644 --- a/src/modules/translation.js +++ b/src/modules/translation.js @@ -1,81 +1,14 @@ -const storage = require("./json-storage"); -const https = require("https"); -const axios = require("axios"); +const translationFiles = require("../resources/translations"); const settingsKey = "translation"; -const axiosConfig = { - httpsAgent: new https.Agent({ - rejectUnauthorized: false, - }), -}; let settings; -let translations = {}; - -const downloadTranslation = async filename => { - return axios - .get(`/trans/${filename}`, axiosConfig) - .then(({ data }) => storage.saveFile(filename, data)); -}; - -const updateTranslations = async () => { - const translations = await axios - .get(`/api/translations`, axiosConfig) - .then(res => res.data.translations) - .catch(() => false); - - if (!translations) { - return; - } - - return Promise.allSettled(translations.map(it => updateTranslation(it))); -}; - -const updateTranslation = async translation => { - const { name, contentLength } = translation; - - if (!storage.filesExists(name)) { - return downloadTranslation(name); - } - - const fileContent = await storage.loadFile(name); - const localContentLength = JSON.stringify(fileContent).length; +let translations = Object.fromEntries( + translationFiles.map(file => [file.lang.culture, file]), +); - if (localContentLength !== contentLength) { - return downloadTranslation(name); - } -}; - -const loadTranslations = async () => { - const translationsList = []; - const storageFiles = await storage.filesList(); - - for (const filename of storageFiles) { - if (filename.indexOf("locale.") >= 0) { - translationsList.push(filename.replace(".json", "")); - } - } - - if (!translationsList.length) { - throw new Error(`No translations found on storage`); - } - - const loadedTranslations = await storage.loadMany(translationsList); - - return Object.fromEntries( - loadedTranslations.map(translation => [ - translation.lang.culture, - translation, - ]), - ); -}; - -const init = async (settingsInstance, downloadHost) => { +const init = async settingsInstance => { settings = settingsInstance; - axiosConfig.baseURL = downloadHost; - - await updateTranslations(); - translations = await loadTranslations(); let selectedTranslation = current(); diff --git a/src/resources/translations/en_US.json b/src/resources/translations/en_US.json new file mode 100644 index 0000000..0249dfd --- /dev/null +++ b/src/resources/translations/en_US.json @@ -0,0 +1,134 @@ +{ + "lang": { + "culture": "en_US", + "name": "English" + }, + "auth": { + "check": "Looking for a session...", + "session": "Session - ", + "ses_not_found": "Session not found", + "connection_error": "Connection error", + "browser_loading": "loading", + "or": "or", + "steam_login": "Login via Steam", + "enter_cookies": "Enter Cookies", + "lng_choice_title": "Change translation", + "choose_lang": "Select a language", + "no_avail_trans": "Other translations are not available", + "go_back": "Back" + }, + "ui": { + "menu": { + "services": "Services", + "settings": "Settings" + }, + "logout": "Sign out", + "upd_progress": "Updating", + "upd_downloaded": "The update is downloaded and will be installed after you close the app" + }, + "service": { + "started": "Bot is running", + "stopped": "Bot is stopped", + "loaded": "Service is loaded", + "logs": "Log", + "settings": "Settings", + "clear_log": "Clear the log", + "log_cleared": "Log is cleared", + "open_website": "Go to the site", + "btn_start": "Start", + "btn_stop": "Stop", + "btn_checking": "Checking", + "btn_awaiting": "Awaiting", + "connection_error": "Unable to get established connection with the service...", + "session_expired": "Session expired", + "connection_lost": "Connection is lost", + "timer": "Timer (minutes)", + "timer_title": "Frequency of visits in minutes", + "interval": "Interval (seconds)", + "interval_title": "Interval between giveaway joinings", + "interval_from": "Min interval (seconds)", + "interval_from_title": "Minimum interval between giveaway joinings", + "interval_to": "Max interval (seconds)", + "interval_to_title": "Maximum interval between giveaway joinings", + "entered_in": "Entered in", + "pages": "Pages", + "pages_title": "How many first pages should be checked for the available giveaways", + "cant_start": "Couldn't autostart - session not found", + "reconnect_in_5_min": "Auto reconnect after 5 minutes", + "follx": { + "value_label": "Energy" + }, + "indiegala": { + "value_label": "GalaCoins" + }, + "opiumpulses": { + "on_start_reminder": "The current version of the program only joins free giveaways", + "value_label": "Points" + }, + "steamgifts": { + "value_label": "Points", + "cost": "Cost", + "ending": "GA ending (minutes)", + "ending_title": "Don't join giveaways before the end of which more than the specified time. 0 - without any restrictions", + "chance": "Chance", + "sort_by_chance": "Sort by winning chance", + "sort_by_chance_title": "Sort by winning chance", + "min_chance": "Min. chance(%)", + "min_chance_title": "Min. chance to join giveaways. 0 - ignore a chance", + "min_level": "Min. level", + "min_level_title": "Don't join giveaways where required level less than the selected", + "points_reserve": "Reserve of points", + "points_reserve_title": "Reserve of points. 0 - without reserve", + "min_cost": "Min. Cost", + "min_cost_title": "Don't join giveaways with a cost lower than your set min.cost.", + "max_cost": "Max. Cost", + "max_cost_title": "Don't join giveaways with a cost higher than your set max.cost. 0 - without any restrictions", + "ignore_on_wish": "Ignore settings for wishlist", + "ignore_on_wish_title": "Ignore level and max cost settings for games in the wishlist", + "reserve_on_wish": "Spend reserve on wishlist", + "reserve_on_wish_title": "Spend reserved points on games in the wishlist", + "wishlist_only": "Wishlist only", + "wishlist_only_title": "Join giveaways only from the wishlist" + }, + "magicdrop": { + "free_case_entered": "Joined free case giveaway" + }, + "justcase": { + "free_case_entered": "Joined free case giveaway" + }, + "ggplayers": { + "value_label": "GG Points" + } + }, + "profile": { + "logout_btn": "Logout", + "start_with_os": "Run at startup", + "start_minimized": "Minimize at startup", + "minimize_on_close": "Minimize on close", + "autostart": "Autostart of services", + "donation": "Donation", + "forum": "Forum", + "steam_group": "Steam group", + "build_version": "Build ver." + }, + "settings": { + "start_with_os": "Run at startup", + "start_minimized": "Minimize at startup", + "minimize_on_close": "Minimize on close", + "autostart": "Autostart of services", + "donation": "Donation", + "forum": "Forum", + "source_code": "Source code", + "steam_group": "Steam group", + "use_system_browser": "Open links through system browser", + "build_version": "Build ver." + }, + "cli": { + "services": { + "setting-get": "Get {0} setting value", + "setting-set": "Set {0} setting value", + "start": "Start {0} service in current session", + "stop": "Stop {0} service in current session" + } + } +} diff --git a/src/resources/translations/index.js b/src/resources/translations/index.js new file mode 100644 index 0000000..7fcc9ae --- /dev/null +++ b/src/resources/translations/index.js @@ -0,0 +1 @@ +module.exports = [require("./en_US.json"), require("./ru_RU.json")]; diff --git a/src/resources/translations/ru_RU.json b/src/resources/translations/ru_RU.json new file mode 100644 index 0000000..0a87cc6 --- /dev/null +++ b/src/resources/translations/ru_RU.json @@ -0,0 +1,126 @@ +{ + "lang": { + "culture": "ru_RU", + "name": "Русский" + }, + "auth": { + "check": "Поиск сессии...", + "session": "Cессия - ", + "ses_not_found": "Сессия не найдена", + "connection_error": "Ошибка соединения", + "browser_loading": "загрузка", + "or": "или", + "steam_login": "Войти через Steam", + "enter_cookies": "Указать Cookies", + "lng_choice_title": "Смена языка", + "choose_lang": "Выберите язык", + "no_avail_trans": "Другие переводы отсутствуют", + "go_back": "Назад" + }, + "ui": { + "menu": { + "services": "Сервисы", + "settings": "Настройки" + }, + "logout": "Выход из аккаунта", + "upd_progress": "Загрузка обновления", + "upd_downloaded": "Обновление загружено и будет установлено после закрытия приложения" + }, + "service": { + "started": "Бот запущен", + "stopped": "Бот остановлен", + "loaded": "Сервис загружен", + "logs": "Лог действий", + "settings": "Настройки", + "clear_log": "Очистить лог", + "log_cleared": "Лог очищен", + "open_website": "На сайт", + "btn_start": "Старт", + "btn_stop": "Стоп", + "btn_checking": "Проверка", + "btn_awaiting": "Ожидание", + "connection_error": "Ошибка соединения с сервисом...", + "session_expired": "Сессия истекла", + "connection_lost": "Соединение потеряно", + "timer": "Таймер (мин)", + "timer_title": "Частота посещения сайта", + "interval": "Интервал (сек)", + "interval_title": "Интервал между вступлениями в розыгрыши", + "interval_from": "Интервал от (сек)", + "interval_from_title": "Минимальный интервал между вступлениями в розыгрыши", + "interval_to": "Интервал до (сек)", + "interval_to_title": "Максимальный интервал между вступлениями в розыгрыши", + "entered_in": "Вступил в", + "pages": "Страницы", + "pages_title": "Количество страниц на которых проверять раздачи", + "cant_start": "Автостарт невозможен - сессия не найдена", + "reconnect_in_5_min": "Автоматическое переподключение через 5 минут", + "follx": { + "value_label": "Энергия" + }, + "indiegala": { + "value_label": "GalaCoins" + }, + "opiumpulses": { + "on_start_reminder": "Текущая версия программы присоединяется только к бесплатным раздачам", + "value_label": "Points" + }, + "steamgifts": { + "value_label": "Points", + "cost": "Стоимость", + "chance": "Шанс", + "ending": "До окончания (мин)", + "ending_title": "Не вступать в раздачи до окончания которых больше установленного времени. 0 - не учитывать время", + "sort_by_chance": "Сортировать по шансу победы", + "sort_by_chance_title": "Сортировать по шансу победы", + "min_chance": "Мин. шанс(%)", + "min_chance_title": "Минимальный шанс для участия в раздаче. 0 - не учитывать шанс", + "min_level": "Мин. уровень", + "min_level_title": "Не вступать в розыгрыши с требуемым уровнем, меньше установленного", + "points_reserve": "Резерв очков", + "points_reserve_title": "Количество очков которое запрещено тратить. 0 - без резерва", + "min_cost": "Мин. стоимость", + "min_cost_title": "Не вступать в раздачи со стоимостью ниже установленной.", + "max_cost": "Макс. стоимость", + "max_cost_title": "Не вступать в раздачи со стоимостью выше установленной. 0 - вступать в любые", + "ignore_on_wish": "Игнорировать настройки для списка желаемого", + "ignore_on_wish_title": "Не учитывать настройки уровня и стоимости для списка желаемого", + "reserve_on_wish": "Тратить резерв на список желаемого", + "reserve_on_wish_title": "Использовать зарезервированные очки для раздачи из списка желаемого", + "wishlist_only": "Только список желаемого", + "wishlist_only_title": "Вступать в раздачи игр которые в вашем списке желаемого" + }, + "magicdrop": { + "free_case_entered": "Принял участие в розыгрыше бесплатного кейса" + }, + "justcase": { + "free_case_entered": "Принял участие в розыгрыше бесплатного кейса" + }, + "ggplayers": { + "value_label": "GG Points" + } + }, + "profile": { + "logout_btn": "Выход", + "start_with_os": "Запускать вместе с системой", + "start_minimized": "Сворачивать при запуске", + "minimize_on_close": "Сворачивать при закрытии", + "autostart": "Автостарт сервисов", + "donation": "Помощь проекту", + "forum": "Форум", + "steam_group": "Группа в Steam", + "build_version": "Версия сборки" + }, + "settings": { + "start_with_os": "Запускать вместе с системой", + "start_minimized": "Сворачивать при запуске", + "minimize_on_close": "Сворачивать при закрытии", + "autostart": "Автостарт сервисов", + "donation": "Помощь проекту", + "forum": "Форум", + "source_code": "Исходный код", + "steam_group": "Группа в Steam", + "use_system_browser": "Открывать ссылки через браузер", + "build_version": "Версия сборки" + } +}