forked from sebastienvercammen/ptc-acc-gen
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
6 changed files
with
396 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
[ | ||
"uniqueuser159", | ||
"betteruser933" | ||
] |
Oops, something went wrong.