Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Code from original GitHub repo.
  • Loading branch information
sebastienvercammen committed Nov 17, 2016
1 parent 757a744 commit 6f21b7e
Show file tree
Hide file tree
Showing 6 changed files with 396 additions and 2 deletions.
17 changes: 17 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Auto detect text files and perform LF normalization
* text=auto

# Custom for Visual Studio
*.cs diff=csharp

# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
38 changes: 38 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history
63 changes: 61 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,61 @@
# ptc-acc-gen
PTC Account Gen (formerly by Seb)
# Nintendo PTC Account Generator

An automation script based on Nightmare.js that can create any number of Nintendo Pokémon Trainer Club accounts with a single e-mail address. This only works because Nintendo doesn't check for "[email protected]" e-mail tricks, where the e-mail host completely ignores any part after (and including) the plus sign and sends it to "[email protected]".

This project was started as a proof of concept: even multi-billion dollar companies that just released the single most popular mobile game (Pokémon Go) sometimes miss the details.

More about plus signs in e-mail addresses [on StackExchange](http://security.stackexchange.com/questions/65244/what-are-the-security-reasons-for-disallowing-the-plus-sign-in-email-addresses).

If you're using Gmail and want to automatically verify all accounts, use this gist: https://gist.github.com/sebastienvercammen/e7e0e9e57db246d7f941b789d8508186

The new version on Nightmare.js now:

* Checks for usernames/e-mails that are already taken
* Can screenshot the result page
* Handles server issues better
* Doesn't require PhantomJS/CasperJS or fiddling with the PATH environment variable

## Requirements
### Prerequisites
* [Node.js](https://nodejs.org/en/)

## Usage

1. Install requirements with `npm install`
2. Open [index.js](index.js) and edit the settings at the top of the file.
3. Run the script with Node.js:
`node index.js`

## Configuration
### 1. Generate 10 accounts in the format USERx, where x is 0 to 9.
This example corresponds to the default settings. It will generate 10 accounts in the same format: user0, user1, ...

In [index.js](index.js):

var start = 0; // Start from x (NAMEx, [email protected])
var end = 10; // Up to x, but not including (exclusive)

var useNicknamesFile = false; // Use nicknames file, or just append numbers to username?
var outputFile = 'accounts.txt'; // File which will contain the generated "username password" combinations.
var outputFormat = '%NICK% %PASS%\r\n'; // Format used to save the account data in outputFile. Supports %NICK%, %PASS%.

var useNicknamesFile = false; // Use nicknames file, or just append numbers to username?
var useRandomPassword = true; // Generate a random password?
var screenshotResult = true; // Saves a screenshot per account creation if set to true
var screenshotOnFailure = true; // Saves a screenshot even if registration failed

### 2. Generate random passwords per account.
* Set `var useRandomPassword = true;` in [index.js](index.js).

### 3. Save screenshots.

var screenshotResult = true; // Saves a screenshot per account creation if set to true
var screenshotOnFailure = true; // Saves a screenshot even if registration failed
var screenshotFolder = "output/screenshots/";

### 4. Use a list of unique usernames instead of USERx combinations.
The list of unique usernames must be stored in [nicknames.json](nicknames.json). An example is available on the repo.

To create a number of accounts with custom usernames instead of user + number combinations, change [index.js](index.js):

var useNicknamesFile = true;
257 changes: 257 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
// Requires
var Nightmare = require('nightmare');
var nicknames = require('./nicknames.json');
var fs = require('fs');

// Settings
var debug = false;
var showWindow = false;

var start = 0; // Start from x (NAMEx, [email protected])
var end = 10;

var useNicknamesFile = false; // Use nicknames file, or just append numbers to username?
var useRandomPassword = true; // Generate a random password?
var screenshotResult = true; // Saves a screenshot per account creation if set to true
var screenshotOnFailure = true; // Saves a screenshot even if registration failed

var outputFile = "output/accounts.txt"; // File which will contain the generated "username password" combinations.
var outputFormat = "%NICK% %PASS%\r\n"; // Format used to save the account data in outputFile. Supports %NICK%, %PASS%.
var screenshotFolder = "output/screenshots/";

var country = "US"; // Country code (e.g. BE, FR, US, CA)
var dob = "1990-01-01"; // Date of birth, yyyy-mm-dd
var username = "CHANGEME"; // User- & display name. Make sure any "(username + number)@domain.com" is 100% unique.
var password = "CHANGEME"; // Static password for all accounts. Ignored if useRandomPassword is true.
var email_user = "CHANGEME"; // If your email is email@domain.com, enter "email"
var email_domain = "CHANGEME.com"; // Domain of e-mail host

// App data
var url_ptc = "https://club.pokemon.com/us/pokemon-trainer-club/sign-up/";
var useragent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36";
var nightmare_opts = {
show: showWindow,
waitTimeout: 10000,
gotoTimeout: 5000,
loadTimeout: 5000
};

// Settings check
if (!useNicknamesFile && (username + end).length > 16) {
console.log("Error: length of username + number can't be longer than 16 characters.");
console.log("Please use a shorter nickname.");
process.exit();
}

if ((email_user + '+' + username + end + '@' + email_domain).length > 75) {
console.log("Error: length of e-mail address including the + trick can't be longer than 75 characters.");
console.log("Please use a shorter e-mail address and/or nickname.");
process.exit();
}

if (!useRandomPassword && password.length > 15) {
console.log("Error: length of password can't be longer than 15 characters.");
console.log("Please use a shorter password.");
process.exit();
}

// LETSAHGO
var nightmare = Nightmare(nightmare_opts);
nightmare.useragent(useragent);

createAccount(start);

// Helpers

function handleError(err) {
if(debug) {
console.log("[DEBUG] Error:" + JSON.stringify(err));
}

return err;
}

function randomPassword() {
return Math.random().toString(36).substr(2, 8);
}

function prepareNightmare(nightmare) {
nightmare.useragent(useragent);
}

function randomPassword() {
return Math.random().toString(36).substr(2, 8);
}

// Pages
function createAccount(ctr) {
console.log("Creating account " + ctr + " of " + end);

// Launch instance
handleFirstPage(ctr);
}

// First page
function handleFirstPage(ctr) {
if(debug) {
console.log("[DEBUG] Handle first page #" + ctr);
}

nightmare.goto(url_ptc)
.evaluate(evaluateDobPage)
.then(function(validated) {
if(!validated) {
// Missing form data, loop over itself
console.log("[" + ctr + "] Servers are acting up... Trying again.");
return function() { nightmare.wait(500).refresh().wait(); handleFirstPage(ctr); };
} else {
return function() { fillFirstPage(ctr); };
}
})
.then(function(next) {
// Handle next step: either a loop to first page in case of error, or form fill on success
return next();
})
.catch(handleError)
.then(function(err) {
if (typeof err !== "undefined") {
return handleFirstPage(ctr);
}
});
}

function fillFirstPage(ctr) {
if(debug) {
console.log("[DEBUG] Fill first page #" + ctr);
}

nightmare.evaluate(function(data) {
document.getElementById("id_dob").value = data.dob;

var els = document.getElementsByName("id_country");
for(var i = 0; i < els.length; i++) {
els[i].value = data.country;
}

return document.getElementById("id_dob").value;
}, { dob: dob, country: country })
.click("form[name='verify-age'] [type=submit]")
.wait("#id_username")
.then(function() {
handleSignupPage(ctr);
})
.catch(handleError)
.then(function(err) {
if (typeof err !== "undefined") {
return handleFirstPage(ctr);
}
});
}

// Signup page
function handleSignupPage(ctr) {
if(debug) {
console.log("[DEBUG] Handle second page #" + ctr);
}

nightmare.evaluate(evaluateSignupPage)
.then(function(validated) {
if(!validated) {
// Missing form data, loop over itself
console.log("[" + ctr + "] Servers are acting up... Trying again.");
return function() { nightmare.wait(500).refresh().wait(); handleFirstPage(ctr); };
} else {
return function() { fillSignupPage(ctr); };
}
}).then(function(next) {
// Handle next step: either a loop to first page in case of error, or form fill on success
return next();
})
.catch(handleError)
.then(function(err) {
if (typeof err !== "undefined") {
return handleSignupPage(ctr);
}
});
}

function fillSignupPage(ctr) {
if(debug) {
console.log("[DEBUG] Fill signup page #" + ctr);
}

var _pass = password;
var _nick = username + ctr;

if(useRandomPassword) {
_pass = randomPassword();
}

// Use nicknames list, or (username + number) combo?
if(useNicknamesFile) {
// Make sure we have a nickname left
if(nicknames.length < 1) {
throw Error("We're out of nicknames to use!");
}

// Get the first nickname off the list & use it
_nick = nicknames.shift();
}

// Fill it all in
nightmare.evaluate(function(data) {
document.getElementById("id_password").value = data.pass;
document.getElementById("id_confirm_password").value = data.pass;
document.getElementById("id_email").value = data.email_user + "+" + data.nick + "@" + data.email_domain;
document.getElementById("id_confirm_email").value = data.email_user + "+" + data.nick + "@" + data.email_domain;
document.getElementById("id_screen_name").value = data.nick;
document.getElementById("id_username").value = data.nick;
}, { "pass": _pass, "nick": _nick, "email_user": email_user, "email_domain": email_domain })
.check("#id_terms")
.click("form[name='create-account'] [type=submit]")
.wait(function() {
return (document.getElementById("signup-signin") !== null || document.getElementById("btn-reset") !== null || document.body.textContent.indexOf("That username already exists") > -1);
})
.evaluate(function() {
return (document.body.textContent.indexOf("Hello! Thank you for creating an account!") > -1);
})
.then(function(success) {
if(success) {
// Log it in the file of used nicknames
var content = outputFormat.replace('%NICK%', _nick).replace('%PASS%', _pass);
fs.appendFile(outputFile, content, function(err) {
//
});
}

if((success && screenshotResult) || screenshotOnFailure) {
// Screenshot
nightmare.screenshot(screenshotFolder + _nick + ".png");
}

// Next one, or stop
if(ctr < end) {
return function() { createAccount(ctr + 1); };
} else {
return nightmare.end();
}
}).then(function(next) {
return next();
}).catch(handleError)
.then(function(err) {
if (typeof err !== "undefined") {
return handleSignupPage(ctr);
}
});
}

// Evaluations
function evaluateDobPage() {
var dob_value = document.getElementById("id_dob");
return ((document.title === "The Official Pokémon Website | Pokemon.com") && (dob_value !== null));
}

function evaluateSignupPage() {
var username_field = document.getElementById("id_username");
return ((document.title === "The Official Pokémon Website | Pokemon.com") && (username_field !== null));
}
4 changes: 4 additions & 0 deletions nicknames.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
"uniqueuser159",
"betteruser933"
]
Loading

0 comments on commit 6f21b7e

Please sign in to comment.