Skip to content

Commit

Permalink
Add client-side encryption to encrypt an entire email body
Browse files Browse the repository at this point in the history
  • Loading branch information
micahflee committed Feb 20, 2025
1 parent efddf0e commit 4d423b1
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
10 changes: 10 additions & 0 deletions hushline/routes/forms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from flask_wtf import FlaskForm
from wtforms import (
HiddenField,
PasswordField,
RadioField,
SelectField,
Expand Down Expand Up @@ -62,6 +63,15 @@ class F(FlaskForm):

self.F = F

# Add email body hidden field
setattr(
self.F,
"encrypted_email_body",
HiddenField(
"Encrypted Email Body", validators=[Optional(), Length(max=10240 * len(fields))]
),
)

# Custom validator to skip choice validation while keeping other validations
def skip_invalid_choice(
form: FlaskForm, field: RadioField | SelectField | MultiCheckboxField
Expand Down
19 changes: 14 additions & 5 deletions hushline/routes/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,21 @@ def submit_message(username: str) -> Response | str:
db.session.commit()

if uname.user.enable_email_notifications:
if not uname.user.email_include_message_content:
email_body = "You have a new Hush Line message! Please log in to read it."
if uname.user.email_include_message_content:
# Only encrypt the entire body if we got the encrypted body from the form
if (
uname.user.email_encrypt_entire_body
and form.encrypted_email_body.data.startswith("-----BEGIN PGP MESSAGE-----")
):
email_body = form.encrypted_email_body.data
else:
# If we don't want to encrypt the entire body, or if client-side encryption
# of the body failed
email_body = ""
for name, value in extracted_fields:
email_body += f"\n\n{name}\n\n{value}\n\n=============="
else:
email_body = ""
for name, value in extracted_fields:
email_body += f"\n\n{name}\n\n{value}\n\n=============="
email_body = "You have a new Hush Line message! Please log in to read it."

do_send_email(uname.user, email_body.strip())

Expand Down
18 changes: 18 additions & 0 deletions hushline/static/js/client-side-encryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ document.addEventListener("DOMContentLoaded", function () {
form.addEventListener("submit", async function (event) {
event.preventDefault();

// Build an email body with all fields, encrypt it, and add it to the DOM as a hidden field
let emailBody = "";
document.querySelectorAll(".form-field").forEach(async (field) => {
const value = getFieldValue(field);
const label = getFieldLabel(field);
emailBody += `# ${label}\n\n${value}\n\n====================\n\n`;
});
const encryptedEmailBody = await encryptMessage(
publicKeyArmored,
emailBody,
);
if (encryptedEmailBody) {
const encryptedEmailBodyEl = document.getElementById("encrypted_email_body");
encryptedEmailBodyEl.value = encryptedEmailBody;
} else {
console.error("Client-side encryption failed for email body");
}

// Loop through all encrypted fields and encrypt them
document.querySelectorAll(".encrypted-field").forEach(async (field) => {
const value = getFieldValue(field);
Expand Down

0 comments on commit 4d423b1

Please sign in to comment.