Notebook Registration Challenges

This module includes support for challenge-response tests posed to users registering for new Sage notebook accounts. These Completely Automated Public Turing tests to tell Computers and Humans Apart, or CAPTCHAs, may be simple math questions, requests for special registration codes, or reCAPTCHAs.

AUTHORS:

class sagenb.notebook.challenge.AbstractChallenge(conf, **kwargs)

Bases: object

An abstract class with a suggested common interface for specific challenge-response schemes.

html(**kwargs)

Returns HTML for the challenge, e.g., to insert into a new account registration page.

INPUT:

  • kwargs - a dictionary of keywords arguments

OUTPUT:

  • a string; HTML form representation of the challenge, including a field for the response, supporting hidden fields, JavaScript code, etc.

TESTS:

sage: from sagenb.notebook.challenge import AbstractChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = AbstractChallenge(nb.conf())
sage: chal.html()
Traceback (most recent call last):
...
NotImplementedError
is_valid_response(**kwargs)

Returns the status of a challenge response.

INPUT:

  • kwargs - a dictionary of keyword arguments

OUTPUT:

TESTS:

sage: from sagenb.notebook.challenge import AbstractChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = AbstractChallenge(nb.conf())
sage: chal.is_valid_response()
Traceback (most recent call last):
...
NotImplementedError
class sagenb.notebook.challenge.ChallengeDispatcher(conf, **kwargs)

Bases: object

A simple dispatcher class that provides access to a specific challenge.

class sagenb.notebook.challenge.ChallengeResponse(is_valid, error_code=None)

Bases: object

A simple challenge response class that indicates whether a response is empty, correct, or incorrect, and, if it’s incorrect, includes an optional error code.

class sagenb.notebook.challenge.NotConfiguredChallenge(conf, **kwargs)

Bases: sagenb.notebook.challenge.AbstractChallenge

A fallback challenge used when an administrator has not configured a specific method.

html(**kwargs)

Returns a suggestion to inform the Notebook server’s administrator about the misconfigured challenge.

INPUT:

  • conf - a ServerConfiguration; an instance of the server’s configuration
  • kwargs - a dictionary of keyword arguments

OUTPUT:

  • a string

TESTS:

sage: from sagenb.notebook.challenge import NotConfiguredChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = NotConfiguredChallenge(nb.conf())
sage: print chal.html()
Please ask the server administrator to configure a challenge!
is_valid_response(**kwargs)

Always reports a failed response, for the sake of security.

INPUT:

  • kwargs - a dictionary of keyword arguments

OUTPUT:

TESTS:

sage: from sagenb.notebook.challenge import NotConfiguredChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = NotConfiguredChallenge(nb.conf())
sage: chal.is_valid_response().is_valid
False
sage: chal.is_valid_response().error_code
''
class sagenb.notebook.challenge.SimpleChallenge(conf, **kwargs)

Bases: sagenb.notebook.challenge.AbstractChallenge

A simple question and answer challenge.

html(**kwargs)

Returns a HTML form posing a randomly chosen question.

INPUT:

  • kwargs - a dictionary of keyword arguments

OUTPUT:

  • a string; the HTML form

TESTS:

sage: from sagenb.notebook.challenge import SimpleChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = SimpleChallenge(nb.conf())
sage: chal.html() # random
'...What is the largest prime factor of 1001?...'
is_valid_response(req_args={}, **kwargs)

Returns the status of a user’s answer to the challenge question.

INPUT:

  • req_args - a string:list dictionary; the arguments of the remote client’s HTTP POST request
  • kwargs - a dictionary of extra keyword arguments

OUTPUT:

TESTS:

sage: from sagenb.notebook.challenge import SimpleChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = SimpleChallenge(nb.conf())
sage: req = {}
sage: chal.is_valid_response(req).is_valid
sage: chal.is_valid_response(req).error_code
''
sage: from sagenb.notebook.challenge import QUESTIONS
sage: ques, ans = sorted(QUESTIONS.items())[0]
sage: ans = ans.split('|')[0]
sage: print ques
How many bits are in one byte?
sage: print ans
8
sage: req['simple_response_field'] = ans
sage: chal.is_valid_response(req).is_valid
False
sage: chal.is_valid_response(req).error_code
''
sage: req['simple_challenge_field'] = ques
sage: chal.is_valid_response(req).is_valid
True
sage: chal.is_valid_response(req).error_code
''
sagenb.notebook.challenge.agree(response, answer)

Returns whether a challenge response agrees with the answer.

INPUT:

  • response - a string; the user’s response to a posed challenge
  • answer - a string; the challenge’s right answer as a regular expression

OUTPUT:

  • a boolean; whether the response agrees with the answer

TESTS:

sage: from sagenb.notebook.challenge import agree
sage: agree('0', r'0|zero')
True
sage: agree('eighty', r'8|eight')
False
sagenb.notebook.challenge.challenge(conf, **kwargs)

Wraps an instance of ChallengeDispatcher and returns an instance of a specific challenge.

INPUT:

  • conf - a ServerConfiguration; a server configuration instance
  • kwargs - a dictionary of keyword arguments

OUTPUT:

TESTS:

sage: from sagenb.notebook.challenge import challenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: nb.conf()['challenge_type'] = 'simple'
sage: chal = challenge(nb.conf())
sage: chal.html() # random
'<p>...'
class sagenb.notebook.challenge.reCAPTCHAChallenge(conf, remote_ip='', is_secure=False, lang='en', **kwargs)

Bases: sagenb.notebook.challenge.AbstractChallenge

A reCAPTCHA challenge adapted from this Python API, also hosted here, written by Ben Maurer and maintained by Josh Bronson.

html(error_code=None, **kwargs)

Returns HTML and JavaScript for a reCAPTCHA challenge and response field.

INPUT:

  • error_code - a string (default: None); an optional error code to embed in the HTML, giving feedback about the user’s previous response
  • kwargs - a dictionary of extra keyword arguments

OUTPUT:

  • a string; HTML and JavaScript to render the reCAPTCHA challenge

TESTS:

sage: from sagenb.notebook.challenge import reCAPTCHAChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = reCAPTCHAChallenge(nb.conf(), remote_ip = 'localhost')
sage: chal.html()
u'...recaptcha...'
sage: chal.html('incorrect-captcha-sol')
u'...incorrect-captcha-sol...'
is_valid_response(req_args={}, **kwargs)

Submits a reCAPTCHA request for verification and returns its status.

INPUT:

  • req_args - a dictionary; the arguments of the responding user’s HTTP POST request
  • kwargs - a dictionary of extra keyword arguments

OUTPUT:

  • a ChallengeResponse instance; whether the user’s response is empty, accepted, or rejected, with an optional error string

TESTS:

sage: from sagenb.notebook.challenge import reCAPTCHAChallenge
sage: tmp = tmp_dir(ext='.sagenb')
sage: import sagenb.notebook.notebook as n
sage: nb = n.Notebook(tmp)
sage: chal = reCAPTCHAChallenge(nb.conf(), remote_ip = 'localhost')
sage: req = {}
sage: chal.is_valid_response(req).is_valid
sage: chal.is_valid_response(req).error_code
''
sage: req['recaptcha_response_field'] = ['subplotTimes']
sage: chal.is_valid_response(req).is_valid
False
sage: chal.is_valid_response(req).error_code
'incorrect-captcha-sol'
sage: req['simple_challenge_field'] = ['VBORw0KGgoANSUhEUgAAAB']
sage: chal.is_valid_response(req).is_valid # random
False
sage: chal.is_valid_response(req).error_code # random
'incorrect-captcha-sol'

Previous topic

Sage Trac Server

Next topic

Miscellaneous Notebook Functions

This Page