roundabout,
created on Monday, 13 May 2024, 15:19:24 (1715613564),
received on Wednesday, 31 July 2024, 06:54:48 (1722408888)
Author identity: vlad <vlad.muntoiu@gmail.com>
f030cdf7e20de9a75bf8bcbf7103c7b1d8a26fb7
app.py
@@ -182,6 +182,20 @@ def settings():
return flask.render_template("user-settings.html", user=user)
@app.route("/settings/confirm-email/<code>")
def confirm_email(code):
request = EmailChangeRequest.query.filter_by(code=code).first()
if not request:
flask.abort(404)
user = db.session.get(User, request.user_username)
user.email = request.new_email
db.session.delete(request)
db.session.commit()
return flask.redirect("/settings", code=303)
@app.route("/settings/profile", methods=["POST"])
def settings_profile():
user = User.query.filter_by(username=flask.session.get("username")).first()
@@ -190,8 +204,12 @@ def settings_profile():
user.URL = flask.request.form["url"]
user.company = flask.request.form["company"]
user.company_URL = flask.request.form["companyurl"]
user.email = flask.request.form.get("email") if flask.request.form.get(
"email") else None
if not flask.request.form.get("email"):
# Deleting the email can be instant; no need to confirm
user.email = ""
elif flask.request.form.get("email") != user.email:
# Changing the email requires confirmation from the address holder
celery_tasks.request_email_change.delay(user.username, flask.request.form["email"])
user.location = flask.request.form["location"]
user.show_mail = True if flask.request.form.get("showmail") else False
user.bio = flask.request.form.get("bio")
celery_tasks.py
@@ -5,7 +5,7 @@ import config
import email_send
import shutil
from celery import shared_task
from app import db
from app import db, _
from smtplib import SMTP
from celery.utils.log import get_task_logger
@@ -21,7 +21,7 @@ def send_notification(user_notification_id):
with (SMTP(config.MAIL_SERVER) as mail):
if notification.data.get("type") == "welcome":
message = email_send.make_multipart_message(
f"Welcome, {user.username}",
"Welcome, {username}".format(username=user.username),
config.NOTIFICATION_EMAIL,
user.email,
"welcome",
@@ -126,9 +126,18 @@ def request_email_change(username, email):
from models import User, EmailChangeRequest
user = db.session.get(User, username)
request = models.EmailChangeRequest(user, email)
request = EmailChangeRequest(user, email)
db.session.add(request)
db.session.commit()
return request.id
message = email_send.make_multipart_message(
"Email change request for {username}".format(username=username),
config.NOTIFICATION_EMAIL,
email,
"email-change",
username=username,
code=request.code,
new_email=email,
url="https://" if config.suggest_https else "http://" + config.BASE_DOMAIN + "/settings/confirm-email/" + request.code
)
config.py
@@ -17,7 +17,7 @@ REPOS_PATH: str = "./repos"
USERDATA_PATH: str = "./userdata"
SITE_PATH: str = "./usersites"
DEFAULT_AVATARS_PATH: str = "./default_avatars"
BASE_DOMAIN: str = "localhost"
BASE_DOMAIN: str = "roundabout-host.com"
SERVER_IPS: set = {"127.0.0.1", "localhost", "0.0.0.0"}
AUTH_REALM: str = "roundabout"
MAX_PAYLOAD_SIZE: int = 4 * 1024**3
@@ -27,7 +27,7 @@ AVATAR_SIZE: tuple = (192, 192)
HASHING_ROUNDS: int = 11
RESERVED_NAMES: tuple = ("git", "settings", "logout", "accounts", "info", "notifications", "about", "newrepo", "favourites",)
suggest_https: bool = True
suggest_https: bool = False # this config is intended for a test server
available_locales: list[str] = ["ro_RO", "en_GB"]
email_send.py
@@ -23,4 +23,6 @@ def make_multipart_message(subject, sender, receiver, template, **kwargs):
message.attach(text)
message.attach(text)
print(text)
return message.as_string()
email_templates/commit.html
@@ -1,8 +1,8 @@
{% extends "mail.html" %}
{% block content %}
<h1>{% trans repo=repo.route, commit=commit.mess %}New commit in {{ repo }}{% endtrans %}</h1>
<h1>New commit in {{ repo }}</h1>
<p>
{% trans %}Commited by{% endtrans} <a href="/{{ commit.owner.username }}">{{ commit.owner.username }}</a>
Commited by <a href="/{{ commit.owner.username }}">{{ commit.owner.username }}</a>
</p>
<h2>
<a href="{{ repo + '/commit/' + commit.sha }}">
email_templates/commit.txt
@@ -1,8 +1,8 @@
{% extends "mail.txt" %}
{% block content %}
{% trans repo=repo.route, commit=commit.mess %}# New commit in {{ repo }}{% endtrans %}
# New commit in {{ repo }}
{% trans %}Commited by{% endtrans} {{ commit.owner.username }}
Commited by {{ commit.owner.username }}
---------------------------------------
email_templates/email-change.html
@@ -0,0 +1,11 @@
{% extends "mail.html" %}
{% block content %}
<h1>You must verify your email address</h1>
<p>
Someone has requested that the account {{ username }} use this email address ({{ new_email }})
on this server. This email is safe to ignore; you will keep your current email address.
This will expire in 24 hours.
Please access the following WWW address to verify this email address:
</p>
<a href="{{ url }}">{{ url }}</a>
{% endblock %}
email_templates/email-change.txt
@@ -0,0 +1,11 @@
{% extends "mail.txt" %}
{% block content %}
# You must verify your email address
Someone has requested that the account {{ username }} use this email address ({{ new_email }})
on this server. This email is safe to ignore; you will keep your current email address.
This will expire in 24 hours.
Please access the following WWW address to verify this email address:
<{{ url }}>
{% endblock %}
email_templates/welcome.html
@@ -1,13 +1,13 @@
{% extends "mail.html" %}
{% block content %}
<h1>{% trans username=username %}Hello, {{ username }}!{% endtrans %}</h1>
<h1>Hello, {{ username }}!</h1>
<p>
{% trans %}Welcome to the roundabout. Make yourself at home.{% endtrans %}
Welcome to the roundabout. Make yourself at home.
</p>
<p>
{% trans %}You've just registered for an account at this server. If it wasn't you, write to us and we'll remove this email from our database.{% endtrans %}
You've just registered for an account at this server. If it wasn't you, write to us and we'll remove this email from our database.
</p>
<p>
{% trans %}No email verification is required; email notifications are provided only for your convenience.{% endtrans %}
No email verification is required; email notifications are provided only for your convenience.
</p>
{% endblock %}
email_templates/welcome.txt
@@ -1,10 +1,10 @@
{% extends "mail.txt" %}
{% block content %}
{% trans username=username %}# Hello, {{ username }}!{% endtrans %}
# Hello, {{ username }}!
{% trans %}Welcome to the roundabout. Make yourself at home.{% endtrans %}
Welcome to the roundabout. Make yourself at home.
{% trans %}You've just registered for an account at this server. If it wasn't you, write to us and we'll remove this email from our database.{% endtrans %}
You've just registered for an account at this server. If it wasn't you, write to us and we'll remove this email from our database.
{% trans %}No email verification is required; email notifications are provided only for your convenience.{% endtrans %}
No email verification is required; email notifications are provided only for your convenience.
{% endblock %}
git_http.py
@@ -31,6 +31,11 @@ def verify_password(username, password):
return False
def get_commit_identity(identity, logged_in_user):
email = identity.rpartition("<")[2].rpartition(">")[0].strip()
email_users = db.query(User).filter_by(email=email).all()
@app.route("/<username>/<repository>/git-upload-pack", methods=["POST"])
@app.route("/git/<username>/<repository>/git-upload-pack", methods=["POST"])
@auth.login_required(optional=True)
models.py
@@ -10,6 +10,7 @@ __all__ = [
"Post",
"Commit",
"PullRequest",
"EmailChangeRequest",
]
import secrets
@@ -112,7 +113,11 @@ with (app.app_context()):
def __init__(self, username, password, email=None, display_name=None):
self.username = username
self.password_hashed = bcrypt.generate_password_hash(password, config.HASHING_ROUNDS).decode("utf-8")
self.email = email
self.email = ""
if email:
email_change_request = EmailChangeRequest(self, email)
db.session.add(email_change_request)
db.session.flush()
self.display_name = display_name
# Create the user's directory