├── test ├── fixtures │ ├── 1.txt │ ├── 2.txt │ ├── 3.txt │ └── 4.txt └── test.js ├── bin └── cli.js ├── .github └── workflows │ └── testing.yml ├── src └── index.js ├── package.json ├── .gitignore └── README.md /test/fixtures/1.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | -------------------------------------------------------------------------------- /test/fixtures/2.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | aa 5 | ab 6 | ac 7 | ba 8 | bb 9 | bc 10 | ca 11 | cb 12 | cc 13 | -------------------------------------------------------------------------------- /test/fixtures/3.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | aa 5 | ab 6 | ac 7 | ba 8 | bb 9 | bc 10 | ca 11 | cb 12 | cc 13 | aaa 14 | aab 15 | aac 16 | aba 17 | abb 18 | abc 19 | aca 20 | acb 21 | acc 22 | baa 23 | bab 24 | bac 25 | bba 26 | bbb 27 | bbc 28 | bca 29 | bcb 30 | bcc 31 | caa 32 | cab 33 | cac 34 | cba 35 | cbb 36 | cbc 37 | cca 38 | ccb 39 | ccc 40 | -------------------------------------------------------------------------------- /bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const yargs = require('yargs'); 4 | const argv = yargs 5 | .usage('Usage: $0 -a [string] -l [num]') 6 | .alias('a', 'alphabet') 7 | .alias('l', 'length') 8 | .demandOption(['a', 'l']) 9 | .argv; 10 | 11 | const a = String(argv.a).split(''); 12 | const l = Number(argv.l); 13 | 14 | const { generate } = require('../src'); 15 | 16 | (function main() { 17 | const gen = generate(a, l); 18 | for (let record of gen) { 19 | console.log(record); 20 | } 21 | })(); 22 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Testing 5 | 6 | on: 7 | push: 8 | branches: ["main"] 9 | pull_request: 10 | branches: ["main"] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [16.x, 18.x, 20.x, 22.x] 19 | 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v4 23 | 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: "npm" 29 | 30 | - run: npm ci 31 | - run: npm run build --if-present 32 | - run: npm run lint --if-present 33 | - run: npm test 34 | - run: npm run e2e --if-present 35 | env: 36 | CI: true 37 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Generate permutation of passed chars. 5 | * 6 | * @example 7 | * const gen = generate(['a', 'b'], 2); 8 | * for (let record of gen) { 9 | * console.log(record); // 'a', 'b', 'aa', 'ab', 'ba', 'bb' 10 | * } 11 | * 12 | * @param {Array} [chars=[]] List of letters to permute 13 | * @param {number} [maxLevels=3] Maximum length of generated word 14 | */ 15 | function generate(chars = [], maxLevels = 3) { 16 | 17 | function * iteratee(prefix, index, level) { 18 | for (let i = 0; i < chars.length; i++) { 19 | const char = chars[i]; 20 | const record = (prefix + char); 21 | 22 | if (index >= level) { 23 | yield record; 24 | } else { 25 | yield * iteratee(record, index + 1, level); 26 | } 27 | } 28 | } 29 | 30 | function * loop(string) { 31 | for (let i = 0; i < maxLevels; i++) { 32 | yield * iteratee(string, 0, i); 33 | } 34 | } 35 | 36 | return loop(''); 37 | } 38 | 39 | module.exports = { 40 | generate 41 | }; 42 | -------------------------------------------------------------------------------- /test/fixtures/4.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | aa 5 | ab 6 | ac 7 | ba 8 | bb 9 | bc 10 | ca 11 | cb 12 | cc 13 | aaa 14 | aab 15 | aac 16 | aba 17 | abb 18 | abc 19 | aca 20 | acb 21 | acc 22 | baa 23 | bab 24 | bac 25 | bba 26 | bbb 27 | bbc 28 | bca 29 | bcb 30 | bcc 31 | caa 32 | cab 33 | cac 34 | cba 35 | cbb 36 | cbc 37 | cca 38 | ccb 39 | ccc 40 | aaaa 41 | aaab 42 | aaac 43 | aaba 44 | aabb 45 | aabc 46 | aaca 47 | aacb 48 | aacc 49 | abaa 50 | abab 51 | abac 52 | abba 53 | abbb 54 | abbc 55 | abca 56 | abcb 57 | abcc 58 | acaa 59 | acab 60 | acac 61 | acba 62 | acbb 63 | acbc 64 | acca 65 | accb 66 | accc 67 | baaa 68 | baab 69 | baac 70 | baba 71 | babb 72 | babc 73 | baca 74 | bacb 75 | bacc 76 | bbaa 77 | bbab 78 | bbac 79 | bbba 80 | bbbb 81 | bbbc 82 | bbca 83 | bbcb 84 | bbcc 85 | bcaa 86 | bcab 87 | bcac 88 | bcba 89 | bcbb 90 | bcbc 91 | bcca 92 | bccb 93 | bccc 94 | caaa 95 | caab 96 | caac 97 | caba 98 | cabb 99 | cabc 100 | caca 101 | cacb 102 | cacc 103 | cbaa 104 | cbab 105 | cbac 106 | cbba 107 | cbbb 108 | cbbc 109 | cbca 110 | cbcb 111 | cbcc 112 | ccaa 113 | ccab 114 | ccac 115 | ccba 116 | ccbb 117 | ccbc 118 | ccca 119 | cccb 120 | cccc 121 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "brute-force-generator", 3 | "description": "🔨 Build a dictionary by permuting passed letters (using ES2015+)", 4 | "version": "1.0.12", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Piotr Kowalski", 8 | "email": "piecioshka@gmail.com", 9 | "url": "https://piecioshka.pl/" 10 | }, 11 | "scripts": { 12 | "clear": "rm -rf dist/ coverage/ .nyc_output/", 13 | "clear:all": "rm -rf node_modules/ && npm run clear", 14 | "test": "jasmine test/**/*.js", 15 | "coverage": "nyc npm run test && nyc report --reporter=html" 16 | }, 17 | "dependencies": { 18 | "yargs": "^17.3.1" 19 | }, 20 | "devDependencies": { 21 | "jasmine": "^3.10.0", 22 | "nyc": "^15.1.0" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+ssh://git@github.com/piecioshka/brute-force-generator.git" 27 | }, 28 | "engines": { 29 | "node": ">=12.0.0" 30 | }, 31 | "files": [ 32 | "bin", 33 | "src" 34 | ], 35 | "keywords": [ 36 | "cli", 37 | "brute", 38 | "force", 39 | "brute force", 40 | "generate", 41 | "generator", 42 | "dictionary", 43 | "dict", 44 | "permutation" 45 | ], 46 | "main": "src/index.js", 47 | "bin": { 48 | "brute-force-generator": "bin/cli.js" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # Yarn Integrity file 63 | .yarn-integrity 64 | 65 | # dotenv environment variables file 66 | .env 67 | .env.test 68 | 69 | # parcel-bundler cache (https://parceljs.org/) 70 | .cache 71 | 72 | # next.js build output 73 | .next 74 | 75 | # nuxt.js build output 76 | .nuxt 77 | 78 | # vuepress build output 79 | .vuepress/dist 80 | 81 | # Serverless directories 82 | .serverless/ 83 | 84 | # FuseBox cache 85 | .fusebox/ 86 | 87 | # DynamoDB Local files 88 | .dynamodb/ 89 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | const letters = ['a', 'b', 'c']; 5 | const fixture1 = fs.readFileSync(path.join(__dirname, 'fixtures/1.txt')).toString(); 6 | const fixture2 = fs.readFileSync(path.join(__dirname, 'fixtures/2.txt')).toString(); 7 | const fixture3 = fs.readFileSync(path.join(__dirname, 'fixtures/3.txt')).toString(); 8 | const fixture4 = fs.readFileSync(path.join(__dirname, 'fixtures/4.txt')).toString(); 9 | 10 | const { generate } = require('../src'); 11 | 12 | function check(fixture, level) { 13 | const output = fixture.trim(); 14 | const chars = letters.slice(); 15 | 16 | const gen = generate(chars, level); 17 | const result = []; 18 | 19 | for (let char of gen) { 20 | result.push(char); 21 | } 22 | 23 | expect(result.join('\n')).toEqual(output); 24 | } 25 | 26 | it('should be a function', () => { 27 | expect(generate).toEqual(jasmine.any(Function)); 28 | }); 29 | 30 | it('should not generate any items when passed empty alphabet', () => { 31 | const gen = generate(); 32 | let empty = true; 33 | 34 | for (let char of gen) { 35 | empty = false; 36 | } 37 | 38 | expect(empty).toBeTruthy(); 39 | }); 40 | 41 | it('should return list of all values when string size is default', () => { 42 | check(fixture3); 43 | }); 44 | 45 | it('should return list of all values when string size equals 1', () => { 46 | const level = 1; 47 | check(fixture1, level); 48 | }); 49 | 50 | it('should return list of all values when string size equals 2', () => { 51 | const level = 2; 52 | check(fixture2, level); 53 | }); 54 | 55 | it('should return list of all values when string size equals 3', () => { 56 | const level = 3; 57 | check(fixture3, level); 58 | }); 59 | 60 | it('should return list of all values when string size equals 4', () => { 61 | const level = 4; 62 | check(fixture4, level); 63 | }); 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # brute-force-generator 2 | 3 | [![cli-available](https://badgen.net/static/cli/available/?icon=terminal)](#cli) 4 | [![node version](https://img.shields.io/node/v/brute-force-generator.svg)](https://www.npmjs.com/package/brute-force-generator) 5 | [![npm version](https://badge.fury.io/js/brute-force-generator.svg)](https://badge.fury.io/js/brute-force-generator) 6 | [![downloads count](https://img.shields.io/npm/dt/brute-force-generator.svg)](https://www.npmjs.com/package/brute-force-generator) 7 | [![size](https://packagephobia.com/badge?p=brute-force-generator)](https://packagephobia.com/result?p=brute-force-generator) 8 | [![license](https://img.shields.io/npm/l/brute-force-generator.svg)](https://piecioshka.mit-license.org) 9 | [![github-ci](https://github.com/piecioshka/brute-force-generator/actions/workflows/testing.yml/badge.svg)](https://github.com/piecioshka/brute-force-generator/actions/workflows/testing.yml) 10 | 11 | 🔨 Build a dictionary by permuting passed letters (using ES2015+) 12 | 13 | ## Usage 14 | 15 | ```javascript 16 | const generate = require('brute-force-generator'); 17 | 18 | const gen = generate(['a', 'b'], 2); 19 | 20 | for (let record of gen) { 21 | console.log(record); // 'a', 'b', 'aa', 'ab', 'ba', 'bb' 22 | } 23 | ``` 24 | 25 | ## CLI 26 | 27 | Installation: 28 | 29 | ```bash 30 | npm install -g brute-force-generator 31 | ``` 32 | 33 | Help: 34 | 35 | ```bash 36 | brute-force-generator --help 37 | 38 | Usage: brute-force-generator -a [string] -l [num] 39 | 40 | Options: 41 | --help Show help [boolean] 42 | --version Show version number [boolean] 43 | -a, --alphabet [required] 44 | -l, --length [required] 45 | ``` 46 | 47 | Usage: 48 | 49 | ```bash 50 | # Lowercase latin alphabet — abcdefghijklmnopqrstuvwxyz 51 | brute-force-generator -a abcdefghijklmnopqrstuvwxyz -l 5 > latin-5.dic 52 | 53 | # Generate infinity wordlist (may take some time 😈) 54 | brute-force-generator -a abcdefghijklmnopqrstuvwxyz -l Infinity 55 | ``` 56 | 57 | ## Related 58 | 59 | * [dicts](https://github.com/piecioshka/dicts) 60 | * [test-md5-tools](https://github.com/piecioshka/test-md5-tools) 61 | * [indexed-string-variation](https://github.com/lmammino/indexed-string-variation) 62 | 63 | ## License 64 | 65 | [The MIT License](https://piecioshka.mit-license.org) @ 2019 66 | --------------------------------------------------------------------------------