Move configuration from config.py to config.json and add support for GitHub organization webhooks
remove _format_watch() from utils.github_webhook as the value of watchers_count is always identical with stargazers_count https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#watch https://developer.github.com/changes/2012-09-05-watcher-api/
This commit is contained in:
+33
-18
@@ -22,6 +22,7 @@ import logging
|
||||
from hashlib import sha256
|
||||
from json.decoder import JSONDecodeError
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
from aiohttp.web_request import Request
|
||||
from multidict import CIMultiDictProxy
|
||||
@@ -29,7 +30,7 @@ from multidict import CIMultiDictProxy
|
||||
from config import GH_WEBHOOKS
|
||||
|
||||
|
||||
async def validate_github_webhook(request: Request) -> bool:
|
||||
async def validate_github_webhook(request: Request) -> Union[str, int, bool]:
|
||||
try:
|
||||
headers = request.headers
|
||||
if not headers.get('User-Agent').startswith('GitHub-Hookshot'):
|
||||
@@ -39,20 +40,35 @@ async def validate_github_webhook(request: Request) -> bool:
|
||||
logging.warning("Content type: not json")
|
||||
return False
|
||||
payload = await request.json()
|
||||
repo_name = payload['repository']['full_name']
|
||||
if repo_name not in GH_WEBHOOKS.keys():
|
||||
logging.warning("Repository: not in configuration")
|
||||
hook_target: Optional[dict] = await _get_hook_target(payload)
|
||||
if not hook_target:
|
||||
return False
|
||||
return await _verify_signature(
|
||||
bytes(GH_WEBHOOKS[repo_name]['secret'], 'UTF-8'),
|
||||
valid_signature = await _verify_signature(
|
||||
bytes(hook_target['secret'], 'UTF-8'),
|
||||
headers.get('X-Hub-Signature-256').split('=')[1],
|
||||
await request.read()
|
||||
)
|
||||
if valid_signature:
|
||||
return hook_target['chat_id']
|
||||
else:
|
||||
return False
|
||||
except (JSONDecodeError, AttributeError) as error:
|
||||
logging.warning("Invalid: %s", error)
|
||||
return False
|
||||
|
||||
|
||||
async def _get_hook_target(payload: dict) -> Optional[dict]:
|
||||
name = (payload.get('organization', {}).get('login')
|
||||
or payload.get('repository', {}).get('full_name'))
|
||||
if not name:
|
||||
logging.warning("no repo or organization found")
|
||||
return None
|
||||
target = GH_WEBHOOKS.get(name, None)
|
||||
if not target:
|
||||
logging.warning("unknown repo or organization")
|
||||
return target
|
||||
|
||||
|
||||
async def _verify_signature(secret: bytes, sig: str, msg: bytes) -> bool:
|
||||
mac = hmac.new(secret, msg=msg, digestmod=sha256)
|
||||
valid_signature = hmac.compare_digest(mac.hexdigest(), sig)
|
||||
@@ -96,10 +112,11 @@ async def _format_discussion(payload: dict) -> str:
|
||||
|
||||
async def _format_fork(payload: dict) -> str:
|
||||
forkee = payload['forkee']
|
||||
return "\u2192 <a href=\"{url}\">{name}</a>".format(
|
||||
text = ["\u2192 <a href=\"{url}\">{name}</a>".format(
|
||||
url=forkee['html_url'],
|
||||
name=forkee['full_name']
|
||||
)
|
||||
), await _get_repo_star_and_fork(payload['repository'])]
|
||||
return "\n".join(text)
|
||||
|
||||
|
||||
async def _format_issues(payload: dict) -> str:
|
||||
@@ -153,26 +170,24 @@ async def _format_push(payload: dict) -> str:
|
||||
async def _format_star(payload: dict) -> str:
|
||||
time = payload['starred_at']
|
||||
text = [f"\u2192 starred at <code>{time}</code>"] if time else []
|
||||
text.append(await _get_repo_watch_star_fork(payload['repository']))
|
||||
text.append(await _get_repo_star_and_fork(payload['repository']))
|
||||
return "\n".join(text)
|
||||
|
||||
|
||||
async def _format_watch(payload: dict) -> str:
|
||||
return await _get_repo_watch_star_fork(payload['repository'])
|
||||
|
||||
|
||||
async def _get_event_title(event: str, payload: dict) -> str:
|
||||
sender = payload['sender']['login']
|
||||
action = payload.get('action') or ''
|
||||
summary = [payload['sender']['login']]
|
||||
# if action := payload.get('action'): summary.append(action)
|
||||
action = payload.get('action')
|
||||
summary.append(action) if action else []
|
||||
summary.append(event)
|
||||
return "<b>{name}</b> | <i>{summary}</i>".format(
|
||||
name=payload['repository']['full_name'],
|
||||
summary=" ".join([sender, action, event])
|
||||
summary=" ".join(summary)
|
||||
)
|
||||
|
||||
|
||||
async def _get_repo_watch_star_fork(repo: dict) -> str:
|
||||
async def _get_repo_star_and_fork(repo: dict) -> str:
|
||||
return '\u2192 ' + ", ".join([
|
||||
f"<b>{repo['watchers_count']}</b> watchers",
|
||||
f"<b>{repo['stargazers_count']}</b> stargazers",
|
||||
f"<b>{repo['forks_count']}</b> forks"
|
||||
])
|
||||
|
||||
+4
-8
@@ -24,13 +24,14 @@ from typing import Union
|
||||
from aiohttp import ClientSession, ClientResponse
|
||||
from aiohttp.web_request import Request
|
||||
|
||||
from config import BOT_TOKEN, GH_WEBHOOKS
|
||||
from config import BOT_TOKEN
|
||||
from utils.github_webhook import format_github_webhook
|
||||
|
||||
|
||||
async def send_to_telegram(session: ClientSession, request: Request) -> str:
|
||||
async def send_to_telegram(session: ClientSession,
|
||||
chat_id: Union[str, int],
|
||||
request: Request) -> str:
|
||||
message_text: Optional[str] = await format_github_webhook(request)
|
||||
chat_id: int = await get_corresponding_chat_id(await request.json())
|
||||
if not message_text:
|
||||
tg_status = "nothing to send"
|
||||
else:
|
||||
@@ -39,11 +40,6 @@ async def send_to_telegram(session: ClientSession, request: Request) -> str:
|
||||
return tg_status
|
||||
|
||||
|
||||
async def get_corresponding_chat_id(payload: dict) -> int:
|
||||
repo_name = payload['repository']['full_name']
|
||||
return GH_WEBHOOKS[repo_name]['chat_id']
|
||||
|
||||
|
||||
async def send_message(session: ClientSession,
|
||||
chat_id: Union[int, str],
|
||||
text: str) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user