Skip to content

Commit

Permalink
Merge 7e1efc5 into 26c9e42
Browse files Browse the repository at this point in the history
  • Loading branch information
d-Rickyy-b committed Mar 4, 2020
2 parents 26c9e42 + 7e1efc5 commit b4c0590
Show file tree
Hide file tree
Showing 34 changed files with 959 additions and 86 deletions.
7 changes: 4 additions & 3 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ about: Suggest an idea for this project

---

**Is your feature request related to a problem? Please describe.**
**User Story / Use Case**
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
**Possible solution**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
**Alternative solution**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Expand Down
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/question.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: Question
about: Ask questions about this project or about how to use it

---

> Please provide a clear description of your question and include all (technical) details, in case they are relevant for the question.
> Please remove this line before creating the issue!
18 changes: 18 additions & 0 deletions .github/workflows/changelog_reminder.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Changelog Reminder

on: pull_request

jobs:
remind:
name: Changelog Reminder
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@master
- name: Changelog Reminder
uses: peterjgrainger/action-changelog-reminder@v1.2.0
with:
changelog_regex: '/CHANGELOG.md'
customPrMessage: "We couldn't find any modification to the CHANGELOG.md file. If your changes are not suitable for the changelog, that's fine. Otherwise please add them to the changelog!"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
12 changes: 12 additions & 0 deletions .github/workflows/stylecheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Stylecheck

on: [push]

jobs:
build:

runs-on: ubuntu-latest

steps:
- name: wemake-python-styleguide
uses: wemake-services/wemake-python-styleguide@0.13.4
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.3.0] - 2020-03-03
### Added
- Implemented base64analyzer, which matches if a found base64 string decodes to valid ascii ([b535781](https://github.com/d-Rickyy-b/pastepwn/commit/b535781d7e1760c7f846432d7ef87b97784e2d49))
- Implemented IrcAction - the previous implementation was not working ([546b87f](https://github.com/d-Rickyy-b/pastepwn/commit/546b87f508420da0a9ea6f54f1df65684b73648f))
### Changed
- SaveFileAction now got a parameter to set the file ending and a template ([c3d75f7](https://github.com/d-Rickyy-b/pastepwn/commit/c3d75f72036fa1284eebc8f3c1967a4374428dca))
### Fixed
- Analyzers now check if a passed action is a subclass of BasicAction, which prevents issues such as [#175](https://github.com/d-Rickyy-b/pastepwn/issues/175)
- The DiscordAction now also uses the templating engine - it was forgotten in a previous update ([#176](https://github.com/d-Rickyy-b/pastepwn/issues/176))
- The SyslogAction now also uses the templating engine - it was forgotten in a previous update ([54d3652](https://github.com/d-Rickyy-b/pastepwn/commit/54d3652e4de3fdbaedfdd522f8750aa241890c3c))
- The SaveFileAction does now store each paste in a different file as it should be ([#179](https://github.com/d-Rickyy-b/pastepwn/issues/179))
- The IrcAction did not send the correct data. This was fixed and eventually the action was rewritten from scratch (see "Added")

## [1.2.0] - 2020-02-05
### Added
- Analyzers can now return a boolean or **a list of matched results**
Expand Down Expand Up @@ -145,7 +158,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.0.8] - 2018-10-22
First stable release

[unreleased]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.2.0...HEAD
[unreleased]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.3.0...HEAD
[1.3.0]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.0.16...v1.1.0
[1.0.16]: https://github.com/d-Rickyy-b/pastepwn/compare/v1.0.15...v1.0.16
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
To use the pastepwn framework you need to follow these simple steps:

1) **Make sure** to have a [Pastebin premium](https://pastebin.com/pro) account!
2) Install pastepwn via pip (`pip install pastepwn`
2) Install pastepwn via pip (`pip3 install pastepwn`
3) Create a file (e.g. `main.py`) in your project root, where you put your code in²
4) Fill that file with content - add analyzers and actions. Check the [example](https://github.com/d-Rickyy-b/pastepwn/tree/master/examples/example.py) implementation.

¹ Note that pastepwn only works with python3.5 or higher (so better use pip3)
¹ Note that pastepwn **only works with python3.5 or above** (so better use pip3)
² *(If you want to store all pastes, make sure to setup a `mongodb`, `mysql` or `sqlite` instance)*

### Behind a proxy
Expand All @@ -32,11 +32,12 @@ There are 2 ways to use this tool behind a proxy:
- Define the following environment variables: `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`.
- When initializing the PastePwn object, use the `proxies` argument. `proxies` is a dict as defined in [requests' documentation](http://docs.python-requests.org/en/master/user/advanced/#proxies).

### ToDos
There are quite some features which will be implemented in the (near) future.
### Troubleshooting
If you are having troubles, check out the [wiki pages](https://github.com/d-Rickyy-b/pastepwn/wiki) first.
If your question/issue is not resolved there, feel free to [create an issue](https://github.com/d-Rickyy-b/pastepwn/issues/new/choose) or [contact me on Telegram](https://t.me/d_Rickyy_b).

### Roadmap and ToDos
Check the [bug tracker](https://github.com/d-Rickyy-b/pastepwn/issues) on GitHub to get an up-to-date status about features and ToDos.

- REST API for querying paste data
- Adding more analyzers and actions, based on community input
- Adding support for other paste sites
- REST API for querying paste data (will be another project)
- Add a helpful wiki with instructions and examples
57 changes: 37 additions & 20 deletions pastepwn/actions/discordaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,40 @@
import json
import logging
import sys
from string import Template

from pastepwn.util import Request, DictWrapper
from pastepwn.util import Request
from pastepwn.util import TemplatingEngine
from .basicaction import BasicAction


class DiscordAction(BasicAction):
"""Action to send a Discord message to a certain webhook or channel."""
name = "DiscordAction"

def __init__(self, webhook=None, token=None, channel_id=None, template=None):
def __init__(self, webhook_url=None, token=None, channel_id=None, template=None):
"""
Action to send a Discord message to a certain webhook or channel.
Either the webhook parameter or the token & channel_id parameters are needed.
1) You can setup a webhook in the discord server settings. A webhook is tied to one server & text channel
> https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks
2) Setup a discord bot (token) in the developer portal:
> https://discordapp.com/developers/applications/
After creating an app you can obtain the token by going to
> https://discordapp.com/developers/applications/{your_app_id}/bot
Format:
> NTI5MzI1MzY4OTAyMDI1MjI3.DwvNFQ.5aNKUvYlAKqKKq6UJ1fRiARKNXQ
3) Obtain the channel_id (18 digit number):
> User Settings > Appearance > Enable Developer Mode and after that right click on any text channel to copy the ID
:param webhook_url: The url obtained from the server settings
:param token: A bot token obtained from the developer portal
:param channel_id: The channel ID of a text channel you want to send messages into
:param template: A template string describing how the paste variables should be filled in
"""
super().__init__()
self.logger = logging.getLogger(__name__)
self.bot_available = True
Expand All @@ -24,10 +47,11 @@ def __init__(self, webhook=None, token=None, channel_id=None, template=None):
self.logger.warning("Could not import 'websockets' module. So you can only use webhooks for discord.")
self.bot_available = False

self.webhook = webhook
if webhook is None:
self.webhook_url = webhook_url
if webhook_url is None:
# When there is no webhook_url, we need both token and channel_id
if token is None or channel_id is None:
raise ValueError('Invalid arguments: requires either webhook or token+channel_id arguments')
raise ValueError('Invalid arguments: requires either webhook_url or token+channel_id arguments')

if not self.bot_available:
raise NotImplementedError("You can't use bot functionality without the 'websockets' module. Please import it or use webhooks!")
Expand All @@ -36,10 +60,7 @@ def __init__(self, webhook=None, token=None, channel_id=None, template=None):
self.channel_id = channel_id
self.identified = False

if template is not None:
self.template = Template(template)
else:
self.template = None
self.template = template

@asyncio.coroutine
def _identify(self, ws_url):
Expand Down Expand Up @@ -83,10 +104,11 @@ def _identify(self, ws_url):

def initialize_gateway(self):
"""Initialize the bot token so Discord identifies it properly."""
if self.webhook is not None:
if self.webhook_url is not None:
raise NotImplementedError('Gateway initialization is only necessary for bot accounts.')

# Call Get Gateway Bot to get the websocket URL
# https://discordapp.com/developers/docs/reference#authentication
r = Request()
r.headers = {'Authorization': 'Bot {}'.format(self.token)}
res = json.loads(r.get('https://discordapp.com/api/gateway/bot'))
Expand All @@ -101,16 +123,11 @@ def initialize_gateway(self):
def perform(self, paste, analyzer_name=None, matches=None):
"""Send a message via Discord to a specified channel, without checking for errors"""
r = Request()
if self.template is None:
text = "New paste matched by analyzer '{0}' - Link: {1}".format(analyzer_name, paste.full_url)
else:
paste_dict = paste.to_dict()
paste_dict["analyzer_name"] = analyzer_name
text = self.template.safe_substitute(DictWrapper(paste_dict))
text = TemplatingEngine.fill_template(paste, analyzer_name, template_string=self.template, matches=matches)

if self.webhook is not None:
if self.webhook_url is not None:
# Send to a webhook (no authentication)
url = self.webhook
url = self.webhook_url
else:
# Send through Discord bot API (header-based authentication)
url = 'https://discordapp.com/api/channels/{0}/messages'.format(self.channel_id)
Expand All @@ -123,7 +140,7 @@ def perform(self, paste, analyzer_name=None, matches=None):

res = json.loads(res)

if res.get('code') == 40001 and self.bot_available and self.webhook is None and not self.identified:
if res.get('code') == 40001 and self.bot_available and self.webhook_url is None and not self.identified:
# Unauthorized access, bot token hasn't been identified to Discord Gateway
self.logger.info('Accessing Discord Gateway to initialize token')
self.initialize_gateway()
Expand Down
Loading

0 comments on commit b4c0590

Please sign in to comment.