Skip to content

Commit

Permalink
Merge pull request #24 from claabs/feature/manual-captcha
Browse files Browse the repository at this point in the history
Email user when a Captcha needs to be solved
  • Loading branch information
claabs authored Jul 4, 2020
2 parents 9c2e671 + 13b5049 commit 77d0d10
Show file tree
Hide file tree
Showing 17 changed files with 1,431 additions and 1,211 deletions.
12 changes: 9 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ WORKDIR /usr/app
FROM base as build

# Copy all source files
COPY src package*.json tsconfig.json ./
# Prod deps already installed, add dev deps
COPY package*.json tsconfig.json ./

# Add dev deps
RUN npm ci

# Copy source code
COPY src src

RUN npm run build

########
Expand All @@ -39,8 +43,10 @@ COPY package*.json ./
RUN npm ci --only=production

# Steal compiled code from build image
COPY --from=build /usr/app/dist ./dist/
COPY --from=build /usr/app/dist ./dist

COPY entrypoint.sh .

EXPOSE 3000

ENTRYPOINT [ "/usr/app/entrypoint.sh" ]
89 changes: 65 additions & 24 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ I decided to take a different approach by only using the APIs that the Epic Game
* Login
* CSRF/XSRF
* Captcha
* Automation via Google Cloud speech-to-text
* ~~Automation via Google Cloud speech-to-text~~
* Emails you when a link to solve a Captcha when required
* 2FA handing via TOTP token
* Session ID
* Game catalog discovery
Expand All @@ -31,22 +32,34 @@ I decided to take a different approach by only using the APIs that the Epic Game
* Schedule check/purchase via cron string
* Authentication refresh to reduce login count
* Support for multiple accounts
* *TODO:* Proper global store support (not just `en-US`)
* *TODO:* Proper global store support (Works fine for now)
* *TODO:* Redeem all free games, not just the weekly promotion

## Setup

### Google Speech-to-text

Epic uses FunCaptcha to stop bots, however the FunCaptcha audio game is fairly easy to crack using Google Speech-to-text. Google gives you 60 minutes of free transcription, and charges a small fee after that.
**Heads up: Epic Games/Arkose Labs broke the audio Captcha method this project used to automate Captchas. See [below](#captcha-emails) for the workaround.**

1. Create a new project for this bot. [GCP Console](https://console.cloud.google.com/)
1. [Add a billing account](https://console.cloud.google.com/billing) for the project. This is required even for the free 60 minutes of transcription per month. To limit your spending, using a [Privacy Card](https://privacy.com/) is recommended.
1. [Create a service account](https://console.cloud.google.com/iam-admin/serviceaccounts) for the project.
* Don't add any roles to the service account
* Don't add any users to the service account
1. After creating the service account, click the "Actions" button in the list and create a JSON key.
1. Add this JSON key file to the config folder for the project (`./config/account-name-abcdef12345.json`).
1. [Enable data logging](https://console.cloud.google.com/apis/api/speech.googleapis.com/data_logging) to be charged a lower fee in case you go over 60 minutes of transcription.
### Captcha Emails

Recent events have removed the ability to easily automate Captcha solving with Google Speech-to-text. This is a workaround that makes **you** solve a captcha by emailing you a link where you can solve it.
To use this requires:

* The ability to expose ports on your machine/local network/internet
* Where you expose the port limits where you can solve captchas from (the machine running the container/your home network/anywhere, respectively)
* Access to an SMTP server for email (Gmail works)

#### Email Setup

1. Expose port 3000 in your Docker run config (e.g. `-p 81:3000` maps the machine's port 81 to the container's port 3000)
1. If you want to access the Captcha solving page from outside your network, setup any port forwarding/reverse proxy/DNS
1. Set the `baseUrl` in the config
1. Set the SMTP settings in the email config
* [Example Gmail settings](https://www.siteground.com/kb/google_free_smtp_server)
* If you have 2FA setup for your Google account, you'll need to create an [app password](https://support.google.com/mail/answer/185833)

If you want to test the email and webserver, delete an account's `<email>-cookies.json` from your config directory, as this usually forces a fresh login with a captcha. Then just restart the container.

### JSON Configuration

Expand All @@ -70,6 +83,19 @@ The config file is store in the mounted `./config` directory.
"cronSchedule": "0 12 * * *",
"runOnce": false,
"logLevel": "info",
"baseUrl": "https://example.com",
"email": {
"smtpHost": "smtp.gmail.com",
"smtpPort": 587,
"emailSenderAddress": "hello@gmail.com",
"emailSenderName": "Epic Games Captchas",
"emailRecipientAddress": "hello@gmail.com",
"secure": false,
"auth": {
"user": "hello@gmail.com",
"pass": "abc123",
},
}
}
```

Expand All @@ -79,17 +105,32 @@ If you are using full JSON configuration, the only remaining Docker configurable

#### Environment Variables

| Variable | Example | Default | Description |
|-----------------|---------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| EMAIL | `example@gmail.com` | | Epic Games login email |
| PASSWORD | `abc123` | | Epic Games login password |
| TOTP | `EMNCF83ULU39CYFO...YI69R39NE` | | (**Maybe required**) If 2FA is enabled, add your TOTP secret. [See details below.](#two-factor-login) |
| GCP_CONFIG_NAME | `account-name-abcdef12345.json` | | (Optional) GCP credentials JSON filename located in `./config/`. Required if login requires captcha |
| RUN_ON_STARTUP | `true` | `false` | (Optional) If true, the process will run on startup in addition to the scheduled time |
| CRON_SCHEDULE | `0 12 * * *` | `0 12 * * *` | (Optional) Cron string of when to run the process. If using `TZ=UTC`, a value of `5 16 * * *` will run 5 minutes after the new games are available |
| RUN_ONCE | `true` | `false` | (Optional) If true, don't schedule runs. Use with RUN_ON_STARTUP to run once and shutdown. |
| LOG_LEVEL | `info` | `info` | (Optional) Log level in lower case. Can be [silent, error, warn, info, debug, trace] |
| TZ | `America/Chicago` | `UTC` | (Optional) [TZ name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) |
| Variable | Example | Default | Description |
|-------------------------|--------------------------------|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------|
| EMAIL | `example@gmail.com` | | Epic Games login email |
| PASSWORD | `abc123` | | Epic Games login password |
| BASE_URL | `https://epic.example.com` | `http://localhost:3000` | The URL you will access to solve Captchas when required. Extra path names are supported |
| SMTP_HOST | `smtp.gmail.com` | | The outgoing SMTP host name |
| SMTP_PORT | `587` | | The outgoing SMTP port (SSL or TLS, see `secure`) |
| EMAIL_SENDER_ADDRESS | `hello@gmail.com` | | The sender of the email you will recieve (can be your email address) |
| EMAIL_SENDER_NAME | `Epic Games Captchas` | | The name of the email sender |
| EMAIL_RECIPIENT_ADDRESS | `hello@gmail.com` | | The recipient of the email (can be your email address) |
| SMTP_SECURE | `true` | | `true` for SSL (port 465), `false` for TLS |
| SMTP_USERNAME | `hello@gmail.com` | | The SMTP username (if necessary) |
| SMTP_PASSWORD | `abc123` | | The SMTP password (if necessary) |
| TOTP | `EMNCF83ULU39CYFO...YI69R39NE` | | (**Maybe required**) If 2FA is enabled, add your TOTP secret. [See details below.](#two-factor-login) |
| SERVER_PORT | `3333` | `3000` | (Optional) Where the Express server listens. Useful for inter-container networks in Docker Compose, otherwise just stick to `-p` |
| RUN_ON_STARTUP | `true` | `false` | (Optional) If true, the process will run on startup in addition to the scheduled time |
| CRON_SCHEDULE | `0 12 * * *` | `0 12 * * *` | (Optional) Cron string of when to run the process. If using `TZ=UTC`, a value of `5 16 * * *` will run 5 minutes after the new games are available |
| RUN_ONCE | `true` | `false` | (Optional) If true, don't schedule runs. Use with RUN_ON_STARTUP to run once and shutdown. |
| LOG_LEVEL | `info` | `info` | (Optional) Log level in lower case. Can be [silent, error, warn, info, debug, trace] |
| TZ | `America/Chicago` | `UTC` | (Optional) [TZ name](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) |

#### Ports

| Host port | Container port | Description |
|-----------|----------------|-------------------------------------------------------------------------------|
| `3001` | `3000` | Port mapping on which the web server hosting the Captcha solving page resides |

#### Volumes

Expand All @@ -114,11 +155,11 @@ If you have two-factor authentication (2FA) enabled on your account, you need to

#### With JSON Config

`$ docker run -d -e TZ=America/Chicago -v /my/host/dir/:/usr/app/config:rw charlocharlie/epicgames-freegames:latest`
`$ docker run -d -e TZ=America/Chicago -v /my/host/dir/:/usr/app/config:rw -p 3000:3000 charlocharlie/epicgames-freegames:latest`

#### Without JSON Config

`$ docker run -d -e TZ=America/Chicago -e EMAIL=example@gmail.com -e PASSWORD=abc123 -e TOTP=ABC123 -e GCP_CONFIG_NAME=account-name-abcdef12345.json -e RUN_ON_STARTUP=true -v /my/host/dir/:/usr/app/config:rw charlocharlie/epicgames-freegames:latest`
`$ docker run -d -e TZ=America/Chicago -e EMAIL=example@gmail.com -e PASSWORD=abc123 -e TOTP=ABC123 -e RUN_ON_STARTUP=true -e BASE_URL=https://example.com -e SMTP_HOST=smtp.gmail.com -e SMTP_PORT=587 -e SMTP_HOST=smtp.gmail.com -e EMAIL_SENDER_ADDRESS=hello@gmail.com -e EMAIL_SENDER_NAME="Epic Games Captchas" -e EMAIL_RECIPIENT_ADDRESS=hello@gmail.com -e SMTP_SECURE=true -e SMTP_USERNAME=hello@gmail.com -e SMTP_PASSWORD=abc123 -v /my/host/dir/:/usr/app/config:rw -p 3001:3000 charlocharlie/epicgames-freegames:latest`

## Development

Expand Down
12 changes: 8 additions & 4 deletions commands.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { usage } from 'yargs';
import AccountManager from './test/util/account';
import { getAllFreeGames } from './src/free-games';
import { purchaseGames } from './src/purchase';
import { newCookieJar } from './src/common/request';
import FreeGames from './src/free-games';
import Purchase from './src/purchase';

interface ReleaseArgs {
[x: string]: unknown;
Expand Down Expand Up @@ -38,8 +39,11 @@ const redeemGames = async (args: RedeemArgs): Promise<void> => {
if (!user || !pass || !totp) throw new Error('Missing username, password, or TOTP');
const account = new AccountManager(user, pass, totp);
await account.login();
const offers = await getAllFreeGames(); // Get purchasable offers
await purchaseGames(offers); // Purchase games;
const requestClient = newCookieJar(user);
const freeGames = new FreeGames(requestClient, account.permMailAddress);
const purchase = new Purchase(requestClient, account.permMailAddress);
const offers = await freeGames.getAllFreeGames(); // Get purchasable offers
await purchase.purchaseGames(offers); // Purchase games;
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
Loading

0 comments on commit 77d0d10

Please sign in to comment.