Exemple #1
0
def savedata():
    """
    User has finished the experiment and is posting their data in the form of a
    (long) string. They will receive a debreifing back.
    """
    print request.args.keys()
    if not request.args.has_key('uniqueId'):
        raise ExperimentError('improper_inputs')
    else:
        uniqueId = request.args['uniqueId']
    print "/debrief called with", uniqueId

    user = Participant.query.\
           filter(Participant.uniqueid == uniqueId).\
           one()

    if config.getboolean('Task Parameters', 'use_debriefing'):
        user.status = COMPLETED
        user.endhit = datetime.datetime.now()
        db_session.add(user)
        db_session.commit()
    
        return render_template('debriefing.html', workerId=user.workerid, assignmentId=user.assignmentid)

    else:
        user.status = DEBRIEFED
        user.endhit = datetime.datetime.now()
        db_session.add(user)
        db_session.commit()

        return render_template('closepopup.html')
Exemple #2
0
def set_diceware_password(user, password):
    try:
        user.set_password(password)
    except PasswordError:
        flash(gettext(
            'You submitted a bad password! Password not changed.'), 'error')
        return

    try:
        db_session.commit()
    except Exception:
        flash(gettext(
            'There was an error, and the new password might not have been '
            'saved correctly. To prevent you from getting locked '
            'out of your account, you should reset your password again.'),
            'error')
        current_app.logger.error('Failed to update a valid password.')
        return

    # using Markup so the HTML isn't escaped
    flash(Markup("<p>" + gettext(
        "Password updated. Don't forget to "
        "save it in your KeePassX database. New password:") +
        ' <span><code>{}</code></span></p>'.format(password)),
        'success')
Exemple #3
0
def add_admin():
    while True:
        username = raw_input("Username: "******"Sorry, that username is already in use."
        else:
            break

    while True:
        password = getpass("Password: "******"Confirm Password: "******"Passwords didn't match!"

    hotp_input = raw_input("Is this admin using a YubiKey [HOTP]? (y/N): ")
    otp_secret = None
    if hotp_input.lower() == "y" or hotp_input.lower() == "yes":
        while True:
            otp_secret = raw_input("Please configure your YubiKey and enter the secret: ")
            if otp_secret:
                break

    admin = Journalist(username=username, password=password, is_admin=True, otp_secret=otp_secret)
    try:
        db_session.add(admin)
        db_session.commit()
    except Exception, e:
        if "username is not unique" in str(e):
            print "ERROR: That username is already taken!"
        else:
            print "ERROR: An unknown error occurred, traceback:"
            print e
Exemple #4
0
def enterexp():
    """
    AJAX listener that listens for a signal from the user's script when they
    leave the instructions and enter the real experiment. After the server
    receives this signal, it will no longer allow them to re-access the
    experiment applet (meaning they can't do part of the experiment and
    referesh to start over).
    """
    app.logger.info("Accessing /inexp")
    if not 'uniqueId' in request.form:
        raise ExperimentError('improper_inputs')
    unique_id = request.form['uniqueId']

    try:
        user = Participant.query.\
            filter(Participant.uniqueid == unique_id).one()
        user.status = STARTED
        user.beginexp = datetime.datetime.now()
        db_session.add(user)
        db_session.commit()
        resp = {"status": "success"}
    except exc.SQLAlchemyError:
        app.logger.error("DB error: Unique user not found.")
        resp = {"status": "error, uniqueId not found"}
    return jsonify(**resp)
Exemple #5
0
def admin_edit_user(user_id):
    user = Journalist.query.get(user_id)

    if request.method == "POST":
        if request.form["username"] != "":
            user.username = request.form["username"]

        if request.form["password"] != "":
            if request.form["password"] != request.form["password_again"]:
                flash("Passwords didn't match", "error")
                return redirect(url_for("admin_edit_user", user_id=user_id))
            try:
                user.set_password(request.form["password"])
            except InvalidPasswordLength:
                flash(
                    "Your password is too long " "(maximum length {} characters)".format(Journalist.MAX_PASSWORD_LEN),
                    "error",
                )
                return redirect(url_for("admin_edit_user", user_id=user_id))

        user.is_admin = bool(request.form.get("is_admin"))

        try:
            db_session.add(user)
            db_session.commit()
        except Exception, e:
            db_session.rollback()
            if "username is not unique" in str(e):
                flash("That username is already in use", "notification")
            else:
                flash("An unknown error occurred, please inform your administrator", "error")
Exemple #6
0
def insertData(qiniukey):
    share = Share.query.filter(Share.share_qiniuurl == qiniukey).first()
    if share is None:
        share = Share(None, qiniukey)
        db_session.add(share)
        db_session.commit()
    return share
Exemple #7
0
def quitter():
    """
    Mark quitter as such.
    """
    unique_id = request.form['uniqueId']
    if unique_id[:5] == "debug":
        debug_mode = True
    else:
        debug_mode = False

    if debug_mode:
        resp = {"status": "didn't mark as quitter since this is debugging"}
        return jsonify(**resp)
    else:
        try:
            unique_id = request.form['uniqueId']
            app.logger.info("Marking quitter %s" % unique_id)
            user = Participant.query.\
                filter(Participant.uniqueid == unique_id).\
                one()
            user.status = QUITEARLY
            db_session.add(user)
            db_session.commit()
        except exc.SQLAlchemyError:
            raise ExperimentError('tried_to_quit')
        else:
            resp = {"status": "marked as quitter"}
            return jsonify(**resp)
Exemple #8
0
def edit_skills():
    """ About block edit
    """

    #saved?
    saved = False

    if request.method == 'POST':
        for field in request.form:
            if field.startswith('skill'):
                skill, skill_id = field.split('_')
                skill = Skill.query.get(int(skill_id))
                skill.percent = int(escape(request.form[field]))

                db_session.add(skill)
                db_session.commit()

        saved = True

    skills = Skill.query.all()

    prop = dict()
    prop.update(default)
    prop['skills'] = skills
    prop['saved'] = saved

    return render_template('admin/edit_skills.html', **prop)
Exemple #9
0
def new_client():
    """ About block edit
    """
    # if errors detected
    errors = []

    # if form incoming
    if request.method == 'POST':
        if not request.form['title']:
            errors += ['Title required!']

        if not errors:
            client = dict()
            client['title'] = unicode(escape(request.form['title']))
            client['description'] = unicode(escape(request.form['description']))
            client['logo'] = unicode(escape(request.form['logo']))
            client['link'] = unicode(escape(request.form['link']))

            client = Client(**client)

            try:
                db_session.add(client)
                db_session.commit()
            except exc.SQLAlchemyError:
                db_session.rollback()
                errors += ['Error creating client #{0}\n'.format(client.id)]

            return redirect(url_for('edit_client', client_id=client.id))

    prop = dict()
    prop.update(default)
    prop['errors'] = errors

    return render_template('admin/new_client.html', **prop)
Exemple #10
0
def edit_about():
    """ About block edit
    """
    # saved?
    saved = False

    if request.method == 'POST':
        about = Info.query.filter(Info.title == 'about').first()
        about.value = unicode(request.form['about'])

        try:
            db_session.add(about)
            db_session.commit()
            saved = True
        except exc.SQLAlchemyError:
            db_session.rollback()
            saved = False

    about = Info.query.filter(Info.title == 'about').first()

    prop = dict()
    prop.update(default)
    prop['about'] = about.value
    prop['saved'] = saved

    return render_template('admin/edit_about.html', **prop)
Exemple #11
0
def submit():
    msg = request.form['msg']
    fh = request.files['fh']
    strip_metadata = True if 'notclean' in request.form else False

    fnames = []

    if msg:
        fnames.append(store.save_message_submission(g.sid, msg))
        flash("Thanks! We received your message.", "notification")
    if fh:
        fnames.append(store.save_file_submission(g.sid, fh.filename,
            fh.stream, fh.content_type, strip_metadata))
        flash("Thanks! We received your document '%s'."
              % fh.filename or '[unnamed]', "notification")

    for fname in fnames:
        submission = Submission(g.source, fname)
        db_session.add(submission)

    if g.source.pending:
        g.source.pending = False

        # Generate a keypair now, if there's enough entropy (issue #303)
        entropy_avail = int(open('/proc/sys/kernel/random/entropy_avail').read())
        if entropy_avail >= 2400:
            crypto_util.genkeypair(g.sid, g.codename)

    g.source.last_updated = datetime.now()
    db_session.commit()
    normalize_timestamps(g.sid)

    return redirect(url_for('lookup'))
Exemple #12
0
def update(uid=None):
    """
    Save experiment data, which should be a JSON object and will be stored
    after converting to string.
    """
    app.logger.info("PUT /sync route with id: %s" % uid)

    try:
        user = Participant.query.\
            filter(Participant.uniqueid == uid).\
            one()
    except exc.SQLAlchemyError:
        app.logger.error("DB error: Unique user not found.")

    if hasattr(request, 'json'):
        user.datastring = request.data.decode('utf-8').encode(
            'ascii', 'xmlcharrefreplace'
        )
        db_session.add(user)
        db_session.commit()

    try:
        data = json.loads(user.datastring)
    except:
        data = {}

    trial = data.get("currenttrial", None)
    app.logger.info("saved data for %s (current trial: %s)", uid, trial)
    resp = {"status": "user data saved"}
    return jsonify(**resp)
    def _admin_logs_in(self):
        # Create a test admin user for logging in
        admin_user_info = dict(
            username='******',
            password='******',
            is_admin=True)
        admin_user = Journalist(**admin_user_info)
        db_session.add(admin_user)
        db_session.commit()

        # Stash the admin user on self so we can use it in later tests
        self.admin_user = admin_user_info
        self.admin_user['orm_obj'] = admin_user

        self._login_user(admin_user_info['username'],
                         admin_user_info['password'],
                         admin_user.totp.now())

        # Admin user should log in to the same interface as a normal user,
        # since there may be users who wish to be both journalists and admins.
        headline = self.driver.find_element_by_css_selector('span.headline')
        self.assertIn('Sources', headline.text)

        # Admin user should have a link that take them to the admin page
        links = self.driver.find_elements_by_tag_name('a')
        self.assertIn('Admin', [el.text for el in links])
Exemple #14
0
def delete_user(args):
    """Deletes a journalist or administrator from the application."""
    username = _get_username_to_delete()
    try:
        selected_user = Journalist.query.filter_by(username=username).one()
    except NoResultFound:
        print('ERROR: That user was not found!')
        return 0

    # Confirm deletion if user is found
    if not _get_delete_confirmation(selected_user.username):
        return 0

    # Try to delete user from the database
    try:
        db_session.delete(selected_user)
        db_session.commit()
    except Exception as e:
        # If the user was deleted between the user selection and confirmation,
        # (e.g., through the web app), we don't report any errors. If the user
        # is still there, but there was a error deleting them from the
        # database, we do report it.
        try:
            Journalist.query.filter_by(username=username).one()
        except NoResultFound:
            pass
        else:
            raise e

    print('User "{}" successfully deleted'.format(username))
    return 0
def update_broadcasting_status(group_id):
    users = db_session.query(models.User).filter(models.User.group_id == group_id)
    if users:
        for user in users:
            user.is_near_dorm = NOT_BROADCASTING
        db_session.commit()
    return 1
Exemple #16
0
def post_delete(id):
    post = db_session.query(Post).get(id)
    if post is None:
        abort(404)
    db_session.delete(post)
    db_session.commit()
    return redirect(url_for('index'))
def update(id=None):
    """
    Save experiment data, which should be a JSON object and will be stored
    after converting to string.
    """
    app.logger.info("accessing the /sync route with id: %s" % id)

    try:
        user = Participant.query.\
                filter(Participant.uniqueid == id).\
                one()
    except:
        app.logger.error( "DB error: Unique user not found.")

    if hasattr(request, 'json'):
        user.datastring = request.data.decode('utf-8').encode('ascii', 'xmlcharrefreplace')
        db_session.add(user)
        db_session.commit()

    resp = {"condition": user.cond,
            "counterbalance": user.counterbalance,
            "assignmentId": user.assignmentid,
            "workerId": user.workerid,
            "hitId": user.hitid}

    return jsonify(**resp)
Exemple #18
0
def callback():
    code=request.args.get('code')
    if not code:
        return 'failed'
    url = AUTHORIZE_URL.format(code=code, 
        client_id=clientid,
        secret=secret)
    resp = requests.get(url)
    if resp.ok:
        access_token = resp.json()['access_token']
        # now get 4sq id and name from self endpoint
        payload = {'oauth_token': access_token,
                   'v': API_VERSION}
        resp2 = requests.get(SELF_URL, params=payload)
        if resp2.ok:
            user_w = resp2.json()
            user = user_w.get('response',{}).get('user',{})
            if user:
                name = user.get('firstName') + ' ' + user.get('lastName','')
                foursquare_id = user.get('id')
                u = User.query.filter(User.foursquare_id == foursquare_id).first()
                if u:
                    u.access_token = access_token
                    db_session.commit()
                else:
                    u = User(foursquare_id, access_token, name)
                    db_session.add(u)
                    db_session.commit()

                return 'callback ok (POST)'
    else:
        return 'something went wrong...'
def create_single_version_file_on_drive(task, parent_drive_id, redmine_type, redmine_id,
                                        file_name, local_path, description, mime_type,
                                        version, modified_date):
    if not parent_drive_id:
        raise Exception("parent_drive_id is required")
    if not redmine_type:
        raise Exception("redmine_type is required")
    if redmine_id is None:
        raise Exception("redmine_id is required")
    if not file_name:
        raise Exception("folder_name is required")
    if not local_path:
        raise Exception("local_path is required")
    if not os.path.isfile(local_path):
        raise Exception("local_path %s is missing" % local_path)

    db_mapping = db_session.query(RedmineToDriveMapping).filter_by(redmine_id=redmine_id).filter_by(
        mapping_type=redmine_type).first()

    if db_mapping and db_mapping.drive_id:
        logger.info("File %s already mapped to %s", file_name, db_mapping.drive_id)
        return

    if not db_mapping:
        try:
            db_mapping = RedmineToDriveMapping(redmine_id=redmine_id, mapping_type=redmine_type,
                                               last_update=datetime.datetime.utcnow())
            db_session.add(db_mapping)
            db_session.commit()
            logger.info("Created mapping for %s %s id:%s", redmine_type, file_name, redmine_id)
        except IntegrityError, e:
            logger.info("Cannot create mapping due to duplicate, will retry: %s", e)
            db_session.rollback()
            task.retry(countdown=min(2 + (2 * current_task.request.retries), 128))
Exemple #20
0
def update(id=None):
    """
    Save experiment data, which should be a JSON object and will be stored
    after converting to string.
    """
    print "accessing the /sync route with id:", id
    
    try:
        user = Participant.query.\
                filter(Participant.uniqueid == id).\
                one()
    except:
        print "DB error: Unique user not found."
    
    if hasattr(request, 'json'):
        user.datastring = request.data
        db_session.add(user)
        db_session.commit()
    
    resp = {"condition": user.cond,
            "counterbalance": user.counterbalance,
            "assignmentId": user.assignmentid,
            "workerId": user.workerid,
            "hitId": user.hitid}
    
    return jsonify(**resp)
Exemple #21
0
def make_star_false(filesystem_id):
    source = get_source(filesystem_id)
    if not source.star:
        source_star = SourceStar(source)
        db_session.add(source_star)
        db_session.commit()
    source.star.starred = False
Exemple #22
0
 def reset_two_factor_hotp():
     uid = request.form['uid']
     otp_secret = request.form.get('otp_secret', None)
     if otp_secret:
         user = Journalist.query.get(uid)
         try:
             user.set_hotp_secret(otp_secret)
         except TypeError as e:
             if "Non-hexadecimal digit found" in str(e):
                 flash(gettext(
                     "Invalid secret format: "
                     "please only submit letters A-F and numbers 0-9."),
                       "error")
             elif "Odd-length string" in str(e):
                 flash(gettext(
                     "Invalid secret format: "
                     "odd-length secret. Did you mistype the secret?"),
                       "error")
             else:
                 flash(gettext(
                     "An unexpected error occurred! "
                     "Please inform your administrator."), "error")
                 current_app.logger.error(
                     "set_hotp_secret '{}' (id {}) failed: {}".format(
                         otp_secret, uid, e))
             return render_template('admin_edit_hotp_secret.html', uid=uid)
         else:
             db_session.commit()
             return redirect(url_for('admin.new_user_two_factor', uid=uid))
     else:
         return render_template('admin_edit_hotp_secret.html', uid=uid)
Exemple #23
0
def login():
    if request.method == "POST":
        try:
            user = Journalist.login(request.form["username"], request.form["password"], request.form["token"])
        except Exception as e:
            app.logger.error("Login for '{}' failed: {}".format(request.form["username"], e))
            login_flashed_msg = "Login failed."

            if isinstance(e, LoginThrottledException):
                login_flashed_msg += " Please wait at least 60 seconds before logging in again."
            else:
                try:
                    user = Journalist.query.filter_by(username=request.form["username"]).one()
                    if user.is_totp:
                        login_flashed_msg += " Please wait for a new two-factor token before logging in again."
                except:
                    pass

            flash(login_flashed_msg, "error")
        else:
            app.logger.info(
                "Successful login for '{}' with token {}".format(request.form["username"], request.form["token"])
            )

            # Update access metadata
            user.last_access = datetime.utcnow()
            db_session.add(user)
            db_session.commit()

            session["uid"] = user.id
            return redirect(url_for("index"))

    return render_template("login.html")
Exemple #24
0
def admin_reset_two_factor_totp():
    uid = request.form["uid"]
    user = Journalist.query.get(uid)
    user.is_totp = True
    user.regenerate_totp_shared_secret()
    db_session.commit()
    return redirect(url_for("admin_new_user_two_factor", uid=uid))
    def test_source_is_deleted_while_logged_in(self, logger):
        """If a source is deleted by a journalist when they are logged in,
        a NoResultFound will occur. The source should be redirected to the
        index when this happens, and a warning logged."""

        with self.client as client:
            codename = new_codename(client, session)
            resp = client.post('login', data=dict(codename=codename),
                               follow_redirects=True)

            # Now the journalist deletes the source
            filesystem_id = crypto_util.hash_codename(codename)
            crypto_util.delete_reply_keypair(filesystem_id)
            source = Source.query.filter_by(filesystem_id=filesystem_id).one()
            db_session.delete(source)
            db_session.commit()

            # Source attempts to continue to navigate
            resp = client.post('/lookup', follow_redirects=True)
            self.assertEqual(resp.status_code, 200)
            self.assertIn('Submit documents for the first time', resp.data)
            self.assertNotIn('logged_in', session.keys())
            self.assertNotIn('codename', session.keys())

        logger.assert_called_once_with(
            "Found no Sources when one was expected: "
            "No row was found for one()")
Exemple #26
0
 def reset_two_factor_hotp():
     otp_secret = request.form.get('otp_secret', None)
     if otp_secret:
         g.user.set_hotp_secret(otp_secret)
         db_session.commit()
         return redirect(url_for('account.new_two_factor'))
     else:
         return render_template('account_edit_hotp_secret.html')
Exemple #27
0
def _add_user(is_admin=False):
    username = _get_username()

    print("Note: Passwords are now autogenerated.")
    password = _make_password()
    print("This user's password is: {}".format(password))

    is_hotp = _get_yubikey_usage()
    otp_secret = None
    if is_hotp:
        while True:
            otp_secret = raw_input(
                "Please configure this user's YubiKey and enter the secret: ")
            if otp_secret:
                tmp_str = otp_secret.replace(" ", "")
                if len(tmp_str) != 40:
                    print("The length of the secret is not correct. "
                          "Expected 40 characters, but received {0}. "
                          "Try again.".format(len(tmp_str)))
                    continue
            if otp_secret:
                break

    try:
        user = Journalist(username=username,
                          password=password,
                          is_admin=is_admin,
                          otp_secret=otp_secret)
        db_session.add(user)
        db_session.commit()
    except Exception as exc:
        db_session.rollback()
        if "UNIQUE constraint failed: journalists.username" in str(exc):
            print('ERROR: That username is already taken!')
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            print(repr(traceback.format_exception(exc_type, exc_value,
                                                  exc_traceback)))
        return 1
    else:
        print('User "{}" successfully added'.format(username))
        if not otp_secret:
            # Print the QR code for FreeOTP
            print('\nScan the QR code below with FreeOTP:\n')
            uri = user.totp.provisioning_uri(username,
                                             issuer_name='SecureDrop')
            qr = qrcode.QRCode()
            qr.add_data(uri)
            sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
            qr.print_ascii(tty=sys.stdout.isatty())
            print('\nIf the barcode does not render correctly, try changing '
                  "your terminal's font (Monospace for Linux, Menlo for OS "
                  'X). If you are using iTerm on Mac OS X, you will need to '
                  'change the "Non-ASCII Font", which is your profile\'s Text '
                  "settings.\n\nCan't scan the barcode? Enter following "
                  'shared secret '
                  'manually:\n{}\n'.format(user.formatted_otp_secret))
        return 0
Exemple #28
0
def vote(poll_id, answer_id):
    user_id = get_user_id()
    poll = Poll.query.filter(Poll.id == poll_id).first()
    answer = Answer.query.filter(Answer.id == answer_id).first()
    if poll.vote_limit > count_votes(poll, user_id):
        answer.votes.append(Vote(user_id))
        db_session.add(answer)
        db_session.commit()
    return redirect("/view/%s" % poll.id)
Exemple #29
0
def doc(sid, fn):
    if ".." in fn or fn.startswith("/"):
        abort(404)
    try:
        Submission.query.filter(Submission.filename == fn).one().downloaded = True
    except NoResultFound as e:
        app.logger.error("Could not mark " + fn + " as downloaded: %s" % (e,))
    db_session.commit()
    return send_file(store.path(sid, fn), mimetype="application/pgp-encrypted")
Exemple #30
0
def bulk_delete(sid, items_selected):
    for item in items_selected:
        item_path = store.path(sid, item.filename)
        worker.enqueue(store.secure_unlink, item_path)
        db_session.delete(item)
    db_session.commit()

    flash("Submission{} deleted.".format("s" if len(items_selected) > 1 else ""), "notification")
    return redirect(url_for("col", sid=sid))
Exemple #31
0
def start():
    pid = request.args.get("pid")
    password = request.args.get("password")

    # get by pid
    try:
        poll = db_session.query(Poll).filter_by(pid=pid).filter_by(
            password=password).first()
        poll.started = True
        db_session.commit()

        #push message saying owner started
        pusher.trigger(
            pid, "notify-status", {
                "status":
                "COMPLETED" if poll.completed else
                ("STARTED" if poll.started else "WAITING")
            })

        return "Poll started", 200

    except Exception as e:
        return "Invalid pid or password.", 400
Exemple #32
0
def edit_data():
    if "admin_email" not in request.form:
        build_html_error_response("Missing Field", 400,
                                  "Missing admin email when registering app")
    if "name" not in request.form:
        build_html_error_response("Missing Field", 400,
                                  "Missing name when registering app")
    if "homepage" not in request.form:
        build_html_error_response("Missing Field", 400,
                                  "Missing homepage when registering app")
    if "callback_url" not in request.form:
        build_html_error_response("Missing Field", 400,
                                  "Missing callback when registering app")

    app = Apps.query.filter_by(client_id=session["client_id"]).first()
    app.name = request.form.get("name")
    app.admin_email = request.form.get("admin_email")
    app.homepage = request.form.get("homepage")
    app.callback = request.form.get("callback_url")

    db_session.commit()

    return redirect(url_for("apps.get", client_id=app.client_id))
def create_user_tokens():
    # write the user tokens to the appropriate db fields
    counter = 0

    try:
        users = db_session.query(User).filter(User.active == 1).all()

        for user in users:
            token = token_serializer.dumps({
                'username': user.username,
                'user_id': user.id
            }).decode('utf-8')
            user.token = token
            user.token_last_update = datetime.now()
            db_session.commit()
            db_session.flush()
            print('*** token for {} ***: {}\n'.format(user.username, token))
            counter += 1

        print('Updated {} tokens.'.format(str(counter)))

    except exc.SQLAlchemyError as err:
        print('Database error updating tokens: {}'.format(str(err)))
Exemple #34
0
def add_admin():
    while True:
        username = raw_input("Username: "******"Sorry, that username is already in use."
        else:
            break

    while True:
        password = getpass("Password: "******"Confirm Password: "******"Passwords didn't match!"

    hotp_input = raw_input("Is this admin using a YubiKey [HOTP]? (y/N): ")
    otp_secret = None
    if hotp_input.lower() == "y" or hotp_input.lower() == "yes":
        while True:
            otp_secret = raw_input(
                "Please configure your YubiKey and enter the secret: ")
            if otp_secret:
                break

    admin = Journalist(username=username,
                       password=password,
                       is_admin=True,
                       otp_secret=otp_secret)
    try:
        db_session.add(admin)
        db_session.commit()
    except Exception, e:
        if "username is not unique" in str(e):
            print "ERROR: That username is already taken!"
        else:
            print "ERROR: An unknown error occurred, traceback:"
            print e
Exemple #35
0
def delete_user():  # pragma: no cover
    """Deletes a journalist or administrator from the application."""
    # Select user to delete
    username = raw_input('Username to delete: ')
    try:
        selected_user = Journalist.query.filter_by(username=username).one()
    except NoResultFound:
        print('ERROR: That user was not found!')
        return 0

    # Confirm deletion if user is found
    confirmation = raw_input('Are you sure you want to delete user '
                             '{} (y/n)?'.format(selected_user))
    if confirmation.lower() != 'y':
        print('Confirmation not received: user "{}" was NOT '
              'deleted'.format(username))
        return 0

    # Try to delete user from the database
    try:
        db_session.delete(selected_user)
        db_session.commit()
    except:
        # If the user was deleted between the user selection and confirmation,
        # (e.g., through the web app), we don't report any errors. If the user
        # is still there, but there was a error deleting them from the
        # database, we do report it.
        try:
            selected_user = Journalist.query.filter_by(username=username).one()
        except NoResultFound:
            pass
        else:
            raise

    print('User "{}" successfully deleted'.format(username))
    return 0
Exemple #36
0
def logout():
    if 'redirect_url' in request.args:
        referrer = request.args.get('redirect_url')
    else:
        referrer = request.referrer
    if 'Access-Token' not in request.headers and 'access_token' not in request.args:
        return build_html_error_response("Missing authentication", \
                                    400,\
                                    "Access-Token header not present in the request")
    if 'Access-Token' not in request.headers:
        access_token = request.args.get('access_token')
    else:
        access_token = request.headers.get('Access-Token')
    user = Users.query.filter_by(access_token=access_token).first()
    if user == None:
        return build_html_error_response("Invalid authentication", \
                                    401,\
                                    "Access-Token is invalid for this service")
    user.token_valid = False
    db_session.commit()

    return render_template("logout.html",
                           referrer=referrer.split('?')[0],
                           email=user.email)
Exemple #37
0
def add_task():
    """Convert the input JSON to task object and add it to the database"""
    try:
        task_json_object = validate_json_task(request.json)
    except (ValueError, ValidationError) as validation_error:
        return Response("Incorrect JSON input: " + str(validation_error), 400)

    # Model attribute names are the same as JSON keys,
    # so we can use dict unpacking
    current_task = Task(**task_json_object)

    if request.access_route:
        current_task.author_ip = request.access_route[0]
    else:
        current_task.author_ip = request.remote_addr

    if not current_task.done:
        current_task.done = False
    elif not current_task.done_date:
        current_task.done_date = datetime.datetime.utcnow()

    db_session.add(current_task)
    db_session.commit()
    return jsonify(task_id=current_task.id)
Exemple #38
0
def login():
    if request.method == 'POST':
        try:
            user = Journalist.login(request.form['username'],
                                    request.form['password'],
                                    request.form['token'])
        except Exception as e:
            app.logger.error("Login for '{}' failed: {}".format(
                request.form['username'], e))
            login_flashed_msg = "Login failed."

            if isinstance(e, LoginThrottledException):
                login_flashed_msg += " Please wait at least 60 seconds before logging in again."
            else:
                try:
                    user = Journalist.query.filter_by(
                        username=request.form['username']).one()
                    if user.is_totp:
                        login_flashed_msg += " Please wait for a new two-factor token before logging in again."
                except:
                    pass

            flash(login_flashed_msg, "error")
        else:
            app.logger.info("Successful login for '{}' with token {}".format(
                request.form['username'], request.form['token']))

            # Update access metadata
            user.last_access = datetime.utcnow()
            db_session.add(user)
            db_session.commit()

            session['uid'] = user.id
            return redirect(url_for('index'))

    return render_template("login.html")
Exemple #39
0
def download(zip_basename, submissions):
    """Send client contents of zipfile *zip_basename*-<timestamp>.zip
    containing *submissions*. The zipfile, being a
    :class:`tempfile.NamedTemporaryFile`, is stored on disk only
    temporarily.

    :param str zip_basename: The basename of the zipfile download.

    :param list submissions: A list of :class:`db.Submission`s to
                             include in the zipfile.
    """
    zf = store.get_bulk_archive(submissions,
                                zip_directory=zip_basename)
    attachment_filename = "{}--{}.zip".format(
        zip_basename, datetime.utcnow().strftime("%Y-%m-%d--%H-%M-%S"))

    # Mark the submissions that have been downloaded as such
    for submission in submissions:
        submission.downloaded = True
    db_session.commit()

    return send_file(zf.name, mimetype="application/zip",
                     attachment_filename=attachment_filename,
                     as_attachment=True)
Exemple #40
0
def admin_edit_user(user_id):
    user = Journalist.query.get(user_id)

    if request.method == 'POST':
        if request.form['username'] != "":
            user.username = request.form['username']

        if request.form['password'] != "":
            if request.form['password'] != request.form['password_again']:
                flash("Passwords didn't match", "error")
                return redirect(url_for("admin_edit_user", user_id=user_id))
            user.set_password(request.form['password'])

        user.is_admin = bool(request.form.get('is_admin'))

        try:
            db_session.add(user)
            db_session.commit()
        except Exception, e:
            db_session.rollback()
            if "username is not unique" in str(e):
                flash("That username is already in use", "notification")
            else:
                flash("An unknown error occurred, please inform your administrator", "error")
    def _admin_logs_in(self):
        # Create a test admin user for logging in
        admin_user_info = dict(username='******',
                               password='******',
                               is_admin=True)
        admin_user = Journalist(**admin_user_info)
        db_session.add(admin_user)
        db_session.commit()

        # Stash the admin user on self so we can use it in later tests
        self.admin_user = admin_user_info
        self.admin_user['orm_obj'] = admin_user

        self._login_user(admin_user_info['username'],
                         admin_user_info['password'], admin_user.totp.now())

        # Admin user should log in to the same interface as a normal user,
        # since there may be users who wish to be both journalists and admins.
        headline = self.driver.find_element_by_css_selector('span.headline')
        self.assertIn('Sources', headline.text)

        # Admin user should have a link that take them to the admin page
        links = self.driver.find_elements_by_tag_name('a')
        self.assertIn('Admin', [el.text for el in links])
Exemple #42
0
def debug_complete():
    ''' Debugging route for complete. '''
    if not 'uniqueId' in request.args:
        raise ExperimentError('improper_inputs')
    else:
        unique_id = request.args['uniqueId']
        if unique_id[:5] == "debug":
            debug_mode = True
        else:
            debug_mode = False
        try:
            user = Participant.query.\
                filter(Participant.uniqueid == unique_id).one()
            user.status = COMPLETED
            user.endhit = datetime.datetime.now()
            db_session.add(user)
            db_session.commit()
        except:
            raise ExperimentError('error_setting_worker_complete')
        else:
            if debug_mode:
                return render_template('complete.html')
            else:  # send them back to mturk.
                return render_template('closepopup.html')
def validate_account_addresses():
    active_no_wallet_accounts = db_session.query(Account).filter(
        Account.active == 'true', Account.wallet_address == None).all()
    unassigned_accounts = []
    for acc in active_no_wallet_accounts:
        acct_fqdn = acc.fully_qualified_name
        #append qbo fully qualified account name into unassigned_accounts array
        unassigned_accounts.append(acct_fqdn)
        #generate new address and output it to text file in home directory
        get_new_addr_command = base_command % (
            'getnewaddress >~/newaddress.txt 2>&1')
        #os.system(get_new_addr_command)

        cur_dir = os.getcwd()
        tmp_folder = cur_dir + '/tmp'
        print(tmp_folder)
        if not os.path.exists(tmp_folder):
            print('not there')
            os.makedirs(tmp_folder)
        path = tmp_folder + '/newaddress.txt'

        #opens text file and extracts new address and adds it to unassigned_addresses array
        with open(path) as fp:
            for j, line in enumerate(fp):
                if j == 2:
                    unassigned_addresses.append(line)

                    #updates the wallet_address column for the account
                    acc.wallet_address = line

                    db_session.add(acc)
                    #saves database changes as permanent
                    db_session.commit()
    #deletes placeholder text file in home directory
    os.system("cd ~ & sudo rm newaddress.txt")
    return unassigned_accounts, unassigned_addresses
Exemple #44
0
    def mutate(self, info, positionData):

        import utils
        if utils.isAllowAccess():

            from mutation_position import isPositionByPosCodeExist

            newPos = None
            status = False
            msg = 'This posCode \'{}\' is exist.'.format(positionData.posCode)

            if isPositionByPosCodeExist(positionData.posCode, info) is False:
                newPos = PositionDBModel()
                newPos.posCode = positionData.posCode
                newPos.pos_desc = positionData.pos_desc

                db_session.add(newPos)
                db_session.commit()

                status = True
                msg = 'Create position\'s posCode {} success.'.format(
                    positionData.posCode)

            return CreatePosition(position=newPos, status=status, msg=msg)
Exemple #45
0
def completed():
    """
    This is sent in when the participant completes the debriefing. The
    participant can accept the debriefing or declare that they were not
    adequately debriefed, and that response is logged in the database.
    """
    print "accessing the /complete route"
    if not (request.form.has_key('assignmentid')
            and request.form.has_key('agree')):
        raise ExperimentError('improper_inputs')
    assignmentId = request.form['assignmentid']
    workerId = request.form['workerid']
    agreed = request.form['agree']
    print workerId, assignmentId, agreed

    user = Participant.query.\
            filter(Participant.assignmentid == assignmentId).\
            filter(Participant.workerid == workerId).\
            one()
    user.status = DEBRIEFED
    user.debriefed = agreed == 'true'
    db_session.add(user)
    db_session.commit()
    return render_template('closepopup.html')
Exemple #46
0
    def search(self, words: List[str]):
        #        language = tokenizer.guess_language(text)
        #        words = tokenizer.word_tokenize(text, language)
        words_id = db_interface.get_words_id(words)

        # очищаем список слов, использованный при предыдущем поиске
        db_session.query(SearchWords).filter(
            SearchWords.session_id == self.sess.id).delete()
        db_session.commit()

        # найти id всех книг, которые содержат все найденные слова
        for i in words_id:
            db_session.add(SearchWords(session_id=self.session_id, word_id=i))
        db_session.commit()
        q = db_session.query(BookWord.book_id).\
            join(SearchWords, and_(SearchWords.session_id == self.session_id, SearchWords.word_id == BookWord.word_id)).\
            group_by(BookWord.book_id).\
            having(func.count(BookWord.word_id) == db_session.query(func.count(SearchWords.word_id.distinct())).
                   filter(SearchWords.session_id == self.session_id)
                   )
        self.search_result.clear()

        # очищаем результат предыдущего поиска
        db_session.query(SearchResult).filter(
            SearchResult.session_id == self.sess.id).delete()
        db_session.commit()

        for i in q.all():
            book = db_session.query(Book).filter(Book.id == i[0]).first()
            self.search_result.append(
                b.Book(zip_file=book.zip_name,
                       book_name=book.book_name,
                       annotation=book.annotation,
                       authors=book.authors,
                       title=book.title,
                       genre=book.genre))
            db_session.add(
                SearchResult(session_id=self.sess.id, book_id=book.id))
        db_session.commit()
Exemple #47
0
def login_callback():
    info = json.loads(session["info"])

    user = Users.query.filter_by(uid=info["id"]).first()

    # Signup
    if user == None:
        user = Users.query.filter_by(email=info["email"]).first()
        if user != None:
            if user.has_merged:
                user.access_token = base64.b64encode(os.urandom(16))
                user.creation_date = datetime.datetime.now()
                user.token_valid = True
                db_session.commit()
                return redirect(
                    session['referrer'] + "?" +
                    urllib.urlencode({"access_token": user.access_token}), 302)

            if session["platform"] == "facebook":
                return render_template("merge_option.html",
                                       facebook=info,
                                       google=user)
            elif session["platform"] == "google":
                return render_template("merge_option.html",
                                       facebook=user,
                                       google=info)

        user = Users(uid=info["id"],
                     email=info["email"],
                     name=info["name"],
                     picture=info["picture"],
                     platform=info["platform"])

        db_session.add(user)
        db_session.commit()

    # Login
    if not valid_token(user):
        # Renew token
        user.access_token = base64.b64encode(os.urandom(16))
        user.creation_date = datetime.datetime.now()
        user.token_valid = True
        db_session.commit()

    return redirect(
        session['referrer'] + "?" +
        urllib.urlencode({"access_token": user.access_token}), 302)
Exemple #48
0
def get_nearest_cafe(lat, lng):
    geo_json = get_cafe_json(lat, lng)
    if not geo_json:
        return
    cafes = []
    tags_and_cafes = {}
    for data in geo_json.get('results'):
        cafe = Cafe(name=data['name'],
                    lat=data['geometry']['location']['lat'],
                    lng=data['geometry']['location']['lng'],
                    rating=data.get('rating'),
                    address=data['vicinity'])
        saved_cafe = Cafe.query.filter(Cafe.lat == cafe.lat
                                       and Cafe.lng == cafe.lng).first()

        if saved_cafe:
            cafe = saved_cafe
        else:
            db_session.add(cafe)
            db_session.commit()

        cafes.append(cafe)
        for type_name in data.get('types'):
            tags_and_cafes.setdefault(type_name, [])
            tags_and_cafes[type_name].append(cafe.id)

    for tag_name in tags_and_cafes.keys():
        tag = Tag(tag_name=tag_name, localized_name='')
        db_session.add(tag)
        db_session.commit()
        for cafe_id in tags_and_cafes[tag_name]:
            tag_to_add = TagsForCafe(tag_id=tag.id, cafe_id=cafe_id)
            db_session.add(tag_to_add)

    db_session.commit()
    return cafes
Exemple #49
0
def submit():
    msg = request.form['msg']
    fh = request.files['fh']

    # Don't bother submitting anything if it was an "empty" submission. #878.
    if not (msg or fh):
        flash("You must enter a message or choose a file to submit.", "error")
        return redirect(url_for('lookup'))

    fnames = []
    journalist_filename = g.source.journalist_filename
    first_submission = g.source.interaction_count == 0

    if msg:
        g.source.interaction_count += 1
        fnames.append(
            store.save_message_submission(g.filesystem_id,
                                          g.source.interaction_count,
                                          journalist_filename, msg))
    if fh:
        g.source.interaction_count += 1
        fnames.append(
            store.save_file_submission(g.filesystem_id,
                                       g.source.interaction_count,
                                       journalist_filename, fh.filename,
                                       fh.stream))

    if first_submission:
        msg = render_template('first_submission_flashed_message.html')
        flash(Markup(msg), "success")

    else:
        if msg and not fh:
            things = 'message'
        elif not msg and fh:
            things = 'document'
        else:
            things = 'message and document'

        msg = render_template('next_submission_flashed_message.html',
                              things=things)
        flash(Markup(msg), "success")

    for fname in fnames:
        submission = Submission(g.source, fname)
        db_session.add(submission)

    if g.source.pending:
        g.source.pending = False

        # Generate a keypair now, if there's enough entropy (issue #303)
        entropy_avail = int(
            open('/proc/sys/kernel/random/entropy_avail').read())
        if entropy_avail >= 2400:
            async_genkey(g.filesystem_id, g.codename)

    g.source.last_updated = datetime.utcnow()
    db_session.commit()
    normalize_timestamps(g.filesystem_id)

    return redirect(url_for('lookup'))
Exemple #50
0
def delete(id):
  item = Items.query.filter(Items.id == id).one()
  db_session.delete(item)
  db_session.commit()
  return redirect(url_for('index'))
 def worker_bonus(self, chosen_hit, auto, amount, reason='',
                  assignment_ids=None):
     ''' Bonus worker '''
     if self.config.has_option('Shell Parameters', 'bonus_message'):
         reason = self.config.get('Shell Parameters', 'bonus_message')
     while not reason:
         user_input = raw_input("Type the reason for the bonus. Workers "
                                "will see this message: ")
         reason = user_input
     # Bonus already-bonused workers if the user explicitly lists their
     # assignment IDs
     override_status = True
     if chosen_hit:
         override_status = False
         workers = self.amt_services.get_workers("Approved", chosen_hit)
         if not workers:
             print "No approved workers for HIT", chosen_hit
             return
         print 'bonusing workers for HIT', chosen_hit
     elif len(assignment_ids) == 1:
         workers = [self.amt_services.get_worker(assignment_ids[0])]
         if not workers:
             print "No submissions found for requested assignment ID"    
             return
     else:
         workers = self.amt_services.get_workers("Approved")
         if not workers:
             print "No approved workers found."
             return
         workers = [worker for worker in workers if \
                           worker['assignmentId'] in assignment_ids]
     for worker in workers:
         assignment_id = worker['assignmentId']
         try:
             init_db()
             part = Participant.query.\
                    filter(Participant.assignmentid == assignment_id).\
                    filter(Participant.workerid == worker['workerId']).\
                    filter(Participant.endhit != None).\
                    one()
             if auto:
                 amount = part.bonus
             status = part.status
             if amount <= 0:
                 print "bonus amount <=$0, no bonus given for assignment", assignment_id
             elif status == 7 and not override_status:
                 print "bonus already awarded for assignment", assignment_id
             else:
                 success = self.amt_services.bonus_worker(assignment_id,
                                                          amount, reason)
                 if success:
                     print "gave bonus of $" + str(amount) + " for assignment " + \
                     assignment_id
                     part.status = 7
                     db_session.add(part)
                     db_session.commit()
                     db_session.remove()
                 else:
                     print "*** failed to bonus assignment", assignment_id
         except:
             print "*** failed to bonus assignment", assignment_id
Exemple #52
0
def admin_delete_user(user_id):
    user = Journalist.query.get(user_id)
    db_session.delete(user)
    db_session.commit()
    return redirect(url_for('admin_index'))
Exemple #53
0
def start_exp():
    """ Serves up the experiment applet. """
    if not ('hitId' in request.args and 'assignmentId' in request.args
            and 'workerId' in request.args):
        raise ExperimentError('hit_assign_worker_id_not_set_in_exp')
    hit_id = request.args['hitId']
    assignment_id = request.args['assignmentId']
    worker_id = request.args['workerId']
    mode = request.args['mode']
    app.logger.info("Accessing /exp: %(h)s %(a)s %(w)s " % {
        "h": hit_id,
        "a": assignment_id,
        "w": worker_id
    })
    if hit_id[:5] == "debug":
        debug_mode = True
    else:
        debug_mode = False

    # Check first to see if this hitId or assignmentId exists.  If so, check to
    # see if inExp is set
    matches = Participant.query.\
        filter(Participant.workerid == worker_id).\
        all()
    numrecs = len(matches)
    if numrecs == 0:
        # Choose condition and counterbalance
        subj_cond, subj_counter = get_random_condcount()

        worker_ip = "UNKNOWN" if not request.remote_addr else \
            request.remote_addr
        browser = "UNKNOWN" if not request.user_agent.browser else \
            request.user_agent.browser
        platform = "UNKNOWN" if not request.user_agent.platform else \
            request.user_agent.platform
        language = "UNKNOWN" if not request.user_agent.language else \
            request.user_agent.language

        # Set condition here and insert into database.
        participant_attributes = dict(assignmentid=assignment_id,
                                      workerid=worker_id,
                                      hitid=hit_id,
                                      cond=subj_cond,
                                      counterbalance=subj_counter,
                                      ipaddress=worker_ip,
                                      browser=browser,
                                      platform=platform,
                                      language=language)
        part = Participant(**participant_attributes)
        db_session.add(part)
        db_session.commit()

    else:
        # A couple possible problems here:
        # 1: They've already done an assignment, then we should tell them they
        #    can't do another one
        # 2: They've already worked on this assignment, and got too far to
        #    start over.
        # 3: They're in the database twice for the same assignment, that should
        #    never happen.
        # 4: They're returning and all is well.
        nrecords = 0
        for record in matches:
            other_assignment = False
            if record.assignmentid != assignment_id:
                other_assignment = True
            else:
                nrecords += 1
        if nrecords <= 1 and not other_assignment:
            part = matches[0]
            # In experiment (or later) can't restart at this point
            if part.status >= STARTED and not debug_mode:
                raise ExperimentError('already_started_exp')
        else:
            if nrecords > 1:
                app.logger.error("Error, hit/assignment appears in database \
                                 more than once (serious problem)")
                raise ExperimentError(
                    'hit_assign_appears_in_database_more_than_once')
            if other_assignment:
                raise ExperimentError('already_did_exp_hit')

    if mode == 'sandbox' or mode == 'live':
        # If everything goes ok here relatively safe to assume we can lookup
        # the ad.
        ad_id = get_ad_via_hitid(hit_id)
        if ad_id != "error":
            if mode == "sandbox":
                ad_server_location = 'https://sandbox.ad.psiturk.org/complete/'\
                    + str(ad_id)
            elif mode == "live":
                ad_server_location = 'https://ad.psiturk.org/complete/' +\
                str(ad_id)
        else:
            raise ExperimentError('hit_not_registered_with_ad_server')
    else:
        ad_server_location = '/complete'

    return render_template('exp.html',
                           uniqueId=part.uniqueid,
                           condition=part.cond,
                           counterbalance=part.counterbalance,
                           adServerLoc=ad_server_location,
                           mode=mode)
Exemple #54
0
def add_star(sid):
    make_star_true(sid)
    db_session.commit()
    return redirect(url_for('index'))
Exemple #55
0
def remove_star(sid):
    make_star_false(sid)
    db_session.commit()
    return redirect(url_for('index'))
Exemple #56
0
def col_star(cols_selected):
    for sid in cols_selected:
        make_star_true(sid)

    db_session.commit()
    return redirect(url_for('index'))
Exemple #57
0
def col_un_star(cols_selected):
    for source_id in cols_selected:
        make_star_false(source_id)

    db_session.commit()
    return redirect(url_for('index'))
Exemple #58
0
def flag():
    g.source.flagged = True
    db_session.commit()
    return render_template('flag.html',
                           sid=g.sid,
                           codename=g.source.journalist_designation)
Exemple #59
0
import csv
import datetime
from db import User, db_session, Post

posts_list=[]
u=User
with open('blog.csv', 'r' , encoding='utf-8' ) as f:
    fields = ['title', 'image', 'published','content','email','first_name','last_name']
    reader = csv.DictReader(f, fields, delimiter=';')
    for row in reader:
        row['published']=datetime.datetime.strptime(row['published'], '%d.%m.%y %H:%M')
        author=u.query.filter(User.email==row['email']).first()
        row['user_id']=author.id
        posts_list.append(row)

for post_data in posts_list:
    post=Post(post_data['title'],post_data['image'], post_data['published'],post_data['content'], post_data['user_id'])
    db_session.add(post)

db_session.commit()
Exemple #60
0
def _add_user(is_admin=False):  # pragma: no cover
    while True:
        username = raw_input('Username: '******'Password: '******'Confirm Password: '******'Your password is too long (maximum length {} characters). '
                  'Please pick a shorter '
                  'password.'.format(Journalist.MAX_PASSWORD_LEN))
            continue

        if len(password) < Journalist.MIN_PASSWORD_LEN:
            print('Error: Password needs to be at least {} characters.'.format(
                Journalist.MIN_PASSWORD_LEN
            ))
            continue

        if password == password_again:
            break
        print("Passwords didn't match!")

    hotp_input = raw_input('Will this user be using a YubiKey [HOTP]? (y/N): ')
    otp_secret = None
    if hotp_input.lower() in ('y', 'yes'):
        while True:
            otp_secret = raw_input(
                'Please configure your YubiKey and enter the secret: ')
            if otp_secret:
                break

    try:
        user = Journalist(username=username,
                          password=password,
                          is_admin=is_admin,
                          otp_secret=otp_secret)
        db_session.add(user)
        db_session.commit()
    except Exception as exc:
        db_session.rollback()
        if "UNIQUE constraint failed: journalists.username" in str(exc):
            print('ERROR: That username is already taken!')
        else:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            print(repr(traceback.format_exception(exc_type, exc_value,
                                                  exc_traceback)))
        return 1
    else:
        print('User "{}" successfully added'.format(username))
        if not otp_secret:
            # Print the QR code for FreeOTP/ Google Authenticator
            print('\nScan the QR code below with FreeOTP or Google '
                  'Authenticator:\n')
            uri = user.totp.provisioning_uri(username,
                                             issuer_name='SecureDrop')
            qr = qrcode.QRCode()
            qr.add_data(uri)
            qr.print_ascii(tty=sys.stdout.isatty())
            print('\nIf the barcode does not render correctly, try changing '
                  "your terminal's font (Monospace for Linux, Menlo for OS "
                  'X). If you are using iTerm on Mac OS X, you will need to '
                  'change the "Non-ASCII Font", which is your profile\'s Text '
                  "settings.\n\nCan't scan the barcode? Enter following "
                  'shared secret '
                  'manually:\n{}\n'.format(user.formatted_otp_secret))
        return 0