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

Implement AWS Session Token Analyzer #122 #138

Merged
merged 80 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
a8746f1
#69 Private key analyzer added.
michalpirchala Oct 1, 2019
4777489
Added empy analyzer
Oct 1, 2019
0aa63ad
Added basic database dump analyzer
Oct 1, 2019
e940630
TASK: Analyser for DB connector strings
YellowFoxH4XOR Oct 2, 2019
0555d02
Merge pull request #74 from michalpirchala/master
d-Rickyy-b Oct 3, 2019
15e9027
TASK: Fixed Typo and Regex Expression for Db connector
YellowFoxH4XOR Oct 3, 2019
67bda70
Merge branch 'master' into master
d-Rickyy-b Oct 3, 2019
641afb3
Merge pull request #79 from YellowFoxH4XOR/master
d-Rickyy-b Oct 3, 2019
eafdc1c
Create discordaction.py
Mxrk Oct 3, 2019
21ee196
Update __init__.py
Mxrk Oct 3, 2019
6601b30
minor fix
Oct 4, 2019
77cbfe9
minor fix
Oct 4, 2019
9ff58b9
Add files via upload
gmassacc Oct 5, 2019
513e042
Update __init__.py
gmassacc Oct 5, 2019
d00fc83
Add Pastebinscraper by default
Samyak2 Oct 5, 2019
2780af9
Initialized PastebinScraper before adding
Samyak2 Oct 5, 2019
9839f8a
Fixed import
Samyak2 Oct 5, 2019
688e44f
Fixed a typo
Samyak2 Oct 5, 2019
d3ca548
Merge branch 'master' into dump-analyzer
d-Rickyy-b Oct 5, 2019
4325f7c
FIX: Missing commas in module
d-Rickyy-b Oct 5, 2019
fd57259
Merge pull request #91 from gmassacc/master
d-Rickyy-b Oct 5, 2019
9063308
Merge branch 'master' into dump-analyzer
d-Rickyy-b Oct 5, 2019
0c87633
Merge pull request #76 from sedaboni/dump-analyzer
d-Rickyy-b Oct 5, 2019
539d791
improved the phone number analyzer and added test cases for it
qkniep Oct 5, 2019
af97877
Merge pull request #94 from qkniep/master
d-Rickyy-b Oct 5, 2019
dee2a15
Merge pull request #95 from d-Rickyy-b/dev
d-Rickyy-b Oct 6, 2019
494d1af
TASK: Fix SHA hash analyzer to accept multiple length hashes; add uni…
bcongdon Oct 6, 2019
cf40629
Merge pull request #103 from bcongdon/tests/SHAHashAnalyzer
d-Rickyy-b Oct 6, 2019
d0d715d
Create originkeyanalyzer.py
jmmille Oct 6, 2019
27273a6
Added steam key analyzer
mike-k0 Oct 6, 2019
2e6194b
Added steamkeyanalyzer import
mike-k0 Oct 6, 2019
ac85ed4
Update __init__.py
jmmille Oct 6, 2019
1806078
Merge pull request #105 from mikek2/steam-keys
d-Rickyy-b Oct 6, 2019
38097ac
Implement Uplay Key Analyzer with tests
DaRuudii Oct 6, 2019
3be3603
Fixed copy/paste fails
DaRuudii Oct 6, 2019
5b69b8b
Merge pull request #107 from DaRuudii/master
d-Rickyy-b Oct 6, 2019
6529deb
Updated Steam Key Analyzer to match 5 segment keys
DaRuudii Oct 6, 2019
0cd956b
Tried to fix circular import
Samyak2 Oct 6, 2019
da9cd44
FIX: Only import when necessary
d-Rickyy-b Oct 6, 2019
6b291e2
Merge pull request #93 from Samyak2/samyak-patch-1
d-Rickyy-b Oct 6, 2019
56c19ca
Merge pull request #1 from d-Rickyy-b/master
Zeroji Oct 6, 2019
5043e0c
Add custom request headers
Zeroji Oct 6, 2019
7c0942e
TASK: Improve steam key regex
d-Rickyy-b Oct 6, 2019
6ce23c4
Merge pull request #110 from Zeroji/custom-request-headers
d-Rickyy-b Oct 6, 2019
0ab488a
Merge pull request #108 from DaRuudii/master
d-Rickyy-b Oct 6, 2019
9e7919b
Update originkeyanalyzer.py
jmmille Oct 6, 2019
3ffc03b
Adds bot-based discord messaging
Zeroji Oct 6, 2019
899e949
Create originkeyanalyzer_test.py
jmmille Oct 6, 2019
6e9d41d
Merge branch 'master' into master
jmmille Oct 6, 2019
65cb51b
Merge branch 'master' into discord-action-authenticated
Zeroji Oct 6, 2019
a9ec528
Remove unused import and clean up comments
Zeroji Oct 6, 2019
2ea238d
Merge pull request #106 from jmmille/master
d-Rickyy-b Oct 6, 2019
e072017
Merge pull request #112 from d-Rickyy-b/dev
d-Rickyy-b Oct 6, 2019
8927204
Implement Battle.Net Key Analyzer
DaRuudii Oct 6, 2019
44a8a12
Fix incorrect import
DaRuudii Oct 6, 2019
58bf828
Merge pull request #113 from DaRuudii/master
d-Rickyy-b Oct 6, 2019
fbf3770
Merge pull request #1 from d-Rickyy-b/master
jmmille Oct 6, 2019
442fbf8
Create microsoftkeyanalyzer.py
jmmille Oct 6, 2019
da3c270
Create microsoftkeyanalyzer_test.py
jmmille Oct 6, 2019
ea43599
Merge branch 'master' of https://github.com/jmmille/pastepwn
jmmille Oct 6, 2019
1693e3d
Update __init__.py
jmmille Oct 6, 2019
0890ee9
Merge pull request #114 from jmmille/master
d-Rickyy-b Oct 6, 2019
e904977
Add Discord Gateway identification
Zeroji Oct 6, 2019
7b13d75
TASK: Remove custom payload as that's not used anyway
d-Rickyy-b Oct 6, 2019
1786bf4
TASK: Make websocket package optional
d-Rickyy-b Oct 6, 2019
7d9ee0d
FIX: Issue with discord webhooks because of empty response
d-Rickyy-b Oct 6, 2019
03f1259
FIX: Issue with multithreading in discordaction
d-Rickyy-b Oct 6, 2019
7f26f4d
Merge pull request #111 from Zeroji/discord-action-authenticated
d-Rickyy-b Oct 6, 2019
71f598c
Merge pull request #116 from d-Rickyy-b/discord-action-bot
d-Rickyy-b Oct 6, 2019
da122da
Created basic Epic Key analyzer with unit test
synackray Oct 7, 2019
320b6a9
Merge pull request #118 from synackray/dev
d-Rickyy-b Oct 7, 2019
f0af9cb
[#82] Add email and password pair analyzer (#87)
bajubullet Oct 7, 2019
4e52345
Add Adobe Key Analyzer (#117)
jmmille Oct 7, 2019
de882d6
Updated Epic Key Analyzer
DaRuudii Oct 7, 2019
c9485a8
Merge pull request #121 from DaRuudii/master
d-Rickyy-b Oct 7, 2019
0a8e839
Updated Key Analyzers
DaRuudii Oct 7, 2019
8d50fbe
Base64 Analyser (#127)
martin-bucinskas Oct 7, 2019
a0ae002
Merge pull request #124 from DaRuudii/master
d-Rickyy-b Oct 7, 2019
bb51e3e
facebook access token analyzer (#126)
Adam-Jimenez Oct 7, 2019
cae0eae
Added AWS Session Token Analyzer
Ideneal Oct 8, 2019
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
2 changes: 0 additions & 2 deletions examples/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from pastepwn.actions import TelegramAction
from pastepwn.analyzers import MailAnalyzer, WordAnalyzer
from pastepwn.database import MongoDB
from pastepwn.scraping.pastebin import PastebinScraper

# Setting up the logging
logdir_path = os.path.dirname(os.path.abspath(__file__))
Expand All @@ -25,7 +24,6 @@
database = MongoDB(ip="192.168.240.128")

pastepwn = PastePwn(database)
pastepwn.add_scraper(PastebinScraper())

# Generic action to send Telegram messages on new matched pastes
telegram_action = TelegramAction(token="token", receiver="-1001348376474")
Expand Down
2 changes: 2 additions & 0 deletions pastepwn/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .databaseaction import DatabaseAction
from .savejsonaction import SaveJSONAction
from .twitteraction import TwitterAction
from .discordaction import DiscordAction

__all__ = (
"BasicAction",
Expand All @@ -18,4 +19,5 @@
"DatabaseAction",
"SaveJSONAction",
"TwitterAction",
"DiscordAction",
)
131 changes: 131 additions & 0 deletions pastepwn/actions/discordaction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
import asyncio
import json
import logging
import sys
from string import Template

from pastepwn.util import Request, DictWrapper
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):
super().__init__()
self.logger = logging.getLogger(__name__)
self.bot_available = True

try:
import websockets
except ImportError:
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:
if token is None or channel_id is None:
raise ValueError('Invalid arguments: requires either webhook 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!")

self.token = token
self.channel_id = channel_id
self.identified = False

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

@asyncio.coroutine
def _identify(self, ws_url):
"""Connect to the Discord Gateway to identify the bot."""
# Docs: https://discordapp.com/developers/docs/topics/gateway#connecting-to-the-gateway
# Open connection to the Discord Gateway
socket = yield from websockets.connect(ws_url + '/?v=6&encoding=json')
try:
# Receive Hello
hello_str = yield from socket.recv()
hello = json.loads(hello_str)
if hello.get('op') != 10:
self.logger.warning('[ws] Expected Hello payload but received %s', hello_str)

# Send heartbeat and receive ACK
yield from socket.send(json.dumps({"op": 1, "d": {}}))
ack_str = yield from socket.recv()
ack = json.loads(ack_str)
if ack.get('op') != 11:
self.logger.warning('[ws] Expected Heartbeat ACK payload but received %s', ack_str)

# Identify
payload = {
"token": self.token,
"properties": {
"$os": sys.platform,
"$browser": "pastepwn",
"$device": "pastepwn"
}
}
yield from socket.send(json.dumps({"op": 2, "d": payload}))

# Receive READY event
ready_str = yield from socket.recv()
ready = json.loads(ready_str)
if ready.get('t') != 'READY':
self.logger.warning('[ws] Expected READY event but received %s', ready_str)
finally:
# Close websocket connection
yield from socket.close()

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

# Call Get Gateway Bot to get the websocket URL
r = Request()
r.headers = {'Authorization': 'Bot {}'.format(self.token)}
res = json.loads(r.get('https://discordapp.com/api/gateway/bot'))
ws_url = res.get('url')

# Start websocket client
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(self._identify(ws_url))
self.identified = True

def perform(self, paste, analyzer_name=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))

if self.webhook is not None:
# Send to a webhook (no authentication)
url = self.webhook
else:
# Send through Discord bot API (header-based authentication)
url = 'https://discordapp.com/api/channels/{0}/messages'.format(self.channel_id)
r.headers = {'Authorization': 'Bot {}'.format(self.token)}

res = r.post(url, {"content": text})
if res == "":
# If the response is empty, skip further execution
return

res = json.loads(res)

if res.get('code') == 40001 and self.bot_available and self.webhook 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()
# Retry action
self.perform(paste, analyzer_name=analyzer_name)
39 changes: 36 additions & 3 deletions pastepwn/analyzers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
# -*- coding: utf-8 -*-
from .alwaystrueanalyzer import AlwaysTrueAnalyzer
from .basicanalyzer import BasicAnalyzer
from .battlenetkeyanalyzer import BattleNetKeyAnalyzer
from .bcrypthashanalyzer import BcryptHashAnalyzer
from .md5hashanalyzer import MD5HashAnalyzer
from .shahashanalyzer import SHAHashAnalyzer
from .creditcardanalyzer import CreditCardAnalyzer
from .databasedumpanalyzer import DatabaseDumpAnalyzer
from .dbconnstringanalyzer import DBConnAnalyzer
from .emailpasswordpairanalyzer import EmailPasswordPairAnalyzer
from .genericanalyzer import GenericAnalyzer
from .ibananalyzer import IBANAnalyzer
from .mailanalyzer import MailAnalyzer
from .md5hashanalyzer import MD5HashAnalyzer
from .microsoftkeyanalyzer import MicrosoftKeyAnalyzer
from .originkeyanalyzer import OriginKeyAnalyzer
from .pastebinurlanalyzer import PastebinURLAnalyzer
from .phonenumberanalyzer import PhoneNumberAnalyzer
from .privatekeyanalyzer import PrivateKeyAnalyzer
from .regexanalyzer import RegexAnalyzer
from .shahashanalyzer import SHAHashAnalyzer
from .steamkeyanalyzer import SteamKeyAnalyzer
from .uplaykeyanalyzer import UplayKeyAnalyzer
from .urlanalyzer import URLAnalyzer
from .wordanalyzer import WordAnalyzer
from .ibananalyzer import IBANAnalyzer
from .dbconnstringanalyzer import DBConnAnalyzer
from .privatekeyanalyzer import PrivateKeyAnalyzer
from .adobekeyanalyzer import AdobeKeyAnalyzer
from .facebookaccesstokenanalyzer import FacebookAccessTokenAnalyzer
from .base64analyzer import Base64Analyzer
from .awssessiontokenanalyzer import AWSSessionTokenAnalyzer

__all__ = (
'AlwaysTrueAnalyzer',
Expand All @@ -26,5 +43,21 @@
'RegexAnalyzer',
'URLAnalyzer',
'WordAnalyzer',
'IBANAnalyzer'
'IBANAnalyzer',
'DatabaseDumpAnalyzer',
'DBConnAnalyzer',
'PrivateKeyAnalyzer',
'PhoneNumberAnalyzer',
'OriginKeyAnalyzer',
'SteamKeyAnalyzer',
'UplayKeyAnalyzer',
'BattleNetKeyAnalyzer',
'MicrosoftKeyAnalyzer',
'AdobeKeyAnalyzer',
'DBConnAnalyzer',
'PrivateKeyAnalyzer',
'EmailPasswordPairAnalyzer',
'FacebookAccessTokenAnalyzer',
'Base64Analyzer',
'AWSSessionTokenAnalyzer'
)
16 changes: 16 additions & 0 deletions pastepwn/analyzers/adobekeyanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class AdobeKeyAnalyzer(RegexAnalyzer):
"""Analyzer to match Adobe License Keys"""

def __init__(self, action):
"""
Analyzer to match Adobe License Keys
:param action: Single action or list of actions to be executed when a paste matches
"""
# Tested Regex against https://pastebin.com/fxWBGf8t
regex = r"\b(?<!-)[0-9]{4}(-[0-9]{4}){5}\b(?!-)"

super().__init__(action, regex)
12 changes: 12 additions & 0 deletions pastepwn/analyzers/awssessiontokenanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .regexanalyzer import RegexAnalyzer


class AWSSessionTokenAnalyzer(RegexAnalyzer):
"""
Analyzer to match AWS Session Token via regex
"""
name = "AWSSessionTokenAnalyzer"

def __init__(self, actions):
regex = r"((\\\"|'|`)?((i)?aws)?_?((i)?session)?_?((i)?token)?(\\\"|'|`)?\\\\s{0,50}(:|=>|=)\\\\s{0,50}(\\\"|'|`)?[A-Za-z0-9/+=]{16,}(\\\"|'|`)?)"
super().__init__(actions, regex)
11 changes: 11 additions & 0 deletions pastepwn/analyzers/base64analyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class Base64Analyzer(RegexAnalyzer):
"""Analyzer to match base64 encoding via regex"""
name = "Base64Analyzer"

def __init__(self, actions):
regex = r"^(?:[A-Za-z0-9+\/]{4})+(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$"
super().__init__(actions, regex)
14 changes: 14 additions & 0 deletions pastepwn/analyzers/battlenetkeyanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class BattleNetKeyAnalyzer(RegexAnalyzer):
"""
Analyzer to match battle.net keys via regex
"""
name = "BattleNetKeyAnalyzer"

def __init__(self, actions):
# battle.net activation page shows 4-4-4-4 format, but there are also codes in the 4-4-5-4-4 format which work
regex = r"\b(?<!-)([A-Z0-9]{4}\-[A-Z0-9]{4}\-[A-Z0-9]{4}\-[A-Z0-9]{4}|[A-Z0-9]{4}\-[A-Z0-9]{4}\-[A-Z0-9]{5}\-[A-Z0-9]{4}\-[A-Z0-9]{4})\b(?!-)"
super().__init__(actions, regex)
16 changes: 16 additions & 0 deletions pastepwn/analyzers/databasedumpanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class DatabaseDumpAnalyzer(RegexAnalyzer):
"""Analyzer to match database dump"""
name = "DatabaseDumpAnalyzer"

def __init__(self, actions):
"""
Analyzer to match database dump
:param actions: A single action or a list of actions to be executed on every paste
"""
# This regex match the columns of a database
regex = r"\(((`\w+`|\d)(\s?)+,(\s?)+)+(`\w+`|\d)\)"
super().__init__(actions, regex)
12 changes: 12 additions & 0 deletions pastepwn/analyzers/dbconnstringanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class DBConnAnalyzer(RegexAnalyzer):
"""Analyzer to match on email addresses via regex"""
name = "DBConnAnalyzer"

def __init__(self, actions):
# https:// should be ignored
regex = r"(\b(?!http(s)?\b)\w+[a-zA-Z]+://[a-zA-z0-9.:,]+)"
super().__init__(actions, regex)
12 changes: 12 additions & 0 deletions pastepwn/analyzers/emailpasswordpairanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer

_EMAIL_PASSWORD_REGEX = r'[\w\.\+_-]+@[\w\._-]+\.[a-zA-Z]*\:[\w\.\+\!\$\#\^&\*\(\)\{\}\[\]\_\-\@\%\=\§\\\/\'\`\´\?\<\>\;\"\:\|\,\~]+$'


class EmailPasswordPairAnalyzer(RegexAnalyzer):
"""Analyzer to match username:password pairs"""
name = "EmailPasswordPairAnalyzer"

def __init__(self, actions):
super().__init__(actions, _EMAIL_PASSWORD_REGEX)
17 changes: 17 additions & 0 deletions pastepwn/analyzers/epickeyanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class EpicKeyAnalyzer(RegexAnalyzer):
"""Analyzer to match Epic Licensing Keys"""

def __init__(self, action):
"""
Analyzer to match Epic Licensing Keys
:param action: Single action or list of actions to be executed when a paste matches
"""
# Applied general A-Z or 0-9 based on example provided
# Regex can be adjusted if certain characters are not valid
regex = r"\b(?<!-)[A-Z0-9]{5}\-[A-Z0-9]{5}\-[A-Z0-9]{5}\-[A-Z0-9]{5}\b(?!-)"

super().__init__(action, regex)
15 changes: 15 additions & 0 deletions pastepwn/analyzers/facebookaccesstokenanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class FacebookAccessTokenAnalyzer(RegexAnalyzer):
"""Analyzer to match a Facebook Access Token"""
name = "FacebookAccessTokenAnalyzer"
regex = "EAACEdEose0cBA[0-9A-Za-z]+"

def __init__(self, actions):
"""
Analyzer which always matches a paste to perform actions on every paste
:param actions: A single action or a list of actions to be executed on every paste
"""
super().__init__(actions, self.regex)
2 changes: 1 addition & 1 deletion pastepwn/analyzers/md5hashanalyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ class MD5HashAnalyzer(RegexAnalyzer):
name = "MD5HashAnalyzer"

def __init__(self, actions):
regex = r"[a-f0-9]{32}"
regex = r"\b(?<!-)[a-f0-9]{32}\b(?!-)"
super().__init__(actions, regex)
16 changes: 16 additions & 0 deletions pastepwn/analyzers/microsoftkeyanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class MicrosoftKeyAnalyzer(RegexAnalyzer):
"""Analyzer to match Microsoft Licensing Keys"""

def __init__(self, action):
"""
Analyzer to match Microsoft Licensing Keys
:param action: Single action or list of actions to be executed when a paste matches
"""
# Tested Regex against https://pastebin.com/r3QdpFJf
regex = r"\b(?<!-)[2346789BCDFGHJKMNPQRTVWXY]{5}(-[2346789BCDFGHJKMNPQRTVWXY]{5}){4}\b(?!-)"

super().__init__(action, regex)
16 changes: 16 additions & 0 deletions pastepwn/analyzers/originkeyanalyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
from .regexanalyzer import RegexAnalyzer


class OriginKeyAnalyzer(RegexAnalyzer):
"""Analyzer to match Origin Keys"""

def __init__(self, action):
"""
Analyzer to match Origin Keys
:param action: Single action or list of actions to be executed when a paste matches
"""
# Tested Regex against https://pastebin.com/vyNANvwM
regex = r"\b(?<!-)[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}\b(?!-)"

super().__init__(action, regex)
Loading