Skip to content

Commit

Permalink
V1.5.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Revadike committed May 31, 2021
1 parent 0eecf53 commit c12675c
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 194 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
29 changes: 17 additions & 12 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
{
"env": {
"browser": true,
"node": true,
"es6": true
"es6": true,
"es2017": true,
"es2020": true,
"es2021": true
},
"extends": "eslint:recommended",
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2018
"requireConfigFile": false
},
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": ["error", "consistent"],
"array-bracket-newline": ["error", { "multiline": true }],
"array-bracket-spacing": ["error", "never", { "arraysInArrays": true }],
"array-callback-return": "error",
"array-element-newline": ["error", "consistent"],
"array-element-newline": ["error", {
"ArrayExpression": "consistent",
"ArrayPattern": { "multiline": true }
}],
"arrow-body-style": "error",
"arrow-parens": ["error", "as-needed"],
"arrow-parens": "error",
"arrow-spacing": "error",
"block-scoped-var": "error",
"block-spacing": "error",
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"camelcase": "error",
"class-methods-use-this": "error",
"comma-dangle": ["error", "only-multiline"],
"comma-dangle": ["error", "always-multiline"],
"comma-spacing": "error",
"comma-style": "error",
"complexity": "error",
Expand All @@ -46,7 +52,7 @@
"implicit-arrow-linebreak": "error",
"indent": ["error", 4, { "SwitchCase": 1 }],
"init-declarations": "error",
"key-spacing": ["error", { "mode": "minimum", "align": "value" }],
"key-spacing": ["error", { "align": "value" }],
"keyword-spacing": "error",
"linebreak-style": "error",
"lines-between-class-members": ["error", "always"],
Expand All @@ -67,6 +73,7 @@
"no-dupe-else-if": "error",
"no-duplicate-imports": "error",
"no-else-return": "error",
"no-extra-parens": ["error", "all", { "nestedBinaryExpressions": false }],
"no-empty-function": "error",
"no-eq-null": "error",
"no-eval": "error",
Expand All @@ -93,7 +100,6 @@
"no-new-wrappers": "error",
"no-octal": "error",
"no-octal-escape": "error",
"no-param-reassign": "error",
"no-proto": "error",
"no-redeclare": "error",
"no-return-assign": "error",
Expand Down Expand Up @@ -122,7 +128,7 @@
"no-with": "error",
"no-whitespace-before-property": "error",
"nonblock-statement-body-position": "error",
"object-curly-newline": "error",
"object-curly-newline": ["error", { "multiline": true }],
"object-curly-spacing": ["error", "always"],
"object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }],
"object-shorthand": "error",
Expand Down Expand Up @@ -159,7 +165,6 @@
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": "error",
"strict": ["error", "global"],
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
Expand All @@ -170,4 +175,4 @@
"yield-star-spacing": "error",
"yoda": "error"
}
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*.lnk
node_modules
package-lock.json
DeviceAuthGenerator.exe
device_auths.json
.egstore/*
.vscode/*
!.vscode/settings.json
Expand Down
10 changes: 10 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"eslint.format.enable": true,
"editor.formatOnSave": true,
"eslint.alwaysShowStatus": true,
"prettier.requireConfig": true,
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
}
}
27 changes: 13 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,15 @@
Claim [available free game promotions](https://www.epicgames.com/store/free-games) from the Epic Game Store.

## Requirements
* [DeviceAuthGenerator](https://github.com/xMistt/DeviceAuthGenerator)
* [Node.js](https://nodejs.org/download/)

## Instructions (arguments)
1. Download/clone repo
3. Run `npm install`
4. Run `npm start USERNAME PASSWORD 0|1 2FA_SECRET`*

## Instructions (config)
1. Download/clone repo
## Instructions
1. Download/clone this repository
2. Run `npm install`
3. Edit `config.json` to include your EpicGames credentials and options
4. Run `npm start`*

*Only this step is required after the initial use.
3. Generate `device_auths.json` (using [DeviceAuthGenerator](https://github.com/xMistt/DeviceAuthGenerator))
4. (Optional) Edit `config.json`
5. Run `npm start`

## FAQ
### Why should I use this?
Expand All @@ -28,10 +23,14 @@ Also, this is a good alternative, in case you don't like using Epic's client or
### Why should I even bother claiming these free games?
To which I will say, why not? Most of these games are actually outstanding games! Even if you don't like Epic and their shenanigans, you will be pleased to know that Epic actually funds all the free copies that are given away: ["But we actually found it was more economical to pay developers [a lump sum] to distribute their game free for two weeks..."](https://arstechnica.com/gaming/2019/03/epic-ceo-youre-going-to-see-lower-prices-on-epic-games-store/)

### Can I use the looping or multi-account feature when using launch arguments?
No, these are only usable by using the config.

## Changelog
### V1.5.0
* Fixed login
* Fixed purchase (claiming)
* Removed ownership check (broken)
* Removed unneeded dependencies
* Code restyling

### V1.4.1
* Removed the need for graphql query

Expand Down
113 changes: 16 additions & 97 deletions claimer.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
"use strict";

const { "Launcher": EpicGames } = require("epicgames-client");
const { freeGamesPromotions } = require("./src/gamePromotions");

const Auths = require(`${__dirname}/device_auths.json`);
const CheckUpdate = require("check-update-github");
const ClientLoginAdapter = require("epicgames-client-login-adapter");
const Config = require(`${__dirname}/config.json`);
const Logger = require("tracer").console(`${__dirname}/logger.js`);
const Package = require("./package.json");
const TwoFactor = require("node-2fa");
const Cookie = require('tough-cookie').Cookie;

const { freeGamesPromotions } = require('./src/gamePromotions');

function isUpToDate() {
return new Promise((res, rej) => {
CheckUpdate({
"name": Package.name,
"currentVersion": Package.version,
"user": "revadike",
"branch": "master"
"branch": "master",
}, (err, latestVersion) => {
if (err) {
rej(err);
Expand All @@ -27,116 +26,36 @@ function isUpToDate() {
});
}

function getChromeCookie(cookie) {
cookie = Object.assign({}, cookie);
cookie.name = cookie.key;
if (cookie.expires instanceof Date) {
cookie.expires = cookie.expires.getTime() / 1000.0;
} else {
delete cookie.expires;
}
return cookie;
}

function getToughCookie(cookie) {
cookie = Object.assign({}, cookie);
cookie.key = cookie.name;
cookie.expires = new Date(cookie.expires * 1000);
return new Cookie(cookie);
function sleep(delay) {
return new Promise((res) => setTimeout(res, delay * 60000));
}

(async() => {
if (!await isUpToDate()) {
Logger.warn(`There is a new version available: ${Package.url}`);
}

let { accounts, options, delay, loop } = Config;
if (!options) {
options = {};
}
let sleep = delay => new Promise(res => setTimeout(res, delay * 60000));
let { options, delay, loop } = Config;
do {
if (process.argv.length > 2) {
loop = false;
accounts = [{
"email": process.argv[2],
"password": process.argv[3],
"rememberLastSession": Boolean(Number(process.argv[4])),
"secret": process.argv[5],
}];
}

for (let account of accounts) {
let noSecret = !account.secret || account.secret.length === 0;
if (!noSecret) {
let { token } = TwoFactor.generateToken(account.secret);
account.twoFactorCode = token;
}

let epicOptions = Object.assign({}, options);
Object.assign(epicOptions, account);

let client = new EpicGames(epicOptions);

for (let email in Auths) {
let useDeviceAuth = true;
let clientOptions = { email, ...options };
let client = new EpicGames(clientOptions);
if (!await client.init()) {
throw new Error("Error while initialize process.");
}

let success = false;
try {
success = await client.login(account);
} catch (error) {
Logger.warn(error.message);
}

let success = await client.login({ useDeviceAuth });
if (!success) {
Logger.warn(`Failed to login as ${client.config.email}, please attempt manually.`);


if (account.rememberLastSession) {
if (!options.cookies) {
options.cookies = [];
}
if (account.cookies && account.cookies.length) {
options.cookies = options.cookies.concat(account.cookies);
}
client.http.jar._jar.store.getAllCookies((err, cookies) => {
for (const cookie of cookies) {
options.cookies.push(getChromeCookie(cookie));
}
});
}

let auth = await ClientLoginAdapter.init(account, options);
let exchangeCode = await auth.getExchangeCode();

if (account.rememberLastSession) {
let cookies = await auth.getPage().then(p => p.cookies());
for (let cookie of cookies) {
cookie = getToughCookie(cookie);
client.http.jar.setCookie(cookie, "https://" + cookie.domain);
}
}

await auth.close();

if (!await client.login(null, exchangeCode)) {
throw new Error("Error while logging in.");
}
throw new Error(`Failed to login as ${client.config.email}`);
}

Logger.info(`Logged in as ${client.account.name} (${client.account.id})`);

let { country } = client.account.country;
let { country } = client.account;
let freePromos = await freeGamesPromotions(client, country, country);

for (let offer of freePromos) {
let launcherQuery = await client.launcherQuery(offer.namespace, offer.id);
if (launcherQuery.data.Launcher.entitledOfferItems.entitledToAllItemsInOffer) {
Logger.info(`${offer.title} is already claimed for this account`);
continue;
}

try {
let purchased = await client.purchase(offer, 1);
if (purchased) {
Expand Down Expand Up @@ -167,7 +86,7 @@ function getToughCookie(cookie) {
process.exit(0);
}
} while (loop);
})().catch(err => {
})().catch((err) => {
Logger.error(err);
process.exit(1);
});
15 changes: 0 additions & 15 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,4 @@
{
"accounts": [
{
"email": "YOUR_EMAIL1_HERE",
"password": "YOUR_PASSWORD1_HERE",
"secret": "YOUR_2FA_SECRET1_HERE_OR_EMPTY",
"rememberLastSession": true
},
{
"email": "YOUR_EMAIL2_HERE",
"password": "YOUR_PASSWORD2_HERE",
"secret": "YOUR_2FA_SECRET2_HERE_OR_EMPTY",
"rememberLastSession": true,
"cookies": []
}
],
"options": {},
"delay": 1440,
"loop": true
Expand Down
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "epicgames-freebies-claimer",
"version": "1.4.1",
"version": "1.5.0",
"description": "Claim free game promotions from the Epic Game Store",
"author": {
"name": "Revadike",
Expand Down Expand Up @@ -28,16 +28,15 @@
"homepage": "https://github.com/revadike/epicgames-freebies-claimer",
"url": "https://github.com/revadike/epicgames-freebies-claimer",
"devDependencies": {
"@babel/eslint-parser": "latest",
"chai": "*",
"eslint": "^6.8.0",
"eslint": "latest",
"mocha": "*"
},
"dependencies": {
"check-update-github": "^0.0.4",
"colors": "^1.4.0",
"epicgames-client": "Revadike/node-epicgames-client#develop",
"epicgames-client-login-adapter": "Revadike/node-epicgames-client-login-adapter",
"node-2fa": "^1.1.2",
"tracer": "^1.0.3"
}
}
Loading

0 comments on commit c12675c

Please sign in to comment.