mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-12 13:13:45 +01:00
Registration page: the initial commit
This commit is contained in:
@@ -11,6 +11,7 @@ import EmailHelper from '../Helpers/EmailHelper.mjs'
|
||||
import EditorRealTimeController from '../Editor/EditorRealTimeController.mjs'
|
||||
import AnalyticsManager from '../Analytics/AnalyticsManager.mjs'
|
||||
import SessionManager from '../Authentication/SessionManager.mjs'
|
||||
import Features from '../../infrastructure/Features.mjs'
|
||||
import { RateLimiter } from '../../infrastructure/RateLimiter.mjs'
|
||||
import { z, zz, parseReq } from '../../infrastructure/Validation.mjs'
|
||||
import { expressify } from '@overleaf/promise-utils'
|
||||
@@ -334,7 +335,11 @@ async function viewInvite(req, res) {
|
||||
user_first_name: owner.first_name,
|
||||
}
|
||||
AuthenticationController.setRedirectInSession(req)
|
||||
return res.redirect('/register')
|
||||
if (Features.hasFeature('registration-page')) {
|
||||
return res.redirect('/register')
|
||||
} else {
|
||||
return res.redirect('/login')
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup if set for register page
|
||||
@@ -374,7 +379,11 @@ async function viewSharingLink(req, res) {
|
||||
const currentUser = SessionManager.getSessionUser(req.session)
|
||||
if (!currentUser) {
|
||||
AuthenticationController.setRedirectInSession(req)
|
||||
return res.redirect('/register')
|
||||
if (Features.hasFeature('registration-page')) {
|
||||
return res.redirect('/register')
|
||||
} else {
|
||||
return res.redirect('/login')
|
||||
}
|
||||
}
|
||||
|
||||
// cleanup if set for register page
|
||||
|
||||
@@ -34,6 +34,7 @@ const Features = {
|
||||
return (
|
||||
(Boolean(Settings.ldap) && Boolean(Settings.ldap.enable)) ||
|
||||
(Boolean(Settings.saml) && Boolean(Settings.saml.enable)) ||
|
||||
(Boolean(Settings.oidc) && Boolean(Settings.oidc.enable)) ||
|
||||
Boolean(Settings.overleaf)
|
||||
)
|
||||
},
|
||||
@@ -51,10 +52,7 @@ const Features = {
|
||||
case 'homepage':
|
||||
return Boolean(Settings.enableHomepage)
|
||||
case 'registration-page':
|
||||
return (
|
||||
!Features.externalAuthenticationSystemUsed() ||
|
||||
Boolean(Settings.overleaf) || Settings.oidc?.allowedOIDCEmailDomains
|
||||
)
|
||||
return Boolean(Settings.enableRegistrationPage)
|
||||
case 'registration':
|
||||
return Boolean(Settings.overleaf)
|
||||
case 'chat':
|
||||
|
||||
@@ -1212,6 +1212,7 @@ module.exports = {
|
||||
'authentication/saml',
|
||||
'authentication/oidc',
|
||||
'admin-tools', // import after authentication
|
||||
'registration-page', // import after authentication
|
||||
'template-gallery',
|
||||
'git-bridge',
|
||||
'github-sync',
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
"account_not_linked_to_dropbox": "Dein Konto ist nicht mit Dropbox verknüpft",
|
||||
"account_settings": "Kontoeinstellungen",
|
||||
"account_with_email_exists": "Anscheinend existiert bereits ein <b>__appName__</b>-Konto mit der E-Mail-Adresse <b>__email__</b>.",
|
||||
"account_with_this_email_exists": "Anscheinend existiert bereits ein <b>__appName__</b>-Konto mit dieser E-Mail-Adresse.",
|
||||
"acct_linked_to_institution_acct_2": "Du kannst dich jetzt mit dem Konto deiner Institution <0>__institutionName__</0> bei Overleaf anmelden.",
|
||||
"actions": "Aktionen",
|
||||
"activate": "Aktivieren",
|
||||
@@ -579,6 +580,7 @@
|
||||
"export_project_to_github": "Projekt nach GitHub exportieren",
|
||||
"failed_to_publish_as_a_template": "Veröffentlichung als Vorlage fehlgeschlagen.",
|
||||
"failed_to_send_managed_user_invite_to_email": "Der Versand der Einladung für Verwaltete Benutzer an <0>__email__</0> hat nicht funktioniert. Bitte versuche es später noch einmal.",
|
||||
"failed_to_send_registration_email": "Die Registrierungs-E-Mail konnte nicht gesendet werden. Bitte überprüfe die E-Mail-Adresse.",
|
||||
"faq_how_does_free_trial_works_answer": "Während deines __len__-tägigen Probe-Abonnements erhältst du vollen Zugriff auf die Funktionen des von dir gewählten __appName__-Abonnements. Es besteht keine Verpflichtung, über die Testperiode hinaus fortzufahren. Deine Karte wird am Ende des __len__-tägigen Testzeitraums belastet, sofern du nicht vorher gekündigt hast. Um zu kündigen, gehe zu deinen Abonnementeinstellungen in deinem Konto.",
|
||||
"fast": "Schnell",
|
||||
"fast_draft": "Schnell [Entwurf]",
|
||||
@@ -791,6 +793,7 @@
|
||||
"inactive_projects": "Inaktive Projekte",
|
||||
"include_caption": "Beschriftung anzeigen",
|
||||
"include_label": "Label anzeigen",
|
||||
"including_all_subdomains": "einschließlich aller Subdomains",
|
||||
"increased_compile_timeout": "Zeitlimit beim Kompilieren erhöhen",
|
||||
"info": "Info",
|
||||
"inr_discount_modal_info": "Erhalte Dokumentenverlauf, Änderungsverfolgung, weitere Mitarbeiter und mehr zu Preisen nach Kaufkraftparität.",
|
||||
@@ -1268,11 +1271,13 @@
|
||||
"regards": "Viele Grüße",
|
||||
"register": "Registrieren",
|
||||
"register_error": "Registrierungsfehler",
|
||||
"register_success": "Registrierung erfolgreich. Bitte überprüfen Sie Ihre E-Mail, um Ihr Konto zu aktivieren.",
|
||||
"register_intercept_sso": "Du kannst dein __authProviderName__-Konto nach der Anmeldung auf der Seite Kontoeinstellungen verknüpfen.",
|
||||
"register_to_edit_template": "Bitte registriere dich um die __templateName__ Vorlage zu bearbeiten",
|
||||
"register_with_another_email": "<a href=\"__link__\">Registriere Dich bei __appName__</a> mit einer anderen E-Mail-Adresse.",
|
||||
"registered": "Registriert",
|
||||
"registering": "Registrieren",
|
||||
"registration_is_restricted_to_the_following_email_domains": "Die Registrierung ist auf die folgenden E-Mail-Domänen beschränkt:",
|
||||
"reject": "Verwerfen",
|
||||
"related_tags": "Ähnliche Stichwörter",
|
||||
"relink_your_account": "Verknüpfe dein Konto neu",
|
||||
@@ -1447,6 +1452,7 @@
|
||||
"store_your_work": "Speichere deine Arbeit auf deiner eigenen Infrastruktur",
|
||||
"student": "Student",
|
||||
"student_disclaimer": "Der Bildungsrabatt gilt für alle Studierenden an weiterführenden und höheren Bildungseinrichtungen (Schulen und Universitäten). Wir können dich kontaktieren, damit du den Anspruch auf den Rabatt bestätigst.",
|
||||
"subdomains_of_this_domain_only": "nur Subdomains dieser Domain",
|
||||
"subject": "Betreff",
|
||||
"submit": "Absenden",
|
||||
"submit_title": "Einreichen",
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
"account_not_linked_to_dropbox": "Your account is not linked to Dropbox",
|
||||
"account_settings": "Account settings",
|
||||
"account_with_email_exists": "It looks like an <b>__appName__</b> account with the email <b>__email__</b> already exists.",
|
||||
"account_with_this_email_exists": "It looks like an <b>__appName__</b> account with this email address already exists.",
|
||||
"acct_linked_to_institution_acct_2": "You can <0>log in</0> to Overleaf through your <0>__institutionName__</0> institutional login.",
|
||||
"action_needed": "Action needed",
|
||||
"actions": "Actions",
|
||||
@@ -903,6 +904,7 @@
|
||||
"failed_to_publish_as_a_template": "Failed to publish as a template.",
|
||||
"failed_to_send_group_invite_to_email": "Failed to send group invite to <0>__email__</0>. Please try again later.",
|
||||
"failed_to_send_managed_user_invite_to_email": "Failed to send Managed User invite to <0>__email__</0>. Please try again later.",
|
||||
"failed_to_send_registration_email": "Failed to send the registration email. Please check the email address.",
|
||||
"failed_to_send_sso_link_invite_to_email": "Failed to send SSO invite reminder to <0>__email__</0>. Please try again later.",
|
||||
"fair_usage_policy_applies": "Fair usage policy applies.",
|
||||
"faq_how_does_free_trial_works_answer": "You get full access to your chosen __appName__ plan during your __len__-day free trial. There is no obligation to continue beyond the trial. Your card will be charged at the end of your __len__ day trial unless you cancel before then. You can cancel via your subscription settings.",
|
||||
@@ -1277,6 +1279,7 @@
|
||||
"include_the_error_message_and_ai_response": "Include the error message and AI response",
|
||||
"included_as_part_of_your_writefull_subscription": "Included as part of your Writefull subscription",
|
||||
"includes": "includes",
|
||||
"including_all_subdomains": "including all subdomains",
|
||||
"increase_indent": "Increase indentation",
|
||||
"increased_ai_allowance": "Increased AI allowance",
|
||||
"increased_ai_allowance_tooltip": "10 AI uses per day across all AI tools.",
|
||||
@@ -2182,12 +2185,14 @@
|
||||
"regards": "Regards",
|
||||
"register": "Register",
|
||||
"register_error": "Registration error",
|
||||
"register_success": "Registration successful. Please check your email to activate your account.",
|
||||
"register_intercept_sso": "You can link your __authProviderName__ account from the Account settings page after logging in.",
|
||||
"register_to_accept_invitation": "Register to accept invitation",
|
||||
"register_to_edit_template": "Please register to edit the __templateName__ template",
|
||||
"register_with_another_email": "<a href=\"__link__\">Register with __appName__</a> using another email.",
|
||||
"registered": "Registered",
|
||||
"registering": "Registering",
|
||||
"registration_is_restricted_to_the_following_email_domains": "The registration is restricted to the following email domains:",
|
||||
"reject": "Reject",
|
||||
"reject_change": "Reject change",
|
||||
"reject_selected_changes": "Reject selected changes",
|
||||
@@ -2619,6 +2624,7 @@
|
||||
"student_discount_tooltip": "Available to students currently enrolled at a degree-granting institution.",
|
||||
"student_verification_required": "Student verification required",
|
||||
"students": "Students",
|
||||
"subdomains_of_this_domain_only": "subdomains of this domain only",
|
||||
"subject": "Subject",
|
||||
"subject_area": "Subject area",
|
||||
"submit": "submit",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
"account_information": "Информация об аккаунте",
|
||||
"account_not_linked_to_dropbox": "Ваш аккаунт не синхронизирован с Dropbox",
|
||||
"account_settings": "Настройки профиля",
|
||||
"account_with_this_email_exists": "Похоже, что учётная запись <b>__appName__</b> с этим адресом электронной почты уже существует.",
|
||||
"actions": "Действия",
|
||||
"activate": "Активировать",
|
||||
"activate_account": "Активируйте Ваш аккаунт",
|
||||
@@ -185,6 +186,7 @@
|
||||
"explore_plans": "Посмотреть тарифы",
|
||||
"export_project_to_github": "Экспорт проекта на GitHub",
|
||||
"failed_to_publish_as_a_template": "Не удалось создать шаблон.",
|
||||
"failed_to_send_registration_email": "Не удалось отправить письмо для подтверждения регистрации. Пожалуйста, проверьте адрес электронной почты.",
|
||||
"fast": "быстрый",
|
||||
"features": "Возможности",
|
||||
"february": "Февраль",
|
||||
@@ -244,6 +246,7 @@
|
||||
"importing": "Импорт",
|
||||
"importing_and_merging_changes_in_github": "Импорт и слияние изменений в GitHub",
|
||||
"inactive_projects": "Неактивные проекты",
|
||||
"including_all_subdomains": "включая все поддомены",
|
||||
"info": "Информация",
|
||||
"institution": "Организация",
|
||||
"invalid_file_name": "Неверное имя файла",
|
||||
@@ -409,9 +412,11 @@
|
||||
"refresh_page_after_starting_free_trial": "Пожалуйста, обновите страницу",
|
||||
"regards": "С уважением",
|
||||
"register": "Регистрация",
|
||||
"register_success": "Регистрация успешно завершена. Пожалуйста, проверьте свою электронную почту, чтобы активировать учётную запись.",
|
||||
"register_to_edit_template": "Пожалуйста, зарегистрируйтесь, чтобы редактировать шаблон __templateName__",
|
||||
"registered": "Зарeгистрирован",
|
||||
"registering": "Создание аккаунта",
|
||||
"registration_is_restricted_to_the_following_email_domains": "Регистрация разрешена только для следующих доменов электронной почты:",
|
||||
"remove_from_group": "Удалить из группы",
|
||||
"removed": "удалено",
|
||||
"removing": "Удаление",
|
||||
@@ -484,6 +489,7 @@
|
||||
"stop_compile": "Остановить компиляцию",
|
||||
"stop_on_validation_error": "Проверить синтаксис перед компиляцией",
|
||||
"student": "Студент",
|
||||
"subdomains_of_this_domain_only": "только поддомены этого домена",
|
||||
"subject": "Тема",
|
||||
"subscribe": "Подписаться",
|
||||
"subscribe_now": "Подписаться сейчас",
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
import Path from 'path'
|
||||
import logger from '@overleaf/logger'
|
||||
import registerNewUserAndSendActivationEmail from './UserRegistrationHandler.mjs'
|
||||
import EmailHelper from '../../../../app/src/Features/Helpers/EmailHelper.mjs'
|
||||
import Settings from '@overleaf/settings'
|
||||
|
||||
async function registrationPage(req, res, next) {
|
||||
// Check if the user is already logged in
|
||||
if (req.user != null) {
|
||||
return res.redirect(`/`)
|
||||
}
|
||||
|
||||
const sharedProjectData = req.session.sharedProjectData || {}
|
||||
|
||||
const newTemplateData = {}
|
||||
if (req.session.templateData != null) {
|
||||
newTemplateData.templateName = req.session.templateData.templateName
|
||||
}
|
||||
|
||||
const allowedDomains = Settings.allowedRegistrationEmailDomains || []
|
||||
const displayDomains = new Map()
|
||||
|
||||
for (const domain of allowedDomains) {
|
||||
const subdomainsOnly = domain.startsWith('*.')
|
||||
const base = subdomainsOnly ? domain.substring(2) : domain
|
||||
|
||||
const existing = displayDomains.get(base)
|
||||
|
||||
displayDomains.set(base, {
|
||||
domain: base,
|
||||
exact: existing?.exact || !subdomainsOnly,
|
||||
subdomains: existing?.subdomains || subdomainsOnly,
|
||||
})
|
||||
}
|
||||
|
||||
const __dirname = Path.dirname(new URL(import.meta.url).pathname)
|
||||
res.render(Path.resolve(__dirname, '../views/register'), {
|
||||
title: 'register',
|
||||
sharedProjectData,
|
||||
newTemplateData,
|
||||
displayDomains: [...displayDomains.values()],
|
||||
csrfToken: req.csrfToken(),
|
||||
})
|
||||
}
|
||||
|
||||
async function registerNewUser(req, res, next) {
|
||||
const { email, first_name, last_name } = req.body
|
||||
|
||||
if (
|
||||
typeof first_name !== 'string' || first_name.length > 100 ||
|
||||
typeof last_name !== 'string' || last_name.length > 100
|
||||
) {
|
||||
return res.status(400).json({ message: 'Too long name.' })
|
||||
}
|
||||
|
||||
const parsedEmail = EmailHelper.parseEmail(email)
|
||||
if (!parsedEmail) {
|
||||
return res.status(400).json({ message: 'Invalid email address.' })
|
||||
}
|
||||
|
||||
// If registration is restricted to a specific email domains,
|
||||
// check that the email domain is allowed
|
||||
const domain = parsedEmail.split('@').pop()
|
||||
const allowedDomains = Settings.allowedRegistrationEmailDomains
|
||||
|
||||
if (
|
||||
allowedDomains &&
|
||||
!allowedDomains.some(pattern => {
|
||||
if (pattern.startsWith('*.')) {
|
||||
const base = pattern.slice(2)
|
||||
return domain.endsWith(`.${base}`)
|
||||
}
|
||||
return domain === pattern
|
||||
})
|
||||
) {
|
||||
return res.status(403).json({
|
||||
message: 'Registration is not available for this email domain.',
|
||||
})
|
||||
}
|
||||
|
||||
const t = req.i18n.translate
|
||||
try {
|
||||
const userDetails = { email, first_name, last_name }
|
||||
const success = await registerNewUserAndSendActivationEmail(userDetails)
|
||||
if (success) {
|
||||
return res.status(200).json({ message: t('register_success') })
|
||||
} else {
|
||||
return res.status(409).json({ message: { key: 'account_with_this_email_exists' } })
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message === 'error sending message') {
|
||||
return res.status(422).json({ message: t('failed_to_send_registration_email') })
|
||||
}
|
||||
return next(error)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
registrationPage,
|
||||
registerNewUser
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import logger from "@overleaf/logger"
|
||||
import Settings from "@overleaf/settings"
|
||||
import RegistrationPageController from './RegistrationPageController.mjs'
|
||||
import AuthenticationController from '../../../../app/src/Features/Authentication/AuthenticationController.mjs'
|
||||
import RateLimiterMiddleware from "../../../../app/src/Features/Security/RateLimiterMiddleware.mjs"
|
||||
import { RateLimiter } from "../../../../app/src/infrastructure/RateLimiter.mjs"
|
||||
|
||||
// Limit registration attempts to 3 per minute per IP
|
||||
const registrationRateLimiters = {
|
||||
postRegister: new RateLimiter('postRegister', {
|
||||
points: 5,
|
||||
duration: 60,
|
||||
}),
|
||||
}
|
||||
|
||||
export default {
|
||||
apply(webRouter) {
|
||||
logger.debug({}, 'Init Registration Page module')
|
||||
|
||||
// remove default registration router if it exists
|
||||
webRouter.stack = webRouter.stack.filter(layer => {
|
||||
return !(layer.route && layer.route.path === '/register' && layer.route.methods.get)
|
||||
})
|
||||
|
||||
webRouter.get('/register', RegistrationPageController.registrationPage)
|
||||
|
||||
webRouter.post(
|
||||
'/register',
|
||||
RateLimiterMiddleware.rateLimit(registrationRateLimiters.postRegister),
|
||||
RegistrationPageController.registerNewUser
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import crypto from 'node:crypto'
|
||||
import settings from '@overleaf/settings'
|
||||
import logger from '@overleaf/logger'
|
||||
import UserRegistrationHandler from '../../../../app/src/Features/User/UserRegistrationHandler.mjs'
|
||||
import UserDeleter from '../../../../app/src/Features/User/UserDeleter.mjs'
|
||||
import EmailHandler from '../../../../app/src/Features/Email/EmailHandler.mjs'
|
||||
import OneTimeTokenHandler from '../../../../app/src/Features/Security/OneTimeTokenHandler.mjs'
|
||||
|
||||
const ONE_WEEK = 7 * 24 * 60 * 60 // seconds
|
||||
|
||||
export default async function registerNewUserAndSendActivationEmail(userData) {
|
||||
let user
|
||||
try {
|
||||
const password = crypto.randomBytes(32).toString('hex')
|
||||
user = await UserRegistrationHandler.promises.registerNewUser({ ...userData, password })
|
||||
} catch (error) {
|
||||
if (error.message === 'EmailAlreadyRegistered') {
|
||||
logger.debug({ email: userData.email }, 'user already registered')
|
||||
return false
|
||||
}
|
||||
throw error
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await OneTimeTokenHandler.promises.getNewToken(
|
||||
'password',
|
||||
{ user_id: user._id.toString(), email: user.email },
|
||||
{ expiresIn: ONE_WEEK }
|
||||
)
|
||||
|
||||
const setNewPasswordUrl = `${settings.siteUrl}/user/activate?token=${token}&user_id=${user._id}`
|
||||
|
||||
await EmailHandler.promises.sendEmail('registered', {
|
||||
to: user.email,
|
||||
setNewPasswordUrl,
|
||||
})
|
||||
} catch (error) {
|
||||
try {
|
||||
await UserDeleter.promises.deleteUser(user._id, {
|
||||
ipAddress: '127.0.0.1',
|
||||
skipEmail: true,
|
||||
})
|
||||
await UserDeleter.promises.expireDeletedUser(user._id)
|
||||
} catch (err) {
|
||||
logger.error({ err, userId: user._id }, 'failed delete user')
|
||||
}
|
||||
throw error
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{ "extends": "../../../../tsconfig.backend.json" }
|
||||
@@ -0,0 +1,98 @@
|
||||
extends ../../../../app/views/layout-website-redesign
|
||||
|
||||
block vars
|
||||
- isWebsiteRedesign = true
|
||||
|
||||
block content
|
||||
main#main-content.content
|
||||
.container
|
||||
.row
|
||||
.registration-message
|
||||
if sharedProjectData.user_first_name !== undefined
|
||||
h1 #{translate("user_wants_you_to_see_project", {username:sharedProjectData.user_first_name, projectname:""})}
|
||||
em #{sharedProjectData.project_name}
|
||||
div
|
||||
| #{translate("join_sl_to_view_project")}.
|
||||
div
|
||||
| #{translate("already_have_sl_account")}
|
||||
|
|
||||
a(href='/login') #{translate("login_here")}
|
||||
else if newTemplateData.templateName !== undefined
|
||||
h1 #{translate("register_to_edit_template", {templateName:newTemplateData.templateName})}
|
||||
|
||||
div #{translate("already_have_sl_account")}
|
||||
|
|
||||
a(href='/login') #{translate("login_here")}
|
||||
.row
|
||||
.col-lg-8.offset-lg-2.col-xl-6.offset-xl-3
|
||||
.page-header
|
||||
h1.login-register-header-heading-focus.h3 #{translate("register")}
|
||||
if displayDomains.length
|
||||
.alert.alert-info
|
||||
div.small.fst-italic.mb-2 #{translate("registration_is_restricted_to_the_following_email_domains")}
|
||||
ul.mb-0.small
|
||||
each item in displayDomains
|
||||
li
|
||||
span.small.fst-italic
|
||||
code #{item.domain}
|
||||
if item.subdomains && item.exact
|
||||
| (#{translate("including_all_subdomains")})
|
||||
else if item.subdomains
|
||||
| (#{translate("subdomains_of_this_domain_only")})
|
||||
form(
|
||||
data-ol-async-form
|
||||
name="registrationForm"
|
||||
action="/register",
|
||||
method="POST",
|
||||
aria-label=translate('create_account')
|
||||
)
|
||||
input(name='_csrf' type='hidden' value=csrfToken)
|
||||
+formMessagesNewStyle()
|
||||
+customFormMessageNewStyle('account_with_this_email_exists', 'warn')
|
||||
| !{translate("account_with_this_email_exists")}
|
||||
a.d-block.mt-1(href='/user/password/reset') #{translate("forgot_your_password")}?
|
||||
.form-group
|
||||
label(for='firstNameField') #{translate("first_name")}
|
||||
input.form-control(
|
||||
aria-label="first_name"
|
||||
id='firstNameField'
|
||||
type='text',
|
||||
name='first_name',
|
||||
placeholder=translate("first_name"),
|
||||
required,
|
||||
autocomplete="given-name",
|
||||
maxlength="100"
|
||||
autofocus
|
||||
)
|
||||
.form-group
|
||||
label(for='lastNameField') #{translate("last_name")}
|
||||
input.form-control(
|
||||
aria-label="last_name"
|
||||
id='lastNameField'
|
||||
type='text',
|
||||
name='last_name',
|
||||
placeholder=translate("last_name"),
|
||||
required,
|
||||
autocomplete="family-name",
|
||||
maxlength="100"
|
||||
)
|
||||
.form-group
|
||||
label(for='emailField') #{translate("email")}
|
||||
input.form-control(
|
||||
aria-label="email"
|
||||
id='emailField'
|
||||
type='email',
|
||||
name='email',
|
||||
placeholder=translate("email"),
|
||||
required,
|
||||
autocomplete="username",
|
||||
maxlength="100"
|
||||
)
|
||||
div(style="margin-top: 3rem")
|
||||
.actions
|
||||
button.btn.btn-primary.w-100(
|
||||
type='submit',
|
||||
data-ol-disabled-inflight
|
||||
)
|
||||
span(data-ol-inflight="idle") #{translate("create_account")}
|
||||
span(hidden data-ol-inflight="pending") #{translate("registering")}…
|
||||
@@ -0,0 +1,30 @@
|
||||
import Settings from '@overleaf/settings'
|
||||
import { boolFromEnv } from '../authentication/utils.mjs'
|
||||
|
||||
let RegistrationPageModule = {}
|
||||
|
||||
let enableRegistrationPage = boolFromEnv(process.env.OVERLEAF_ENABLE_REGISTRATION_PAGE)
|
||||
|
||||
// if the env var is not set, enable registration page iff the external authentication is not enabled
|
||||
if (enableRegistrationPage === undefined) {
|
||||
enableRegistrationPage = !(Settings.ldap?.enable || Settings.saml?.enable || Settings.oidc?.enable)
|
||||
}
|
||||
|
||||
if (enableRegistrationPage) {
|
||||
const { default: router } = await import('./app/src/RegistrationPageRouter.mjs')
|
||||
|
||||
Settings.enableRegistrationPage = true
|
||||
|
||||
if (process.env.OVERLEAF_ALLOWED_REGISTRATION_EMAIL_DOMAINS) {
|
||||
Settings.allowedRegistrationEmailDomains = process.env.OVERLEAF_ALLOWED_REGISTRATION_EMAIL_DOMAINS
|
||||
.split(/[,\s]+/)
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
RegistrationPageModule = {
|
||||
name: 'registration-page',
|
||||
router: router,
|
||||
}
|
||||
}
|
||||
|
||||
export default RegistrationPageModule
|
||||
Reference in New Issue
Block a user