This file is indexed.

/usr/lib/python2.7/dist-packages/sagenb/flask_version/authentication.py is in python-sagenb 1.0.1+ds1-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
import os
import random
from flask import Blueprint, url_for, render_template, request, session, redirect, g, current_app
from .decorators import with_lock
from flask_babel import gettext, ngettext, lazy_gettext
_ = gettext

authentication = Blueprint('authentication',
                           'sagenb.flask_version.authentication')

##################
# Authentication #
##################
@authentication.before_request
def lookup_current_user():
    g.username = None
    if 'username' in session:
        g.username = session['username']


@authentication.route('/login', methods=['POST', 'GET'])
def login(template_dict={}):
    from sagenb.misc.misc import SAGE_VERSION
    template_dict.update({'accounts': g.notebook.user_manager().get_accounts(),
                          'recovery': g.notebook.conf()['email'],
                          'next': request.values.get('next', ''),
                          'sage_version': SAGE_VERSION,
                          'openid': g.notebook.conf()['openid'],
                          'username_error': False,
                          'password_error': False})

    if request.method == 'POST':
        username = request.form['email']
        password = request.form['password']

        if username == 'COOKIESDISABLED':
            return _("Please enable cookies or delete all Sage cookies and localhost cookies in your browser and try again.")

        # we only handle ascii usernames.
        from sagenb.notebook.misc import is_valid_username, is_valid_password
        if is_valid_username(username):
            try:
                U = g.notebook.user_manager().user(username)
            except (KeyError, LookupError):
                U = None
                template_dict['username_error'] = True
        else:
            U = None
            template_dict['username_error'] = True

        # It is critically important that it be impossible to login as the
        # pub, _sage_, or guest users.  This _sage_ user is a fake user that is used
        # internally by the notebook for the doc browser and other tasks.
        if username in ['_sage_', 'guest', 'pub']:
            U = None
            template_dict['username_error'] = True

        if U is None:
            pass
        elif (is_valid_password(password, username) and
              g.notebook.user_manager().check_password(username, password)):
            if U.is_suspended():
                #suspended
                return _("Your account is currently suspended")
            else:
                #Valid user, everything is okay
                session['username'] = username
                session.modified = True
                return redirect(request.values.get('next', url_for('base.index')))
        else:
            template_dict['password_error'] = True

    response = current_app.make_response(render_template(os.path.join('html', 'login.html'), **template_dict))
    response.set_cookie('cookie_test_%s'%g.notebook.port, 'cookie_test')
    return response

@authentication.route('/logout/')
def logout():
    username = session.pop('username', None)
    g.notebook.logout(username)
    return redirect(url_for('base.index'))




################
# Registration #
################

#XXX: Yuck!  This global variable should not be here.
#This is data should be stored somewhere more persistant.
waiting = {}

@authentication.route('/register', methods = ['GET','POST'])
@with_lock
def register():
    if not g.notebook.user_manager().get_accounts():
        return redirect(url_for('base.index'))
    from sagenb.notebook.misc import is_valid_username, is_valid_password, \
    is_valid_email, do_passwords_match
    from sagenb.notebook.challenge import challenge

    # VALIDATORS: is_valid_username, is_valid_password,
    # do_passwords_match, is_valid_email,
    # challenge.is_valid_response
    # INPUT NAMES: username, password, retype_password, email +
    # challenge fields

    # TEMPLATE VARIABLES: error, username, username_missing,
    # username_taken, username_invalid, password_missing,
    # password_invalid, passwords_dont_match,
    # retype_password_missing, email, email_missing,
    # email_invalid, email_address, challenge, challenge_html,
    # challenge_missing, challenge_invalid

    # PRE-VALIDATION setup and hooks.
    required = set(['username', 'password'])
    empty = set()
    validated = set()

    # Template variables.  We use empty_form_dict for empty forms.
    empty_form_dict = {}
    template_dict = {}

    if g.notebook.conf()['email']:
        required.add('email')
        empty_form_dict['email'] = True

    if g.notebook.conf()['challenge']:
        required.add('challenge')
        empty_form_dict['challenge'] = True
        chal = challenge(g.notebook.conf(),
                         is_secure = g.notebook.secure,
                         remote_ip = request.environ['REMOTE_ADDR'])
        empty_form_dict['challenge_html'] = chal.html()

    template_dict.update(empty_form_dict)

    # VALIDATE FIELDS.

    # Username.  Later, we check if a user with this username
    # already exists.
    username = request.values.get('username', None)
    if username:
        if not is_valid_username(username):
            template_dict['username_invalid'] = True
        elif g.notebook.user_manager().user_exists(username):
            template_dict['username_taken'] = True
        else:
            template_dict['username'] = username
            validated.add('username')
    else:
        template_dict['username_missing'] = True
        empty.add('username')

    # Password.
    password = request.values.get('password', None)
    retype_password = request.values.get('retype_password', None)
    if password:
        if not is_valid_password(password, username):
            template_dict['password_invalid'] = True
        elif not do_passwords_match(password, retype_password):
            template_dict['passwords_dont_match'] = True
        else:
            validated.add('password')
    else:
        template_dict['password_missing'] = True
        empty.add('password')

    # Email address.
    email_address = ''
    if g.notebook.conf()['email']:
        email_address = request.values.get('email', None)
        if email_address:
            if not is_valid_email(email_address):
                template_dict['email_invalid'] = True
            else:
                template_dict['email_address'] = email_address
                validated.add('email')
        else:
            template_dict['email_missing'] = True
            empty.add('email')

    # Challenge (e.g., reCAPTCHA).
    if g.notebook.conf()['challenge']:
        status = chal.is_valid_response(req_args = request.values)
        if status.is_valid is True:
            validated.add('challenge')
        elif status.is_valid is False:
            err_code = status.error_code
            if err_code:
                template_dict['challenge_html'] = chal.html(error_code = err_code)
            else:
                template_dict['challenge_invalid'] = True
        else:
            template_dict['challenge_missing'] = True
            empty.add('challenge')

    # VALIDATE OVERALL.
    if empty == required:
        # All required fields are empty.  Not really an error.
        return render_template(os.path.join('html', 'accounts', 'registration.html'),
                               **empty_form_dict)
    elif validated != required:
        # Error(s)!
        errors = len(required) - len(validated)
        template_dict['error'] = 'E ' if errors == 1 else 'Es '
        return render_template(os.path.join('html', 'accounts', 'registration.html'),
                        **template_dict)

    # Create an account, if username is unique.
    try:
        g.notebook.user_manager().add_user(username, password, email_address)
    except ValueError:
        template_dict['username_taken'] = True
        template_dict['error'] = 'E '

        form = render_template(os.path.join('html', 'accounts', 'registration.html'),
                        **template_dict)
        return HTMLResponse(stream = form)

    #XXX: Add logging support
    #log.msg("Created new user '%s'"%username)

    # POST-VALIDATION hooks.  All required fields should be valid.
    if g.notebook.conf()['email']:
        from sagenb.notebook.smtpsend import send_mail
        from sagenb.notebook.register import make_key, build_msg

        # TODO: make this come from the server settings
        key = make_key()
        listenaddr = g.notebook.interface
        port = g.notebook.port
        fromaddr = 'no-reply@%s' % listenaddr
        body = build_msg(key, username, listenaddr, port, g.notebook.secure)

        # Send a confirmation message to the user.
        try:
            send_mail(fromaddr, email_address,
                      _("Sage Notebook Registration"), body)
            waiting[key] = username
        except ValueError:
            pass

    # Go to the login page.
    from sagenb.misc.misc import SAGE_VERSION
    template_dict = {'accounts': g.notebook.user_manager().get_accounts(),
                     'welcome_user': username,
                     'recovery': g.notebook.conf()['email'],
                     'sage_version': SAGE_VERSION}

    return render_template(os.path.join('html', 'login.html'), **template_dict)


@authentication.route('/confirm')
@with_lock
def confirm():
    if not g.notebook.conf()['email']:
        return current_app.message(_('The confirmation system is not active.'))
    key = int(request.values.get('key', '-1'))

    invalid_confirm_key = _("""\
    <h1>Invalid confirmation key</h1>
    <p>You are reporting a confirmation key that has not been assigned by this
    server. Please <a href="/register">register</a> with the server.</p>
    """)
    try:
        username = waiting[key]
        user = g.notebook.user(username)
        user.set_email_confirmation(True)
    except KeyError:
        return current_app.message(invalid_confirm_key, '/register')
    success = _("""<h1>Email address confirmed for user %(username)s</h1>""", username=username)
    del waiting[key]
    return current_app.message(success, title=_('Email Confirmed'), username=username)

@authentication.route('/forgotpass')
@with_lock
def forgot_pass():
    if not g.notebook.conf()['email']:
        return current_app.message(_('The account recovery system is not active.'))

    username = request.values.get('username', '').strip()
    if not username:
        return render_template(os.path.join('html', 'accounts', 'account_recovery.html'))

    def error(msg):
        return current_app.message(msg, url_for('forgot_pass'))

    try:
        user = g.notebook.user(username)
    except KeyError:
        return error(_('Username is invalid.'))

    if not user.is_email_confirmed():
        return error(_("The e-mail address hasn't been confirmed."))

    #XXX: some of this could be factored out into a random passowrd
    #function.  There are a few places in admin.py that also use it.
    from random import choice
    import string
    chara = string.letters + string.digits
    old_pass = user.password()
    password = ''.join([choice(chara) for i in range(8)])

    from sagenb.notebook.smtpsend import send_mail
    from sagenb.notebook.register import build_password_msg
    # TODO: make this come from the server settings

    listenaddr = g.notebook.interface
    port = g.notebook.port
    fromaddr = 'no-reply@%s' % listenaddr
    body = build_password_msg(password, username, listenaddr, port, g.notebook.secure)
    destaddr = user.get_email()
    try:
        send_mail(fromaddr, destaddr, _("Sage Notebook Account Recovery"), body)
    except ValueError:
        # the email address is invalid
        return error(_("The new password couldn't be sent to %(dest)s.", dest=destaddr))
    else:
        g.notebook.user_manager().set_password(username, password)

    return current_app.message(_("A new password has been sent to your e-mail address."), url_for('base.index'))