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. 8
      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
'''

8
tests/test_honeypot.py

@ -25,17 +25,21 @@ import pytest
def test_example_unittest(): def test_example_unittest():
""" example unittest """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
@pytest.mark.fun @pytest.mark.fun
def test_example_functional_test(): def test_example_functional_test():
""" example unittest """example unittest
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