Add files via upload

This commit is contained in:
David Rotermund 2024-07-17 11:59:31 +02:00 committed by GitHub
parent e7321b7230
commit 2d158f8f77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 273 additions and 0 deletions

View file

@ -0,0 +1,26 @@
FROM python:3.12.4
RUN apt-get update
RUN apt -y install mc
RUN apt -y install docker.io
RUN pip install pymongo
RUN pip install email_validator
RUN pip install flask
RUN pip install gunicorn
RUN pip install requests
RUN pip install BeautifulSoup4
RUN apt -y install bash
RUN pip install --upgrade pip
RUN pip install flask_wtf
RUN pip install wtforms
RUN pip install flask_recaptcha
RUN pip install Markup
RUN pip install captcha Pillow
COPY tools .
EXPOSE 80
ENTRYPOINT ["/bin/bash", "-c", "gunicorn wsgi:app --bind 0.0.0.0:80"]

View file

@ -1 +1,2 @@
Set a secret key in tools/secret_key.json. Then build the docker image with make_image.sh.

View file

@ -0,0 +1,20 @@
services:
overleafregister:
image: "overleafregister_image"
container_name: overleafregister
hostname: overleafregister
restart: always
networks:
- overleaf-network
volumes:
- overleaf_register:/data
- /var/run/docker.sock:/var/run/docker.sock
volumes:
overleaf_register:
networks:
overleaf-network:
external: true

View file

@ -0,0 +1,2 @@
docker compose down

View file

@ -0,0 +1 @@
docker exec -it overleafregister bash

View file

@ -0,0 +1,2 @@
docker compose logs -f

View file

@ -0,0 +1 @@
docker build --network host -t overleafregister_image .

View file

@ -0,0 +1,5 @@
{
"allowed_domains": [
"uni-bremen.de"
]
}

View file

@ -0,0 +1,6 @@
{
"blocked_users": [
""
]
}

View file

@ -0,0 +1,13 @@
import pymongo
def check_invites(email_to_find: str,container_name:str = "overleafmongo", port: int = 27017) -> bool:
client = pymongo.MongoClient(container_name, port)
db = client.sharelatex
project_invites = db.projectInvites
search_result = project_invites.find_one({"email": email_to_find})
if search_result is None:
return False
else:
return True

View file

@ -0,0 +1,13 @@
import pymongo
def check_user(email_to_find: str, container_name:str = "overleafmongo", port: int = 27017) -> bool:
client = pymongo.MongoClient(container_name, port)
db = client.sharelatex
users = db.users
search_result = users.find_one({"email": email_to_find})
if search_result is None:
return False
else:
return True

View file

@ -0,0 +1,14 @@
import subprocess
def create_account(email: str = "davrot@uni-bremen.de", container_name: str = "overleafserver"):
work_string: str = f"cd /overleaf/services/web && node modules/server-ce-scripts/scripts/create-user --email={email}"
result = subprocess.run(["docker", "exec", container_name, "/bin/bash", "-ce", work_string ], capture_output=True, text=True)
success: bool = False
for i in result.stdout.splitlines():
if i.startswith(f"Successfully created {email} as a"):
success = True
return success

View file

@ -0,0 +1,53 @@
import json
from flask import Flask, render_template, request, Response, send_from_directory, session
from io import BytesIO
from captcha.image import ImageCaptcha
import random
import base64
from process_emails import process_emails
container_name_mongo:str = "overleafmongo"
port_mongo: int = 27017
container_name_overleaf: str = "overleafserver"
app = Flask(__name__)
with open("secret_key.json", "r") as file:
secret_key: dict = json.load(file)
assert secret_key is not None
assert secret_key["secret_key"] is not None
app.config['SECRET_KEY'] = secret_key["secret_key"]
def generate_captcha():
image = ImageCaptcha(width=280, height=90)
captcha_text = ''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', k=6))
data = image.generate(captcha_text)
return captcha_text, data
@app.route("/register", methods=["GET", "POST"])
def index() -> Response:
if request.method == "GET":
captcha_text, captcha_image = generate_captcha()
session['captcha'] = captcha_text
captcha_base64 = base64.b64encode(captcha_image.getvalue()).decode('utf-8')
return render_template('post.html', captcha_image=captcha_base64)
elif request.method == "POST":
post_content = request.form.get('content')
email = request.form.get('email')
user_captcha = request.form.get('captcha')
if user_captcha and user_captcha.upper() == session.get('captcha'):
if process_emails(mail_address=email,container_name_mongo=container_name_mongo,port_mongo=port_mongo,container_name_overleaf=container_name_overleaf):
return f"A email was sent to {email}. Please click the activation link. Please check your spam folder! <p> <a href='https://overleaf.neuro.uni-bremen.de/'>Back to the overleaf site...</a>"
else:
return f"We couldn't register your email {email}."
else:
return f"There was a problem with solving the captcha. Try again. Sorry!"
@app.route("/register/static/<path:path>", methods=["GET"])
def serve_static_files(path) -> Response:
return send_from_directory("static", path)

View file

@ -0,0 +1,56 @@
from email_validator import validate_email # type: ignore
import email_validator
import json
from check_invites import check_invites
from check_user import check_user
from create_account import create_account
def process_emails(
mail_address: str,
config_file: str = "allowed_domains.json",
blocked_user_file: str = "blocked_users.json",
container_name_mongo:str = "overleafmongo",
port_mongo: int = 27017,
container_name_overleaf: str = "overleafserver",
) -> bool:
with open(config_file, "r") as file:
allowed_domains: dict = json.load(file)
with open(blocked_user_file, "r") as file:
blocked_users: dict = json.load(file)
if (mail_address == "") or (mail_address is None):
return False
try:
emailinfo = validate_email(mail_address, check_deliverability=False)
mail_address = emailinfo.normalized
except email_validator.exceptions_types.EmailSyntaxError:
return False
except email_validator.exceptions_types.EmailNotValidError:
return False
for blocked_user in blocked_users["blocked_users"]:
if mail_address == blocked_user:
return False
is_email_allowed: bool = False
if check_invites(email_to_find=mail_address,container_name=container_name_mongo, port=port_mongo):
is_email_allowed = True
if check_user(email_to_find=mail_address,container_name=container_name_mongo, port=port_mongo):
is_email_allowed = True
if is_email_allowed is False:
domain_found: bool = False
for domain in allowed_domains["allowed_domains"]:
if mail_address.endswith(domain):
domain_found = True
if domain_found is False:
return False
return create_account(email=mail_address, container_name=container_name_overleaf)

View file

@ -0,0 +1 @@
gunicorn wsgi:app --bind 0.0.0.0:80

View file

@ -0,0 +1,4 @@
{
"secret_key": "REDACTED"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Register your overleaf account</title>
</head>
<body>
<header>
<img src="/register/static/logo.png" alt="Logo" style="max-width: 200px;">
</header>
<h1>Register your overleaf account</h1>
<form method="POST" id="demo-form">
<div>
<label for="email">Email:</label><br>
<input type="email" id="email" name="email" required>
</div>
<p>
<div>
<label for="captcha">CAPTCHA:</label>
<br>
<img src="data:image/png;base64,{{ captcha_image }}" alt="CAPTCHA">
<br>
<input type="text" id="captcha" name="captcha" required>
</div>
<p>
<button type="submit">Register</button>
</form>
<h1>What is this?</h1>
This overleaf server is a side project for me.<br>
Thus, please don't expect a perfectly hosted system with zero downtime. It runs on a ZfN cloud machine.<br>
If you want to help me maintain this system, you are more than welcome.<br>
I will do my best but server maintainance is not one of my core duties.<br>
If you have questions, send me an email: davrot@uni-bremen.de.<br>
<h1>Who can register?</h1>
You can register if you have a University of Bremen email address ending in uni-bremen.de. <br>
Or someone has invited you to a project. In the latter case you don't need an email address from Univesity of Bremen.
<h1>Allgemeines</h1>
<a href="https://www.uni-bremen.de/impressum">Impressum</a><br>
<a href="https://www.uni-bremen.de/datenschutz">Datenschutz</a><br>
<a href="https://www.uni-bremen.de/notfall">Notfall</a>
</body>
</html>

View file

@ -0,0 +1,4 @@
from main import app
if __name__ == "__main__":
app.run(debug=True)

View file

@ -0,0 +1,2 @@
docker compose up -d