Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions assets/js/hubce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"use strict";

// requires newsletter.js
const VERIFY_EMAIL_URL = API_BASE_URL + '/connect/email/verify';
const REFRESH_LICENSE_URL = API_BASE_URL + '/licenses/hub/refresh';

class HubCE {
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused class HubCE.

Copilot uses AI. Check for mistakes.

constructor(form, feedbackData, submitData, searchParams) {
this._form = form;
this._feedbackData = feedbackData;
this._submitData = submitData;
this._searchParams = searchParams;
this._submitData.oldLicense = searchParams.get('oldLicense');

// continue after email verified:
if (searchParams.get('verifiedEmail')) {
feedbackData.currentStep = 1;
feedbackData.emailVerified = true;
}
}

submit() {
if (this._feedbackData.currentStep === 0) {
this.validateEmail();
} else if (this._feedbackData.currentStep === 1) {
this.sendConfirmationEmail();
} else if (this._feedbackData.currentStep === 2) {
this.getHubLicense();
}
}

validateEmail() {
if (!$(this._form)[0].checkValidity()) {
$(this._form).find(':input').addClass('show-invalid');
this._feedbackData.errorMessage = 'Please fill in all required fields.';
return;
}
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validateEmail() allows progression even when oldLicense is missing (it’s only blocked by the disabled button in the HTML). Because the form can be submitted via Enter key, this path can advance with a null/empty token and later POST it to the backend. Add an explicit oldLicense check here (and surface a clear error) to match the UI constraint.

Suggested change
}
}
// Ensure oldLicense is present before allowing progression.
const oldLicense = this._submitData.oldLicense;
if (!oldLicense) {
this._feedbackData.inProgress = false;
this._feedbackData.errorMessage = 'License information is missing. Please open this page using the link provided in your email.';
return;
}

Copilot uses AI. Check for mistakes.
this.onValidationSucceeded();
}

onValidationFailed(error) {
this._feedbackData.inProgress = false;
this._feedbackData.errorMessage = error;
}

onValidationSucceeded() {
this._feedbackData.currentStep++;
this._feedbackData.inProgress = false;
this._feedbackData.errorMessage = '';
}

sendConfirmationEmail() {
if (!$(this._form)[0].checkValidity()) {
$(this._form).find(':input').addClass('show-invalid');
this._feedbackData.errorMessage = 'Please fill in all required fields.';
return;
}

this._feedbackData.success = false;
this._feedbackData.inProgress = true;
this._feedbackData.errorMessage = '';
$.ajax({
url: VERIFY_EMAIL_URL,
type: 'POST',
data: {
email: this._submitData.email,
oldLicense: this._submitData.oldLicense,
verifyCaptcha: this._submitData.captcha,
verifyEmail: this._submitData.email,
verifyTarget: 'registerhubce'
}
}).done(_ => {
this.onRequestSucceeded();
if (this._submitData.acceptNewsletter) {
subscribeToNewsletter(this._submitData.email, 7); // FIXME move to backend
}
}).fail(xhr => {
this.onRequestFailed(xhr.responseJSON?.message || 'Sending confirmation email failed.');
});
}

getHubLicense() {
this._feedbackData.inProgress = true;
this._feedbackData.errorMessage = '';
$.ajax({
url: REFRESH_LICENSE_URL,
type: 'POST',
data: {
token: this._submitData.oldLicense,
captcha: this._submitData.captcha
}
}).done(response => {
this._feedbackData.licenseText = response;
this._feedbackData.inProgress = false;
}).fail(xhr => {
this.onRequestFailed(xhr.responseJSON?.message || 'Fetching license failed.');
});
}

onRequestFailed(error) {
this._feedbackData.inProgress = false;
this._feedbackData.errorMessage = error;
}

onRequestSucceeded() {
this._feedbackData.emailSent = true;
this._feedbackData.inProgress = false;
this._feedbackData.errorMessage = '';
}

}
5 changes: 5 additions & 0 deletions content/hub-register.de.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Cryptomator Hub: Registrieren"
url: "/de/hub/register"
type: "hub-register"
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a German page (hub-register.de.html), but there are no German i18n entries for the new hub_ce_registration_* keys (verified: no matches in i18n/de.yaml). The German page will render fallback IDs instead of translations. Add the corresponding i18n/de.yaml entries or avoid publishing the DE page until translations exist.

Suggested change
type: "hub-register"
type: "hub-register"
draft: true

Copilot uses AI. Check for mistakes.
---
5 changes: 5 additions & 0 deletions content/hub-register.en.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Cryptomator Hub: Register"
url: "/hub/register"
type: "hub-register"
---
39 changes: 39 additions & 0 deletions i18n/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,45 @@
- id: hub_demo_contact_us_button
translation: "Contact Us"

# Hub CE Registration
- id: hub_ce_registration_description
translation: "Register your Cryptomator Hub instance for a free Community Edition license."

- id: hub_ce_registration_steps_title
translation: "Step <span x-text=\"feedbackData.currentStep + 1\"></span> of <span x-text=\"steps.length\"></span>"
- id: hub_ce_registration_steps_next
translation: "Next"
- id: hub_ce_registration_steps_continue
translation: "Continue"

- id: hub_ce_registration_step_1_nav_title
translation: "Email Address"
- id: hub_ce_registration_step_1_title
translation: "What's your email address?"
- id: hub_ce_registration_step_1_email_placeholder
translation: "Email address"

- id: hub_ce_registration_step_2_confirmation_nav_title
translation: "Confirmation"
- id: hub_ce_registration_step_2_confirmation_title
translation: "Please confirm your email address"
- id: hub_ce_registration_step_2_instructions
translation: "We are going to send a confirmation email to <span x-text=\"submitData.email\"></span>"
- id: hub_ce_registration_step_2_check_email
translation: "Please check your e-mails."
- id: hub_ce_registration_step_2_email_verified
translation: "Your email has been verified successfully."

- id: hub_ce_registration_step_3_license_nav_title
translation: "License Key"
- id: hub_ce_registration_step_3_license_title
translation: "Your Community Edition License Key"
- id: hub_ce_registration_step_3_loading
translation: "Loading license key..."
- id: hub_ce_registration_step_3_success
translation: "Your new license key:"


# Hub Managed
- id: hub_managed_description
translation: "Request access to a managed instance of Cryptomator Hub and get your team on board with client-side encryption for your cloud storage."
Expand Down
Loading