Deuchnord 7 месяцев назад
committed by GitHub
Родитель
Сommit
5fbbaf148c
Не найден GPG ключ соответствующий данной подписи Идентификатор GPG ключа: B5690EEEBB952194
4 измененных файлов: 127 добавлений и 2 удалений
  1. +64
    -2
      poetry.lock
  2. +1
    -0
      pyproject.toml
  3. +10
    -0
      twason/config.py
  4. +52
    -0
      twason/moderator.py

+ 64
- 2
poetry.lock Просмотреть файл

@@ -84,6 +84,38 @@ files = [
{file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
] ]


[[package]]
name = "filelock"
version = "3.18.0"
description = "A platform independent file lock."
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"},
{file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"},
]

[package.extras]
docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"]
typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""]

[[package]]
name = "idna"
version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
]

[package.extras]
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]

[[package]] [[package]]
name = "irc3" name = "irc3"
version = "1.1.10" version = "1.1.10"
@@ -146,7 +178,7 @@ version = "4.3.8"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
groups = ["dev"]
groups = ["main", "dev"]
files = [ files = [
{file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"},
{file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"},
@@ -157,6 +189,36 @@ docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-a
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"]
type = ["mypy (>=1.14.1)"] type = ["mypy (>=1.14.1)"]


[[package]]
name = "uritools"
version = "5.0.0"
description = "URI parsing, classification and composition"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "uritools-5.0.0-py3-none-any.whl", hash = "sha256:cead3a49ba8fbca3f91857343849d506d8639718f4a2e51b62e87393b493bd6f"},
{file = "uritools-5.0.0.tar.gz", hash = "sha256:68180cad154062bd5b5d9ffcdd464f8de6934414b25462ae807b00b8df9345de"},
]

[[package]]
name = "urlextract"
version = "1.9.0"
description = "Collects and extracts URLs from given text."
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "urlextract-1.9.0-py3-none-any.whl", hash = "sha256:f88963532488b1c7c405e21bd162ae97871754ea04b60e18d33ee075b19b82fd"},
{file = "urlextract-1.9.0.tar.gz", hash = "sha256:70508e02ba9df372e25cf0642db367cece273e8712cd0ce78178fc5dd7ea00db"},
]

[package.dependencies]
filelock = "*"
idna = "*"
platformdirs = "*"
uritools = "*"

[[package]] [[package]]
name = "venusian" name = "venusian"
version = "3.1.1" version = "3.1.1"
@@ -176,4 +238,4 @@ testing = ["coverage", "pytest", "pytest-cov"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "5d7d7513799a39e01fdb8f7159317204c36855b5948f12b89a71ef7b47bd6a1d"
content-hash = "2f1ca53ab2001cae84774e065f5289b84fe9a77ae87307012ffc6fff0db436d4"

+ 1
- 0
pyproject.toml Просмотреть файл

@@ -11,6 +11,7 @@ twason = 'twason.__main__:main'
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.12" python = "^3.12"
irc3 = "^1.1" irc3 = "^1.1"
urlextract = "^1.9"


[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
black = "^25.1" black = "^25.1"


+ 10
- 0
twason/config.py Просмотреть файл

@@ -166,6 +166,16 @@ class Config:
moderator_config.get("min-time-between-occurrence", None), moderator_config.get("min-time-between-occurrence", None),
) )
) )
if mod == 'links':
moderators.append(moderator.LinksModerator(
moderator_config.get(
"message",
"{author}, your message contained forbidden links, it had to be removed for safety."
),
cls.parse_decision(moderator_config.get("decision", "delete")),
moderator_config.get("duration", None),
moderator_config.get("authorized", [])
))


# Generate help command # Generate help command
if params.get("help", True): if params.get("help", True):


+ 52
- 0
twason/moderator.py Просмотреть файл

@@ -19,6 +19,9 @@ from abc import ABC, abstractmethod
from enum import Enum from enum import Enum
from typing import Union from typing import Union
from datetime import datetime, timedelta from datetime import datetime, timedelta
from urlextract import URLExtract
from fnmatch import fnmatch
import re


EPOCH = datetime(1970, 1, 1) EPOCH = datetime(1970, 1, 1)


@@ -162,3 +165,52 @@ class FloodModerator(Moderator):


def declare_raid(self): def declare_raid(self):
self.last_raid = datetime.now() self.last_raid = datetime.now()


class LinksModerator(Moderator):
def __init__(
self,
message: str,
decision: ModerationDecision,
timeout_duration: Union[None, int],
authorized_urls: [str]
):
super().__init__(message, decision, timeout_duration)
self.authorized_urls = authorized_urls

def get_name(self) -> str:
return 'Link'

def vote(self, msg: str, author: str) -> ModerationDecision:
url_extractor = URLExtract()
links = url_extractor.find_urls(msg)

if len(links) == 0:
return ModerationDecision.ABSTAIN

if not self.are_urls_authorized(links):
return self.decision

return ModerationDecision.ABSTAIN

def are_urls_authorized(self, links: [str]) -> bool:

for link in links:
is_link_authorized = False
print(link)

for pattern in self.authorized_urls:
print(pattern)
if dump(fnmatch(link, pattern)) or dump(fnmatch(f"http://{link}", pattern)) or dump(fnmatch(f"https://{link}", pattern)):
is_link_authorized = True
break

if not is_link_authorized:
return False

return True


def dump(what):
print(what)
return what

Загрузка…
Отмена
Сохранить