├── etc └── tfa.png ├── .github ├── dependabot.yml └── FUNDING.yml ├── package.json ├── LICENSE ├── .gitignore ├── lib ├── args.js ├── cli.js └── parse.js └── README.md /etc/tfa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/game-ci/unity-verify-code/HEAD/etc/tfa.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | 8 | - package-ecosystem: npm 9 | directory: / 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: game-ci 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # replace with a single OpenCollective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unity-verify-code", 3 | "version": "0.2.4", 4 | "description": "An email parser to get 6 digit verfication code.", 5 | "main": "./lib/parse.js", 6 | "homepage": "https://github.com/game-ci/unity-verify-code#readme", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/game-ci/unity-verify-code.git" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/game-ci/unity-verify-code/issues" 13 | }, 14 | "scripts": { 15 | "test": "echo \"Error: no test specified\" && exit 1" 16 | }, 17 | "keywords": [ 18 | "unity", 19 | "verify", 20 | "code" 21 | ], 22 | "author": "Jen-Chieh Shen", 23 | "license": "MIT", 24 | "dependencies": { 25 | "imap": "^0.8.19" 26 | }, 27 | "files": [ 28 | "lib" 29 | ], 30 | "directories": { 31 | "lib": "lib" 32 | }, 33 | "devDependencies": {}, 34 | "bin": { 35 | "unity-verify-code": "./lib/cli.js" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2025 Jen-Chieh Shen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/8d9fec1294e804316e211230fdf9679e2ec123e7/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # Typescript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | /data 63 | /test 64 | -------------------------------------------------------------------------------- /lib/args.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * $File: args.js $ 4 | * $Date: 2021-09-21 02:18:26 $ 5 | * $Revision: $ 6 | * $Creator: Jen-Chieh Shen $ 7 | * $Notice: See LICENSE.txt for modification and distribution information 8 | * Copyright © 2021 by Shen, Jen-Chieh $ 9 | */ 10 | 11 | "use strict"; 12 | 13 | /** 14 | * Return true, if there is one invalid arguments. 15 | */ 16 | function checkNull() { 17 | for (let index = 0; index < arguments.length; ++index) { 18 | if (!arguments[index]) 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | /** 25 | * Return argument by it's `name`. 26 | * @param { string } name - The name of the argument. 27 | * @param { any } defaultValue - Default value, this is for optional arguments. 28 | */ 29 | function getArg(name, defaultValue = null) { 30 | let args = process.argv; 31 | if (typeof name === 'number') { 32 | return args[name]; 33 | } else { 34 | for (let index = 0; index < args.length; ++index) { 35 | if (args[index] === name && args.length > index + 1) { 36 | return args[index +1]; 37 | } 38 | } 39 | } 40 | return defaultValue; 41 | } 42 | 43 | /* 44 | * Module Exports 45 | */ 46 | module.exports.checkNull = checkNull; 47 | module.exports.getArg = getArg; 48 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * $File: cli.js $ 4 | * $Date: 2021-09-21 01:03:30 $ 5 | * $Revision: $ 6 | * $Creator: Jen-Chieh Shen $ 7 | * $Notice: See LICENSE.txt for modification and distribution information 8 | * Copyright © 2021 by Shen, Jen-Chieh $ 9 | */ 10 | 11 | "use strict"; 12 | 13 | const fs = require('fs'); 14 | const parse = require('./parse'); 15 | const args = require('./args'); 16 | 17 | const usage = 18 | "usage : unity-verify-code [--port] [--tls]\n" + 19 | " EMAIL [EMAIL ...] PASSWORD [PASSWORD ...]\n" + 20 | " SAVE_PATH [SAVE_PATH ...]\n" + 21 | "\n" + 22 | "Unity License Activate : An email parser to get 6 digit verification code.\n" + 23 | "\n" + 24 | "positional arguments:\n" + 25 | " EMAIL Username or Email you use to register for Unity account\n" + 26 | " PASSWORD Password to login Unity account\n" + 27 | " SAVE_PATH File path to save the 6 digit code.\n" + 28 | "\n" + 29 | "optional arguments:\n" + 30 | " --port Port number of the IMAP server. Default: 143\n" + 31 | " --tls boolean - Perform implicit TLS connection? Default: false\n"; 32 | 33 | /* CLI */ 34 | const cli_md = function () { 35 | let email = args.getArg(2); 36 | let password = args.getArg(3); 37 | let savePath = args.getArg(4); 38 | let port = args.getArg("--port", 993); 39 | let tls = args.getArg("--tls", true); 40 | 41 | // Check valid arguments. 42 | if (args.checkNull(email, password, savePath)) { 43 | console.log("[ERROR] Missing positional arguments"); 44 | console.log(usage); 45 | return; 46 | } 47 | 48 | parse.parse(email, password, port, tls, savePath); 49 | }; 50 | 51 | /** CLI entry */ 52 | if (require.main === module) { 53 | cli_md(); 54 | } 55 | -------------------------------------------------------------------------------- /lib/parse.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * $File: parse.js $ 4 | * $Date: 2021-09-21 01:04:21 $ 5 | * $Revision: $ 6 | * $Creator: Jen-Chieh Shen $ 7 | * $Notice: See LICENSE.txt for modification and distribution information 8 | * Copyright © 2021 by Shen, Jen-Chieh $ 9 | */ 10 | 11 | "use strict"; 12 | 13 | const fs = require('fs'); 14 | const Imap = require('imap'), inspect = require('util').inspect; 15 | 16 | function getHost(email) { 17 | if (email.includes('@gmail.com')) return 'imap.gmail.com'; 18 | if (email.includes('@hotmail.com')) return 'imap-mail.outlook.com'; 19 | if (email.includes('@outlook.com')) return 'imap-mail.outlook.com'; 20 | if (email.includes('@yahoo.com')) return 'imap.mail.yahoo.com'; 21 | if (email.includes('@foxmail.com')) return 'imap.qq.com'; 22 | if (email.includes('@qq.com')) return 'imap.qq.com'; 23 | return null; 24 | } 25 | 26 | function parse(email, password, port, tls, savePath) { 27 | const imap = new Imap({ 28 | user: email, 29 | password: password, 30 | host: getHost(email), 31 | port: port, 32 | tls: tls, 33 | tlsOptions: { 34 | rejectUnauthorized: false 35 | }, 36 | authTimeout: 3000, 37 | }); 38 | 39 | imap.once('error', function (err) { console.log('Source Server Error:- ', err); }); 40 | 41 | imap.once('ready', function () { 42 | imap.openBox('INBOX', false, function (err, box) { 43 | if (err) throw err; 44 | imap.search(['UNSEEN', ['FROM', 'accounts@unity3d.com']], function (err, results) { 45 | if (err) throw err; 46 | 47 | let f = imap.fetch(results, { bodies: '', markSeen: true, }); 48 | f.on('message', function(msg, seqno) { 49 | let prefix = '(#' + seqno + ') '; 50 | msg.on('body', function(stream, info) { 51 | stream.on('data', function (chunk) { 52 | let content = chunk.toString('utf8'); 53 | let startStr= "verification code is "; 54 | let start = content.indexOf(startStr); 55 | let endStr = " and will be expired in"; 56 | let end = content.indexOf(endStr); 57 | 58 | if (start === -1 || end === -1) 59 | return; 60 | 61 | let part = content.substring(start + startStr.length, end); 62 | fs.writeFileSync(savePath, part, { encoding: 'utf8' }); 63 | }); 64 | 65 | return imap.end(); 66 | }); 67 | }); 68 | }); 69 | }); 70 | }); 71 | 72 | imap.connect(); 73 | } 74 | 75 | /* 76 | * Module Exports 77 | */ 78 | module.exports.parse = parse; 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 2 | [![Release](https://img.shields.io/github/tag/jcs090218/unity-verify-code.svg?label=release&logo=github)](https://github.com/jcs090218/unity-verify-code/releases/latest) 3 | [![npm](https://img.shields.io/npm/v/unity-verify-code?logo=npm&color=green)](https://www.npmjs.com/package/unity-verify-code) 4 | [![npm-dt](https://img.shields.io/npm/dt/unity-verify-code.svg)](https://npmcharts.com/compare/unity-verify-code?minimal=true) 5 | [![npm-dm](https://img.shields.io/npm/dm/unity-verify-code.svg)](https://npmcharts.com/compare/unity-verify-code?minimal=true) 6 | 7 | # unity-verify-code 8 | 9 | [![dependencies Status](https://status.david-dm.org/gh/jcs090218/unity-verify-code.svg)](https://david-dm.org/jcs090218/unity-verify-code) 10 | 11 | An email parser to get 6 digit verification code. 12 | 13 | This tool is design to use with [unity-license-activate](https://github.com/jcs090218/unity-license-activate) 14 | so you can feed verification code to get pass Unity's TFA. 15 | 16 |

17 | 18 |

19 | 20 | ## 💾 Prerequisite 21 | 22 | This application uses IMAP to parse your verification email from Unity, so make 23 | sure your email's IMAP service is enabled! 24 | 25 | * `Gmail`, see [How Can i receive incoming mails(gmail) to my application server using imap (nodejs)](https://stackoverflow.com/questions/62404008/how-can-i-receive-incoming-mailsgmail-to-my-application-server-using-imap-nod) 26 | 27 | *P.S. All email services should have the similar steps!* 28 | 29 | ### 📬 Supported mail services 30 | 31 | | Name | Done | Value | 32 | |---------|------|-------------------------| 33 | | Gmail | ✔ | `imap.gmail.com` | 34 | | Hotmail | ✔ | `imap-mail.outlook.com` | 35 | | Outlook | ✔ | `imap-mail.outlook.com` | 36 | | Yahoo | ✔ | `imap.mail.yahoo.com` | 37 | | Foxmail | ✔ | `imap.qq.com` | 38 | | QQ | ✔ | `imap.qq.com` | 39 | 40 | ## 🔨 How to use? 41 | 42 | You can use these tools with any CI/CD system as long as you have the [Node](https://nodejs.org/en/) 43 | environment set up! Here is an example of GitHub Actions. 44 | 45 | ```yml 46 | jobs: 47 | acquire_ulf: 48 | name: Acquire .ulf file 🔑 49 | runs-on: ubuntu-latest 50 | strategy: 51 | matrix: 52 | node-version: [14.x] 53 | steps: 54 | - name: Set up Node.js ${{ matrix.node-version }} 55 | uses: actions/setup-node@v1 56 | with: 57 | node-version: ${{ matrix.node-version }} 58 | 59 | - name: Install node package, `unity-license-activate` 60 | run: npm install --global unity-license-activate 61 | 62 | # You would only have to install it! 63 | - name: Install node package, `unity-verify-code` 64 | run: npm install --global unity-verify-code 65 | 66 | - name: Activate the license 67 | run: unity-license-activate "${{ secrets.UNITY_EMAIL }}" "${{ secrets.UNITY_PASSWORD }}" "${{ needs.request_alf.outputs.alf }}" 68 | ``` 69 | 70 | See the full example [here](https://github.com/jcs090218/JCSUnity/blob/master/.github/workflows/license.yml). 71 | 72 | ## 📇 Command Line Arguments 73 | 74 | ```console 75 | usage : unity-verify-code [--port] [--tls] 76 | EMAIL [EMAIL ...] PASSWORD [PASSWORD ...] HOST [HOST ...] 77 | SAVE_PATH [SAVE_PATH ...] 78 | 79 | Unity License Activate : An email parser to get 6 digit verification code. 80 | 81 | positional arguments: 82 | EMAIL Username or Email you use to register for Unity account 83 | PASSWORD Password to login Unity account 84 | SAVE_PATH File path to save the 6 digit code. 85 | 86 | optional arguments: 87 | --port Port number of the IMAP server. Default: 143 88 | --tls boolean - Perform implicit TLS connection? Default: false 89 | ``` 90 | 91 | ## ⚜️ Licence 92 | 93 | This repository is [MIT](./LICENSE) licensed. 94 | 95 | This includes all contributions from the community. 96 | --------------------------------------------------------------------------------