Browse Source

updated code to latest cookiecutter

main
Holger Frey 3 years ago
parent
commit
3a3e926d6f
  1. 2
      .flake8
  2. 2
      Makefile
  3. 110
      honeypot/__init__.py
  4. 24
      honeypot/utils.py
  5. 61
      pyproject.toml
  6. 4
      tests/test_honeypot.py

2
.flake8

@ -0,0 +1,2 @@
[flake8]
per-file-ignores = tests/*:S101

2
Makefile

@ -76,7 +76,7 @@ install: ## install updated project.toml with flint
devenv: ## setup development environment devenv: ## setup development environment
python3 -m venv --prompt honeypot .venv python3 -m venv --prompt honeypot .venv
.venv/bin/pip3 install --upgrade pip .venv/bin/pip3 install --upgrade pip
.venv/bin/pip3 install flit .venv/bin/pip3 install "flit>3.2"
.venv/bin/flit install --pth-file .venv/bin/flit install --pth-file
repo: devenv ## complete project setup with development environment and git repo repo: devenv ## complete project setup with development environment and git repo

110
honeypot/__init__.py

@ -6,93 +6,88 @@ A honeypot for wiki scrapers
__version__ = "0.0.1" __version__ = "0.0.1"
import os import os
import pickle
import re import re
import pickle # noqa: S403
from collections import OrderedDict
from pyramid.httpexceptions import HTTPFound
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config from pyramid.view import view_config
from pyramid.config import Configurator
from pyramid.httpexceptions import HTTPFound
from pyramid_mailer.message import Message from pyramid_mailer.message import Message
from . import utils from . import utils
class RootResource: class RootResource:
''' A simple 'catch all' resource ''' """A simple 'catch all' resource"""
moin_config_dir = None moin_config_dir = None
moin_wiki_defs = [] moin_wiki_defs = []
admin_emails = [] admin_emails = []
def __init__(self, request): def __init__(self, request):
''' initialization ''' """initialization"""
self.request = request self.request = request
def __getitem__(self, key): def __getitem__(self, key):
''' no child resource lookup, only one view used''' """no child resource lookup, only one view used"""
return self return self
@classmethod @classmethod
def configure(cls, settings): def configure(cls, settings):
''' parses the moinmoin farmconfig file ''' """parses the moinmoin farmconfig file"""
cls.moin_config_dir = settings['moin.config_path'] cls.moin_config_dir = settings["moin.config_path"]
moin_farmconfig = os.path.join(cls.moin_config_dir, 'farmconfig.py') moin_farmconfig = os.path.join(cls.moin_config_dir, "farmconfig.py")
encoding = utils.guess_encoding(moin_farmconfig) encoding = utils.guess_encoding(moin_farmconfig)
with open(moin_farmconfig, 'r', encoding=encoding) as fh: with open(moin_farmconfig, "r", encoding=encoding) as fh:
cls.moin_wiki_defs = list(utils.extract_wiki_definitions(fh)) cls.moin_wiki_defs = list(utils.extract_wiki_definitions(fh))
cls.admin_emails = settings['mail.admin_email'].split() cls.admin_emails = settings["mail.admin_email"].split()
def get_moin_user(self): def get_moin_user(self):
''' returns a name and email address of the current wiki user''' """returns a name and email address of the current wiki user"""
name, email = '<unknown user>', '<unknown email>' name, email = "<unknown user>", "<unknown email>"
try: try:
moin_data_dir = self._get_wiki_data_dir() moin_data_dir = self._get_wiki_data_dir()
moin_session_dir = os.path.join( moin_session_dir = os.path.join(
moin_data_dir, moin_data_dir, "cache", "__session__"
'cache',
'__session__'
) )
moin_user_id = self._get_user_id(moin_session_dir) moin_user_id = self._get_user_id(moin_session_dir)
moin_user_file = os.path.join(moin_data_dir, 'user', moin_user_id) moin_user_file = os.path.join(moin_data_dir, "user", moin_user_id)
with open(moin_user_file, 'r') as fh: with open(moin_user_file, "r") as fh:
for line in fh: for line in fh:
if line.startswith('email='): if line.startswith("email="):
email = line.split('=', 1)[1].strip() email = line.split("=", 1)[1].strip()
if line.startswith('name='): if line.startswith("name="):
name = line.split('=', 1)[1].strip() name = line.split("=", 1)[1].strip()
except: except: # noqa: S110, E722
pass pass
return name, email return name, email
def _get_wiki_data_dir(self): def _get_wiki_data_dir(self):
''' get the data directory by parsing a wiki config ''' """get the data directory by parsing a wiki config"""
wiki_name = self._get_wiki_name() wiki_name = self._get_wiki_name()
wiki_config = os.path.join(self.moin_config_dir, wiki_name + '.py') wiki_config = os.path.join(self.moin_config_dir, wiki_name + ".py")
encoding = utils.guess_encoding(wiki_config) encoding = utils.guess_encoding(wiki_config)
with open(wiki_config, 'r', encoding=encoding) as fh: with open(wiki_config, "r", encoding=encoding) as fh:
data_dir = utils.extract_data_dir(fh) data_dir = utils.extract_data_dir(fh)
return data_dir return data_dir
def _get_wiki_name(self): def _get_wiki_name(self):
''' return the internal wiki name for a url ''' """return the internal wiki name for a url"""
for name, re_url in self.moin_wiki_defs: for name, re_url in self.moin_wiki_defs:
if re.match(re_url, self.request.url): if re.match(re_url, self.request.url):
return name return name
def _get_user_id(self, session_dir): def _get_user_id(self, session_dir):
''' extract the user id from the session store ''' """extract the user id from the session store"""
session_path = self._get_session_path(session_dir) session_path = self._get_session_path(session_dir)
with open(session_path, 'rb') as fh: with open(session_path, "rb") as fh:
session_data = pickle.load(fh) session_data = pickle.load(fh) # noqa: S301
return session_data.get('user.id') return session_data.get("user.id")
def _get_session_path(self, session_dir): def _get_session_path(self, session_dir):
''' get the path to the session store for a given cookie ''' """get the path to the session store for a given cookie"""
for key, value in self.request.cookies.items(): for key, value in self.request.cookies.items():
if key.lower().startswith('moin'): if key.lower().startswith("moin"):
session_path = os.path.join(session_dir, value) session_path = os.path.join(session_dir, value)
if os.path.isfile(session_path): if os.path.isfile(session_path):
return session_path return session_path
@ -101,45 +96,44 @@ class RootResource:
@view_config(context=RootResource) @view_config(context=RootResource)
def the_view(context, request): def the_view(context, request):
''' the one and only view for the app ''' """the one and only view for the app"""
name, email = context.get_moin_user() name, email = context.get_moin_user()
body = [ body = [
'The Honey Pot Was Accessed', "The Honey Pot Was Accessed",
'--------------------------', "--------------------------",
'', "",
'This might be an attempt to scrape the whole wiki', "This might be an attempt to scrape the whole wiki",
'', "",
'wiki user: %s (%s)' % (name, email), "wiki user: %s (%s)" % (name, email),
'', "",
'requested url: %s' % request.url, "requested url: %s" % request.url,
'request method: %s' % request.method, "request method: %s" % request.method,
'client ip address: %s' % request.client_addr, "client ip address: %s" % request.client_addr,
'remote ip address: %s' % request.remote_addr, "remote ip address: %s" % request.remote_addr,
'', "",
'headers:' "headers:",
] ]
headers = [' %s: %s' % (k, v) for k, v in request.headers.items()] headers = [" %s: %s" % (k, v) for k, v in request.headers.items()]
body.extend(headers) body.extend(headers)
body = '\n'.join(body) body = "\n".join(body)
message = Message( message = Message(
subject='[cpi wikis]: HoneyPot Link Was Accessed', subject="[cpi wikis]: HoneyPot Link Was Accessed",
sender=request.registry.settings['mail.default_sender'], sender=request.registry.settings["mail.default_sender"],
recipients=context.admin_emails, recipients=context.admin_emails,
body=body body=body,
) )
request.mailer.send_immediately(message) request.mailer.send_immediately(message)
return HTTPFound('https://www.cpi.uni-freiburg.de/') return HTTPFound("https://www.cpi.uni-freiburg.de/")
def main(global_config, **settings): def main(global_config, **settings):
""" This function returns a Pyramid WSGI application. """This function returns a Pyramid WSGI application."""
"""
RootResource.configure(settings) RootResource.configure(settings)
config = Configurator(settings=settings) config = Configurator(settings=settings)

24
honeypot/utils.py

@ -2,23 +2,24 @@ from chardet.universaldetector import UniversalDetector
def guess_encoding(path): def guess_encoding(path):
''' guess the encoding of a file at a given path ''' """guess the encoding of a file at a given path"""
detector = UniversalDetector() detector = UniversalDetector()
with open(path, 'rb') as fh: with open(path, "rb") as fh:
for line in fh: for line in fh:
detector.feed(line) detector.feed(line)
if detector.done: break if detector.done:
break
detector.close() detector.close()
return detector.result['encoding'] return detector.result["encoding"]
def extract_wiki_definitions(file_handle): def extract_wiki_definitions(file_handle):
''' extract the wiki definitions from a moinmoin farmconfig file ''' """extract the wiki definitions from a moinmoin farmconfig file"""
for line in file_handle: for line in file_handle:
if line.startswith('wikis = ['): if line.startswith("wikis = ["):
break break
for line in file_handle: for line in file_handle:
if line.startswith(']'): if line.startswith("]"):
break break
parts = split_wiki_definitions(line) parts = split_wiki_definitions(line)
if parts is not None: if parts is not None:
@ -26,7 +27,7 @@ def extract_wiki_definitions(file_handle):
def split_wiki_definitions(line): def split_wiki_definitions(line):
''' small helper, returns the wiki name and wiki url regex ''' """small helper, returns the wiki name and wiki url regex"""
for quote in ('"', "'"): for quote in ('"', "'"):
parts = line.split(quote) parts = line.split(quote)
if len(parts) == 5: if len(parts) == 5:
@ -35,12 +36,11 @@ def split_wiki_definitions(line):
def extract_data_dir(fh): def extract_data_dir(fh):
''' returns the data directory from a single moinmoin wiki config ''' """returns the data directory from a single moinmoin wiki config"""
for line in fh: for line in fh:
parts = line.split('=', 1) parts = line.split("=", 1)
if len(parts) == 2: if len(parts) == 2:
name, value = parts name, value = parts
if name.strip() == 'data_dir': if name.strip() == "data_dir":
value = value.strip() value = value.strip()
return value[1:-1] return value[1:-1]

61
pyproject.toml

@ -4,14 +4,17 @@
requires = ["flit"] requires = ["flit"]
build-backend = "flit.buildapi" build-backend = "flit.buildapi"
[tool.flit.metadata] [project]
module = "honeypot" name = "honeypot"
dist-name = "honeypot" readme = "README.md"
author = "Holger Frey" description = "A honeypot for wiki scrapers"
author-email = "frey@imtek.de" license = { file = "LICENSE" }
home-page = "https://git.cpi.imtek.uni-freiburg.de/CPI/honeypot.git" requires-python = ">=3.7"
description-file = "README.md" dynamic = ["version"]
license = "Beerware"
authors = [
{name = "Holger Frey", email = "frey@imtek.de"},
]
# see https://pypi.org/classifiers/ # see https://pypi.org/classifiers/
classifiers = [ classifiers = [
@ -26,16 +29,18 @@ classifiers = [
"License :: Freely Distributable", "License :: Freely Distributable",
] ]
requires = [ dependencies = [
"chardet", "chardet",
"plaster_pastedeploy", "plaster_pastedeploy",
"pyramid", "pyramid",
"pyramid_mailer", "pyramid_mailer",
"waitress", "waitress",
] ]
requires-python = ">=3.7"
[tool.flit.metadata.requires-extra] [project.urls]
Source = "https://git.cpi.imtek.uni-freiburg.de/CPI/honeypot.git"
[project.optional-dependencies]
test = [ test = [
"pytest >=4.0.0", "pytest >=4.0.0",
"pytest-cov", "pytest-cov",
@ -53,19 +58,8 @@ dev = [
"pre-commit", "pre-commit",
] ]
[tool.black] [project.entry-points."paste.app_factory"]
line-length = 79 main = "honeypot:main"
py37 = true
include = "\.pyi?$"
exclude = """
/(
\.git
| \.tox
| \.venv
| build
| dist
)/
"""
[tool.isort] [tool.isort]
line_length=79 line_length=79
@ -73,13 +67,26 @@ multi_line_output=3
length_sort="True" length_sort="True"
include_trailing_comma="True" include_trailing_comma="True"
[tool.pytest.ini_options] [tool.pytest.ini_options]
markers = [ markers = [
'fun: marks tests as functional (deselect with "-m \"not fun\"")', "fun: marks tests as functional (deselect with '-m \"not fun\"')",
] ]
addopts = [ addopts = [
"--strict-markers", "--strict-markers",
] ]
[project.entry-points."paste.app_factory"] [tool.black]
main = "honeypot:main" line-length = 79
target-version = ['py37','py38', 'py39']
include = '\.pyi?$'
extend-exclude = '''
# A regex preceded with ^/ will apply only to files and directories
# in the root of the project.
^/.git
^/.tox
^/.venv
^/.build
^/.dist
'''

4
tests/test_honeypot.py

@ -29,6 +29,8 @@ def test_example_unittest():
will be run by 'make test' and 'make testall' but not 'make coverage' will be run by 'make test' and 'make testall' but not 'make coverage'
""" """
import honeypot # noqa: F401
assert True assert True
@ -38,4 +40,6 @@ def test_example_functional_test():
will be by 'make coverage' and 'make testall' but not 'make test' will be by 'make coverage' and 'make testall' but not 'make test'
""" """
import honeypot # noqa: F401
assert True assert True

Loading…
Cancel
Save