This is now being handled by IPFire People.
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/templates/package-detail-list.html \
src/templates/package-properties.html \
src/templates/queue.html \
- src/templates/register-activation-fail.html \
- src/templates/register-activation-success.html \
- src/templates/register-fail.html \
- src/templates/register.html \
- src/templates/register-success.html \
src/templates/repository-detail.html \
src/templates/repository-edit.html \
src/templates/search-form.html \
src/templates/updates-index.html \
src/templates/uploads-list.html \
src/templates/user-delete.html \
- src/templates/user-forgot-password.html \
src/templates/user-impersonation.html \
src/templates/user-list.html \
src/templates/user-profile-builds.html \
src/templates/user-profile-edit-fail.html \
src/templates/user-profile-edit.html \
src/templates/user-profile.html \
- src/templates/user-profile-need-activation.html \
- src/templates/user-profile-passwd.html \
- src/templates/user-profile-passwd-ok.html \
- src/templates/user-requested-password-recovery.html \
- src/templates/user-reset-password.html \
- src/templates/user-reset-password-success.html \
- src/templates/user-reset-password-fail.html
+ src/templates/user-profile-need-activation.html
templatesdir = $(datadir)/templates
templates_messages_jobsdir = $(templates_messagesdir)/jobs
dist_templates_messages_users_DATA = \
- src/templates/messages/users/account-activation.markdown \
- src/templates/messages/users/email-activation.markdown \
- src/templates/messages/users/password-reset.markdown
+ src/templates/messages/users/email-activation.markdown
templates_messages_usersdir = $(templates_messagesdir)/users
#!/usr/bin/python
-
-
import datetime
import hashlib
import logging
from .decorators import *
-from .users import generate_password_hash, check_password_hash, generate_random_string
-
ACTIVE_STATES = [
"dispatching",
"running",
# Looks like we are ready
return True
+
+
+# A list of possible random characters.
+random_chars = string.ascii_letters + string.digits
+
+def generate_random_string(length=16):
+ """
+ Return a string with random chararcters A-Za-z0-9 with given length.
+ """
+ return "".join([random.choice(random_chars) for i in range(length)])
+
+def generate_password_hash(password, salt=None, algo="sha512"):
+ """
+ This function creates a salted digest of the given password.
+ """
+ # Generate the salt (length = 16) of none was given.
+ if salt is None:
+ salt = generate_random_string(length=16)
+
+ # Compute the hash.
+ # <SALT> + <PASSWORD>
+ if not algo in hashlib.algorithms:
+ raise Exception("Unsupported password hash algorithm: %s" % algo)
+
+ # Calculate the digest.
+ h = hashlib.new(algo)
+ h.update(salt)
+ h.update(password)
+
+ # Output string is of kind "<algo>$<salt>$<hash>".
+ return "$".join((algo, salt, h.hexdigest()))
+
+def check_password_hash(password, password_hash):
+ """
+ Check a plain-text password with the given digest.
+ """
+ # Handle plaintext passwords (plain$<password>).
+ if password_hash.startswith("plain$"):
+ return password_hash[6:] == password
+
+ try:
+ algo, salt, digest = password_hash.split("$", 2)
+ except ValueError:
+ logging.warning("Unknown password hash: %s" % password_hash)
+ return False
+
+ # Re-generate the password hash and compare the result.
+ return password_hash == generate_password_hash(password, salt=salt, algo=algo)
import hashlib
import logging
import pytz
-import random
import re
import string
-import urllib.request, urllib.parse, urllib.error
-from . import ldap
+import urllib.parse
import tornado.locale
from .decorators import *
-# A list of possible random characters.
-random_chars = string.ascii_letters + string.digits
-
-def generate_random_string(length=16):
- """
- Return a string with random chararcters A-Za-z0-9 with given length.
- """
- return "".join([random.choice(random_chars) for i in range(length)])
-
-
-def generate_password_hash(password, salt=None, algo="sha512"):
- """
- This function creates a salted digest of the given password.
- """
- # Generate the salt (length = 16) of none was given.
- if salt is None:
- salt = generate_random_string(length=16)
-
- # Compute the hash.
- # <SALT> + <PASSWORD>
- if not algo in hashlib.algorithms:
- raise Exception("Unsupported password hash algorithm: %s" % algo)
-
- # Calculate the digest.
- h = hashlib.new(algo)
- h.update(salt)
- h.update(password)
-
- # Output string is of kind "<algo>$<salt>$<hash>".
- return "$".join((algo, salt, h.hexdigest()))
-
-def check_password_hash(password, password_hash):
- """
- Check a plain-text password with the given digest.
- """
- # Handle plaintext passwords (plain$<password>).
- if password_hash.startswith("plain$"):
- return password_hash[6:] == password
-
- try:
- algo, salt, digest = password_hash.split("$", 2)
- except ValueError:
- logging.warning("Unknown password hash: %s" % password_hash)
- return False
-
- # Re-generate the password hash and compare the result.
- return password_hash == generate_password_hash(password, salt=salt, algo=algo)
-
-
class Users(base.Object):
def init(self):
self.ldap = ldap.LDAP(self.backend)
user_email.user = self
self.emails.append(user_email)
- # Send activation email if activation is needed
- if not activated:
- user_email.send_activation_mail()
-
return user_email
def send_template(self, *args, **kwargs):
timezone = property(get_timezone, set_timezone)
- def get_password_recovery_code(self):
- return self.data.password_recovery_code
-
- def set_password_recovery_code(self, code):
- self._set_attribute("password_recovery_code", code)
-
- self._set_attribute("password_recovery_code_expires_at",
- datetime.datetime.utcnow() + datetime.timedelta(days=1))
-
- password_recovery_code = property(get_password_recovery_code, set_password_recovery_code)
-
- def forgot_password(self):
- log.debug("User %s reqested password recovery" % self.name)
-
- # We cannot reset te password for ldap users
- if self.ldap_dn:
- # Maybe we should send an email with an explanation
- return
-
- # Add a recovery code to the database and a timestamp when this code expires
- self.password_recovery_code = generate_random_string(64)
-
- # Send an email with the activation code
- self.send_template("messages/users/password-reset", user=self)
-
@property
def activated(self):
return self.data.activated
def deleted(self):
return self.data.deleted
- @property
- def registered_at(self):
- return self.data.registered_at
-
def gravatar_icon(self, size=128):
h = hashlib.new("md5")
if self.email:
def activation_code(self):
return self.data.activation_code
- def send_activation_mail(self):
- if not self.primary:
- return self.send_email_activation_email()
-
- logging.debug("Sending activation mail to %s" % self.email)
-
- self.user.send_template("messages/users/account-activation")
-
def send_email_activation_mail(self):
logging.debug("Sending email address activation mail to %s" % self.email)
self.user.send_template("messages/users/email-activation", email=self)
-
-
-# Some testing code.
-if __name__ == "__main__":
- for password in ("1234567890", "abcdefghij"):
- digest = generate_password_hash(password)
-
- print("%s %s" % (password, digest))
- print(" Matches? %s" % check_password_hash(password, digest))
-
</ul>
{% else %}
<ul class="navbar-nav justify-content-lg-end">
- <li class="nav-item">
- <a class="nav-link" href="/register">{{ _("Register") }}</a>
- </li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ _("Sign in") }}
<input class="form-control btn btn-primary" type="submit" value="{{ _("Sign In") }}">
</div>
</form>
- <a class="dropdown-item text-center" href="/password-recovery">
- <small>{{ _("Forgot your password?") }}</small>
- </a>
-
</div>
</li>
</ul>
<hr>
</div>
</div>
- <div class="row align-items-center justify-content-center">
- <div class="col-12 col-sm-12 col-md-6 col-lg-4 col-xl-4">
- <h3>{{ _("You also might want to...") }}</h3>
- <ul>
- <li>
- <a href="/register">{{ _("Register a new account.") }}</a>
- </li>
- <li>
- <a href="/password-recovery">{{ _("Recover your password.") }}</a>
- </li>
- </ul>
- </div>
- </div>
{% end %}
+++ /dev/null
-Subject: {{ _("Account Activation") }}
-
-{{ _("You, or somebody using your email address, has registered an account on the Pakfire Build Service.") }}
-
-{{ _("To activate your account, please click on the link below:") }}
-
- {{ baseurl }}/user/{{ user.name }}/activate?code={{ user.email.activation_code }}
-
-Sincerely,
--The Pakfire Build Service
\ No newline at end of file
+++ /dev/null
-Subject: {{ _("Password Reset") }}
-
-{{ _("You, or somebody else has requested a password reset for the Pakfire Build Service.") }}
-
-{{ _("To reset your password, please click on the link below:") }}
-
- {{ baseurl }}/password-reset?code={{ user.password_recovery_code }}
-
-Sincerely,
--The Pakfire Build Service
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Account activation failed") }}{% end block %}
-
-{% block body %}
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item active">{{ _("Account activation") }}</li>
- </ol>
- </nav>
- </div>
- </div>
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <div class="alert alert-danger">
- <h2 style="word-wrap: break-word;" class="alert-heading">{{ _("Activation failed") }}</h2>
- <p>
- {{ _("We are sorry.") }}
- {{ _("The activation of your account has failed.") }}
- {{ _("Possibly the registration code is wrong or your registration timed out.") }}
- </p>
- </div>
- </div>
- </div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Account activation successful") }}{% end block %}
-
-{% block body %}
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item active">{{ _("Account activation") }}</li>
- </ol>
- </nav>
- </div>
- </div>
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <div class="alert alert-success">
- <h2 style="word-wrap: break-word;" class="alert-heading">{{ _("Activation successful") }}</h2>
- <p>
- {{ _("Your account has been activated, %s.") % user.realname }}
- {{ _("Have fun!") }}
- </p>
- </div>
- </div>
- </div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block body %}
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <div class="alert alert-danger">
- <h2 style="word-wrap: break-word;" class="alert-heading">{{ _("Registration failed") }}</h2>
- <p>
- {{ _("We are sorry.") }}
- {{ _("We could not create your requested account, because we encountered the following errors:") }}
- </p>
- <ul>
- {% for msg in messages %}
- <li>{{ msg }}</li>
- {% end %}
- </ul>
- <p>
- {{ _("Use the back button on your web browser to go back to the previous page and correct your submission.") }}
- </p>
- </div>
- </div>
- </div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block body %}
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <div class="alert alert-success">
- <h2 style="word-wrap: break-word;" class="alert-heading">{{ _("Registration successful") }}</h2>
- <p>
- {{ _("Your new account has been created, %s.") % user.realname }}
- {{ _("To complete the activation, follow the instructions that were sent to you in an activation email.") }}
- </p>
- </div>
- </div>
- </div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Register a new account") }}{% end block %}
-
-{% block body %}
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item active"><a href="/register">{{ _("Register new account") }}</a></li>
- </ol>
- </nav>
- </div>
- </div>
-
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <h2>
- {{ _("Register a new account") }}
- <small>{{ _("Join the community!") }}</small>
- </h2>
- </div>
- </div>
-
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
-
- <form method="POST" action="">
- {% raw xsrf_form_html() %}
- <fieldset>
- <legend>{{ _("Registration form") }}</legend>
-
- <div class="form-group">
- <label for="name">{{ _("Username") }}</label>
- <input type="text" class="form-control" id="name" name="name" aria-describedby="nameHelp" placeholder="{{ _("Username") }}">
- <small id="nameHelp" class="form-text text-muted">
- {{ _("Must be a unique name you login with.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="email">{{ _("Email address") }}</label>
- <input type="email" class="form-control" id="email" name="email" aria-describedby="emailHelp" placeholder="{{ _("Email address") }}">
- <small id="emailHelp" class="form-text text-muted">
- {{ _("Type in your email address, which is used to verify the account.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="realname">{{ _("Real name (optional)") }}</label>
- <input type="text" class="form-control" id="realname" name="realname" aria-describedby="realnameHelp" placeholder="{{ _("Real name") }}">
- <small id="realnameHelp" class="form-text text-muted">
- {{ _("Type you firstname and your lastname here.") }}
- </small>
- </div>
- </fieldset>
- <fieldset>
- <legend>{{ _("Account security") }}</legend>
-
- <div class="form-group">
- <label for="pass1">{{ _("Password") }}</label>
- <input type="password" class="form-control"
- id="pass1" name="pass1" aria-describedby="pass1Help" placeholder="{{ _("Password") }}">
- <small id="pass1Help" class="form-text text-muted">
- {{ _("The password is used to secure the login and must be at least 8 characters.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="pass2">{{ _("Password") }}</label>
- <input type="password" class="form-control"
- id="pass2" name="pass2" aria-describedby="pass2Help" placeholder="{{ _("Confirm password") }}">
- <small id="pass1Help" class="form-text text-muted">
- {{ _("Pick a password that is as strong as possible.") }}
- {{ _("Don't login at unsecure places where people could spy on your password.") }}
- </small>
- </div>
- </fieldset>
-
- <button type="submit" class="btn btn-primary">{{ _("Sign up!") }}</button>
- </form>
- </div>
- </div>
-{% end block %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Forgot password") }}{% end block %}
-
-{% block body %}
-
-<div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item active"><a href="/password-recovery">{{ _("Forgot password") }}</a></li>
- </ol>
- </nav>
- </div>
- </div>
-
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <h2>
- {{ _("Forgot password") }}
- </h2>
- </div>
- </div>
-
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
- <p>
- {{ _("You have forgotten you password, eh? Shame on you.") }}
- {{ _("However, we allow to re-activate your account.") }}
- </p>
- <p>
- {{ _("You need to enter your username or your email address below") }}
- {{ _("After that, you will receive an email with intructions how to go on.") }}
- </p>
- <hr>
- </div>
- </div>
-
- <div class="row justify-content-center">
- <div class="col-12 col-sm-12 col-md-12 col-lg-8 col-xl-8">
-
- <form class="form-horizontal" method="POST" action="">
- {% raw xsrf_form_html() %}
-
- <fieldset>
- <div class="form-group">
- <label for="name">{{ _("Your username or email address") }}</label>
- <input type="text" class="form-control" id="name" name="name" aria-describedby="nameHelp" placeholder="{{ _("Username or email address") }}">
- </div>
- </fieldset>
- <button type="submit" class="btn btn-primary">{{ _("Submit") }}</button>
- </form>
- </div>
- </div>
-{% end block %}
</div>
</fieldset>
- <fieldset>
- <legend>{{ _("Account security settings") }}</legend>
-
- <div class="form-group">
- <label for="inputPass1">{{ _("Password") }}</label>
- <input type="password" class="form-control"
- id="inputPass1" name="pass1" aria-describedby="pass1Help" placeholder="{{ _("Password") }}">
- <small id="inputPass1Help" class="form-text text-muted">
- {{ _("The password is used to secure the login and must be at least 8 characters.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="inputPass2">{{ _("Confirm Password") }}</label>
- <input type="password" class="form-control"
- id="inputPass2" name="pass2" aria-describedby="inputPass2Help" placeholder="{{ _("Confirm Password") }}">
- <small id="inputPass2Help" class="form-text text-muted">
- {{ _("Leave the password fields empty to keep the current password.") }}
- </small>
- </div>
- </fieldset>
-
<fieldset>
<legend>{{ _("Locale & timezone settings") }}</legend>
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Password changed") }}{% end block %}
-
-{% block body %}
-
-<div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item">
- <a href="/users">{{ _("Users") }}</a>
- </li>
- <li class="breadcrumb-item">
- <a href="/user/{{ user.name }}">{{ user.realname }}</a>
- </li>
- <li class="breadcrumb-item">
- <a href="/user/{{ user.name }}/passwd">{{ _("Change password") }}</a>
- </li>
- <li class="breadcrumb-item">
- {{ _("Done!") }}
- </li>
- </ol>
- </nav>
- </div>
- </div>
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="alert alert-success" role="alert">
- <h2 style="word-wrap: break-word;" class="alert-heading">
- {{ _("Password changed") }}
- </h2>
- {% if current_user == user %}
- <p>
- {{ _("Your password has successfully been changed.") }}
- </p>
- {% else %}
- <p>
- {{ _("The password of %s has successfully been changed.") % user.realname }}
- </p>
- {% end %}
- </div>
- </div>
- </div>
-
- <div class="row justify-content-end">
- <div class="col-12 col-sm-12 col-md-5 col-lg-4 col-xl-3">
- <a class="btn btn-block btn-success" href="/user/{{ user.name }}">{{ _("Ok") }}</a>
- </div>
- </div>
-
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Change password") }}{% end block %}
-
-{% block body %}
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item">
- <a href="/users">{{ _("Users") }}</a>
- </li>
- <li class="breadcrumb-item">
- <a href="/user/{{ user.name }}">{{ user.realname }}</a>
- </li>
- <li class="breadcrumb-item active">
- <a href="/user/{{ user.name }}/passwd">{{ _("Change password") }}</a>
- </li>
- </ol>
- </nav>
- </div>
- </div>
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <h2 style="word-wrap: break-word;">
- {{ _("Change password") }}
- </h2>
- </div>
- </div>
-
- {% if error_msg %}
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="alert alert-danger alert-dismissible fade show" role="alert">
- <h3 style="word-wrap: break-word;" class="alert-heading">
- {{ _("Oops!") }}
- </h3>
- {{ error_msg }}
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
- <span aria-hidden="true">×</span>
- </button>
- </div>
- </div>
- </div>
- {% end %}
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- {% if user == current_user %}
- <p>
- {{ _("You are going to change your password.") }}
- </p>
- <p>
- {{ _("To do so, you need to enter your current password and the new password twice.") }}
- </p>
- {% else %}
- <p>
- {{ _("In this dialog, you may change the password of %s.") % user.realname }}
- </p>
- {% end %}
- <hr />
- </div>
- </div>
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <form method="POST" action="">
- {% raw xsrf_form_html() %}
-
- <fieldset>
- {% if user == current_user %}
- <div class="form-group">
- <label for="pass0">{{ _("Old password") }}</label>
- <input type="password" class="form-control"
- id="pass0" name="pass0" aria-describedby="pass0Help" placeholder="{{ _("Old password") }}">
- <small id="pass0Help" class="form-text text-muted">
- {{ _("Please provide your old password.") }}
- </small>
- </div>
- {% end %}
-
- <div class="form-group">
- <label for="pass1">{{ _("New password") }}</label>
- <input type="password" class="form-control"
- id="pass1" name="pass1" aria-describedby="pass1Help" placeholder="{{ _("New password") }}">
- <small id="pass1Help" class="form-text text-muted">
- {{ _("Choose a new password. Make sure that it is as strong as possible.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="pass2">{{ _("Confirm new password") }}</label>
- <input type="password" class="form-control"
- id="pass2" name="pass2" aria-describedby="pass2Help" placeholder="{{ _("Confirm new password") }}">
- <small id="pass2Help" class="form-text text-muted">
- {{ _("Confirm the new password.") }}
- </small>
- </div>
-
- <button type="submit" class="btn btn-primary">{{ _("Change password") }}</button>
- <a class="btn btn-light" href="/user/{{ user.name }}">{{ _("Cancel") }}</a>
-
- </fieldset>
- </form>
- </div>
- </div>
-{% end %}
<i class="icon-edit"></i>
{{ _("Edit profile") }}
</a>
- <a class="dropdown-item" href="/user/{{ user.name }}/passwd">
- <i class="icon-lock"></i>
- {{ _("Change password") }}
- </a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="/user/{{ user.name }}/delete">
<i class="icon-trash"></i>
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Requested password recovery") }}{% end block %}
-
-{% block body %}
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <h2 style="word-wrap: break-word;">
- {{ _("Password recovery requested") }}
- </h2>
- </div>
- </div>
-
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <p>
- {{ _("An email with instructions how to recover your password was send to your primary email address.") }}
- </p>
- </div>
- </div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Password reset failed") }}{% end block %}
-
-{% block body %}
-<div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="alert alert-danger" role="alert">
- <h2 style="word-wrap: break-word;" class="alert-heading">
- {{ _("Password reset failed") }}
- </h2>
- <p>
- {{ message }}
- </p>
- </div>
- </div>
-</div>
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Password reset succeeded") }}{% end block %}
-
-{% block body %}
-<div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="alert alert-success" role="alert">
- <h2 style="word-wrap: break-word;" class="alert-heading">
- {{ _("Password reset succeeded") }}
- </h2>
- <p>
- {{ _("Successfully reset your password") }}
- </p>
- </div>
- </div>
-</div>
-
-{% end %}
+++ /dev/null
-{% extends "base.html" %}
-
-{% block title %}{{ _("Register a new account") }}{% end block %}
-
-{% block body %}
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <h2 style="word-wrap: break-word;">
- {{ _("Reset password") }}
- </h2>
- </div>
- </div>
-
- <form method="POST" action="">
- {% raw xsrf_form_html() %}
- <input type="hidden" name="code" value="{{ user.password_recovery_code }}">
-
- <fieldset>
- <div class="form-group">
- <label for="password1">{{ _("Password") }}</label>
- <input type="password" class="form-control"
- id="password1" name="password1" aria-describedby="password1Help" placeholder="{{ _("Password") }}">
- <small id="password1Help" class="form-text text-muted">
- {{ _("Choose a new password. Make sure that it is as strong as possible.") }}
- </small>
- </div>
-
- <div class="form-group">
- <label for="password2">{{ _("Confirm password") }}</label>
- <input type="password" class="form-control"
- id="password2" name="password2" aria-describedby="password2Help" placeholder="{{ _("Confirm password") }}">
- <small id="password2Help" class="form-text text-muted">
- {{ _("Confirm the new password.") }}
- </small>
- </div>
-
- <button type="submit" class="btn btn-primary">{{ _("Reset password") }}</button>
- </form>
-{% end block %}
# Entry site that lead the user to index
(r"/", IndexHandler),
- # Handle all the users logins/logouts/registers and stuff.
+ # Authentication
(r"/login", auth.LoginHandler),
(r"/logout", auth.LogoutHandler),
- (r"/register", auth.RegisterHandler),
- (r"/password-recovery", auth.PasswordRecoveryHandler),
- (r"/password-reset", auth.PasswordResetHandler),
# User profiles
(r"/users", users.UsersHandler),
(r"/user/(\w+)/impersonate", users.UserImpersonateHandler),
- (r"/user/(\w+)/passwd", users.UserPasswdHandler),
(r"/user/(\w+)/delete", users.UserDeleteHandler),
(r"/user/(\w+)/edit", users.UserEditHandler),
- (r"/user/(\w+)/activate", auth.ActivationHandler),
(r"/user/(\w+)", users.UserHandler),
(r"/profile", users.UserHandler),
(r"/profile/builds", users.UsersBuildsHandler),
self.redirect(next)
-class RegisterHandler(base.BaseHandler):
- def get(self):
- # If the user is already logged in, we just send him back
- # to the start page.
- if self.current_user:
- self.redirect("/")
- return
-
- self.render("register.html")
-
- def post(self):
- _ = self.locale.translate
- msgs = []
-
- # Read all information from the request.
- name = self.get_argument("name", None)
- email = self.get_argument("email", None)
- realname = self.get_argument("realname", None)
- pass1 = self.get_argument("pass1", None)
- pass2 = self.get_argument("pass2", None)
-
- if not name:
- msgs.append(_("No username provided."))
- elif self.backend.users.get_by_name(name):
- msgs.append(_("The given username is already taken."))
-
- if not email:
- msgs.append(_("No email address provided."))
- elif not "@" in email:
- msgs.append(_("Email address is invalid."))
- elif self.backend.users.get_by_email(email):
- msgs.append(_("The given email address is already used for another account."))
-
- # Check if the passphrase is okay.
- if not pass1:
- msgs.append(_("No password provided."))
- elif not pass1 == pass2:
- msgs.append(_("Passwords do not match."))
- else:
- accepted, score = self.backend.users.check_password_strength(pass1)
- if not accepted:
- msgs.append(_("Your password is too weak."))
-
- if msgs:
- self.render("register-fail.html", messages=msgs)
- return
-
- # All provided data seems okay.
- # Register the new user to the database.
- with self.db.transaction():
- user = self.backend.users.create(name, realname=realname)
-
- # Set passphrase
- user.passphrase = pass1
-
- # Add email address
- user.add_email(email)
-
- # Save locale
- user.locale = self.locale.code
-
- self.render("register-success.html", user=user)
-
-
-class ActivationHandler(base.BaseHandler):
- def get(self, _user):
- user = self.backend.users.get_by_name(_user)
- if not user:
- raise tornado.web.HTTPError(404)
-
- code = self.get_argument("code")
-
- # Check if the activation code matches and then activate the account.
- with self.db.transaction():
- if user.activate_email(code):
- # If an admin activated another account, he impersonates it.
- if self.current_user and self.current_user.is_admin():
- self.session.start_impersonation(user)
-
- else:
- # Automatically login the user.
- self.session = self.backend.sessions.create(user,
- self.current_address, user_agent=self.user_agent)
-
- # Set a session cookie
- self.set_cookie("session_id", self.session.session_id,
- expires=self.session.valid_until)
-
- self.render("register-activation-success.html", user=user)
- return
-
- # Otherwise, show an error message.
- self.render("register-activation-fail.html")
-
-
-class PasswordRecoveryHandler(base.BaseHandler):
- def get(self):
- return self.render("user-forgot-password.html")
-
- def post(self):
- username = self.get_argument("name", None)
-
- with self.db.transaction():
- user = self.backend.users.get_by_email(username) \
- or self.backend.users.get_by_name(username)
-
- if user:
- user.forgot_password()
-
- self.render("user-requested-password-recovery.html")
-
-
-class PasswordResetHandler(base.BaseHandler):
- def get(self):
- code = self.get_argument("code")
-
- user = self.backend.users.get_by_password_recovery_code(code)
- if not user:
- raise tornado.web.HTTPError(400)
-
- self.render("user-reset-password.html", user=user)
-
- def post(self):
- _ = self.locale.translate
-
- code = self.get_argument("code")
- pass1 = self.get_argument("password1")
- pass2 = self.get_argument("password2")
-
- user = self.backend.users.get_by_password_recovery_code(code)
- if not user:
- raise tornado.web.HTTPError(400)
-
- if not pass1 == pass2:
- return self.render("user-reset-password-fail.html",
- message=_("Second password does not match"))
-
- # XXX Check password strength
-
- with self.db.transaction():
- user.passphrase = pass1
- user.password_recovery_code = None
-
- self.render("user-reset-password-success.html")
-
-
class LogoutHandler(base.BaseHandler):
@tornado.web.authenticated
def get(self):
self.render("user-delete.html", user=user)
-class UserPasswdHandler(UserActionHandler):
- @tornado.web.authenticated
- def get(self, name, error_msg=None):
- user = self.get_user(name)
-
- self.render("user-profile-passwd.html", user=user,
- error_msg=error_msg)
-
- @tornado.web.authenticated
- def post(self, name):
- _ = self.locale.translate
-
- # Fetch the user.
- user = self.get_user(name)
-
- # If the user who wants to change the password is not an admin,
- # he needs to provide the old password.
- if not self.current_user.is_admin() or self.current_user == user:
- pass0 = self.get_argument("pass0", None)
- if not pass0:
- return self.get(name, error_msg=_("You need to enter you current password."))
-
- if not self.current_user.check_password(pass0):
- return self.get(name, error_msg=_("The provided account password is wrong."))
-
- pass1 = self.get_argument("pass1", "")
- pass2 = self.get_argument("pass2", "")
-
- error_msg = None
-
- # The password must at least have 8 characters.
- if not pass1 == pass2:
- error_msg = _("The given passwords do not match.")
- elif len(pass1) == 0:
- error_msg = _("The password was blank.")
- else:
- accepted, score = backend.users.check_password_strength(pass1)
- if not accepted:
- error_msg = _("The given password is too weak.")
-
- if error_msg:
- return self.get(name, error_msg=error_msg)
-
- # Update the password.
- user.set_passphrase(pass1)
-
- self.render("user-profile-passwd-ok.html", user=user)
-
-
class UserEditHandler(base.BaseHandler):
@tornado.web.authenticated
def get(self, name):
with self.db.transaction():
email = self.get_argument("primary_email_address")
realname = self.get_argument("realname", user.realname)
- pass1 = self.get_argument("pass1", None)
- pass2 = self.get_argument("pass2", None)
locale = self.get_argument("locale", "")
# Collect error messages
elif not "@" in email:
msgs.append(_("Email address is invalid."))
- # Check if the passphrase is okay.
- if pass1 and not len(pass1) >= 8:
- msgs.append(_("Password has less than 8 characters."))
- elif not pass1 == pass2:
- msgs.append(_("Passwords do not match."))
-
if msgs:
self.render("user-profile-edit-fail.html", messages=msgs)
return
tz = self.get_argument("timezone", None)
user.timezone = tz
- if not user.activated:
- self.render("user-profile-need-activation.html", user=user)
- return
-
self.redirect("/user/%s" % user.name)