🎉 First commit!
This commit is contained in:
commit
99c2c62831
13 changed files with 280 additions and 0 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.env
|
||||||
|
bin
|
||||||
|
lib
|
||||||
|
include
|
10
.env.example
Normal file
10
.env.example
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
BOT_HOMESERVER="https://example.org"
|
||||||
|
BOT_USERNAME="PrayingTimesBotUsername"
|
||||||
|
BOT_PASSWORD="supersecret"
|
||||||
|
REGISTRATION_API_URL="http://localhost:5001/api/token"
|
||||||
|
REGISTRATION_API_SHARED_SECRET="supersecret"
|
||||||
|
REGISTRATION_URL="https://matrix.example.org/register?token="
|
||||||
|
SMTP_HOSTNAME="smtp.example.org"
|
||||||
|
SMTP_USERNAME="username"
|
||||||
|
SMTP_PASSWORD="password"
|
||||||
|
MAIL_FROM_ADDRESS="me@example.org"
|
38
.forgejo/workflows/ci.yaml
Normal file
38
.forgejo/workflows/ci.yaml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- "main"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
services:
|
||||||
|
registry:
|
||||||
|
image: registry:2
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Setup Docker for QEMU
|
||||||
|
uses: https://github.com/papodaca/install-docker-action@main
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Log in to the Container registry
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: code.f2n.me
|
||||||
|
username: ${{ secrets.MY_FORGEJO_USERNAME }}
|
||||||
|
password: ${{ secrets.MY_FORGEJO_TOKEN }}
|
||||||
|
- name: Build and push to local registry
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
tags: code.f2n.me/finn/matrix-bot-invitation-mailer:latest
|
||||||
|
- name: Inspect
|
||||||
|
run: |
|
||||||
|
docker buildx imagetools inspect code.f2n.me/finn/matrix-bot-invitation-mailer:latest
|
21
.forgejo/workflows/python-pep8.yaml
Normal file
21
.forgejo/workflows/python-pep8.yaml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: Python formatting PEP8
|
||||||
|
run-name: ${{ forgejo.actor }} is running PEP8 check
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Python-PEP8:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y python3-pip
|
||||||
|
pip install flake8
|
||||||
|
|
||||||
|
- name: Run checking
|
||||||
|
run: |
|
||||||
|
flake8 --ignore=E501 --extend-exclude bin,lib .
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
bin/
|
||||||
|
lib/
|
||||||
|
include/
|
||||||
|
__pycache__
|
||||||
|
pyvenv.cfg
|
||||||
|
.env
|
||||||
|
session.txt
|
||||||
|
tags
|
13
Dockerfile
Normal file
13
Dockerfile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM python:3.12-alpine
|
||||||
|
|
||||||
|
WORKDIR /bot
|
||||||
|
|
||||||
|
RUN apk update && apk add python3-dev gcc libc-dev libffi-dev
|
||||||
|
|
||||||
|
COPY requirements.txt requirements.txt
|
||||||
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bot/entrypoint.sh"]
|
15
README.md
Normal file
15
README.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# Matrix Bot for sending homeserver invitation link via e-mail
|
||||||
|
|
||||||
|
A early stage and simlpe Matrix bot which I use in addition to [matrix-registration](https://github.com/ZerataX/matrix-registration).
|
||||||
|
|
||||||
|
The bot calls the Api and sends the invitation link via e-mail to a given receipient.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Use container image or run this after cloning:
|
||||||
|
|
||||||
|
```
|
||||||
|
. bin/active
|
||||||
|
python -m matrix_bot_invitation_mailer
|
||||||
|
```
|
||||||
|
|
17
compose.yml
Normal file
17
compose.yml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
services:
|
||||||
|
matrix-bot-invitation-mailer:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
image: code.f2n.me/finn/matrix-bot-invitation-mailer:latest
|
||||||
|
environment:
|
||||||
|
- BOT_HOMESERVER
|
||||||
|
- BOT_USERNAME
|
||||||
|
- BOT_PASSWORD
|
||||||
|
- REGISTRATION_API_URL
|
||||||
|
- REGISTRATION_API_SHARED_SECRET
|
||||||
|
- REGISTRATION_URL
|
||||||
|
- SMTP_HOSTNAME
|
||||||
|
- SMTP_USERNAME
|
||||||
|
- SMTP_PASSWORD
|
||||||
|
- MAIL_FROM_ADDRESS
|
4
data/.gitignore
vendored
Normal file
4
data/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
2
entrypoint.sh
Executable file
2
entrypoint.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
python -m matrix_bot_invitation_mailer
|
0
matrix_bot_invitation_mailer/__init__.py
Normal file
0
matrix_bot_invitation_mailer/__init__.py
Normal file
113
matrix_bot_invitation_mailer/__main__.py
Normal file
113
matrix_bot_invitation_mailer/__main__.py
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import simplematrixbotlib as botlib
|
||||||
|
import requests
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import smtplib
|
||||||
|
import datetime
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
creds = botlib.Creds(
|
||||||
|
os.getenv("BOT_HOMESERVER"),
|
||||||
|
os.getenv("BOT_USERNAME"),
|
||||||
|
os.getenv("BOT_PASSWORD"),
|
||||||
|
session_stored_file="data/session.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
bot = botlib.Bot(creds)
|
||||||
|
PREFIX = '!'
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.listener.on_message_event
|
||||||
|
async def echo(room, message) -> None:
|
||||||
|
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||||
|
|
||||||
|
if match.is_not_from_this_bot() and match.prefix() and match.command("echo"):
|
||||||
|
|
||||||
|
await bot.api.send_text_message(
|
||||||
|
room.room_id, " ".join(arg for arg in match.args())
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.listener.on_message_event
|
||||||
|
async def usage(room, message) -> None:
|
||||||
|
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||||
|
|
||||||
|
response = """usage:
|
||||||
|
- **!invite** <johndoe@example.org> - sends e-mail with invitation link to given mail address
|
||||||
|
- **everything else** - prints this help
|
||||||
|
"""
|
||||||
|
|
||||||
|
if match.is_not_from_this_bot() and not match.prefix() and room.room_id:
|
||||||
|
await bot.api.send_markdown_message(room.room_id, response)
|
||||||
|
|
||||||
|
|
||||||
|
@bot.listener.on_message_event
|
||||||
|
async def invite(room, message) -> None:
|
||||||
|
match = botlib.MessageMatch(room, message, bot, PREFIX)
|
||||||
|
|
||||||
|
if match.is_not_from_this_bot() and match.prefix() and match.command("invite"):
|
||||||
|
logging.info("preparing invite")
|
||||||
|
# TODO: add validation
|
||||||
|
mail_address = " ".join(arg for arg in match.args())
|
||||||
|
|
||||||
|
send_invitation_mail(mail_address)
|
||||||
|
response = "mail sent"
|
||||||
|
await bot.api.send_text_message(room.room_id, response)
|
||||||
|
|
||||||
|
|
||||||
|
def send_invitation_mail(receiver_email):
|
||||||
|
logging.info("sending email...")
|
||||||
|
|
||||||
|
# make reqest to obtain registration token
|
||||||
|
headers = {
|
||||||
|
'Content-Type': "application/json",
|
||||||
|
'Authorization': "SharedSecret {}".format(os.getenv("REGISTRATION_API_SHARED_SECRET"))
|
||||||
|
}
|
||||||
|
payload = {
|
||||||
|
"max-usage": "1",
|
||||||
|
"expiration_date": (datetime.date.today() + datetime.timedelta(days=7)).strftime("%Y-%m-%d")
|
||||||
|
}
|
||||||
|
response = requests.post(os.getenv("REGISTRATION_API_URL"), headers=headers, json=payload)
|
||||||
|
logging.info(response.text)
|
||||||
|
logging.info(response.json())
|
||||||
|
sender_email = os.getenv("MAIL_FROM_ADDRESS")
|
||||||
|
|
||||||
|
body = """Hello,
|
||||||
|
|
||||||
|
you have been invited to the f2n.me matrix homeserver!
|
||||||
|
|
||||||
|
Click the following link and create your account:
|
||||||
|
|
||||||
|
{}
|
||||||
|
|
||||||
|
The link will be valid for 7 days.""".format(os.getenv("REGISTRATION_URL") + response.json()["name"])
|
||||||
|
msg = MIMEText(body, 'plain')
|
||||||
|
msg['From'] = sender_email
|
||||||
|
msg['To'] = receiver_email
|
||||||
|
msg['Subject'] = "Your matrix homeserver invitation link"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Connect to the SMTP server
|
||||||
|
server = smtplib.SMTP(os.getenv("SMTP_HOSTNAME"), os.getenv("SMTP_PORT"))
|
||||||
|
server.starttls() # Secure the connection
|
||||||
|
server.login(os.getenv("SMTP_USERNAME"), os.getenv("SMTP_PASSWORD")) # Login to the server
|
||||||
|
|
||||||
|
# Send the email
|
||||||
|
server.sendmail(sender_email, receiver_email, msg.as_string())
|
||||||
|
|
||||||
|
print("Email sent successfully")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
finally:
|
||||||
|
# Close the connection
|
||||||
|
server.quit()
|
||||||
|
|
||||||
|
|
||||||
|
bot.run()
|
35
requirements.txt
Normal file
35
requirements.txt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
aiofiles==23.2.1
|
||||||
|
aiohttp==3.9.5
|
||||||
|
aiohttp-socks==0.8.4
|
||||||
|
aiosignal==1.3.1
|
||||||
|
async-timeout==4.0.3
|
||||||
|
attrs==23.2.0
|
||||||
|
certifi==2024.6.2
|
||||||
|
cffi==1.16.0
|
||||||
|
charset-normalizer==3.3.2
|
||||||
|
cryptography==42.0.8
|
||||||
|
frozenlist==1.4.1
|
||||||
|
h11==0.14.0
|
||||||
|
h2==4.1.0
|
||||||
|
hpack==4.0.0
|
||||||
|
hyperframe==6.0.1
|
||||||
|
idna==3.7
|
||||||
|
jsonschema==4.22.0
|
||||||
|
jsonschema-specifications==2023.12.1
|
||||||
|
Markdown==3.6
|
||||||
|
matrix-nio==0.24.0
|
||||||
|
multidict==6.0.5
|
||||||
|
pillow==10.3.0
|
||||||
|
pycparser==2.22
|
||||||
|
pycryptodome==3.20.0
|
||||||
|
python-cryptography-fernet-wrapper==1.0.4
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
python-socks==2.5.0
|
||||||
|
referencing==0.35.1
|
||||||
|
requests==2.32.3
|
||||||
|
rpds-py==0.18.1
|
||||||
|
simplematrixbotlib==2.11.0
|
||||||
|
toml==0.10.2
|
||||||
|
unpaddedbase64==2.1.0
|
||||||
|
urllib3==2.2.2
|
||||||
|
yarl==1.9.4
|
Loading…
Reference in a new issue