diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 8d1b867..0000000 --- a/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.idea -*.pyc -*tmp* -bopscrk.egg-info -dist/ -*.log -*.bak -*.xcf -*.test.svg -*_all.svg \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index b7dcf94..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "bopscrk/modules/lyricpass"] - path = bopscrk/modules/lyricpass - url = https://github.com/r3nt0n/lyricpass.git diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 0b935d3..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,17 +0,0 @@ -include LICENSE -include *.in -include *.py -include bopscrk/*.cfg -global-exclude *.pyc *.pyo *~ -global-exclude *test* -global-exclude *tmp* -prune __pycache__ -prune */__pycache__ -prune build -prune dist -prune bopscrk/tests -prune img -prune .gitignore -prune .gitmodules -prune build_package.sh -prune requirements.txt diff --git a/README.md b/README.md index c53b7c1..4e1b088 100644 --- a/README.md +++ b/README.md @@ -1,152 +1,41 @@ -
- +[![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/) +![[Version 1.2](https://github.com/R3nt0n)](http://img.shields.io/badge/version-v1.2-orange.svg) +![[Python 2.7](https://github.com/R3nt0n)](http://img.shields.io/badge/python-2.7-blue.svg) +![[GPL-3.0 License](https://github.com/R3nt0n)](https://img.shields.io/badge/license-GPL%203.0-brightgreen.svg) +![[Date](https://github.com/R3nt0n)](http://img.shields.io/badge/date-06/05/2018-yellow.svg) - -[![BlackArch package](https://repology.org/badge/version-for-repo/blackarch/bopscrk.svg)](https://repology.org/project/bopscrk/versions) -[![Rawsec's CyberSecurity Inventory](https://inventory.raw.pm/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.raw.pm/) -[![Packaging status](https://repology.org/badge/tiny-repos/bopscrk.svg)](https://repology.org/project/bopscrk/versions) -![[GPL-3.0 License](https://github.com/r3nt0n)](https://img.shields.io/badge/license-GPL%203.0-brightgreen.svg) -![[Python 3](https://github.com/r3nt0n)](http://img.shields.io/badge/python-3-blue.svg) -![[Version 2.4.7](https://github.com/r3nt0n)](http://img.shields.io/badge/version-2.4.7-orange.svg) - - - - -
-
- - Logo - - -

bopscrk

- -

- Generate smart and powerful wordlists for targeted attacks -
- Explore the docs » -
-
- View Demo - · - Report Bug - · - Request Feature -

-
- - - - -
- Table of contents -
    -
  1. - About the Project - -
  2. -
  3. - Getting started - -
  4. -
  5. - Usage - -
  6. -
  7. Roadmap
  8. -
  9. - Contributing - -
  10. -
  11. Changelist
  12. -
  13. License
  14. -
  15. Contact
  16. -
  17. Acknowledgments
  18. -
  19. Legal disclaimer
  20. -
-
- - - - -## About the Project - -

- - - -+ **Targeted-attack wordlist creator**: introduce personal info related to target, combines every word and transforms results into possible passwords. The *lyricpass* module allows to **search lyrics related to artists** and include them to the wordlists. -+ **Customizable case** and **leet transforms**: create **custom charsets** and **transforms patterns** trough a simple **config file**. -+ **Interactive mode** and **one-line command interface** supported. -+ Included in **BlackArch Linux** pentesting distribution and **Rawsec's Cybersecurity Inventory** since August 2019. - - -### Built with - -+ **Python 3** (secondary branch keeps Python 2.7 legacy support) - + **requests** - + **alive-progress** - -### What's new - -- **2.4.7 RELEASED** (02/09/2024): Speed and performance dramatically increased. New extensive case transform mode allows to generate all possible case transforms. - -[//]: # (

) - -[//]: # (

) - -

(back to top)

- - - - -## Getting started - -### Installation - -``` -pip install bopscrk -``` - +# Bopscrk +Bopscrk (**Before Outset PaSsword CRacKing**) is a tool to **assist** in all the **previous process of password cracking**. By now, it's able to generate smart and powerful wordlists. + + +

+ +The first idea was inspired by **Cupp** and **Crunch**. We could say that bopscrk is a wordlist generator **situated between them**, taking the best of each one. The challenge was try to apply the Cupp's idea to more generic-situations and amplify the shoot-range of the resultant wordlist, without loosing this custom-wordlist-profiler feature. -*Alternatively, if you want to clone the repo from Github instead of install it from Pypi:* -``` -git clone --recurse-submodules https://github.com/r3nt0n/bopscrk -cd bopscrk -pip install -r requirements.txt -``` +## Changelist +**EXCLUDE WORDLISTS**: Speed improvement using multithreaded exclusions. +**NEW FEATURE**: Lyrics searching related to artists to increase the wordlist chances. -### Run interactive mode -``` -bopscrk -i -``` -

(back to top)

+## How it works ++ You have to **provide** some **words** which will act as a **base**. ++ The tool will generate **all possible combinations** between them. ++ To generate more combinations, it will add some **common separators** (e.g. "-", "_", "."), **random numbers** and **special chars**. ++ You can enable **leet** and **case transforms** to increase your chances. ++ If you enable **lyricpass mode**, the tool will ask you about **artists** and it will download all his **songs' lyrics**. Each line will be added as a new word. Then it will be **transform in several ways** (leet, case, only first letters, with and without spaces...). Artist names will be added too. ++ You can provide wordlists that you already tried against the target in order to exclude all this words from the resultant wordlist (`-x`). + +## Requirements ++ Python 2.7 ++ requests (*optional*, only if you want to use lyricpass) ++ beautifulsoup4 (*optional*, only if you want to use lyricpass) - ## Usage ``` @@ -159,228 +48,36 @@ bopscrk -i -l, --leet enable leet transformations -n max amount of words to combine each time (default: 2) -a , --artists artists to search song lyrics (comma-separated) + -A, --lyrics-all enable all possible transforms with lyrics + -x , --exclude exclude all the words included in other wordlists + (several wordlists should be comma-separated) -o , --output output file to save the wordlist (default: tmp.txt) - -C , --config specify config file to use (default: ./bopscrk.cfg) - --version print version and exit - -``` - -_For more information, please refer to the [Advanced usage](#advanced-usage) section._ -

(back to top)

-### How it works -+ You have to **provide** some **words** which will act as a base. -+ The **lyricpass feature** allow to introduce **artists**. The tool will download all his **songs' lyrics** and each line will be added as a new word. By default, artist names and a word formed by the initial of word on each phrase, will be added too. -+ The tool will generate **all possible combinations** between them. -+ To generate more combinations, it will add some **common separators** (e.g. "-", "_", "."), **numbers** and **special chars** frequently used in passwords. -+ You can use **leet** and **case transforms** to increase your chances. +``` + -[//]: # (+ You can provide **wordlists** that you have already tested against the target in order **to exclude** all this words from the resultant wordlist (`-x`).) - -### Tips +## Tips + Fields can be left **empty**. -+ You **can use accentuation** in your words and special chars (if you use the non-interactive mode, escape special chars like `'` and `"` with backslashes, e.g.: `bopscrk -w John,O\'hara,Doe,foo,bar`). ++ Words have to be written **without accents**, just normal characters. + In the others field you can write **several words comma-separated**. *Example*: 2C,Flipper. -+ If you want to produce **all possible leet transformations**, enable the **recursive_leet option** in configuration file. -+ If you want to produce **all possible case transformations**, enable the **extensive_case option** in configuration file. -+ You can **select which transforms to apply on lyrics phrases** found through the **cfg file**. + Using the **non-interactive mode**, you should provide years in the long and short way (1970,70) to get the same result than the interactive mode. + You have to be careful with **-n** argument. If you set a big value, it could result in **too huge wordlists**. I recommend values between 2 and 5. -+ To provide **several artist names** through command line you should provide it **comma-separated**. *Example*: `-a johndoe,johnsmith` -+ To provide **artist names with spaces** through command line you should provide it **quotes-enclosed**. *Example*: `-a "john doe,john smith"` - -

(back to top)

- - -### Advanced usage - -#### Customizing behaviour using .cfg file -+ In `bopscrk.cfg` file you can specify your own charsets and enable/disable options: - + **extra_combinations** (like `(john, doe) => 123john, john123, 123doe, doe123, john123doe doe123john`) are *enabled by default*. You can disable it in the configuration file in order to get more focused wordlists. - + **separators_chars**: characters to use in extra-combinations. *Can be a single char or a string of chars, e.g.: `!?-/&(`* - + **separators_strings**: strings to use in extra-combinations. *Can be a single string or a list of strings space-separated, e.g.: `123` `34!@`* - + **leet_charset**: characters to replace and correspondent substitute in leet transforms, *e.g.: `e:3 b:8 t:7 a:4`* - + **recursive_leet**: enables a recursive call to leet_transforms() function to get all possible leet transforms. *WARNING*: enabled with huge `--max` values (e.g.: greater than 18) could take a long time. *Can be true or false.* - + **extensive_case**: by default, bopscrk only applies the more common case transforms: all chars to lower, all chars to upper, each char to upper, all pairs to upper, all odds to upper, all consonants to upper and all vowels to upper. You can enable this option to obtain ALL possible case transforms, which can result in much larger wordlists, but might be useful in some scenarios. *Can be true or false.* - + **remove_parenthesis**: remove all parenthesis in lyrics found before any transform - + **take_initials**: produce words based on initial of each word in lyric phrases found (if enabled with remove_parenthesis disabled, it can produce useless words) - + **artist_split_by_word**: split artist names and add each word as a new one - + **lyric_split_by_word**: same with lyrics found - + **artist_space_replacement**: replace spaces in artist names with chars/strings defined in charset - + **lyric_space_replacement**: same with lyrics found - + **space_replacement_chars**: characters to insert instead of spaces inside an artist name or a lyric phrase. *Can be a single char or a string of chars, e.g.: `!?-/&(`* - + **space_replacement_strings**: strings to insert instead of spaces inside an artist name or a lyric phrase. *Can be a single string or a list of strings space-separated, e.g.: `123` `34!@`* - -+ **Parameters configuration examples** - + Combine all the words using dots as separator, and same using commas - `separators_chars=.,` - + Convert all "a/A" occurrences into "4" and all "e/E" occurrences into "3" - `leet_charset=a:4 e:3` - -

(back to top)

++ To feed lyricpass with **several artists** through command line you should provides it **comma-separated** and **quotes-enclosed**. *Example*: `-a "john doe,john smith"` ### Lyricpass -

- -This feature is based in a modified version of a [tool](https://github.com/initstring/lyricpass) developed originally by [initstring](https://github.com/initstring/). The changes are made to integrate input and output's tool with bopscrk. - -It will retrieve all lyrics from all songs which belongs to artists that you provide. **By default it will store each artist, each phrase found with space substitution, each phrase found reduced to its initials** (which will be transformed later if you have activated leet and case transforms). - -

(back to top)

- - -## Roadmap - -- [ ] Improve **memory management** - - [ ] Write wordlists into filesystem during execution and use it as cache (#12) -- [ ] Improve **performance** - - [x] Improve parallelism logic -- [ ] Extra features - - [x] Implement **progress bar** to keep user informed of the execution state - - [ ] Implement **session file** to keep track of the execution point and **be able to stop and resume sessions** (#12) - - [ ] Create **config options** for customized **case transforms** (e.g.: disable pair/odd transforms) - - [ ] Implement "pipable" output to allow integration with other tools (`-q` flag will just output final wordlist to stdout) - -See the [open issues](https://github.com/r3nt0n/bopscrk/issues) for a full list of proposed features (and known issues). - -

(back to top)

- - - - -## Contributing - -Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. - -If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". -Don't forget to give the project a star! Thanks again! - -1. Fork the Project -2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) -3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) -4. Push to the Branch (`git push origin feature/AmazingFeature`) -5. Open a Pull Request - - -### Contributors -* [noraj](https://github.com/noraj) contributed opening several issues and pull requests that have allow to fix some important bugs. He also managed by his own the tool's addition in BlackArch and RawSec repositories, which has increase its popularity and use -* [nylocx](https://github.com/nylocx) and [agoertz-fls](https://github.com/agoertz-fls) contributed adding Python3 support -* [glozanoa](https://github.com/glozanoa) and [fabaff](https://github.com/fabaff) contributed adding bopscrk command (improvements on setup.py) - -Thank you all! - -

(back to top)

- - - -## Changelist -[//]: # (+ `last development version (available on Github)`) -+ `2.4.7 version notes (02/09/2024)` - + Improving **case transform logic** (now it respects the case from the original word) - + Including **new basic case transform operations** - + Implementing **extensive case transform mode** - + Fixing typos - -+ `2.4.6 version notes (30/08/2024)` - + **Increasing parallelism performance** (real multiprocessing implementation) - + Better handling of config parser errors - + Fixing typos - -+ `2.4.5 version notes (02/08/2022)` - + **progress bar** implemented and working - + `version` argument included - + Docs improved - -+ `2.4.4 version notes (31/07/2022)` - + **Relative imports bug fixed** - + Starting to refactor general structure to allow **progressbar feature inclusion** +This feature is based in a modified version of a [tool](https://github.com/initstring/lyricpass) developed originally by [initstring](https://github.com/initstring/). -+ `2.4.3 version notes (28/07/2022)` - + Fixing project structure to allow properly install via pip: - + Add MANIFEST to exclude compiled and tests files when building dist - + Improving structure to properly copy all structure into python packages dir inside a parent dir - + Fixing relative path to config file - + Catch exception when a wrong config file was provided (notice and exit) +It will retrieve all lyrics from all songs which belongs to artists that you provide. As this feature can make the wordlist grow too much, **by default it will store each phrase reduced to its initials** (which will be transformed later if you have activated leet and case transforms). As one of the main methods to use lyrics as a password is to take just initials, It should be usually enough. -+ `2.4 version notes (26/07/2022)` - + Make the installation process easier enabling `pip install` method - + Starting to implement better memory management (cached wordlists writing and reading i/o files), not working yet - + Updating and fixing minor bugs related to dependencies - + **REMOVED FEATURE**: 'exclude from other wordlists', doesn't seem useful, there are other tools to do this specific work +With `--lyrics-all`, it will store the raw phrases too and apply some transforms over them (like convert spaces into dots and other special chars). This method is **strongly unrecommended**, because 5000 phrases could become 5.000.000 easily. -+ `2.3.1 version notes` - + Fixing namespace bug (related to aux.py module, renamed to auxiliars.py) when running on windows systems - + **unittest** (and simple unitary tests for transforms, excluders and combinators functions) **implemented**. +If you want to make an extensive and accurate lyrics-wordlist related to a target, better choice is to use it without any other words added (and maybe without leet and case transforms). -+ `2.3 version notes (15/10/2020)` - + **Customizable** configuration for **artists and lyrics transforms** using the cfg file - + Requirements at **setup.py updated** - + **Multithreads logic improved** - + **Leet and case order reversed** to improve operations efficiency - + **BUG FIXED** in lyrics space replacement - + **BUG FIXED** when remove duplicates (*Type Error: unhashable type: 'list'*) - + **Memory management and efficiency improved** - + **SPLIT INTO MODULES** to improve project structure - + **BUG FIXED** in wordlists-exclusion feature -+ `2.2 version notes (11/10/2020` - + **Configuration file** implemented - + **NEW FEATURE**: Allow to create **custom charsets** and **transforms patterns** trough the **config file** - + **NEW FEATURE**: **Recursive leet transforms** implemented (*disabled by default*, can be enabled in cfg file) +## TO-DO list ++ **Lyricpass** still needs some tweaks to speed up the search process (I would appreciate any help). -+ `2.2~beta version notes (10/10/2020)` - + The **lyricpass** integration have been **updated to run with last version released by initstring** - + `--lyrics-all` option removed (feature integrated in other options) -+ `2.1 version notes (11/07/2020)` - + Fixing **min and max length bug** - -+ `2.0/1.5 version notes (17/06/2020)` - + **PYTHON 3 NOW IS SUPPORTED**: master branch moves to Python 3. Secondary branch keeps Python 2.7 legacy support - -+ `0-1.2(beta) version notes` - + **EXCLUDE WORDLISTS**: speed improvement using multithreaded exclusions - + **NEW FEATURE**: lyrics searching related to artists increase the wordlist chances - -

(back to top)

- - - - -## License - -Distributed under the GNU General Public License v3.0. See `LICENSE` for more information. - -

(back to top)

- - - - -## Contact - -r3nt0n: [Github](https://github.com/r3nt0n) - [email](r3nt0n@protonmail.com) -bopscrk: [Github](https://github.com/r3nt0n/bopscrk) - [Pypi](https://pypi.org/project/bopscrk) - -

(back to top)

- - - - -## Acknowledgments - -* lyricpass module is based on a [project](https://github.com/initstring/lyricpass) created by [initstring](https://github.com/initstring). -* [Pixel Gothic font](https://dafonttop.com/pixel-gothic-font.font) by [Kajetan Andrzejak](https://dafonttop.com/tags.php?key=Kajetan%20Andrzejak). -* [Best-README-Template](https://github.com/othneildrew/Best-README-Template) by [othneildrew](https://github.com/othneildrew/). - -

(back to top)

- - - - ## Legal disclaimer This tool is created for the sole purpose of security awareness and education, it should not be used against systems that you do not have permission to test/attack. The author is not responsible for misuse or for any damage that you may cause. You agree that you use this software at your own risk. - -

(back to top)

- - diff --git a/bopscrk.py b/bopscrk.py new file mode 100755 index 0000000..7763c0b --- /dev/null +++ b/bopscrk.py @@ -0,0 +1,578 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# r3nt0n 25/10/2017 + +""" +Before Outset PaSsword CRacKing is a tool to assist in the previous process of +cracking passwords. By now, it's able to generate smart and powerful wordlists. +""" + +global name, __author__, __version__ +name = 'bopscrk.py' +__author__ = 'r3nt0n' +__version__ = '1.2' +__status__ = 'Development' + + + +import os +import sys +import datetime +import itertools +import argparse +from random import randint, choice +from collections import OrderedDict +from multiprocessing.dummy import Pool as ThreadPool + + + +class color: + PURPLE = '\033[95m' + CYAN = '\033[96m' + DARKCYAN = '\033[36m' + BLUE = '\033[94m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + RED = '\033[91m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + ORANGE = '\033[33m' + #ORANGEBG = '\033[48;2;255;165;0m' + END = '\033[0m' + + RAND_KEY_COLOR = [PURPLE, CYAN, DARKCYAN, YELLOW, ORANGE] + KEY_HIGHL = choice(RAND_KEY_COLOR) + + +################################################################################ +# ARGS DEFINITION +################################################################################ +parser = argparse.ArgumentParser(description='Generates smart and powerful wordlists.') + +parser.add_argument('-i', '--interactive', action="https://github.com/store_true", + help='interactive mode, the script will ask you about target') + +parser.add_argument('-w', action="https://github.com/store", metavar='', type=str, dest='words', + help='words to combine comma-separated (non-interactive mode)') + +parser.add_argument('--min', action="https://github.com/store", metavar='', type=int, dest='min', + default=4, help='min length for the words to generate ' + '(default: 4)') +parser.add_argument('--max', action="https://github.com/store", metavar='', type=int, dest='max', + default=32, help='max length for the words to generate ' + '(default: 32)') + +parser.add_argument('-c', '--case', action="https://github.com/store_true", help='enable case transformations') +parser.add_argument('-l', '--leet', action="https://github.com/store_true", help='enable leet transformations') + +parser.add_argument('-n', action="https://github.com/store", metavar='', type=int, dest='nWords', + default=2, help='max amount of words to combine each time ' + '(default: 2)') + +parser.add_argument('-a', '--artists', action="https://github.com/store", metavar='', type=str, + dest='artists', default=False, + help='artists to search song lyrics (comma-separated)') + +parser.add_argument('-A', '--lyrics-all', action="https://github.com/store_true", default=False, dest='lyrics_all', + help='enable all possible transforms with lyrics') + +parser.add_argument('-x', '--exclude', action="https://github.com/store", metavar='', type=str, + dest='exclude', default=False, + help='exclude all the words included in other wordlists ' + '(several wordlists should be comma-separated)') + +parser.add_argument('-o', '--output', action="https://github.com/store", metavar='', type=str, + dest='outfile', default='tmp.txt', + help='output file to save the wordlist (default: tmp.txt)') + + +################################################################################ +def banner(): + name_rand_leet = leet_transforms(name) + name_rand_leet = name_rand_leet[randint(0, (len(name_rand_leet) - 1))] + name_rand_case = case_transforms(name) + name_rand_case = name_rand_case[randint((len(name_rand_case) - 3), (len(name_rand_case) - 1))] + + print u'\n ,----------------------------------------------------, ,------------,' + print u' | [][][][][] [][][][][] [][][][] [][__] [][][][] | | v{}{}{} |'.format(color.BLUE, __version__, color.END) + print u' | | |------------|' + print u' | [][][][][][][][][][][][][][_] [][][] [][][][] | | {}{}{} |'.format(color.RED, name_rand_leet, color.END) + print u' | [_][][][]{}[]{}[][][][]{}[][]{}[][][ | [][][] [][][][] | | {}{}{}{} |'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END, color.BOLD, color.RED, name, color.END) + print u' | [][_][]{}[]{}[][][][][]{}[]{}[][][][]|| [] [][][][] | | {}{}{} |'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END, color.RED, name_rand_case, color.END) + print u' | [__][][][]{}[]{}[]{}[]{}[][][][][][__] [][][] [][][]|| | |------------|'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END) + print u' | [__][________________][__] [__][]|| | |{} {} {}|'.format(color.GREEN, __author__, color.END) + print u' `----------------------------------------------------´ `------------´\n' + # print u' +--------------------------------------------------------------------+' + # print u' | Names have to be written without accents, just normal characters. |' + # print u' | If you enable case transforms, doesn\'t matter the lower/uppercases |' + # print u' | in your input. |' + # print u' | |' + # print u' | In the others field you can write several words comma-separated. |' + # print u' | Example: 2C,Flipper |' + # print u' | |' + # print u' | Fields can be left empty. |' + # print u' +--------------------------------------------------------------------+\n' + + +################################################################################ +def clear(): + """Clear the screen. Works on Windows and Linux.""" + os.system(['clear', 'cls'][os.name == 'nt']) + + +################################################################################ +def isEmpty(variable): + """ + Check if a variable is empty. + :param date_str: var to check + :return: True or False + """ + empty = False + if len(str(variable)) == 0: + empty = True + return empty + + +################################################################################ +def is_valid_date(date_str): + """ + Check if a string corresponds to a valid date. + :param date_str: date to check + :return: True or False + """ + try: + datetime.datetime.strptime(date_str, '%d/%m/%Y') + return True + except ValueError: + return False + + +################################################################################ +def add_common_separators(wordlist): + """ + Take a wordlist and generate all possible combinations between the words + contained and another wordlist which contains common separator (e.g. _ ). + + :param wordlist: the base wordlist to combine + :return: a new wordlist with all the combinations + """ + common_separators = ['.', '_', '-', '123', '$', '%', '&', '#', '@'] + words = wordlist[:] + new_wordlist = [] + + for word in words: + for sep in common_separators: + new_wordlist.append(word + sep) + new_wordlist.append(sep + word) + + base_wordlist_with_seps = new_wordlist[:] + + for word in words: + for wordsep in base_wordlist_with_seps: + if word not in wordsep: + new_wordlist.append(wordsep + word) + new_wordlist.append(word + wordsep) + + return list(OrderedDict.fromkeys(new_wordlist)) + + +################################################################################ +def combinator(wordlist, nWords): + new_wordlist = wordlist[:] # I need copy to use itertools properly + wlist_combined = itertools.permutations(new_wordlist, nWords) + for combination in wlist_combined: + word = '' + for i in combination: + word += i + if word not in new_wordlist: new_wordlist.append(word) + return new_wordlist + + +################################################################################ +def remove_by_lengths(wordlist, minLength, maxLength): + for word in wordlist: + if (len(word) < minLength) or (len(word) > maxLength): wordlist.remove(word) + return wordlist + + +################################################################################ +def thread_transforms(transform_type, wordlist): + pool = ThreadPool(16) + # process each word in their own thread and return the results + new_wordlist = pool.map(transform_type, wordlist) + pool.close() + pool.join() + for lists in new_wordlist: + wordlist += lists + return new_wordlist + + +################################################################################ +def space_transforms(word): + new_wordlist = [] + new_wordlist.append(word.replace(' ', '')) + new_wordlist.append(word.replace(' ', '.')) + new_wordlist.append(word.replace(' ', '_')) + new_wordlist.append(word.replace(' ', '-')) + return new_wordlist + + +################################################################################ +def take_initials(word): + splitted = word.split(' ') + initials = '' + for char in splitted: + try: initials += char[0] + except IndexError: continue + return initials + + +################################################################################ +def exclude(word): + if word not in words_to_exclude: + return word + + +################################################################################ +def case_transforms(word): + new_wordlist = [] + + # Make each one upper (hello => Hello, hEllo, heLlo, helLo, hellO) + i=0 + for char in word: + new_word = word[:i] + char.upper() + word[i+1:] + i += 1 + if new_word not in new_wordlist: new_wordlist.append(new_word) + + # Make pairs upper (hello => HeLlO) + i=0 + new_word = '' + for char in word: + if i % 2 == 0: new_word += char.upper() + else: new_word += char + i += 1 + if new_word not in new_wordlist: new_wordlist.append(new_word) + + # Make odds upper (hello => hElLo) + i=0 + new_word = '' + for char in word: + if i % 2 != 0: new_word += char.upper() + else: new_word += char + i += 1 + if new_word not in new_wordlist: new_wordlist.append(new_word) + + # Make consonants upper (hello => HeLLo) + vowels = 'aeiou' + new_word = '' + for char in word: + if char not in vowels: new_word += char.upper() + else: new_word += char + if new_word not in new_wordlist: new_wordlist.append(new_word) + + # Make vowels upper (hello => hEllO) + new_word = '' + for char in word: + if char in vowels: new_word += char.upper() + else: new_word += char + if new_word not in new_wordlist: new_wordlist.append(new_word) + + return new_wordlist + + +################################################################################ +def leet_transforms(word): + new_wordlist = [] + i=0 + for char in word: + if char in ('a', 'A'): + char = '4' + elif char in ('i', 'I'): + char = '1' + elif char in ('e', 'E'): + char = '3' + elif char in ('s', 'S'): + char = '5' + elif char in ('b', 'B'): + char = '8' + elif char in ('o', 'O'): + char = '0' + word = word[:i] + char + word[i + 1:] + i += 1 + if word not in new_wordlist: new_wordlist.append(word) + return new_wordlist + + +################################################################################ +def asks(): + while True: + minLength = raw_input(u' {}[?]{} Password\'s min length [1] >>> '.format(color.BLUE, color.END)) + if isEmpty(minLength): minLength = 1; break + else: + try: + minLength = int(minLength); break + except ValueError: + print u' {}[!]{} Min length should be an integer'.format(color.RED, color.END) + while True: + maxLength = raw_input(u' {}[?]{} Password\'s max length [99] >>> '.format(color.BLUE, color.END)) + if isEmpty(maxLength): maxLength = 99; break + else: + try: + maxLength = int(maxLength) + if maxLength < minLength: print u' {}[!]{} Max should be greater or equal than min'.format(color.RED, color.END) + else: break + except ValueError: + print u' {}[!]{} Max length should be an integer'.format(color.RED, color.END) + + firstname = raw_input(u' {}[?]{} First name >>> '.format(color.BLUE, color.END)) + surname = raw_input(u' {}[?]{} Surname >>> '.format(color.BLUE, color.END)) + lastname = raw_input(u' {}[?]{} Last name >>> '.format(color.BLUE, color.END)) + + while True: + birth = raw_input(u' {}[?]{} Birth date (DD/MM/YYYY) >>> '.format(color.BLUE, color.END)) + if not isEmpty(birth) and not is_valid_date(birth): + print u' {}[!]{} Birthdate wrong format'.format(color.RED, color.END) + else: + break + + others = raw_input(u' {}[?]{} Some other relevant words (comma-separated) >>> '.format(color.BLUE, color.END)) + + leet = raw_input(u' {}[?]{} Do yo want to make leet transforms? [y/n] >>> '.format(color.BLUE, color.END)) + case = raw_input(u' {}[?]{} Do yo want to make case transforms? [y/n] >>> '.format(color.BLUE, color.END)) + + if leet.lower() == 'y': leet = True + else: leet = False + + if case.lower() == 'y': case = True + else: case = False + + while True: + nWords = raw_input(u' {}[?]{} How much words do you want to combine at most [2] >>> '.format(color.BLUE, color.END)) + if isEmpty(nWords): nWords = 2; break + else: + try: + nWords = int(nWords) + if nWords < 1: + print u' {}[!]{} Should be greater or equal than 1'.format(color.RED, color.END) + else: + break + except ValueError: + print u' {}[!]{} Should be an integer'.format(color.RED, color.END) + + artists = raw_input(u' {}[?]{} Artist names to search song lyrics (comma-separated) >>> '.format(color.BLUE, color.END)) + if isEmpty(artists): artists = False + + ly_all_transforms = raw_input(u' {}[?]{} Do yo want to make all posible transforms with lyrics? (not recommended) [y/n] >>> '.format(color.BLUE, color.END)) + if ly_all_transforms.lower() == 'y': ly_all_transforms = True + else: ly_all_transforms = False + + while True: + exclude = raw_input(u' {}[?]{} Exclude words from other wordlists? >>> '.format(color.BLUE, color.END)) + if isEmpty(exclude): exclude = False; break + else: + exclude = exclude.split(',') + valid_paths = True + for wl_path in exclude: + if not os.path.isfile(wl_path): + valid_paths = False + print u' {}[!]{} {} not found'.format(color.RED, color.END, wl_path) + + if valid_paths: + break + + outfile = raw_input(u' {}[?]{} Output file [tmp.txt] >>> '.format(color.BLUE, color.END)) + if isEmpty(outfile): outfile = u'tmp.txt' + + wordlist = [] + + if not isEmpty(firstname): + firstname = firstname.lower() + wordlist.append(firstname) + if not isEmpty(surname): + surname = surname.lower() + wordlist.append(surname) + if not isEmpty(lastname): + lastname = lastname.lower() + wordlist.append(lastname) + if not isEmpty(birth): + birth = birth.split('/') + for i in birth: + wordlist.append(i) + wordlist.append((birth[2])[-2:]) # Also add two last digits of the year + if not isEmpty(others): + others = others.split(',') + for i in others: + wordlist.append(i.lower()) + + return wordlist, minLength, maxLength, leet, case, nWords, artists, ly_all_transforms, exclude, outfile + + +################################################################################ +def main(): + args = parser.parse_args() + interactive = args.interactive + if len(sys.argv) == 1: parser.print_help(sys.stdout); sys.exit(2) # Print help and exit when runs without args + + + # SETTINGS + ############################################################################ + if interactive: + clear() + banner() + base_wordlist, minLength, maxLength, case, leet, nWords, artists, ly_all_transforms, exclude_wordlists, outfile = asks() + + else: + base_wordlist = [] + if args.words: + raw_wordlist = (args.words).split(',') + for word in raw_wordlist: + base_wordlist.append(word.lower()) + minLength = args.min + maxLength = args.max + case = args.case + leet = args.leet + nWords = args.nWords + artists = args.artists + outfile = args.outfile + ly_all_transforms = args.lyrics_all + + exclude_wordlists = args.exclude + if exclude_wordlists: + exclude_wordlists = exclude_wordlists.split(',') + for wl_path in exclude_wordlists: + if not os.path.isfile(wl_path): + print u' {}[!]{} {} not found'.format(color.RED, color.END, wl_path) + sys.exit(4) + + if artists: + artists = artists.split(',') + + + # Initial timestamp + start_time = datetime.datetime.now().time().strftime('%H:%M:%S') + wordlist = base_wordlist[:] # Copy to preserve the original + + + # WORD COMBINATIONS + ############################################################################ + if nWords > 1: + wordlist = combinator(base_wordlist, 2) + i = 2 + while i < nWords: + i += 1 + wordlist += combinator(base_wordlist, i) + + # WORD COMBINATIONS WITH COMMON SEPARATORS + ############################################################################ + wordlist += add_common_separators(base_wordlist) + + + # SEARCH FOR LYRICS + ############################################################################ + if artists: + try: + from lib.lyricpass import LyricsFinder + searchLyrics = True + except ImportError: + print u' {}[!]{} missing dependencies, only artist names will be added and transformed'.format(color.RED, color.END) + searchLyrics = False + + for artist in artists: + wordlist.append(artist) + wordlist += space_transforms(artist) + + if searchLyrics: + print u' {}[*]{} Looking for {}\'s lyrics...'.format(color.CYAN, color.END, artist.title()) + lyfinder = LyricsFinder(artist, False, True) + lyrics = lyfinder.lyrics + print u' {}[*] {}{}{} phrases found'.format(color.CYAN, color.GREEN, len(lyrics), color.END) + + # First we remove all the parenthesis in the phrases + lyrics = ([s.replace('(', '') for s in lyrics]) + lyrics = ([s.replace(')', '') for s in lyrics]) + + # Now take just the initials + base_lyrics = lyrics[:] + ly_initials_wl = thread_transforms(take_initials, base_lyrics) + for phrase in ly_initials_wl: + wordlist.append(phrase) + + # Make all possible transforms taking the song's phrases as base (leet, case and spaces) + if ly_all_transforms: + # Add the raw phrases to main wordlist + wordlist += lyrics + # Make space transforms and add it too + lyrics = thread_transforms(space_transforms, lyrics) + for phrase in lyrics: + wordlist += phrase + + + # Check for duplicates + wordlist = list(OrderedDict.fromkeys(wordlist)) + # Remove words which doesn't match the min-max range established + wordlist = remove_by_lengths(wordlist, minLength, maxLength) + + + # UPPER/LOWER TRANSFORMS + ############################################################################ + if case: + thread_transforms(case_transforms, wordlist) + + + # LEET TRANSFORMS + ############################################################################ + if leet: + thread_transforms(leet_transforms, wordlist) + + + # EXCLUDE FROM OTHER WORDLISTS + ############################################################################ + if exclude_wordlists: + global words_to_exclude + words_to_exclude = [] + + for wl_path in exclude_wordlists: + with open(wl_path, 'rb') as wlist_file: + wl = wlist_file.read() + wl = wl.split('\n') + words_to_exclude += wl + + pool = ThreadPool(16) + final_wordlist = pool.map(exclude, wordlist) + pool.close() + pool.join() + + wordlist = [word for word in final_wordlist if word is not None] + + + # Check for duplicates + wordlist = list(OrderedDict.fromkeys(wordlist)) + + + # SAVE WORDLIST TO FILE + ############################################################################ + with open(outfile, 'wb') as f: + for word in wordlist: + f.write(word + '\n') + + + # Final timestamp + end_time = datetime.datetime.now().time().strftime('%H:%M:%S') + total_time = (datetime.datetime.strptime(end_time, '%H:%M:%S') - + datetime.datetime.strptime(start_time, '%H:%M:%S')) + + # PRINT RESULTS + ############################################################################ + print u'\n {}[+]{} Time elapsed:\t{}'.format(color.GREEN, color.END, total_time) + print u' {}[+]{} Output file:\t{}{}{}{}'.format(color.GREEN, color.END, color.BOLD, color.BLUE, outfile, color.END) + print u' {}[+]{} Words generated:\t{}{}{}\n'.format(color.GREEN, color.END, color.RED, len(wordlist), color.END) + sys.exit(0) + + +################################################################################ +################################################################################ + +if __name__ == '__main__': + try: main() + except KeyboardInterrupt: print u'\n\n {}[!]{} Exiting...\n'.format(color.RED, color.END); sys.exit(3) + diff --git a/bopscrk/__main__.py b/bopscrk/__main__.py deleted file mode 100644 index d6f54bf..0000000 --- a/bopscrk/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk - diff --git a/bopscrk/bopscrk.cfg b/bopscrk/bopscrk.cfg deleted file mode 100644 index 399d445..0000000 --- a/bopscrk/bopscrk.cfg +++ /dev/null @@ -1,56 +0,0 @@ -################################################################################### -## bopscrk.py - main configuration file ## -## https://github.com/r3nt0n/bopscrk ## -##-------------------------------------------------------------------------------## -## EXTENSIVE LEET charset made by r3nt0n, suggestions are welcome! ## -## EXTENSIVE SEPARATORS and SPACE-REPLACEMENT charset from: ## -## https://owasp.org/www-community/password-special-characters ## -##-------------------------------------------------------------------------------## -## (!) WARNING: characters like % must be escaped (%%) to avoid syntax conflicts ## -################################################################################### - -[GENERAL] -# Reserved for potential future uses - -[COMBINATIONS] -# Enables extra combination and additions at beginning and end of words -# example: (john, doe) => 123john, john123, 123doe, doe123, john123doe doe123john -extra_combinations=false -# SEPARATORS CHARSET - Characters to use in extra-combinations -separators_chars=._-+&@! -separators_strings=!! 123 -# To get extensive charsets, uncomment the following lines: -#separators_chars=!"#$%%&'()*+,-./:;<=>?@[\]^_`{|}~ -#separators_strings=!! ¡¡ !!! ¡¡¡ ¡!¡ !¡! 123 1234 xXx XxX WwW wWw - - -[TRANSFORMS] -# LEET REPLACEMENT CHARSET -# characters to replace and correspondent substitute in leet transforms -leet_charset=a:4 e:3 i:1 o:0 s:$ -# To get an extensive charset, uncomment the following line -# leet_charset=a:4 a:@ e:3 i:1 i:! i:¡ l:1 o:0 s:$ s:5 b:8 t:7 c:( - -# RECURSIVE LEET TRANSFORMS - Enables a recursive call to leet_transforms() function -# Comment this line or set it to false in case you don't want to get all possible leet transforms -# (!) Warning: enabled with huge --max parameters (e.g.: greater than 18) could take several minutes -recursive_leet=true -extensive_case=false - -[LYRICS] -# Remove all parenthesis in lyrics found before any transform -remove_parenthesis=true -# Produce words based on initial of each word in phrases found -# (if enabled with remove_parenthesis disabled, it can produce useless words) -take_initials=true -artist_split_by_word=true -artist_space_replacement=true -lyric_split_by_word=false -lyric_space_replacement=true -# SPACE REPLACEMENT CHARSET - Characters and/or strings to insert instead of spaces -# inside an artist name or a lyric phrase -# Comment two above lines or set it empty in order to don't replace spaces, just remove them -space_replacement_chars=._-+&@! -space_replacement_strings= -# To get an extensive charset, uncomment the following line -#space_replacement_chars=!"#$%%&'()*+,-./:;<=>?@[\]^_`{|}~ diff --git a/bopscrk/bopscrk.py b/bopscrk/bopscrk.py deleted file mode 100644 index e63ac74..0000000 --- a/bopscrk/bopscrk.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - init script - - -name = 'bopscrk.py' -desc = 'Generate smart and powerful wordlists' -__version__ = '2.4.7' -__author__ = 'r3nt0n' -__status__ = 'Development' - - -def start(): - try: - from .modules import main - except ImportError: - # catching except when running python3 bopscrk.py - # (sketchy, need some refactor) - from modules import main - - main.run(name, __version__) - - -if __name__ == '__main__': - start() diff --git a/bopscrk/modules/__init__.py b/bopscrk/modules/__init__.py deleted file mode 100644 index 60ad33a..0000000 --- a/bopscrk/modules/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk - - -from .args import Arguments -from .config import Config - - -args = Arguments() -Config = Config(args.cfg_file) -#Config.setup() \ No newline at end of file diff --git a/bopscrk/modules/args.py b/bopscrk/modules/args.py deleted file mode 100644 index f63248b..0000000 --- a/bopscrk/modules/args.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# r3nt0n - -import os, sys, argparse - -from .color import color -from .auxiliars import is_empty, is_valid_date - - -class Arguments: - def __init__(self): - self.DEFAULT_MIN = 4 - self.DEFAULT_MAX = 12 - self.DEFAULT_N_WORDS = 2 - self.DEFAULT_OUTPUT_FILE = 'tmp.txt' - # scratch, still need to be regorganized - import os - self.DEFAULT_CFG_FILE = os.path.abspath( - os.path.join(os.path.dirname(os.path.abspath(__file__)), - '../bopscrk.cfg') - ) - #self.DEFAULT_CFG_FILE = './bopscrk.cfg' - - parser = argparse.ArgumentParser(description='Generates smart and powerful wordlists.') - - parser.add_argument('-i', '--interactive', action="https://github.com/store_true", - help='interactive mode, the script will ask you about target') - - parser.add_argument('-w', action="https://github.com/store", metavar='', type=str, dest='words', - help='words to combine comma-separated (will be combined with all words)') - - parser.add_argument('-m', '--min', action="https://github.com/store", metavar='', type=int, dest='min', - default=self.DEFAULT_MIN, help='min length for the words to generate (default: {})'.format(self.DEFAULT_MIN)) - - parser.add_argument('-M', '--max', action="https://github.com/store", metavar='', type=int, dest='max', - default=self.DEFAULT_MAX, help='max length for the words to generate (default: {})'.format(self.DEFAULT_MAX)) - - parser.add_argument('-c', '--case', action="https://github.com/store_true", help='enable case transformations') - - parser.add_argument('-l', '--leet', action="https://github.com/store_true", help='enable leet transformations') - - parser.add_argument('-n', action="https://github.com/store", metavar='', type=int, dest='n_words', - default=self.DEFAULT_N_WORDS, help='max amount of words to combine each time ' - '(default: {})'.format(self.DEFAULT_N_WORDS)) - parser.add_argument('-a', '--artists', action="https://github.com/store", metavar='', type=str, - dest='artists', default=False, - help='artists to search song lyrics (comma-separated)') - - # parser.add_argument('-x', '--exclude', action="https://github.com/store", metavar='', type=str, - # dest='exclude', default=False, - # help='exclude all the words included in other wordlists ' - # '(several wordlists should be comma-separated)') - - parser.add_argument('-o', '--output', action="https://github.com/store", metavar='', type=str, - dest='outfile', default=self.DEFAULT_OUTPUT_FILE, - help='output file to save the wordlist (default: {})'.format(self.DEFAULT_OUTPUT_FILE)) - - parser.add_argument('-C', '--config', action="https://github.com/store", metavar='', type=str, - dest='cfg_file', default=self.DEFAULT_CFG_FILE, - help='specify config file to use (default: {})'.format(self.DEFAULT_CFG_FILE)) - - parser.add_argument('--version', action="https://github.com/store_true", help='print version and exit') - - self.parser = parser - self.args = parser.parse_args() - self.interactive = self.args.interactive - self.cfg_file = self.args.cfg_file - self.print_version = self.args.version - - def set_interactive_options(self): - while True: - min_length = input(' {}[?]{} Passwords min length [{}] >>> '.format(color.BLUE, color.END, self.DEFAULT_MIN)) - if is_empty(min_length): - self.min_length = self.DEFAULT_MIN; break - else: - try: - self.min_length = int(min_length) - break - except ValueError: - print(' {}[!]{} Min length should be an integer'.format(color.RED, color.END)) - while True: - max_length = input(' {}[?]{} Password\'s max length [{}] >>> '.format(color.BLUE, color.END, self.DEFAULT_MAX)) - if is_empty(max_length): - self.max_length = self.DEFAULT_MAX; break - else: - try: - max_length = int(max_length) - if max_length < self.min_length: - print(' {}[!]{} Max should be greater or equal than min'.format(color.RED, color.END)) - else: - self.max_length = max_length - break - except ValueError: - print(' {}[!]{} Max length should be an integer'.format(color.RED, color.END)) - - firstname = input(' {}[?]{} First name >>> '.format(color.BLUE, color.END)) - surname = input(' {}[?]{} Surname >>> '.format(color.BLUE, color.END)) - lastname = input(' {}[?]{} Last name >>> '.format(color.BLUE, color.END)) - - while True: - birth = input(' {}[?]{} Birth date (DD/MM/YYYY) >>> '.format(color.BLUE, color.END)) - if not is_empty(birth) and not is_valid_date(birth): - print(' {}[!]{} Birthdate wrong format'.format(color.RED, color.END)) - else: - break - - self.artists = input(' {}[?]{} Artist names to search song lyrics (comma-separated) >>> '.format(color.BLUE, color.END)) - if is_empty(self.artists): - self.artists = False - else: - self.artists = self.artists.split(',') - - others = input(' {}[?]{} Some other relevant words (comma-separated) >>> '.format(color.BLUE, color.END)) - - leet = input(' {}[?]{} Do yo want to make leet transforms? [y/n] >>> '.format(color.BLUE, color.END)) - case = input(' {}[?]{} Do yo want to make case transforms? [y/n] >>> '.format(color.BLUE, color.END)) - - if leet.lower() == 'y': self.leet = True - else: self.leet = False - - if case.lower() == 'y': self.case = True - else: self.case = False - - while True: - n_words = input(' {}[?]{} How much words do you want to combine at most [{}] >>> '.format(color.BLUE, color.END, self.DEFAULT_N_WORDS)) - if is_empty(n_words): - self.n_words = self.DEFAULT_N_WORDS; break - else: - try: - n_words = int(n_words) - if n_words < 1: - print(' {}[!]{} Should be greater or equal than 1'.format(color.RED, color.END)) - else: - self.n_words = n_words - break - except ValueError: - print(' {}[!]{} Should be an integer'.format(color.RED, color.END)) - - # while True: - # exclude = input(' {}[?]{} Exclude words from other wordlists? >>> '.format(color.BLUE, color.END)) - # if is_empty(exclude): - # self.exclude_wordlists = False; break - # else: - # exclude = exclude.split(',') - # valid_paths = True - # for wl_path in exclude: - # if not os.path.isfile(wl_path): - # valid_paths = False - # print(' {}[!]{} {} not found'.format(color.RED, color.END, wl_path)) - # if valid_paths: - # self.exclude_wordlists = exclude - # break - - self.outfile = input(' {}[?]{} Output file [{}] >>> '.format(color.BLUE, color.END, self.DEFAULT_OUTPUT_FILE)) - if is_empty(self.outfile): self.outfile = self.DEFAULT_OUTPUT_FILE - - print('') # Print blank line after all questions - - self.base_wordlist = [] - # here I can select on which wordlist include each info by their weight (to implement) - if not is_empty(firstname): - firstname = firstname - self.base_wordlist.append(firstname) - if not is_empty(surname): - surname = surname - self.base_wordlist.append(surname) - if not is_empty(lastname): - lastname = lastname - self.base_wordlist.append(lastname) - if not is_empty(birth): - birth = birth.split('/') - for i in birth: - self.base_wordlist.append(i) - self.base_wordlist.append((birth[2])[-2:]) # Also add two last digits of the year - if not is_empty(others): - others = others.split(',') - for i in others: - self.base_wordlist.append(i) - - def set_cli_options(self): - self.base_wordlist = [] - if self.args.words: - [self.base_wordlist.append(word) for word in ((self.args.words).split(','))] - self.min_length = self.args.min - self.max_length = self.args.max - self.leet = self.args.leet - self.case = self.args.case - self.n_words = self.args.n_words - self.artists = self.args.artists - self.outfile = self.args.outfile - # self.exclude_wordlists = self.args.exclude - # if self.exclude_wordlists: - # self.exclude_wordlists = self.exclude_wordlists.split(',') - # for wl_path in self.exclude_wordlists: - # if not os.path.isfile(wl_path): - # print(' {}[!]{} {} not found'.format(color.RED, color.END, wl_path)) - # sys.exit(4) - if self.artists: - self.artists = self.artists.split(',') diff --git a/bopscrk/modules/auxiliars.py b/bopscrk/modules/auxiliars.py deleted file mode 100644 index 9958ad9..0000000 --- a/bopscrk/modules/auxiliars.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - auxiliar functions module - -import os, datetime - - -def clear(): - """Clear the screen. Works on Windows and Linux.""" - os.system(['clear', 'cls'][os.name == 'nt']) - -def is_empty(variable): - """ - Check if a variable (in a type convertible to string) is empty. Returns True or False - """ - empty = False - if len(str(variable)) == 0: - empty = True - return empty - -def is_valid_date(date_str): - """ - Check if a string corresponds to a valid date. - :param date_str: date to check - :return: True or False - """ - try: - datetime.datetime.strptime(date_str, '%d/%m/%Y') - return True - except ValueError: - return False - -def append_wordlist_to_file(filepath, wordlist): - """ - Save wordlist into filepath provided (creates it if not exists, add words to the end if exists). - :param filepath: path to file - :param wordlist: list of words to save - :return: True or False - """ - try: - with open(filepath, 'a') as f: - for word in wordlist: - f.write(word + '\n') - return True - except: - return False - - -def remove_duplicates_from_file(infile_path, outfile_path="temp.000000000.bopscrk"): - lines_seen = set() # holds lines already seen - outfile = open(outfile_path, "w") - infile = open(infile_path, "r") - for line in infile: - if line not in lines_seen: # not a duplicate - outfile.write(line) - lines_seen.add(line) - outfile.close() - infile.close() - os.remove(infile_path) - os.rename(outfile_path, infile_path) \ No newline at end of file diff --git a/bopscrk/modules/banners.py b/bopscrk/modules/banners.py deleted file mode 100644 index 74eb746..0000000 --- a/bopscrk/modules/banners.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - banner and help functions module - -from time import sleep -from random import randint - -from .color import color -from .transforms import * - - -# Set the time interval (in secs) between printing each line -interval = 0.03 - -def banner(name, version, author="r3nt0n"): - try: - name_rand_leet = leet_transforms(name) - name_rand_leet = name_rand_leet[randint(0, (len(name_rand_leet) - 1))] - except: - name_rand_leet = name - name_rand_case = case_transforms_basic(name) - name_rand_case = name_rand_case[randint((len(name_rand_case) - 3), (len(name_rand_case) - 1))] - #version = version[:3] - print(' ,----------------------------------------------------, ,------------,');sleep(interval) - print(' | [][][][][] [][][][][] [][][][] [][__] [][][][] | | v{}{}{} |'.format(color.BLUE, version, color.END));sleep(interval) - print(' | | |------------|');sleep(interval) - print(' | [][][][][][][][][][][][][][_] [][][] [][][][] |===| {}{}{} |'.format(color.RED, name_rand_leet, color.END));sleep(interval) - print(' | [_][][][]{}[]{}[][][][]{}[][]{}[][][ | [][][] [][][][] |===| {}{}{}{} |'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END, color.BOLD, color.RED, name, color.END));sleep(interval) - print(' | [][_][]{}[]{}[][][][][]{}[]{}[][][][]|| [] [][][][] |===| {}{}{} |'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END, color.RED, name_rand_case, color.END));sleep(interval) - print(' | [__][][][]{}[]{}[]{}[]{}[][][][][][__] [][][] [][][]|| | |------------|'.format(color.KEY_HIGHL, color.END, color.KEY_HIGHL, color.END));sleep(interval) - print(' | [__][________________][__] [__][]|| | |{} {} {}|'.format(color.GREEN, author, color.END));sleep(interval) - print(' `----------------------------------------------------´ `------------´\n');sleep(interval) - -def help_banner(): - print(u' Advanced usage and documentation: {}https://github.com/r3nt0n/bopscrk{}'.format(color.ORANGE,color.END));sleep(interval) - -def bopscrk_banner(): - sleep(interval * 4) - print('\n') - print(u'{} ▄▄▄▄ ▒█████ ██▓███ ██████ ▄████▄ ██▀███ ██ ▄█▀'.format(color.ORANGE));sleep(interval) - print(u' ▓█████▄ ▒██▒ ██▒▓██░ ██▒▒██ ▒ ▒██▀ ▀█ ▓██ ▒ ██▒ ██▄█▒ ');sleep(interval) - print(u' ▒██▒ ▄██▒██░ ██▒▓██░ ██▓▒░ ▓██▄ ▒▓█ ▄ ▓██ ░▄█ ▒▓███▄░ ');sleep(interval) - print(u' ▒██░█▀ ▒██ ██░▒██▄█▓▒ ▒ ▒ ██▒▒▓▓▄ ▄██▒▒██▀▀█▄ ▓██ █▄ ');sleep(interval) - print(u' ░▓█ ▀█▓░ ████▓▒░▒██▒ ░ ░▒██████▒▒▒ ▓███▀ ░░██▓ ▒██▒▒██▒ █▄');sleep(interval) - print(u' ░▒▓███▀▒░ ▒░▒░▒░ ▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░░ ░▒ ▒ ░░ ▒▓ ░▒▓░▒ ▒▒ ▓▒');sleep(interval) - print(u' ▒░▒ ░ ░ ▒ ▒░ ░▒ ░ ░ ░▒ ░ ░ ░ ▒ ░▒ ░ ▒░░ ░▒ ▒░');sleep(interval) - print(u' ░ ░ ░ ░ ░ ▒ ░░ ░ ░ ░ ░ ░░ ░ ░ ░░ ░');sleep(interval) - print(u' ░ ░ ░ ░ ░ ░ ░ ░ ░');sleep(interval) - print(u' ░ ░ {}'.format(color.END));sleep(interval) - #sleep(interval*2) \ No newline at end of file diff --git a/bopscrk/modules/color.py b/bopscrk/modules/color.py deleted file mode 100644 index caa31cb..0000000 --- a/bopscrk/modules/color.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk - -from random import choice - -class color: - PURPLE = u'\033[95m' - CYAN = u'\033[96m' - DARKCYAN = u'\033[36m' - BLUE = u'\033[94m' - GREEN = u'\033[92m' - YELLOW = u'\033[93m' - RED = u'\033[91m' - BOLD = u'\033[1m' - UNDERLINE = u'\033[4m' - ORANGE = u'\033[33m' - GREY = u'\033[90m' - #ORANGEBG = '\033[48;2;255;165;0m' - END = u'\033[0m' - - RAND_KEY_COLOR = [PURPLE, CYAN, DARKCYAN, YELLOW, ORANGE] - KEY_HIGHL = choice(RAND_KEY_COLOR) diff --git a/bopscrk/modules/combinators.py b/bopscrk/modules/combinators.py deleted file mode 100644 index f5b4745..0000000 --- a/bopscrk/modules/combinators.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - combinators functions module - -import itertools - -#from tqdm import tqdm -from alive_progress import alive_bar - -from . import Config -from .excluders import remove_duplicates - - -def add_common_separators(wordlist): - words = wordlist[:] - new_wordlist = [] - for word in words: - for separator in Config.SEPARATORS_CHARSET: - new_wordlist.append(word + separator) - new_wordlist.append(separator + word) - - base_wordlist_with_seps = new_wordlist[:] - - #with tqdm(total=len(words)) as progressbar: - with alive_bar(total=len(words),bar='bubbles',unknown='bubbles',spinner='bubbles',receipt=False) as progressbar: - for word in words: - for wordseparated in base_wordlist_with_seps: - if word not in wordseparated: - new_wordlist.append(wordseparated + word) - new_wordlist.append(word + wordseparated) - #progressbar.update() - progressbar() - - return remove_duplicates(new_wordlist) - - -def combinator(wordlist, nWords): - new_wordlist = wordlist[:] # I need copy to use itertools properly - wlist_combined = itertools.permutations(new_wordlist, nWords) - #list_combined_length = (sum(1 for _ in wlist_combined)) - wlist_combined = [''.join(i) for i in wlist_combined] - - #with tqdm(total=len(wlist_combined)) as progressbar: - with alive_bar(total=len(wlist_combined), bar='bubbles', unknown='bubbles', spinner='bubbles',receipt=False) as progressbar: - for combination in wlist_combined: - #progressbar.set_description("Processing %s" % combination) - word = '' - for i in combination: - word += i - if word not in new_wordlist: new_wordlist.append(word) - #progressbar.update() - progressbar() - - return remove_duplicates(new_wordlist) - diff --git a/bopscrk/modules/config.py b/bopscrk/modules/config.py deleted file mode 100644 index 4d20e14..0000000 --- a/bopscrk/modules/config.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - parsing configuration module - -import configparser - -#CFG_FILE_example = './bopscrk.cfg' # path relative to bopscrk.py - -class Config: - def __init__(self, cfg_file): - self.CFG_FILE = cfg_file - self.cfg = configparser.ConfigParser(strict=False) - - def read_config(self, category, field): - try: - self.cfg.read([self.CFG_FILE]) - value = self.cfg.get(category, field) - except Exception as e: - print(e) - value = False - return value - - def merge_settings(self, chars, strings): - final_list = [] - if chars: - final_list[:] = chars - if strings: - final_list.extend(strings.split()) - return final_list - - def parse_booleans(self, value): - try: - if value.lower() == 'true': - return True - return False - except AttributeError: - return None - - def setup(self): - self.EXTRA_COMBINATIONS = self.parse_booleans(self.read_config('COMBINATIONS', 'extra_combinations')) - self.SEPARATORS_CHARSET = self.merge_settings(self.read_config('COMBINATIONS', 'separators_chars'), - self.read_config('COMBINATIONS', 'separators_strings')) - self.LEET_CHARSET = (self.read_config('TRANSFORMS', 'leet_charset')).split() - self.RECURSIVE_LEET = self.parse_booleans(self.read_config('TRANSFORMS', 'recursive_leet')) - self.EXTENSIVE_CASE = self.parse_booleans(self.read_config('TRANSFORMS', 'extensive_case')) - self.REMOVE_PARENTHESIS = self.parse_booleans(self.read_config('LYRICS', 'remove_parenthesis')) - self.TAKE_INITIALS = self.parse_booleans(self.read_config('LYRICS', 'take_initials')) - self.ARTIST_SPLIT_BY_WORD = self.parse_booleans(self.read_config('LYRICS', 'artist_split_by_word')) - self.LYRIC_SPLIT_BY_WORD = self.parse_booleans(self.read_config('LYRICS', 'lyric_split_by_word')) - self.ARTIST_SPACE_REPLACEMENT = self.parse_booleans(self.read_config('LYRICS', 'artist_space_replacement')) - self.LYRIC_SPACE_REPLACEMENT = self.parse_booleans(self.read_config('LYRICS', 'lyric_space_replacement')) - self.SPACE_REPLACEMENT_CHARSET = self.merge_settings(self.read_config('LYRICS', 'space_replacement_chars'), - self.read_config('LYRICS', 'space_replacement_strings')) diff --git a/bopscrk/modules/excluders.py b/bopscrk/modules/excluders.py deleted file mode 100644 index a89669b..0000000 --- a/bopscrk/modules/excluders.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - transform functions module - -from multiprocessing import Pool, cpu_count -from collections import OrderedDict - -from . import Config - -def compare(word_to_exclude, word_in_wordlist): - if word_in_wordlist is not word_to_exclude: - return word_in_wordlist - -# Remove word to exclude from final_wordlist -def multithread_exclude(word_to_exclude, wordlist): - diff_wordlist = [] - with Pool(cpu_count()) as pool: - #args = (word, words_to_exclude) - diff_wordlist += pool.starmap(compare, [(word_to_exclude, word) for word in wordlist]) - - # Rewriting here removes excluded words from final_wordlist before it checks next wordlist - final_wordlist = [word for word in diff_wordlist if word is not None] - return final_wordlist - -def remove_duplicates(wordlist): - return list(OrderedDict.fromkeys(wordlist)) - -def remove_by_lengths(wordlist, min_length, max_length): - '''expect a list, return a new list with the values between min and max length provided''' - new_wordlist = [] - for word in wordlist: - #if (len(str(word)) < min_length) or (len(str(word)) > max_length): wordlist.remove(word) - if (len(str(word)) >= min_length) and (len(str(word)) <= max_length): new_wordlist.append(str(word)) - return new_wordlist \ No newline at end of file diff --git a/bopscrk/modules/lyricpass b/bopscrk/modules/lyricpass deleted file mode 160000 index 4008826..0000000 --- a/bopscrk/modules/lyricpass +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4008826d59d8ba056d8e2745f623c65751901957 diff --git a/bopscrk/modules/main.py b/bopscrk/modules/main.py deleted file mode 100644 index 3068ed0..0000000 --- a/bopscrk/modules/main.py +++ /dev/null @@ -1,231 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - script opts and presentation - -import sys, os, datetime - -#from bopscrk.bopscrk import name, __version__, __author__ -from . import args, Config -from .auxiliars import clear, remove_duplicates_from_file -from . import banners -from .color import color -from .transforms import leet_transforms, case_transforms, artist_space_transforms, lyric_space_transforms, multiprocess_transforms, take_initials, transform_cached_wordlist_and_save -from .combinators import combinator, add_common_separators -from .excluders import remove_by_lengths, remove_duplicates, multithread_exclude - - -def run(name, version): - # check Python version - if sys.version_info < (3, 0): print('Python 3 is required'); sys.exit(1) - # Print simple help and exit when runs without args - if len(sys.argv) == 1: args.parser.print_help(sys.stdout); sys.exit(2) - # Print version and exit (when runs with -v) - if args.print_version: print(name + '_' + version); sys.exit(0) - - try: - # setting args whether interactive or not - if args.interactive: - clear() - banners.bopscrk_banner() - banners.help_banner() - banners.banner(name, version) - args.set_interactive_options() - else: - banners.bopscrk_banner() - banners.help_banner() - banners.banner(name, version) - args.set_cli_options() - - # Check if config file exists - if not os.path.exists(args.cfg_file): - print(' {}[!]{} error trying to load config file {}'.format(color.RED, color.END, args.cfg_file)) - sys.exit(3) - - else: - Config.setup() - print(' {}[V]{} config file {} loaded'.format(color.GREEN, color.END, args.cfg_file)) - - # Initial timestamp - start_time = datetime.datetime.now().time().strftime('%H:%M:%S') - - # Inserting original values into final_wordlist - base_wordlist = args.base_wordlist - print(' {}[+]{} Appending words provided (base wordlist length: {})...'.format(color.BLUE, color.END, len(base_wordlist))) - final_wordlist = base_wordlist[:] # Copy to preserve the original - - # SEARCH FOR LYRICS - if args.artists: - print(' {}[+]{} Appending artist names (base wordlist length: {})...'.format(color.BLUE, color.END,(len(base_wordlist)+len(args.artists)))) - for artist in args.artists: - # Add IN BASE WORDLIST artist name as a word - base_wordlist.append(artist) - - # Add artist name with all space transformed configured (and enabled) into a specific charset - if not (Config.SPACE_REPLACEMENT_CHARSET and Config.ARTIST_SPACE_REPLACEMENT): - print(' {}[!]{} Any space-replacement charset specified in {}'.format(color.ORANGE, color.END, args.cfg_file)) - print(' {}[!]{} Spaces inside artists names won\'t be replaced\n'.format(color.ORANGE, color.END)) - elif Config.ARTIST_SPACE_REPLACEMENT: - print(' {}[+]{} Producing new words replacing any space in {}...'.format(color.BLUE, color.END,artist)) - final_wordlist += artist_space_transforms(artist) - - # Search lyrics if it meets dependencies for lyricpass - try: - from .lyricpass import lyricpass - print('\n{} -- Starting lyricpass module --\n'.format(color.GREY)) - print(' {}[*]{} Looking for {}\'s lyrics...'.format(color.CYAN, color.END, artist.title())) - lyrics = lyricpass.lyricpass(artist) - #lyrics = [s.decode("utf-8") for s in lyfinder.lyrics] - print('\n {}[*] {}{}{} phrases found'.format(color.CYAN, color.GREEN, len(lyrics), color.END)) - print('\n{} -- Stopping lyricpass module --\n'.format(color.GREY)) - - # First we remove all the parenthesis in the phrases (if enabled) - if Config.REMOVE_PARENTHESIS: - lyrics = ([s.replace('(', '') for s in lyrics]) - lyrics = ([s.replace(')', '') for s in lyrics]) - - # Add the phrases to BASE wordlist - lyrics = remove_by_lengths(lyrics, args.min_length, args.max_length) - print(' {}[+]{} Adding raw phrases filtering by min and max length range ({} phrases remain)...'.format(color.BLUE, color.END,len(lyrics))) - final_wordlist += lyrics - - # Take just the initials on each phrase and add as a new word to FINAL wordlist - if Config.TAKE_INITIALS: - base_lyrics = lyrics[:] - ly_initials_wordlist = multiprocess_transforms(take_initials, base_lyrics) - final_wordlist += ly_initials_wordlist - - # Make space transforms and add it too - if not (Config.SPACE_REPLACEMENT_CHARSET and Config.LYRIC_SPACE_REPLACEMENT): - print(' {}[!]{} Any spaces-replacement charset specified in {}'.format(color.ORANGE, color.END, args.cfg_file)) - print(' {}[!]{} Spaces inside lyrics won\'t be replaced\n'.format(color.ORANGE,color.END)) - elif Config.LYRIC_SPACE_REPLACEMENT: - print(' {}[+]{} Producing new words replacing spaces in {} phrases...'.format(color.BLUE, color.END, len(lyrics))) - base_lyrics = lyrics[:] - space_transformed_lyrics = multiprocess_transforms(lyric_space_transforms, base_lyrics) - final_wordlist += space_transformed_lyrics - - except ImportError: - print(' {}[!]{} missing dependencies, only artist names will be added and transformed'.format(color.RED, color.END)) - - # WORD COMBINATIONS - if ((args.n_words > 1)): - print(' {}[+]{} Creating all posible combinations between words...'.format(color.BLUE, color.END)) - i = 1 - while ((i < args.n_words) and (len(base_wordlist) > i)): - i += 1 - final_wordlist += combinator(base_wordlist, i) - print(' {}[*]{} {} words combined using {} words (words produced: {})'.format(color.CYAN,color.END,len(base_wordlist),i, len(final_wordlist))) - - # WORD COMBINATIONS (WITH COMMON SEPARATORS) - if Config.EXTRA_COMBINATIONS: - if Config.SEPARATORS_CHARSET: - #print(' {}[+]{} Creating extra combinations (separators charset in {}{}{})...'.format(color.BLUE, color.END,color.CYAN, args.cfg_file,color.END)) - print(' {}[+]{} Creating extra combinations using separators charset...'.format(color.BLUE,color.END)) - final_wordlist += add_common_separators(base_wordlist) - print(' {}[*]{} Words produced: {}'.format(color.CYAN, color.END, len(final_wordlist))) - else: - print(' {}[!]{} No separators charset specified in {}{}'.format(color.ORANGE, color.END, args.cfg_file,color.END)) - - # Remove words by min-max length range established - print(' {}[-]{} Removing words by min and max length provided ({}-{})...'.format(color.PURPLE, color.END,args.min_length,args.max_length)) - final_wordlist = remove_by_lengths(final_wordlist, args.min_length, args.max_length) - print(' {}[*]{} Words remaining: {}'.format(color.CYAN, color.END, len(final_wordlist))) - # (!) Check for duplicates (is checked before return in combinator() and add_common_separators()) - #final_wordlist = remove_duplicates(final_wordlist) - - - # # CASE TRANSFORMS - # if args.case: - # print(' {}[+]{} Applying case transforms to {} words...'.format(color.BLUE, color.END, len(final_wordlist))) - # - # # transform_cached_wordlist_and_save(case_transforms, args.outfile) # not working yet, infinite loop ?¿?¿ - # temp_wordlist = [] - # temp_wordlist += multithread_transforms(case_transforms, final_wordlist) - # final_wordlist += temp_wordlist - # - # final_wordlist = remove_duplicates(final_wordlist) - # - # # SAVE WORDLIST TO FILE BEFORE LEET TRANSFORMS - # ############################################################################ - # with open(args.outfile, 'w') as f: - # for word in final_wordlist: - # f.write(word + '\n') - - # LEET TRANSFORMS - if args.leet: - if not Config.LEET_CHARSET: - print(' {}[!]{} No leet charset specified in {}'.format(color.ORANGE, color.END, args.cfg_file)) - print(' {}[!]{} Skipping leet transforms...'.format(color.ORANGE, color.END, args.cfg_file)) - else: - recursive_msg = '' - if Config.RECURSIVE_LEET: - # print('\n {}[!] WARNING: Recursive leet is enabled, depending on the words\n' - # ' max-length configured (now is {}{}{}) and the size of your\n' - # ' wordlist at this point (now contains {}{}{} words), this process\n' - # ' could take a long time{}\n'.format(color.ORANGE,color.END,args.max_length,color.ORANGE,color.END,len(final_wordlist),color.ORANGE,color.END)) - recursive_msg = '{}recursive{} '.format(color.ORANGE,color.END) - print(' {}[+]{} Applying {}leet transforms to {} words...'.format(color.BLUE, color.END, recursive_msg,len(final_wordlist))) - - #transform_cached_wordlist_and_save(leet_transforms, args.outfile) - #remove_duplicates_from_file(args.outfile) - - temp_wordlist = [] - temp_wordlist += multiprocess_transforms(leet_transforms, final_wordlist) - final_wordlist += temp_wordlist - - # CASE TRANSFORMS - if args.case: - extensive_msg = '' - if Config.EXTENSIVE_CASE: - extensive_msg = '{}extensive{} '.format(color.ORANGE, color.END) - print(' {}[+]{} Applying {}case transforms to {} words...'.format(color.BLUE, color.END, extensive_msg, len(final_wordlist))) - - # transform_cached_wordlist_and_save(case_transforms, args.outfile) # not working yet, infinite loop ?¿?¿ - - temp_wordlist = [] - temp_wordlist += multiprocess_transforms(case_transforms, final_wordlist) - final_wordlist += temp_wordlist - - print(' {}[-]{} Removing duplicates...'.format(color.PURPLE, color.END)) - final_wordlist = remove_duplicates(final_wordlist) - print(' {}[*]{} Words remaining: {}'.format(color.CYAN, color.END, len(final_wordlist))) - - # EXCLUDE FROM OTHER WORDLISTS (deprecated) - #if args.exclude_wordlists: - # For each path to wordlist provided - # for wl_path in args.exclude_wordlists: - # print(' {}[+]{} Excluding wordlist {}...'.format(color.BLUE, color.END, os.path.basename(wl_path))) - # # Open the file - # with open(wl_path, 'r') as x_wordlist_file: - # # Read line by line in a loop - # while True: - # word_to_exclude = x_wordlist_file.readline() - # if not word_to_exclude: break # breaks the loop when file ends - # final_wordlist = multithread_exclude(word_to_exclude, final_wordlist) - - # re-check for duplicates - #final_wordlist = remove_duplicates(final_wordlist) - - # SAVE WORDLIST TO FILE - ########################################################################### - with open(args.outfile, 'w') as f: - for word in final_wordlist: - f.write(word + '\n') - - # Final timestamps - end_time = datetime.datetime.now().time().strftime('%H:%M:%S') - total_time = (datetime.datetime.strptime(end_time, '%H:%M:%S') - - datetime.datetime.strptime(start_time, '%H:%M:%S')) - - # PRINT RESULTS - ############################################################################ - print('\n {}[+]{} Words generated:\t{}{}{}'.format(color.GREEN, color.END, color.RED, len(final_wordlist),color.END)) - print(' {}[+]{} Elapsed time:\t{}'.format(color.GREEN, color.END, total_time)) - print(' {}[+]{} Output file:\t{}{}{}{}'.format(color.GREEN, color.END, color.BOLD, color.BLUE, args.outfile, color.END)) - #print(' {}[+]{} Words generated:\t{}{}{}\n'.format(color.GREEN, color.END, color.RED, str(sum(1 for line in open(args.outfile))), color.END)) - sys.exit(0) - - except KeyboardInterrupt: - print('\n\n {}[!]{} Exiting...\n'.format(color.RED, color.END)) - sys.exit(3) diff --git a/bopscrk/modules/transforms.py b/bopscrk/modules/transforms.py deleted file mode 100644 index 66ad47c..0000000 --- a/bopscrk/modules/transforms.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - transform functions module - -import itertools -from multiprocessing import cpu_count, Pool -from alive_progress import alive_bar - -from . import Config -from .excluders import remove_duplicates -from .auxiliars import append_wordlist_to_file - -# EXTENSIVE: generates all case transforms possibilities -def case_transforms_extensive(word): - word = word.lower() - return [new_word for new_word in map(''.join, itertools.product(*zip(word.upper(), word.lower())))] - -# BASIC: generates the more probable case transformations, but not all possibilities -def case_transforms_basic(word): - word = word.lower() - new_wordlist = [] - - # Include all chars to lower and all chars to upper - new_wordlist.append(word) - new_wordlist.append(word.upper()) - - # Make each one upper (hello => Hello, hEllo, heLlo, helLo, hellO) - i=0 - for char in word: - new_word = word[:i] + char.upper() + word[i+1:] - i += 1 - if new_word not in new_wordlist: new_wordlist.append(new_word) - - # Make pairs upper (hello => HeLlO) - i=0 - new_word = '' - for char in word: - if i % 2 == 0: new_word += char.upper() - else: new_word += char - i += 1 - if new_word not in new_wordlist: new_wordlist.append(new_word) - - # Make odds upper (hello => hElLo) - i=0 - new_word = '' - for char in word: - if i % 2 != 0: new_word += char.upper() - else: new_word += char - i += 1 - if new_word not in new_wordlist: new_wordlist.append(new_word) - - # Make consonants upper (hello => HeLLo) - vowels = 'aeiou' - new_word = '' - for char in word: - if char.lower() not in vowels: new_word += char.upper() - else: new_word += char - if new_word not in new_wordlist: new_wordlist.append(new_word) - - # Make vowels upper (hello => hEllO) - new_word = '' - for char in word: - if char.lower() in vowels: new_word += char.upper() - else: new_word += char - if new_word not in new_wordlist: new_wordlist.append(new_word) - - return new_wordlist - -def case_transforms(word): - if Config.EXTENSIVE_CASE: - return case_transforms_extensive(word) - return case_transforms_basic(word) - -def leet_transforms(word): - new_wordlist = [] - original_size = len(new_wordlist) - i=0 - leet_charset = Config.LEET_CHARSET - for char in word: - for lchar in leet_charset: - leeted_char = '' - if lchar.startswith(char.lower()): - leeted_char = lchar[-1:] - new_word = word[:i] + leeted_char + word[i + 1:] - if new_word not in new_wordlist: new_wordlist.append(new_word) - # don't break to allow multiple transforms to a single char (e.g. a into 4 and @) - i += 1 - - if Config.RECURSIVE_LEET: - for new_word in new_wordlist: - original_size = len(new_wordlist) - new_wordlist.extend(leet_transforms(new_word)) - if len(new_wordlist) == original_size: - break # breaking recursive call - - return remove_duplicates(new_wordlist) - - -def take_initials(word): - splitted = word.split(' ') - initials = '' - for char in splitted: - try: initials += char[0] - except IndexError: continue - return initials - - -def artist_space_transforms(word): - new_wordlist = [] - if ' ' in word: # Avoiding non-space words to be included many - if Config.ARTIST_SPLIT_BY_WORD: - # Add each word in the artist name splitting by spaces (e.g.: ['bob', 'dylan']) - new_wordlist.extend(word.split(' ')) - # Add artist name without spaces (e.g.: 'bobdylan') - new_wordlist.append(word.replace(' ', '')) - # Replace spaces in artist name with all space replacements charset - if (Config.ARTIST_SPACE_REPLACEMENT and Config.SPACE_REPLACEMENT_CHARSET): - for character in Config.SPACE_REPLACEMENT_CHARSET: - new_wordlist.append(word.replace(' ', character)) - - return new_wordlist - - -def lyric_space_transforms(word): - new_wordlist = [] - if ' ' in word: # Avoiding non-space words to be included many - if Config.LYRIC_SPLIT_BY_WORD: - # Add each word in the phrase splitting by spaces (e.g.: ['hello', 'world']) - new_wordlist.extend(word.split(' ')) - # Add phrase without spaces (e.g.: 'helloworld') - new_wordlist.append(word.replace(' ', '')) - # Replace spaces in phrase with all space replacements charset - if (Config.LYRIC_SPACE_REPLACEMENT and Config.SPACE_REPLACEMENT_CHARSET): - for character in Config.SPACE_REPLACEMENT_CHARSET: - new_wordlist.append(word.replace(' ', character)) - return new_wordlist - - -def multiprocess_transforms(transform_type, wordlist): - # process each word in their own thread and return the results - new_wordlists = [] - with Pool(cpu_count()) as pool: - with alive_bar(bar=None,spinner='bubbles', monitor=False,elapsed=False,stats=False,receipt=False) as progressbar: - new_wordlists += pool.map(transform_type, wordlist) - progressbar() - new_wordlist = [] - for nlist in new_wordlists: - new_wordlist += nlist - return new_wordlist - - -def transform_cached_wordlist_and_save(transform_type, filepath): - - last_position = 0 - - while True: - - cached_wordlist = [] - new_wordlist = [] - - with open(filepath, 'r', encoding='utf-8') as f: - counter = 0 - f.seek(last_position) # put point on last position - while True: - line = f.readline() - if counter >= 8000: - last_position = f.tell() # save last_position and break inner loop - break - if not line: - break - if line.strip() not in cached_wordlist: - cached_wordlist.append(line.strip()) - counter += 1 - last_position = f.tell() # save last_position - - new_wordlist += multiprocess_transforms(transform_type, cached_wordlist) - #cached_wordlist += new_wordlist - append_wordlist_to_file(filepath, new_wordlist) - - # read again the file to check if it ended - with open(filepath, 'r', encoding='utf-8') as f: - f.seek(last_position) # put point on last position - line = f.readline() - if not line: - break \ No newline at end of file diff --git a/bopscrk/tests/__init__.py b/bopscrk/tests/__init__.py deleted file mode 100644 index 6949f8a..0000000 --- a/bopscrk/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk diff --git a/bopscrk/tests/bopscrk.cfg b/bopscrk/tests/bopscrk.cfg deleted file mode 100644 index 3a97688..0000000 --- a/bopscrk/tests/bopscrk.cfg +++ /dev/null @@ -1,54 +0,0 @@ -################################################################################### -## bopscrk.py - tests configuration file ## -## https://github.com/r3nt0n/bopscrk ## -##-------------------------------------------------------------------------------## -## EXTENSIVE LEET charset made by r3nt0n, suggestions are welcome! ## -## EXTENSIVE SEPARATORS and SPACE-REPLACEMENT charset from: ## -## https://owasp.org/www-community/password-special-characters ## -##-------------------------------------------------------------------------------## -## (!) WARNING: characters like % must be escaped (%%) to avoid syntax conflicts ## -################################################################################### - -[GENERAL] -# Number of threads to use in multithreaded operations -threads=32 - -[COMBINATIONS] -# Enables extra combination and additions at begining and end of words -# example: (john, doe) => 123john, john123, 123doe, doe123, john123doe doe123john -extra_combinations=true -# SEPARATORS CHARSET - Characters to use in extra-combinations -separators_chars=._-$%%&#@ -separators_strings=123 xXx !! -# Uncomment the following line to get an extensive charset for separators -# separators_chars=!"#$%%&'()*+,-./:;<=>?@[\]^_`{|}~ - -[TRANSFORMS] -# LEET REPLACEMENT CHARSET -# characters to replace and correspondent substitute in leet transforms -leet_charset=a:4 e:3 i:1 o:0 s:$ t:7 -# Uncomment the following line to get an extensive (and expensive) charset -# leet_charset=a:4 a:@ e:3 i:1 i:! i:¡ l:1 o:0 s:$ s:5 b:8 t:7 c:( - -# RECURSIVE LEET TRANSFORMS - Enables a recursive call to leet_transforms() function -# Comment this line or set it to false in case you don't want to get all possible leet transforms -# (!) Warning: enabled with huge --max parameters (e.g.: greater than 18) could take several minutes -recursive_leet=true - -[LYRICS] -# Remove all parenthesis in lyrics found before any transform -remove_parenthesis=true -# Produce words based on initial of each word in phrases found -# (if enabled with remove_parenthesis disabled, it can produce useless words) -take_initials=true -artist_split_by_word=true -artist_space_replacement=true -lyric_split_by_word=true -lyric_space_replacement=true -# SPACE REPLACEMENT CHARSET - Characters and/or strings to insert instead of spaces -# inside an artist name or a lyric phrase -# Comment two above lines or set it empty in order to don't replace spaces, just remove them -space_replacement_chars=!@+._- -space_replacement_strings= -# Uncomment the following line to get an extensive charset -#space_replacement_chars=!"#$%%&'()*+,-./:;<=>?@[\]^_`{|}~ \ No newline at end of file diff --git a/bopscrk/tests/combinators_tests.py b/bopscrk/tests/combinators_tests.py deleted file mode 100644 index dbef1ed..0000000 --- a/bopscrk/tests/combinators_tests.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - excluders functions tests - -import unittest - -import sys -from os import path -sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) - -from ..modules.excluders import compare, multithread_exclude, remove_duplicates, remove_by_lengths - - -class TestExcluders(unittest.TestCase): - def setUp(self): - pass - def tearDown(self): - pass - - def test_compare(self): - word_to_exclude = 'tested-password' - word_in_wordlist = 'new-password' - self.assertEqual('new-password', compare(word_to_exclude, word_in_wordlist)) - word_in_wordlist = 'tested-password' - self.assertEqual(None, compare(word_to_exclude, word_in_wordlist)) - - def test_multithread_exclude(self): - word_to_exclude = 'tested-password' - wordlist = ['new-password', 'N3w_p4S$w0Rd', 'tested-password', 'anotHer.n3w.Pa$$word'] - self.assertEqual(['new-password', 'N3w_p4S$w0Rd', 'anotHer.n3w.Pa$$word'], - multithread_exclude(word_to_exclude, wordlist)) - - def test_remove_by_duplicates(self): - wordlist = ['duplicate-password', 'unique_password', 'duplicate-password'] - self.assertEqual(['duplicate-password', 'unique_password'], remove_duplicates(wordlist)) - - def test_remove_by_lengths(self): - wordlist = ['p', 'pa', 'pas', 'pass', 'passw', 'passwo', 'passwor', 'password'] - self.assertEqual(['pass', 'passw', 'passwo'], remove_by_lengths(wordlist, 4, 6)) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/bopscrk/tests/excluders_tests.py b/bopscrk/tests/excluders_tests.py deleted file mode 100644 index dbef1ed..0000000 --- a/bopscrk/tests/excluders_tests.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - excluders functions tests - -import unittest - -import sys -from os import path -sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) - -from ..modules.excluders import compare, multithread_exclude, remove_duplicates, remove_by_lengths - - -class TestExcluders(unittest.TestCase): - def setUp(self): - pass - def tearDown(self): - pass - - def test_compare(self): - word_to_exclude = 'tested-password' - word_in_wordlist = 'new-password' - self.assertEqual('new-password', compare(word_to_exclude, word_in_wordlist)) - word_in_wordlist = 'tested-password' - self.assertEqual(None, compare(word_to_exclude, word_in_wordlist)) - - def test_multithread_exclude(self): - word_to_exclude = 'tested-password' - wordlist = ['new-password', 'N3w_p4S$w0Rd', 'tested-password', 'anotHer.n3w.Pa$$word'] - self.assertEqual(['new-password', 'N3w_p4S$w0Rd', 'anotHer.n3w.Pa$$word'], - multithread_exclude(word_to_exclude, wordlist)) - - def test_remove_by_duplicates(self): - wordlist = ['duplicate-password', 'unique_password', 'duplicate-password'] - self.assertEqual(['duplicate-password', 'unique_password'], remove_duplicates(wordlist)) - - def test_remove_by_lengths(self): - wordlist = ['p', 'pa', 'pas', 'pass', 'passw', 'passwo', 'passwor', 'password'] - self.assertEqual(['pass', 'passw', 'passwo'], remove_by_lengths(wordlist, 4, 6)) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/bopscrk/tests/transforms_tests.py b/bopscrk/tests/transforms_tests.py deleted file mode 100644 index 6d3a564..0000000 --- a/bopscrk/tests/transforms_tests.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk -# bopscrk - transform functions tests - -import unittest - -import sys -from os import path -sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) - -from ..modules.transforms import case_transforms, leet_transforms, multiprocess_transforms, \ - take_initials, artist_space_transforms, lyric_space_transforms - - -class TestTransforms(unittest.TestCase): - def setUp(self): - pass - def tearDown(self): - pass - - def test_leet_transform(self): - word = 'aeiost' - self.assertEqual(63, len(leet_transforms(word))) - - def test_case_transform(self): - word = 'hello' - self.assertEqual(9, len(case_transforms(word))) - - def test_multithread_transform(self): - wordlist = ['hello', 'world', 'lorem', 'ipsum'] - self.assertEqual(33, len(multiprocess_transforms(case_transforms, wordlist))) - self.assertEqual(10, len(multiprocess_transforms(leet_transforms, wordlist))) - - def test_take_initials(self): - word = 'hello world lorem ipsum' - self.assertEqual('hwli', take_initials(word)) - - def test_lyric_space_transform(self): - word = 'hello world lorem ipsum' - self.assertEqual(11, len(lyric_space_transforms(word))) - - def test_artist_lyric_space_transform(self): - word = 'hello world lorem ipsum' - self.assertEqual(11, len(artist_space_transforms(word))) - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/build_package.sh b/build_package.sh deleted file mode 100644 index 151a800..0000000 --- a/build_package.sh +++ /dev/null @@ -1,6 +0,0 @@ -# Update submodule (https://stackoverflow.com/a/1032653) -#git submodule update --init --recursive # only the first time -git submodule update --recursive --remote - -# Build package -python3 setup.py -v sdist diff --git a/img/bopscrk.gif b/img/bopscrk.gif deleted file mode 100644 index 8cbc494..0000000 Binary files a/img/bopscrk.gif and /dev/null differ diff --git a/img/original.gif b/img/example.gif similarity index 100% rename from img/original.gif rename to img/example.gif diff --git a/img/logo.svg b/img/logo.svg deleted file mode 100644 index 42a3ccd..0000000 --- a/img/logo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -bopscrk logoƂbhttps://github.com/r3nt0n1/08/2022bopscrk logohttps://github.com/r3nt0n/bopscrk diff --git a/img/logo_raster.svg b/img/logo_raster.svg deleted file mode 100644 index df140d1..0000000 --- a/img/logo_raster.svg +++ /dev/null @@ -1,262 +0,0 @@ - - - -bopscrk logohttps://github.com/r3nt0n1/08/2022bopscrk logohttps://github.com/r3nt0n/bopscrk diff --git a/img/lyricpass_demo.png b/img/lyricpass_demo.png deleted file mode 100644 index 03016c7..0000000 Binary files a/img/lyricpass_demo.png and /dev/null differ diff --git a/img/progressbar_example1.gif b/img/progressbar_example1.gif deleted file mode 100644 index 9af899f..0000000 Binary files a/img/progressbar_example1.gif and /dev/null differ diff --git a/img/progressbar_example2.gif b/img/progressbar_example2.gif deleted file mode 100644 index cd5e4c4..0000000 Binary files a/img/progressbar_example2.gif and /dev/null differ diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..d9096cb --- /dev/null +++ b/lib/__init__.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# bopscrk (https://www.github.com/R3nt0n/bopscrk) +# R3nt0n (https://www.github.com/R3nt0n) diff --git a/lib/lyricpass.py b/lib/lyricpass.py new file mode 100644 index 0000000..9ae0122 --- /dev/null +++ b/lib/lyricpass.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# This is a modified version of a tool created by initstring. +# +# Original version: https://github.com/initstring/lyricpass +# Author's blog: https://initblog.com/ +# +# Modified by: r3nt0n (https://github.com/R3nt0n) (05/2018) +# Included in: bopscrk (https://github.com/R3nt0n/bopscrk) + + +from bs4 import BeautifulSoup +import requests +import string + + +class LyricsFinder: + def __init__(self, artist, lower=False, punct=False): + """ + :param artist (str): string to search + :param lower (bool): if True, switches all letters to lower case. + :param punct (bool): if True, preserves punctuation (which is removed by default). + """ + self.lower = lower + self.punctuation = punct + + artist = artist.title() + + lyrics = [] + + artisturl = self.create_artist_url(https://github.com/artist) # create a workable URL + songlinks = self.get_songs(artisturl, artist) # find all the songs for this artist + for s in songlinks: + for l in self.get_lyrics(s): # get a list of lyric lines + try: + lyrics.append(l) # append found lines to master list + except: + continue + + ######################################################################## + # [!] r3nt0n => Tried with threads to speed up, no lucky + ######################################################################## + # from multiprocessing.dummy import Pool as ThreadPool + # pool = ThreadPool(16) + # # process each word in their own thread and return the results + # lyricsLists = pool.map(self.get_lyrics, songlinks) + # pool.close() + # pool.join() + # for lst in lyricsLists: + # try: lyrics += lst + # except: continue + ######################################################################## + + self.lyrics = self.format_lyrics(lyrics) # format lyrics as specified in arguments + + + # The web site uses underscores in place of spaces. This function will format for us: + def create_artist_url(https://github.com/self,%20a): + a = a.replace(' ', '_') + url = 'http://lyrics.wikia.com/wiki/' + a + return url + + + # The site has a standard format for URLs. After we find the song names, we can use this to get the URL: + def create_song_url(https://github.com/self,%20song,%20artist): + song = song.replace(' ', '_') + artist = artist.replace(' ', '_') + url = 'http://lyrics.wikia.com/wiki/' + artist + ':' + song + return url + + + # This function attempts to create a list of links to songs based on the artist put in on the command line. + # Later, we will use these song names to go looking for the lyrics: + def get_songs(self, artisturl, artist): + cleanlinks = [] + response = requests.get(artisturl) # We want to scrape the artist's landing page + soup = BeautifulSoup(response.content, "html.parser") + rawlinks = soup.select("ol li b a") # On that page, find the bulleted song lists + for l in rawlinks: + url = self.create_song_url(https://github.com/l.text,%20artist) # Create a new link based on artist and song name + cleanlinks.append(url) # Stash this song link in a list to return + return cleanlinks + + + # After we know the song names, we can use the artist name and the url function above to go find the actual lyrics. + # This function does some basic cleaning of HTML tags out of the return strings. I found that unexpected data + # is occasionally returned and generated errors trying to append to a list, so we will work around that with try + # and except: + def get_lyrics(self, songurl): + l = [] + response = requests.get(songurl) # Now we scrape each individual song page + soup = BeautifulSoup(response.content, "html.parser") # Use bs4 to parse the html data + lyricbox = soup.find('div', {'class': 'lyricbox'}) # The lyrics are stored in a div tag called lyricbox + if lyricbox: # Verify we find lyrics on the page + for line in lyricbox: + line = line.encode('utf-8').strip() # Encode the data and remove whitespaces + if line and '<' not in line.decode('utf-8') and '\\' not in line.decode('utf-8'): # Hacky, need to improve + try: + l.append(line) # If this is good, clean text: append it to the list + except: + continue + return l # This returns a long list of lyrics to the main func + + + # This function can be used to further deduplicate the list after punctuation is removed. + def dedupe(self, seq): + seen = set() + seen_add = seen.add + return [x for x in seq if not (x in seen or seen_add(x))] + + + # This function cleans up the data before writing, including any optional parameters specified at launch: + def format_lyrics(self, rawlyrics): + formatted = rawlyrics + if self.lower: + formatted = [element.lower() for element in formatted] + if not self.punctuation: + formatted = [''.join(c for c in s if c not in string.punctuation) for s in formatted] + formatted = self.dedupe(formatted) + + return formatted \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 837f0db..d1def6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -requests -alive-progress \ No newline at end of file +requests==2.20.0 +beautifulsoup4==4.6.0 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 76b73e1..0000000 --- a/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[metadata] -description-file=README.md -license_files=LICENSE diff --git a/setup.py b/setup.py deleted file mode 100644 index 08e439e..0000000 --- a/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# https://github.com/r3nt0n/bopscrk - -# packages with python3 setup.py -v sdist - -from setuptools import setup, find_packages -from bopscrk.bopscrk import __version__, desc - -# Read project description -with open('README.md', 'r') as f: - long_desc = f.read() - -setup( - name='bopscrk', - version=__version__, - url='https://github.com/r3nt0n/bopscrk', - author='r3nt0n', - author_email='r3nt0n@protonmail.com', - license='GNU General Public License v3.0', - description=desc, - long_description=long_desc, - long_description_content_type="text/markdown", - include_package_data=True, - package_data={ - # If any package contains *.cfg files, include them - '': ['*.cfg'], - }, - #packages=['modules',], - #packages=find_packages(), - packages=['bopscrk', 'bopscrk.modules', 'bopscrk.modules.lyricpass'], - #scripts=['bopscrk/bopscrk.py'], - install_requires=['requests', 'alive-progress'], - entry_points = { - 'console_scripts':[ - #'bopscrk = bopscrk.modules.main:run' - 'bopscrk = bopscrk.bopscrk:start' - ] - } -)