aboutsummaryrefslogtreecommitdiff
path: root/server/szurubooru/api/password_reset_api.py
blob: 887d2f0d751e2da427436638c7be7f67d87f9b0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from typing import Dict
from szurubooru import config, errors, rest
from szurubooru.func import auth, mailer, users, versions
from hashlib import md5


MAIL_SUBJECT = 'Password reset for {name}'
MAIL_BODY = (
    'You (or someone else) requested to reset your password on {name}.\n'
    'If you wish to proceed, click this link: {url}\n'
    'Otherwise, please ignore this email.')


@rest.routes.get('/password-reset/(?P<user_name>[^/]+)/?')
def start_password_reset(
        ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
    user_name = params['user_name']
    user = users.get_user_by_name_or_email(user_name)
    if not user.email:
        raise errors.ValidationError(
            'User %r hasn\'t supplied email. Cannot reset password.' % (
                user_name))
    token = auth.generate_authentication_token(user)

    if 'HTTP_ORIGIN' in ctx.env:
        url = ctx.env['HTTP_ORIGIN'].rstrip('/')
    else:
        url = ''
    url += '/password-reset/%s:%s' % (user.name, token)

    mailer.send_mail(
        'noreply@%s' % config.config['name'],
        user.email,
        MAIL_SUBJECT.format(name=config.config['name']),
        MAIL_BODY.format(name=config.config['name'], url=url))

    return {}


def _hash(token: str) -> str:
    return md5(token.encode('utf-8')).hexdigest()


@rest.routes.post('/password-reset/(?P<user_name>[^/]+)/?')
def finish_password_reset(
        ctx: rest.Context, params: Dict[str, str]) -> rest.Response:
    user_name = params['user_name']
    user = users.get_user_by_name_or_email(user_name)
    good_token = auth.generate_authentication_token(user)
    token = ctx.get_param_as_string('token')
    if _hash(token) != _hash(good_token):
        raise errors.ValidationError('Invalid password reset token.')
    new_password = users.reset_user_password(user)
    versions.bump_version(user)
    ctx.session.commit()
    return {'password': new_password}

© 2015 - 2026 Jakob L. Kreuze