~fnux/meta.sr.ht

meta.sr.ht/metasrht-manageuser -rwxr-xr-x 4.3 KiB
28f5dba0Timothée Floure auth: remove duplicated password reset log for LDAP backend 5 months ago
                                                                                
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python3
import os
import sys
from getopt import getopt, GetoptError
from getpass import getpass

from srht.config import cfg
from srht.database import DbSession
from srht.oauth import UserType
from srht.validation import Validation

from metasrht import auth_validation
from metasrht.auth import auth_method
from metasrht.auth.base import get_user
from metasrht.auth.builtin import hash_password
from metasrht.types import User

USER_TYPES = [x.value for x in UserType]


def print_usage():
    print(f"""Usage:
    {sys.argv[0]} [-fmPps] [-e <EMAIL>] [-t <USER_TYPE>] <USERNAME>

Options:
    -e <EMAIL>      set user email
    -f              perform action even if using different authentication method
    -m              modify existing user
    -P              clear password
    -p              set password (default if creating a new user)
    -s              read initial password from stdin (only effective with -p)
    -t <USER_TYPE>  set user type to USER_TYPE; USER_TYPE must be one of these
                    values: unconfirmed, active_non_paying, active_free,
                    active_paying, active_delinquent, admin, unknown, suspended""")


def get_args():
    try:
        opts, args = getopt(sys.argv[1:], "e:fmPpst:")
    except GetoptError as ex:
        print(ex, file=sys.stderr)
        print_usage()
        sys.exit(1)

    if len(args) == 0:
        print("Username not specified", file=sys.stderr)
        print_usage()
        sys.exit(1)

    if len(args) > 1:
        print("Too many arguments", file=sys.stderr)
        print_usage()
        sys.exit(1)

    force = ("-f", "") in opts
    modify_existing = ("-m", "") in opts
    clear_password = ("-P", "") in opts
    set_password = ("-p", "") in opts
    stdin = ("-s", "") in opts
    email = [y for x, y in opts if x == "-e"]
    email = email[0] if email else None
    user_type = [y for x, y in opts if x == "-t"]
    user_type = user_type[0] if user_type else None

    username = args[0]

    if clear_password and set_password:
        sys.exit('Only one of -P, -p can be present at the same time')

    if not modify_existing and not clear_password:
        set_password = True

    if not modify_existing and email is None:
        sys.exit("Must specify -e when creating a new user!")

    if user_type and user_type not in USER_TYPES:
        sys.exit(f"-t must be one of {USER_TYPES}")

    return force, modify_existing, clear_password, set_password, stdin, email, \
           user_type, username


def get_password(stdin):
    if not stdin:
        password1 = getpass("Enter password: ")
        password2 = getpass("Repeat password: ")

        if password1 != password2:
            sys.exit("Repeated password does not match")

        return password1
    else:
        return sys.stdin.readline().rstrip(os.linesep)


def error_on_invalid(valid):
    if not valid.ok:
        for error in valid.errors:
            print(error.message, file=sys.stderr)
        sys.exit(1)


def validate_user(username, email):
    valid = Validation({})
    auth_validation.validate_username(valid, username)
    auth_validation.validate_email(valid, email)
    error_on_invalid(valid)


def validate_password(password):
    valid = Validation({})
    auth_validation.validate_password(valid, password)
    error_on_invalid(valid)


if __name__ == '__main__':
    force, modify_existing, clear_password, set_password, stdin, email, \
        user_type, username = get_args()

    if not force and auth_method != 'builtin':
        sys.exit("Can't create accounts if not using builtin authentication!")

    db = DbSession(cfg("meta.sr.ht", "connection-string"))
    db.init()

    if modify_existing:
        user = get_user(username)
        if user is None:
            sys.exit(f"User {username} not found!")
    else:
        validate_user(username, email)
        user = User(username)
        user.invites = cfg("meta.sr.ht::settings", "user-invites", default=0)
        db.session.add(user)

    if set_password:
        password = get_password(stdin)
        validate_password(password)
        user.password = hash_password(password)
    elif clear_password:
        user.password = ''

    if email is not None:
        user.email = email

    if user_type is not None:
        user.user_type = UserType[user_type]

    db.session.commit()