Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run modes #5

Merged
merged 9 commits into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 88 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,84 @@ Pattern Expander was intended as password recovery tool where the
password follows a certain pattern.

For example `p[a@][s$][s$]` will result in:
`pass, p@ss, pa$s, p@$s, pas$, p@s$, pa$$, p@$$`

```sh
pass
p@ss
pa$s
p@$s
pas$
p@s$
pa$$
p@$$
```


Characters between [ ] are a group. Every character in a group is substituted
at the given position.

## Installation

### Requirements
- gcc
- make
- gtest
- gcov

On Debian, those can be installed via:
`sudo apt-get install build-essential libgtest-dev gcovr`

### Build and install
```sh
make
sudo make install
```

You don't need to install patext, after building, you can run it from the the `./bin/` folder

## Usage
```
patexp [-h | --help] <command> [<args>]
commands:
run [<pat1> <pat2> .. ] | <stdin> : Generates strings from a list of patterns
validate [<pat1> <pat2> .. ] | <stdin> : Validates if the patterns provided are syntaxically correct
configure: Sets the various configuration options
```

### Examples

Assuming you have compiled and running out of the local bin folder:

```sh
$./bin/patexp run [a-c] [1-3] abc[1-3]
a
b
c
1
2
3
abc1
abc2
abc3

```

We can load the patterns from a file via

```sh
$cat patters.txt | ./bin/patexp run
a
b
c
1
2
3
abc1
abc2
abc3

```


## Syntax

Expand Down Expand Up @@ -62,24 +135,28 @@ All characters are case sensative.
Result: 1a, 2a, 3a, 1b, 2b, 3b, 1c, 2c, 3c


## Building
## Development

### Targets:
- release: default target. Builds the main executable
- test: Builds the main executable with debug info. Builds and runs the unit tests.
- report - creates a coverage report
- debug: Builds with debug information and test coverage enabled
- test: Builds with debug information and test coverage enabled. Builds and runs the unit tests.
- report: Creates a test coverage report


### Install build requirements:
`sudo apt-get install build-essential libgtest-dev gcovr`
### Testing
Some example patters are given in the `test_data` folder. Those can be used for system level testing.
For example:

### Compile:
`make`
```sh
cat test_data/valid_patterns.txt | patext run
```

```sh
cat test_data/valid_patterns.txt | xargs patext run
```

### Run unit tests
`make test`


## Usage
`patexp <pattern>`

98 changes: 60 additions & 38 deletions src/Expander.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ using namespace std;
using namespace PatternExpander;

Expander::Expander(wchar_t esc, wchar_t range, wchar_t grpBegin, wchar_t grpEnd) :
escapeSymbol(esc), rangeSymbol(range), groupBegin(grpBegin), groupEnd(grpEnd) {}
escapeSymbol(esc), rangeSymbol(range), groupBegin(grpBegin), groupEnd(
grpEnd)
{
}

void Expander::generate(const wstring &pattern)
{
{
vector<wstring> results;

//This will expand all range (a-b) expressions
wstring expandedPattern = expand(pattern);
size_t pLength = expandedPattern.length();
if (pLength == 0) {
if (pLength == 0)
{
return;
}

Expand All @@ -28,8 +32,8 @@ void Expander::generate(const wstring &pattern)
bool isFirstInGroup = true;
vector<wstring> partials;


for (uint i = 0; i < pLength; i++) {
for (uint i = 0; i < pLength; i++)
{
if (expandedPattern[i] == escapeSymbol) //escape character reached
{
if (isEscSeq(expandedPattern, i)) //check if the next character is a valid escape sequence
Expand All @@ -38,11 +42,15 @@ void Expander::generate(const wstring &pattern)
continue;
}

} else if (expandedPattern[i] == groupBegin && !escSeqReached) {
}
else if (expandedPattern[i] == groupBegin && !escSeqReached)
{
isFirstInGroup = true;
load++;
continue;
} else if (expandedPattern[i] == groupEnd && !escSeqReached) {
}
else if (expandedPattern[i] == groupEnd && !escSeqReached)
{
load--;
continue;
}
Expand All @@ -52,9 +60,10 @@ void Expander::generate(const wstring &pattern)
{
if (currentItem == 0) //data array is empty
{
results.push_back(wstring(1,expandedPattern[i]));
results.push_back(wstring(1, expandedPattern[i]));
currentItem++;
} else //variations are present.
}
else //variations are present.
{
//add the constant character to all variations
//Just appending the constant character to all patterns
Expand All @@ -63,7 +72,8 @@ void Expander::generate(const wstring &pattern)
results[j] = results[j] + pattern[i];
}
}
} else if (load > 0) //wchar_tacter inside a variable block
}
else if (load > 0) //wchar_tacter inside a variable block
{
//when we first enter the variable block, we save the
//existing patterns
Expand All @@ -81,12 +91,14 @@ void Expander::generate(const wstring &pattern)
//That means that the result set is empty
//If that's the case, just add the first item from the varible block
if (partials.empty())
results.push_back(wstring(1,expandedPattern[i]));
else {
results.push_back(wstring(1, expandedPattern[i]));
else
{
//The result set is not empty
//Append the first item of the variable block to the existing patterns,
//then add it the result set.
for (uint item = 0; item < partials.size(); item++) {
for (uint item = 0; item < partials.size(); item++)
{
results.push_back(partials[item] + expandedPattern[i]);
}
}
Expand All @@ -95,19 +107,19 @@ void Expander::generate(const wstring &pattern)
escSeqReached = false;
} //end for


data.insert(data.end(), results.begin(), results.end());
}

uint Expander::getBlockElements(const wstring& pattern, uint& start,
vector<wstring>& items)
uint Expander::getBlockElements(const wstring &pattern, uint &start,
vector<wstring> &items)
{
uint currentIndx = start; //remember we are going from right to left

//Find the end of the block
while (currentIndx >= 0) //we are going backwards
{
if (pattern[currentIndx] == groupBegin || pattern[currentIndx] == groupEnd)
if (pattern[currentIndx] == groupBegin
|| pattern[currentIndx] == groupEnd)
break; //reached the end of the block
currentIndx--;
}
Expand All @@ -134,9 +146,9 @@ uint Expander::getBlockElements(const wstring& pattern, uint& start,
}
} //end for
//We should have the actual number of items
//*items = new wstring[itemCount];
//*items = new wstring[itemCount];

//Extract the items
//Extract the items
uint i = 0;
wstring temp;
for (currentIndx = endIndx + 1; currentIndx <= start; currentIndx++) //now we move left to right
Expand All @@ -160,7 +172,7 @@ uint Expander::getBlockElements(const wstring& pattern, uint& start,
{
//TODO: Check if we really need to have an exclude symbol
// if (pattern[currentIndx] != excludeSymbol)
items[i] = pattern[currentIndx];
items[i] = pattern[currentIndx];
// else
// (*items)[i] = "";
// i++;
Expand All @@ -176,23 +188,27 @@ uint Expander::getBlockElements(const wstring& pattern, uint& start,
return itemCount;
}

inline bool Expander::isEscSeq(const std::wstring& pattern, uint position) const
inline bool Expander::isEscSeq(const std::wstring &pattern, uint position) const
{
bool result = false;
if (position + 1 <= pattern.length() && pattern[position] == escapeSymbol) //first char. in sequence is indeed escape char.
{
//check second char in sequence
wchar_t second = pattern[position + 1];
if (second == escapeSymbol || second == rangeSymbol || second == groupBegin || second == groupEnd) {
if (second == escapeSymbol || second == rangeSymbol
|| second == groupBegin || second == groupEnd)
{
result = true;
} else {
result = false;
}
else
{
result = false;
}
}
return result;
}

std::wstring Expander::expand(const std::wstring& pattern)
std::wstring Expander::expand(const std::wstring &pattern)
{
int size = pattern.length();
wstring result = pattern;
Expand All @@ -217,12 +233,12 @@ std::wstring Expander::expand(const std::wstring& pattern)

wchar_t startRange = pattern[i - 1];
wchar_t endRange = pattern[i + 1];

std::locale loc2("C.UTF8");

//if both are alphabetical chars
if ((isalpha(startRange, loc2) && isalpha(endRange, loc2))
|| (isdigit(startRange, loc2) && isdigit(endRange, loc2)))
|| (isdigit(startRange, loc2) && isdigit(endRange, loc2)))
{
if ((int) startRange < (int) endRange) //inorder
{
Expand Down Expand Up @@ -254,17 +270,17 @@ std::wstring Expander::expand(const std::wstring& pattern)
return result;
}



bool Expander::validate(const wstring& pattern)
bool Expander::validate(const wstring &pattern)
{
int loadBrackets = 0;
uint loadQuotes = 0;

for (uint i = 0; i < pattern.size(); i++)
{
if (pattern[i] == escapeSymbol) {
if (!isEscSeq(pattern, i)) {
if (pattern[i] == escapeSymbol)
{
if (!isEscSeq(pattern, i))
{
output << "Error: Invalid escape sequence detected" << endl;
output << pattern << endl;
output << std::setw(i) << "^" << endl;
Expand Down Expand Up @@ -295,10 +311,16 @@ bool Expander::validate(const wstring& pattern)
}
}

if (loadBrackets != 0)
{
output << "Error: Unclosed group bracket" << endl;
}

return ((loadQuotes % 2 == 0) && (loadBrackets % 2 == 0));
}

void Expander::getCombinations(vector<wstring>& data, vector<wstring>& newElements)
void Expander::getCombinations(vector<wstring> &data,
vector<wstring> &newElements)
{
vector<wstring> original = data;
vector<wstring> temp = data;
Expand All @@ -313,14 +335,14 @@ void Expander::getCombinations(vector<wstring>& data, vector<wstring>& newElemen
}

//If the initial list is empty, just add the first entity of the new list
if(numOrgElements == 0)
if (numOrgElements == 0)
{
data.push_back(newElements[0]);
}
else
{

for (int i= 0; i < numOrgElements; i++)
for (int i = 0; i < numOrgElements; i++)
{
data[i] = data[i] + newElements[0];
}
Expand All @@ -337,8 +359,7 @@ void Expander::getCombinations(vector<wstring>& data, vector<wstring>& newElemen
}
}

void Expander::processGroup(const wstring& pattern, uint& i,
uint& currentItem)
void Expander::processGroup(const wstring &pattern, uint &i, uint &currentItem)
{
//wstring* newItems = NULL;
vector<wstring> newItems;
Expand Down Expand Up @@ -382,6 +403,7 @@ void Expander::processGroup(const wstring& pattern, uint& i,
//delete[] newItems; //clean up temporary resource
}

std::vector<std::wstring> Expander::getData() {
std::vector<std::wstring> Expander::getData()
{
return data;
}
Loading