Add files via upload
This commit is contained in:
parent
e7321b7230
commit
2d158f8f77
20 changed files with 273 additions and 0 deletions
26
container_to_container/Dockerfile
Normal file
26
container_to_container/Dockerfile
Normal 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"]
|
||||
|
||||
|
|
@ -1 +1,2 @@
|
|||
Set a secret key in tools/secret_key.json. Then build the docker image with make_image.sh.
|
||||
|
||||
|
|
20
container_to_container/compose.yaml
Normal file
20
container_to_container/compose.yaml
Normal 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
|
2
container_to_container/down.sh
Normal file
2
container_to_container/down.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
docker compose down
|
||||
|
1
container_to_container/exec.sh
Normal file
1
container_to_container/exec.sh
Normal file
|
@ -0,0 +1 @@
|
|||
docker exec -it overleafregister bash
|
2
container_to_container/logs.sh
Normal file
2
container_to_container/logs.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
docker compose logs -f
|
||||
|
1
container_to_container/make_image.sh
Normal file
1
container_to_container/make_image.sh
Normal file
|
@ -0,0 +1 @@
|
|||
docker build --network host -t overleafregister_image .
|
5
container_to_container/tools/allowed_domains.json
Normal file
5
container_to_container/tools/allowed_domains.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"allowed_domains": [
|
||||
"uni-bremen.de"
|
||||
]
|
||||
}
|
6
container_to_container/tools/blocked_users.json
Normal file
6
container_to_container/tools/blocked_users.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"blocked_users": [
|
||||
""
|
||||
]
|
||||
}
|
||||
|
13
container_to_container/tools/check_invites.py
Normal file
13
container_to_container/tools/check_invites.py
Normal 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
|
||||
|
13
container_to_container/tools/check_user.py
Normal file
13
container_to_container/tools/check_user.py
Normal 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
|
||||
|
14
container_to_container/tools/create_account.py
Normal file
14
container_to_container/tools/create_account.py
Normal 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
|
||||
|
||||
|
53
container_to_container/tools/main.py
Normal file
53
container_to_container/tools/main.py
Normal 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)
|
56
container_to_container/tools/process_emails.py
Normal file
56
container_to_container/tools/process_emails.py
Normal 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)
|
||||
|
1
container_to_container/tools/run.sh
Normal file
1
container_to_container/tools/run.sh
Normal file
|
@ -0,0 +1 @@
|
|||
gunicorn wsgi:app --bind 0.0.0.0:80
|
4
container_to_container/tools/secret_key.json
Normal file
4
container_to_container/tools/secret_key.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"secret_key": "REDACTED"
|
||||
}
|
||||
|
BIN
container_to_container/tools/static/logo.png
Normal file
BIN
container_to_container/tools/static/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6 KiB |
49
container_to_container/tools/templates/post.html
Normal file
49
container_to_container/tools/templates/post.html
Normal 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>
|
4
container_to_container/tools/wsgi.py
Normal file
4
container_to_container/tools/wsgi.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from main import app
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
2
container_to_container/up.sh
Normal file
2
container_to_container/up.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
docker compose up -d
|
||||
|
Loading…
Reference in a new issue