diff --git a/.gitignore b/.gitignore
index 938ccba254497..dbfd9a657b379 100644
--- a/.gitignore
+++ b/.gitignore
@@ -151,3 +151,6 @@ clover.xml
# Tests - dependencies
tests/acceptance/composer.lock
tests/acceptance/vendor/
+config/config.php.test
+.htaccess
+.htaccess
diff --git a/.htaccess b/.htaccess
index cc2e0c95eb11c..9aa16c7cb933c 100644
--- a/.htaccess
+++ b/.htaccess
@@ -65,3 +65,7 @@ Options -Indexes
ModPagespeed Off
+#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####
+
+ErrorDocument 403 //
+ErrorDocument 404 //
diff --git a/config/config.sample.php b/config/config.sample.php
index b25a4baeadd5d..7d50c362debd7 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -54,6 +54,14 @@
*/
'passwordsalt' => '',
+/**
+ * The adminitsrator email provides a place to personalize a support email to
+ * display in all messages errors
+ *
+ * 'administrator_email' => 'support@nextcloud.com',
+ */
+'administrator_email' => 'your administrator email',
+
/**
* Your list of trusted domains that users can log into. Specifying trusted
* domains prevents host header poisoning. Do not remove this, as it performs
diff --git a/core/Controller/LostController.php b/core/Controller/LostController.php
index 96018555ec3c4..9cb3f649474be 100644
--- a/core/Controller/LostController.php
+++ b/core/Controller/LostController.php
@@ -32,8 +32,10 @@
namespace OC\Core\Controller;
use OC\Authentication\TwoFactorAuth\Manager;
+use OC\Security\Bruteforce\Throttler;
use OC\HintException;
use \OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use \OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -47,6 +49,8 @@
use \OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\ISession;
+use OCP\Util;
use OCP\Mail\IMailer;
use OCP\Security\ICrypto;
use OCP\Security\ISecureRandom;
@@ -73,6 +77,8 @@ class LostController extends Controller {
protected $encryptionManager;
/** @var IConfig */
protected $config;
+ /** @var ISession */
+ protected $session;
/** @var ISecureRandom */
protected $secureRandom;
/** @var IMailer */
@@ -85,6 +91,9 @@ class LostController extends Controller {
private $logger;
/** @var Manager */
private $twoFactorManager;
+ /** @var Throttler */
+ private $throttler;
+
/**
* @param string $appName
@@ -94,6 +103,7 @@ class LostController extends Controller {
* @param Defaults $defaults
* @param IL10N $l10n
* @param IConfig $config
+ * @param ISession $session
* @param ISecureRandom $secureRandom
* @param string $defaultMailAddress
* @param IManager $encryptionManager
@@ -108,6 +118,7 @@ public function __construct($appName,
Defaults $defaults,
IL10N $l10n,
IConfig $config,
+ ISession $session,
ISecureRandom $secureRandom,
$defaultMailAddress,
IManager $encryptionManager,
@@ -115,7 +126,8 @@ public function __construct($appName,
ITimeFactory $timeFactory,
ICrypto $crypto,
ILogger $logger,
- Manager $twoFactorManager) {
+ Manager $twoFactorManager,
+ Throttler $throttler) {
parent::__construct($appName, $request);
$this->urlGenerator = $urlGenerator;
$this->userManager = $userManager;
@@ -125,11 +137,13 @@ public function __construct($appName,
$this->from = $defaultMailAddress;
$this->encryptionManager = $encryptionManager;
$this->config = $config;
+ $this->session = $session;
$this->mailer = $mailer;
$this->timeFactory = $timeFactory;
$this->crypto = $crypto;
$this->logger = $logger;
$this->twoFactorManager = $twoFactorManager;
+ $this->throttler = $throttler;
}
/**
@@ -171,6 +185,95 @@ public function resetform($token, $userId) {
'guest'
);
}
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ * @BruteForceProtection(action=passwordResetEmail)
+ * @AnonRateThrottle(limit=10, period=300)
+ * @UseSession
+ *
+ * @param string $userId
+ *
+ * @return TemplateResponse
+ */
+ public function showPasswordEmailForm($userId) : Http\Response {
+ return $this->showNewPasswordForm($userId);
+ }
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ * @BruteForceProtection(action=passwordResetEmail)
+ * @AnonRateThrottle(limit=10, period=300)
+ * @UseSession
+ *
+ * @param string $user
+ *
+ * @return TemplateResponse
+ */
+ public function showNewPasswordForm($user = null) : Http\Response {
+
+ $parameters = [];
+ $renewPasswordMessages = $this->session->get('loginMessages');
+ $errors = [];
+ $messages = [];
+
+ if (is_array($renewPasswordMessages)) {
+ list($errors, $messages) = $renewPasswordMessages;
+ }
+ $this->session->remove('loginMessages');
+ foreach ($errors as $value) {
+ $parameters[$value] = true;
+ }
+ $parameters['messages'] = $messages;
+
+ $parameters['resetPasswordLink'] = $this->config
+ ->getSystemValue('lost_password_link', '');
+
+ // disable the form if setting 'password reset' is disabled
+ if ($parameters['resetPasswordLink'] !== '') {
+ return new TemplateResponse('core', 'error', [
+ 'errors' => [['error' => $this->l10n->t('Password reset is disabled')]]
+ ],
+ 'guest'
+ );
+ }
+
+ $userObj = null;
+ if ($user !== null && $user !== '') {
+ try {
+ $userObj = $this->findUserByIdOrMail($user);
+ $parameters['displayName'] = $userObj->getDisplayName();
+ $parameters['loginName'] = $userObj->getEMailAddress();
+ //the timestamp of the user's last login or 0 if the user did never
+ $parameters['last_login'] = $userObj->getLastLogin();
+ $parameters['user_autofocus'] = false;
+ } catch(\InvalidArgumentException $exception){
+ // $user parameter is unknown or desactivated
+ $parameters['messages'][] = $user . ' :' . $this->l10n->t('unknown text');
+ $parameters['loginName'] = null;
+ $parameters['displayName'] = null;
+ $parameters['last_login'] = null;
+ $parameters['user_autofocus'] = true;
+ }
+ }
+
+ $parameters = $this->setPasswordResetParameters($userObj, $parameters);
+ $parameters['administrator_email'] = $this->config->getSystemValue('administrator_email');
+ $parameters['login_form_autocomplete'] = 'on';
+ $parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
+
+ // OpenGraph Support: http://ogp.me/
+ Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
+ Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
+ Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
+ Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
+ Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
+ Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
+
+ return new TemplateResponse(
+ $this->appName, 'lostpassword/newpassword', $parameters, 'guest'
+ );
+ }
/**
* @param string $token
@@ -229,9 +332,10 @@ private function success($data = []) {
* @AnonRateThrottle(limit=10, period=300)
*
* @param string $user
+ * @param string $action optional
* @return JSONResponse
*/
- public function email($user){
+ public function email($user,$action=null){
if ($this->config->getSystemValue('lost_password_link', '') !== '') {
return new JSONResponse($this->error($this->l10n->t('Password reset is disabled')));
}
@@ -244,7 +348,7 @@ public function email($user){
// FIXME: use HTTP error codes
try {
- $this->sendEmail($user);
+ $this->sendEmail($user,$action);
} catch (\Exception $e) {
// Ignore the error since we do not want to leak this info
$this->logger->logException($e, [
@@ -309,9 +413,10 @@ public function setPassword($token, $userId, $password, $proceed) {
/**
* @param string $input
+ * @param string $action
* @throws \Exception
*/
- protected function sendEmail($input) {
+ protected function sendEmail($input,$action=null) {
$user = $this->findUserByIdOrMail($input);
$email = $user->getEMailAddress();
@@ -341,22 +446,44 @@ protected function sendEmail($input) {
'link' => $link,
]);
- $emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
- $emailTemplate->addHeader();
- $emailTemplate->addHeading($this->l10n->t('Password reset'));
+ if((empty($action)) || ($action == 'RESET')) {
+ $emailTemplate->setSubject($this->l10n->t('%s password reset', [$this->defaults->getName()]));
+ $emailTemplate->addHeader();
+ $emailTemplate->addHeading($this->l10n->t('Password reset'));
- $emailTemplate->addBodyText(
- htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
- $this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
- );
+ $emailTemplate->addBodyText(
+ htmlspecialchars($this->l10n->t('Click the following button to reset your password. If you have not requested the password reset, then ignore this email.')),
+ $this->l10n->t('Click the following link to reset your password. If you have not requested the password reset, then ignore this email.')
+ );
- $emailTemplate->addBodyButton(
- htmlspecialchars($this->l10n->t('Reset your password')),
- $link,
- false
- );
- $emailTemplate->addFooter();
+ $emailTemplate->addBodyButton(
+ htmlspecialchars($this->l10n->t('Reset your password')),
+ $link,
+ false
+ );
+ } else if($action == 'NEW'){
+ $emailTemplate->setSubject($this->l10n->t('%s activate and choose a password', [$this->defaults->getName()]));
+ $emailTemplate->addHeader();
+ $emailTemplate->addHeading($this->l10n->t('Activate and choose a password'));
+
+ $emailTemplate->addBodyText(
+ htmlspecialchars($this->l10n->t('Click the following button to activate and choose a new password. If you have not requested the new password, then ignore this email.')),
+ $this->l10n->t('Click the following link to activate and choose a new password. If you have not requested the new password, then ignore this email.')
+ );
+
+ $emailTemplate->addBodyButton(
+ htmlspecialchars($this->l10n->t('Activate and choose your new password')),
+ $link,
+ false
+ );
+
+ } else {
+ throw new \Exception($this->l10n->t(
+ 'Couldn\'t send reset email. Please contact your administrator.'
+ ));
+ }
+ $emailTemplate->addFooter();
try {
$message = $this->mailer->createMessage();
$message->setTo([$email => $user->getUID()]);
@@ -394,9 +521,37 @@ protected function findUserByIdOrMail($input) {
});
if (\count($users) === 1) {
- return $users[0];
+ return $users[1];
}
throw $userNotFound;
}
+
+ /**
+ * Sets the password reset params.
+ *
+ * Users may not change their passwords if:
+ * - The account is disabled
+ * - The backend doesn't support password resets
+ * - The password reset function is disabled
+ *
+ * @param IUser $userObj
+ * @param array $parameters
+ * @return array
+ */
+ protected function setPasswordResetParameters(
+ $userObj = null, array $parameters): array {
+
+ if ($parameters['resetPasswordLink'] === 'disabled') {
+ $parameters['canResetPassword'] = false;
+ } else if (!$parameters['resetPasswordLink'] && $userObj !== null) {
+ $parameters['canResetPassword'] = $userObj->canChangePassword();
+ } else if ($userObj !== null && $userObj->isEnabled() === false) {
+ $parameters['canResetPassword'] = false;
+ } else {
+ $parameters['canResetPassword'] = true;
+ }
+
+ return $parameters;
+ }
}
diff --git a/core/js/lostpassword.js b/core/js/lostpassword.js
index 75e91ffac7acb..59c3c825658be 100644
--- a/core/js/lostpassword.js
+++ b/core/js/lostpassword.js
@@ -134,7 +134,7 @@ OC.Lostpassword = {
getSendStatusNode : function(){
if (!$('#lost-password').length){
- $('
').insertBefore($('#remember_login'));
+ $('').insertBefore($('#lost-password-back'));
} else {
$('#lost-password').replaceWith($(''));
}
diff --git a/core/js/lostpassword/newpassword.js b/core/js/lostpassword/newpassword.js
new file mode 100644
index 0000000000000..a516482982c88
--- /dev/null
+++ b/core/js/lostpassword/newpassword.js
@@ -0,0 +1,136 @@
+/**
+ * Copyright (c) 2019
+ * Guillaume Compagnon gcompagnon@outlook.com
+ * This file is licensed under the Affero General Public License version 3 or later.
+ * See the COPYING-README file.
+ */
+OC.Newpassword = {
+
+ sendErrorMsg : t('core', 'Couldn\'t send reset email. Please contact your administrator.'),
+
+ sendSuccessResetPasswordMsg : t('core', 'We have send a password reset e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator.'),
+
+ sendSuccessNewPasswordMsg : t('core', 'We have send a password create e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator.'),
+
+ resetErrorMsg : t('core', 'Password can not be changed. Please contact your administrator.'),
+
+ init : function() {
+ $('form[name=email]').submit(OC.Newpassword.onSendLink);
+ $('#new-password-close').click(OC.Newpassword.closeWindows);
+ $('#new-password-submit').click(OC.Newpassword.resetPassword);
+ OC.Newpassword.resetButtons();
+ },
+
+ resetButtons : function() {
+ $('#submit-wrapper .submit-icon')
+ .addClass('icon-confirm-white')
+ .removeClass('icon-loading-small-dark');
+ if( $('#action').val() == 'NEW') {
+ $('#new-password-submit')
+ .attr('value', t('core', 'First connection'))
+ .prop('disabled', false);
+ $('#user').prop('disabled', true);
+ } else if( $('#action').val() == 'RESET') {
+ $('#new-password-submit')
+ .attr('value', t('core', 'Reset password'))
+ .prop('disabled', false);
+ $('#user').prop('disabled', false);
+ }
+ $('.login-additional').fadeIn();
+ //$('.new-password-wrapper').fadeIn();
+ $('form[name=email]').attr('action', 'lostpassword/email');
+ },
+
+ onSendLink: function (event) {
+ // Only if password reset form is active
+ if($('form[name=email][action]').length === 1) {
+ if (event) {
+ event.preventDefault();
+ }
+ $('#submit-wrapper .submit-icon')
+ .removeClass('icon-confirm-white')
+ .addClass('icon-loading-small-dark');
+ $('#new-password-submit')
+ .attr('value', t('core', 'Sending email …'))
+ .prop('disabled', true);
+ $('#user').prop('disabled', true);
+
+ $('.login-additional').fadeOut();
+ $('.new-password-wrapper').slideDown().fadeOut();
+
+ $.post(
+ OC.generateUrl('/lostpassword/email'),
+ {
+ user : $('#user').val(),
+ action : $('#action').val()
+ },
+ OC.Newpassword.sendLinkDone
+ ).fail(function() {
+ OC.Newpassword.sendLinkError(OC.Newpassword.sendErrorMsg);
+ });
+ }
+ },
+
+ sendLinkDone : function(result){
+ var sendErrorMsg;
+ if (result && result.status === 'success'){
+ OC.Newpassword.sendLinkSuccess();
+ } else {
+ if (result && result.msg){
+ sendErrorMsg = result.msg;
+ } else {
+ sendErrorMsg = OC.Newpassword.sendErrorMsg;
+ }
+ OC.Newpassword.sendLinkError(sendErrorMsg);
+ }
+ },
+
+ sendLinkSuccess : function(msg){
+ var node = OC.Newpassword.getSendStatusNode();
+ // update is the better success message styling
+ node.addClass('update').css({width:'auto'});
+ if( $('#action').val() == 'NEW') {
+ node.html(OC.Newpassword.sendSuccessNewPasswordMsg);
+ $('#action').val('RESET');
+ } else if ( $('#action').val() == 'RESET') {
+ node.html(OC.Newpassword.sendSuccessResetPasswordMsg);
+ }
+ $('#new-password-close').slideDown().fadeIn();
+ OC.Newpassword.resetButtons();
+ },
+
+ sendLinkError : function(msg){
+ var node = OC.Newpassword.getSendStatusNode();
+ node.addClass('warning');
+ node.html(msg);
+ $('#new-password-close').slideDown().fadeIn();
+ $('#new-password-admin').slideDown().fadeIn();
+ OC.Newpassword.resetButtons();
+ },
+
+ getSendStatusNode : function(){
+ if (!$('#new-password').length){
+ $('').insertBefore($('#new-password-close'));
+ } else {
+ $('#new-password').replaceWith($(''));
+ }
+ return $('#new-password');
+ },
+
+ resetPassword : function(event){
+
+ $('#submit-wrapper .submit-icon')
+ .removeClass('icon-confirm-white')
+ .addClass(OCA.Theming && OCA.Theming.inverted
+ ? 'icon-loading-small'
+ : 'icon-loading-small-dark');
+ },
+
+ closeWindows : function(event){
+ window.close();
+ },
+
+
+};
+
+$(document).ready(OC.Newpassword.init);
diff --git a/core/l10n/fr.js b/core/l10n/fr.js
index 81833c829f075..3dab925b20e9e 100644
--- a/core/l10n/fr.js
+++ b/core/l10n/fr.js
@@ -21,11 +21,17 @@ OC.L10N.register(
"Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable",
"Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré",
"Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
+ "Could not send reset email because there is no email address for this username. Please contact %s." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter %s.",
"%s password reset" : "Réinitialisation de votre mot de passe %s",
"Password reset" : "Réinitialiser le mot de passe",
"Click the following button to reset your password. If you have not requested the password reset, then ignore this email." : "Cliquez sur le bouton suivant pour réinitialiser votre mot de passe. Si vous n'avez pas demandé cette réinitialisation de mot de passe, vous pouvez ignorer ce courriel.",
"Click the following link to reset your password. If you have not requested the password reset, then ignore this email." : "Cliquer sur le lien suivant pour réinitialiser votre mot de passe. Si vous n'avez pas demandé cette réinitialisation de mot de passe, alors ignorez ce courriel.",
"Reset your password" : "Réinitialiser votre mot de passe",
+ "%s activate and choose a password" : "Activer et choisir votre mot de passe %s",
+ "Activate and choose a password" : "Activer et choisir un mot de passe",
+ "Click the following button to activate and choose a new password. If you have not requested the new password, then ignore this email." : "Cliquez sur le bouton suivant pour activer et choisir votre nouveau mot de passe. Si vous n'avez pas demandé cette activation, vous pouvez ignorer ce courriel.",
+ "Click the following link to activate and choose a new password. If you have not requested the new password, then ignore this email." : "Cliquer sur le lien suivant pour activer et choisir votre nouveau mot de passe. Si vous n'avez pas demandé cette activation, alors ignorez ce courriel.",
+ "Activate and choose your new password" : "Activer et choisir votre nouveau mot de passe",
"Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
"Some of your link shares have been removed" : "Certains de vos liens partagés ont été supprimés.",
@@ -107,11 +113,12 @@ OC.L10N.register(
"Show all contacts …" : "Montrer tous les contacts...",
"Loading your contacts …" : "Chargement de vos contacts...",
"Looking for {term} …" : "Recherche de {term} ...",
- "We have send a password reset e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail de réinitialisation de mot de passe à l'adresse e-mail que nous connaissons pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
+ "We have send a password reset e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail de réinitialisation de mot de passe à l'adresse e-mail connue pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
+ "We have send a password create e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail afin d'activer le compte et de choisir votre mot de passe à l'adresse e-mail connue pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
"Your files are encrypted. There will be no way to get your data back after your password is reset.
If you are not sure what to do, please contact your administrator before you continue.
Do you really want to continue?" : "Vos fichiers sont chiffrés. Il n'y aura aucun moyen de récupérer vos données une fois le mot de passe réinitialisé.
Si vous n'êtes pas sûr de ce que vous faites, veuillez contacter votre administrateur avant de continuer.
Voulez-vous vraiment continuer ?",
"I know what I'm doing" : "Je sais ce que je fais",
"Password can not be changed. Please contact your administrator." : "Le mot de passe ne peut être modifié. Veuillez contacter votre administrateur.",
- "Reset password" : "Réinitialiser le mot de passe",
+ "Reset password" : "Réinitialisez le mot de passe",
"Sending email …" : "Envoi du mail en cours...",
"Logging in …" : "Connexion…",
"New in" : "Nouveau dans",
@@ -340,6 +347,7 @@ OC.L10N.register(
"Please contact your administrator." : "Veuillez contacter votre administrateur.",
"An internal error occurred." : "Une erreur interne est survenue.",
"Please try again or contact your administrator." : "Veuillez réessayer ou contactez votre administrateur.",
+ "Please try again or contact %s." : "Veuillez réessayer ou contactez %s.",
"Username or email" : "Utilisateur ou email",
"Log in" : "Se connecter",
"Wrong username or password." : "Utilisateur ou mot de passe incorrect.",
@@ -358,6 +366,11 @@ OC.L10N.register(
"Your client should now be connected! You can close this window." : "Votre client devrait maintenant être connecté ! Vous pouvez fermer cette fenêtre.",
"New password" : "Nouveau mot de passe",
"New Password" : "Nouveau mot de passe",
+ "First connection" : "Activez votre compte",
+ "Welcome %s" : "Bienvenue %s",
+ "Close this window" : "Fermez cette fenêtre",
+ "Click on 'First connection' to receive an email for choosing your first password" : "Cliquer sur 'Activez votre compte' afin de recevoir un email permettant de choisir votre mot de passe",
+ "Click on 'Reset password' to receive an email for setting up a new password" : "Cliquer sur 'Rénitialisez le mot de passe' afin de recevoir un email permettant de réinitialiser votre mot de passe",
"This share is password-protected" : "Ce partage est protégé par mot de passe",
"The password is wrong. Try again." : "Le mot de passe est incorrect. Veuillez réessayer.",
"Two-factor authentication" : "Second facteur d'authentification",
@@ -415,5 +428,4 @@ OC.L10N.register(
"%s will be updated to version %s" : "%s sera mis à jour vers la version %s",
"This page will refresh itself when the %s instance is available again." : "Cette page se rafraîchira d'elle-même lorsque l'instance %s sera à nouveau disponible.",
"Thank you for your patience." : "Merci de votre patience."
-},
-"nplurals=2; plural=(n > 1);");
+},"nplurals=2; plural=(n > 1);");
diff --git a/core/l10n/fr.json b/core/l10n/fr.json
index 1967c237fd78b..5321a25f70734 100644
--- a/core/l10n/fr.json
+++ b/core/l10n/fr.json
@@ -19,11 +19,17 @@
"Couldn't reset password because the token is invalid" : "Impossible de réinitialiser le mot de passe car le jeton n'est pas valable",
"Couldn't reset password because the token is expired" : "Impossible de réinitialiser le mot de passe car le jeton a expiré",
"Could not send reset email because there is no email address for this username. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter votre administrateur.",
+ "Could not send reset email because there is no email address for this username. Please contact %s." : "Impossible d'envoyer le courriel de réinitialisation car il n'y a aucune adresse de courriel pour cet utilisateur. Veuillez contacter %s.",
"%s password reset" : "Réinitialisation de votre mot de passe %s",
"Password reset" : "Réinitialiser le mot de passe",
"Click the following button to reset your password. If you have not requested the password reset, then ignore this email." : "Cliquez sur le bouton suivant pour réinitialiser votre mot de passe. Si vous n'avez pas demandé cette réinitialisation de mot de passe, vous pouvez ignorer ce courriel.",
"Click the following link to reset your password. If you have not requested the password reset, then ignore this email." : "Cliquer sur le lien suivant pour réinitialiser votre mot de passe. Si vous n'avez pas demandé cette réinitialisation de mot de passe, alors ignorez ce courriel.",
"Reset your password" : "Réinitialiser votre mot de passe",
+ "%s activate and choose a password" : "Activer et choisir votre mot de passe %s",
+ "Activate and choose a password" : "Activer et choisir un mot de passe",
+ "Click the following button to activate and choose a new password. If you have not requested the new password, then ignore this email." : "Cliquez sur le bouton suivant pour activer et choisir votre nouveau mot de passe. Si vous n'avez pas demandé cette activation, vous pouvez ignorer ce courriel.",
+ "Click the following link to activate and choose a new password. If you have not requested the new password, then ignore this email." : "Cliquer sur le lien suivant pour activer et choisir votre nouveau mot de passe. Si vous n'avez pas demandé cette activation, alors ignorez ce courriel.",
+ "Activate and choose your new password" : "Activer et choisir votre nouveau mot de passe",
"Couldn't send reset email. Please contact your administrator." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez contacter votre administrateur.",
"Couldn't send reset email. Please make sure your username is correct." : "Impossible d'envoyer le courriel de réinitialisation. Veuillez vérifier que votre nom d'utilisateur est correct.",
"Some of your link shares have been removed" : "Certains de vos liens partagés ont été supprimés.",
@@ -105,11 +111,12 @@
"Show all contacts …" : "Montrer tous les contacts...",
"Loading your contacts …" : "Chargement de vos contacts...",
"Looking for {term} …" : "Recherche de {term} ...",
- "We have send a password reset e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail de réinitialisation de mot de passe à l'adresse e-mail que nous connaissons pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
+ "We have send a password reset e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail de réinitialisation de mot de passe à l'adresse e-mail connue pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
+ "We have send a password create e-mail to the e-mail address known to us for this account. If you do not receive it within a reasonable amount of time, check your spam/junk folders.
If it is not there ask your local administrator." : "Nous avons envoyé un e-mail afin d'activer le compte et de choisir votre mot de passe à l'adresse e-mail connue pour ce compte. Si vous ne le recevez pas dans un délai raisonnable, vérifiez vos dossiers de courrier indésirable/pourriel/spam.
S'il n'est pas présent, demandez à votre administrateur local.",
"Your files are encrypted. There will be no way to get your data back after your password is reset.
If you are not sure what to do, please contact your administrator before you continue.
Do you really want to continue?" : "Vos fichiers sont chiffrés. Il n'y aura aucun moyen de récupérer vos données une fois le mot de passe réinitialisé.
Si vous n'êtes pas sûr de ce que vous faites, veuillez contacter votre administrateur avant de continuer.
Voulez-vous vraiment continuer ?",
"I know what I'm doing" : "Je sais ce que je fais",
"Password can not be changed. Please contact your administrator." : "Le mot de passe ne peut être modifié. Veuillez contacter votre administrateur.",
- "Reset password" : "Réinitialiser le mot de passe",
+ "Reset password" : "Réinitialisez le mot de passe",
"Sending email …" : "Envoi du mail en cours...",
"Logging in …" : "Connexion…",
"New in" : "Nouveau dans",
@@ -338,6 +345,7 @@
"Please contact your administrator." : "Veuillez contacter votre administrateur.",
"An internal error occurred." : "Une erreur interne est survenue.",
"Please try again or contact your administrator." : "Veuillez réessayer ou contactez votre administrateur.",
+ "Please try again or contact %s." : "Veuillez réessayer ou contactez %s.",
"Username or email" : "Utilisateur ou email",
"Log in" : "Se connecter",
"Wrong username or password." : "Utilisateur ou mot de passe incorrect.",
@@ -356,6 +364,11 @@
"Your client should now be connected! You can close this window." : "Votre client devrait maintenant être connecté ! Vous pouvez fermer cette fenêtre.",
"New password" : "Nouveau mot de passe",
"New Password" : "Nouveau mot de passe",
+ "First connection" : "Activez votre compte",
+ "Welcome %s" : "Bienvenue %s",
+ "Close this window" : "Fermez cette fenêtre",
+ "Click on 'First connection' to receive an email for choosing your first password" : "Cliquer sur 'Activez votre compte' afin de recevoir un email permettant de choisir votre mot de passe",
+ "Click on 'Reset password' to receive an email for setting up a new password" : "Cliquer sur 'Rénitialisez le mot de passe' afin de recevoir un email permettant de réinitialiser votre mot de passe",
"This share is password-protected" : "Ce partage est protégé par mot de passe",
"The password is wrong. Try again." : "Le mot de passe est incorrect. Veuillez réessayer.",
"Two-factor authentication" : "Second facteur d'authentification",
diff --git a/core/routes.php b/core/routes.php
index 1544fd67e070d..f472db860018f 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -40,6 +40,8 @@
['name' => 'lost#email', 'url' => '/lostpassword/email', 'verb' => 'POST'],
['name' => 'lost#resetform', 'url' => '/lostpassword/reset/form/{token}/{userId}', 'verb' => 'GET'],
['name' => 'lost#setPassword', 'url' => '/lostpassword/set/{token}/{userId}', 'verb' => 'POST'],
+ ['name' => 'lost#showPasswordEmailForm', 'url' => '/newpassword/{userId}', 'verb' => 'GET'],
+ ['name' => 'lost#showNewPasswordForm', 'url' => '/newpassword', 'verb' => 'GET'],
['name' => 'user#getDisplayNames', 'url' => '/displaynames', 'verb' => 'POST'],
['name' => 'avatar#getAvatar', 'url' => '/avatar/{userId}/{size}', 'verb' => 'GET'],
['name' => 'avatar#deleteAvatar', 'url' => '/avatar/', 'verb' => 'DELETE'],
diff --git a/core/templates/lostpassword/newpassword.php b/core/templates/lostpassword/newpassword.php
new file mode 100644
index 0000000000000..71d38edafb1ff
--- /dev/null
+++ b/core/templates/lostpassword/newpassword.php
@@ -0,0 +1,130 @@
+
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+style('core', 'lostpassword/resetpassword');
+
+script('core', 'visitortimezone');
+script('core', 'lostpassword/newpassword');
+use OC\Core\Controller\LostController;
+?>
+
+
+
\ No newline at end of file
diff --git a/lib/private/SystemConfig.php b/lib/private/SystemConfig.php
index 444e5842437a4..e80fc5324c998 100644
--- a/lib/private/SystemConfig.php
+++ b/lib/private/SystemConfig.php
@@ -44,6 +44,7 @@ class SystemConfig {
'dbhost' => true,
'dbpassword' => true,
'dbuser' => true,
+ 'administrator_email' => true,
'mail_from_address' => true,
'mail_domain' => true,
'mail_smtphost' => true,
diff --git a/tests/nextcloudPostgresql.sql b/tests/nextcloudPostgresql.sql
new file mode 100644
index 0000000000000..cb24b1bbe4364
--- /dev/null
+++ b/tests/nextcloudPostgresql.sql
@@ -0,0 +1,10 @@
+SELECT table_name FROM information_schema.tables WHERE table_schema='public';
+
+CREATE USER nextcloud CREATEDB;
+CREATE DATABASE nextcloud OWNER nextcloud;
+
+
+
+select * from oc_users;
+
+update oc_users set uid ='sagis2', uid_lower='sagis2' where uid='sagis'
\ No newline at end of file