Skip to content

Commit

Permalink
v0.1.2 - Various Fixes After Refactor (#3)
Browse files Browse the repository at this point in the history
* Applied the rest of the fixes for v0.1.2
  • Loading branch information
bamhm182 authored Feb 13, 2022
1 parent 9dff143 commit b055224
Show file tree
Hide file tree
Showing 17 changed files with 68 additions and 47 deletions.
1 change: 0 additions & 1 deletion .github/workflows/mdbook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on:
push:
branches:
- main
- wip-alembic
pull_request:

jobs:
Expand Down
4 changes: 2 additions & 2 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Summary

- [Introduction](./index.md)
- [Support](./support/index.md)
- [Tests](./tests/index.md)
- [Usage](./usage/index.md)
- [Examples](./usage/examples/index.md)
- [Check Invisible Missions](./usage/examples/check-invisible-missions.md)
Expand All @@ -22,5 +24,3 @@
- [Templates](./usage/plugins/templates.md)
- [Transactions](./usage/plugins/transactions.md)
- [Users](./usage/plugins/users.md)
- [Support](./support/index.md)
- [Tests](./tests/index.md)
13 changes: 13 additions & 0 deletions docs/src/patches.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Patches

This is a terrbile way to handle this, but it technically works.
v0.1 saw a HUGE refactor and I broke some things.
While I am working out the kinks, you can run these commands to 'patch' your version.

Once I get everything fixed, I will release v0.1.2.

## v0.1.1

```
sed -i 's/filter_targets/find_targets/g' ~/.local/lib/python*/site-packages/synack/plugins/targets.py
```
Binary file not shown.
2 changes: 1 addition & 1 deletion docs/src/usage/examples/mission-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ for m in msns:
template = h.missions.get_file(m)
if template:
template = replace_placeholders(template)
h.missions.set_evidences(template)
h.missions.set_evidences(m, template)

```

Expand Down
7 changes: 6 additions & 1 deletion docs/src/usage/examples/register-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ python3 -c "import synack; synack.Handler().targets.set_registered()"
This could be thrown into a cronjob (`crontab -e`) as seen below to register any new targets once an hour:

```sh
0 * * * * python3 -c "import synack; synack.Handler().targets.set_registered()"
0 * * * * python3 -c "import synack; synack.Handler(login=True).targets.set_registered()"
```

Do note that the `login` State variable is set to True here.
This means that every time this function is called, it will confirm you are logged in and if not, it will log you in.
This is not default behavior because it makes between 1 and 5 requests each time Handler is initiated.
That said, you likely want to make sure you are having the SynackAPI log in often on one or two scripts.
5 changes: 2 additions & 3 deletions docs/src/usage/main-components/handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ h = synack.Handler()
From there, you can use any of the Plugins as follows:

```
h.missions.get_missions_count()
h.targets.do_register_all()
h.missions.get_count()
h.targets.set_registered()
```


## Setting One-Off States

It's important to note that you can easily change some of the State variables by passing them into the Handler.
Expand Down
8 changes: 6 additions & 2 deletions docs/src/usage/main-components/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ As seen in the following example, you can create a State variable externally and
In the event that you do not pass in a State, one is created automatically.
You can also continue to manipulate the State in the ways shown below.



```
#!/usr/bin/env python3
Expand All @@ -32,6 +30,12 @@ handler.state.debug = True
handler.debug.log("Test", "This message WILL be seen")
```

Out of all of the State variables, `login` is the most important to understand.
If this is set to true, whenever your Handler is created, it will make sure you are logged in.
If you have a bunch of scripts based on SynackAPI, it is probably a good idea to have `login` set to False, which is the default, for the majority of scripts.
Then you can have a couple scripts which are run periodically with `login` set to True so it becomes responsible for making sure that everything is logged in.

As an example of a good function to set `login` to True, check out the [Register Targets](../examples/register-targets.md) Example.

## Database vs State

Expand Down
6 changes: 3 additions & 3 deletions src/synack/plugins/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ def set_login_script(self):
"if (loc.href.startsWith('https://login.synack.com/')) {" +\
"loc.replace('https://platform.synack.com');" +\
"}" +\
"},60000);" +\
"},15000);" +\
"sessionStorage.setItem(" +\
"'shared-session-com.synack.accessToken'," +\
"'shared-session-com.synack.accessToken','" +\
self.db.api_token +\
");})();"
"');})();"
with open(self.state.config_dir / 'login.js', 'w') as fp:
fp.write(script)

Expand Down
11 changes: 6 additions & 5 deletions src/synack/plugins/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ class Db(Plugin):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sqlite_db = self.state.config_dir / 'synackapi.db'

self.set_migration()

engine = sa.create_engine(f'sqlite:///{str(self.sqlite_db)}')
sa.event.listen(engine, 'connect', self._fk_pragma_on_connect)
self.Session = sessionmaker(bind=engine)
Expand Down Expand Up @@ -182,10 +185,9 @@ def debug(self, value):
def email(self):
if self.state.email is None:
ret = self.get_config('email')
if ret is None:
if not ret:
ret = input("Synack Email: ")
self.email = ret
self.state.email = ret
return ret
else:
return self.state.email
Expand Down Expand Up @@ -223,7 +225,7 @@ def notifications_token(self, value):
def otp_secret(self):
if self.state.otp_secret is None:
ret = self.get_config('otp_secret')
if ret is None:
if not ret:
ret = input("Synack OTP Secret: ")
self.otp_secret = ret
self.state.otp_secret = ret
Expand All @@ -240,10 +242,9 @@ def otp_secret(self, value):
def password(self):
if self.state.password is None:
ret = self.get_config('password')
if ret is None:
if not ret:
ret = input("Synack Password: ")
self.password = ret
self.state.password = ret
return ret
else:
return self.state.password
Expand Down
18 changes: 10 additions & 8 deletions src/synack/plugins/missions.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def get_evidences(self, mission):
ret = evidences.json()
ret["title"] = mission["title"]
ret["asset"] = mission["assetTypes"][0]
ret["type"] = mission["taskType"]
ret["taskType"] = mission["taskType"]
ret["structuredResponse"] = mission["validResponses"][1]["value"]

return ret
Expand All @@ -171,21 +171,23 @@ def set_disclaimed(self, mission):
"""
return self.set_status(mission, "DISCLAIM")

def set_evidences(self, mission):
def set_evidences(self, mission, template=None):
"""Upload a template to a mission
Arguments:
mission -- A single mission
"""
template = self.templates.get_template(mission)
if template is None:
template = self.templates.get_file(mission)
if template:
curr = self.get_evidences(mission)
safe = True
for f in ['introduction', 'testing_methodology',
'conclusion']:
if len(curr.get(f)) >= 20:
safe = False
break
if curr:
for f in ['introduction', 'testing_methodology',
'conclusion']:
if len(curr.get(f)) >= 20:
safe = False
break
if safe:
res = self.api.request('PATCH',
'tasks/v2/tasks/' +
Expand Down
10 changes: 5 additions & 5 deletions src/synack/plugins/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@ def build_codename_from_slug(self, slug):
slug -- Slug of desired target
"""
codename = None
targets = self.db.filter_targets(slug=slug)
targets = self.db.find_targets(slug=slug)
if not targets:
self.get_registered_summary()
targets = self.db.filter_targets(slug=slug)
targets = self.db.find_targets(slug=slug)
if targets:
codename = targets[0].codename
return codename

def build_slug_from_codename(self, codename):
"""Return a slug for a target given its codename"""
slug = None
targets = self.db.filter_targets(codename=codename)
targets = self.db.find_targets(codename=codename)
if not targets:
self.get_registered_summary()
targets = self.db.filter_targets(codename=codename)
targets = self.db.find_targets(codename=codename)
if targets:
slug = targets[0].slug
return slug
Expand All @@ -49,7 +49,7 @@ def get_assessments(self):

def get_credentials(self, **kwargs):
"""Get Credentials for a target"""
target = self.db.filter_targets(**kwargs)[0]
target = self.db.find_targets(**kwargs)[0]
if target:
res = self.api.request('POST',
'asset/v1/organizations/' +
Expand Down
2 changes: 1 addition & 1 deletion src/synack/plugins/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def build_filepath(self, mission):
def build_safe_name(name):
"""Simplify a name to use for a file path"""
name = name.lower()
name = re.sub('[^a-z]', '_', name)
name = re.sub('[^a-z0-9]', '_', name)
return re.sub('_+', '_', name)

def build_sections(self, path):
Expand Down
Binary file added test/.test_missions.py.swp
Binary file not shown.
2 changes: 0 additions & 2 deletions test/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,6 @@ def test_email(self):
self.db.get_config.return_value = "[email protected]"

self.assertEqual("[email protected]", self.db.email)
self.assertEqual("[email protected]", self.db.state.email)

def test_email_state(self):
"""Should pull email from the state"""
Expand Down Expand Up @@ -443,7 +442,6 @@ def test_password(self):
self.db.get_config.return_value = "password1234"

self.assertEqual("password1234", self.db.password)
self.assertEqual("password1234", self.db.state.password)

def test_password_state(self):
"""Should pull password from the state"""
Expand Down
6 changes: 3 additions & 3 deletions test/test_missions.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ def test_set_evidences_safe(self):
"validResponses": [{}, {"value": "uieth8rgyub"}],
"listingCodename": "SLAPPYMONKEY"
}
self.missions.templates.get_template = MagicMock()
self.missions.templates.get_template.return_value = template
self.missions.templates.get_file = MagicMock()
self.missions.templates.get_file.return_value = template
self.missions.get_evidences = MagicMock()
self.missions.get_evidences.return_value = curr
self.missions.api.request = MagicMock()
Expand Down Expand Up @@ -384,7 +384,7 @@ def test_get_evidences(self):
ret = {
"title": m["title"],
"asset": "web",
"type": "MISSION",
"taskType": "MISSION",
"structuredResponse": "uieth8rgyub"
}
self.missions.api.request = MagicMock()
Expand Down
20 changes: 10 additions & 10 deletions test/test_targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ def test_get_assessments_all_passed(self):
def test_build_slug_from_codename(self):
"""Should return a slug for a given codename"""
ret_targets = [Target(slug="qwerty")]
self.targets.db.filter_targets.return_value = ret_targets
self.targets.db.find_targets.return_value = ret_targets
self.assertEqual("qwerty",
self.targets.build_slug_from_codename("qwerty"))
self.targets.db.filter_targets.assert_called_with(codename="qwerty")
self.targets.db.find_targets.assert_called_with(codename="qwerty")

def test_build_slug_from_codename_no_targets(self):
"""Should update the targets if empty"""
self.targets.db.filter_targets.side_effect = [
self.targets.db.find_targets.side_effect = [
[],
[Target(slug="qwerty")]
]
Expand All @@ -75,20 +75,20 @@ def test_build_slug_from_codename_no_targets(self):

slug = self.targets.build_slug_from_codename("CHONKEYMONKEY")
self.assertEqual("qwerty", slug)
self.targets.db.filter_targets.assert_has_calls(calls)
self.targets.db.find_targets.assert_has_calls(calls)
self.targets.get_registered_summary.assert_called_with()

def test_build_codename_from_slug(self):
"""Should return a codename for a given slug"""
ret_targets = [Target(codename="SLOPPYSLUG")]
self.targets.db.filter_targets.return_value = ret_targets
self.targets.db.find_targets.return_value = ret_targets
self.assertEqual("SLOPPYSLUG",
self.targets.build_codename_from_slug("qwfars"))
self.targets.db.filter_targets.assert_called_with(slug="qwfars")
self.targets.db.find_targets.assert_called_with(slug="qwfars")

def test_build_codename_from_slug_no_targets(self):
"""Should update the targets if empty"""
self.targets.db.filter_targets.side_effect = [
self.targets.db.find_targets.side_effect = [
[],
[Target(codename="SLOPPYSLUG")]
]
Expand All @@ -99,7 +99,7 @@ def test_build_codename_from_slug_no_targets(self):
self.targets.get_registered_summary = MagicMock()
self.assertEqual("SLOPPYSLUG",
self.targets.build_codename_from_slug("qwfars"))
self.targets.db.filter_targets.assert_has_calls(calls)
self.targets.db.find_targets.assert_has_calls(calls)
self.targets.get_registered_summary.assert_called_with()

def test_get_connected(self):
Expand Down Expand Up @@ -163,9 +163,9 @@ def test_get_registered_summary(self):
def test_get_credentials(self):
"""Should get credentials for a given target"""
target = Target(organization="qwewqe", slug="asdasd")
self.targets.db.filter_targets = MagicMock()
self.targets.db.find_targets = MagicMock()
self.targets.api = MagicMock()
self.targets.db.filter_targets.return_value = [target]
self.targets.db.find_targets.return_value = [target]
self.targets.db.user_id = 'bobby'
self.targets.api.request.return_value.status_code = 200
self.targets.api.request.return_value.json.return_value = "json_return"
Expand Down

0 comments on commit b055224

Please sign in to comment.