def edit_part_task(request):
    """Handles the ``parts/{pid}/timed-tasks/{tid}/edit`` URL, providing the UI
    and backend for editing an existing :class:`~wte.models.TimedTask` that
    belongs to a :class:`~wte.models.Part`.

    Requires that the user has "edit" rights on the
    :class:`~wte.models.Part`.
    """
    dbsession = DBSession()
    part = dbsession.query(Part).filter(
        Part.id == request.matchdict['pid']).first()
    task = dbsession.query(TimedTask).filter(
        TimedTask.id == request.matchdict['tid']).first()
    if part and task:
        if part.allow('edit', request.current_user):
            crumbs = create_part_crumbs(
                request, part,
                [{
                    'title': 'Timed Actions',
                    'url': request.route_url('part.timed_task', pid=part.id)
                }, {
                    'title': 'Edit',
                    'url': request.current_route_url
                }])
            if request.method == 'POST':
                try:
                    options = []
                    if task.name == 'change_status':
                        status = ['available', 'unavailable']
                        if part.type == 'module':
                            status.append('archived')
                        options.append(('target_status',
                                        formencode.validators.OneOf(status)))
                    params = EditTimedTaskSchema(options).to_python(
                        request.params, State(request=request))
                    dbsession = DBSession()
                    with transaction.manager:
                        dbsession.add(task)
                        task.timestamp = datetime.combine(
                            params['date'], params['time'])
                        if 'options' in params and params['options']:
                            task.options = params['options']
                            task.status = 'ready'
                    dbsession.add(part)
                    raise HTTPSeeOther(
                        request.route_url('part.timed_task', pid=part.id))
                except formencode.Invalid as e:
                    return {
                        'errors': e.error_dict,
                        'values': request.params,
                        'part': part,
                        'task': task,
                        'crumbs': crumbs,
                        'include_footer': True,
                        'help': ['user', 'teacher', 'timed_actions.html']
                    }
            return {
                'part': part,
                'task': task,
                'crumbs': crumbs,
                'include_footer': True,
                'help': ['user', 'teacher', 'timed_actions.html']
            }
        else:
            unauthorised_redirect(request)
    else:
        raise HTTPNotFound()
Esempio n. 2
0
def manage_alias_post_(request):
    form = request.web_input(username="")

    useralias.set(request.userid, define.get_sysname(form.username))
    raise HTTPSeeOther(location="/control")
Esempio n. 3
0
def logout(request):
    _ = request.translate
    if 'uid' in request.session:
        del request.session['uid']
        request.messages.info(_('Logged out.'))
    return HTTPSeeOther(location=request.route_url('home'))
Esempio n. 4
0
def control_unignoreuser_(request):
    form = request.web_input(username="")

    ignoreuser.remove(request.userid, define.get_userid_list(form.username))
    raise HTTPSeeOther(location="/manage/ignore")
Esempio n. 5
0
def manage_avatar_post_(request):
    form = request.web_input(image="", x1=0, y1=0, x2=0, y2=0)

    avatar.create(request.userid, form.x1, form.y1, form.x2, form.y2)
    raise HTTPSeeOther(location="/control")
Esempio n. 6
0
def verify_project_role(request):
    token_service = request.find_service(ITokenService, name="email")
    user_service = request.find_service(IUserService, context=None)

    def _error(message):
        request.session.flash(message, queue="error")
        return HTTPSeeOther(request.route_path("manage.projects"))

    try:
        token = request.params.get("token")
        data = token_service.loads(token)
    except TokenExpired:
        return _error(request._("Expired token: request a new project role invite"))
    except TokenInvalid:
        return _error(request._("Invalid token: request a new project role invite"))
    except TokenMissing:
        return _error(request._("Invalid token: no token supplied"))

    # Check whether this token is being used correctly
    if data.get("action") != "email-project-role-verify":
        return _error(request._("Invalid token: not a collaboration invitation token"))

    user = user_service.get_user(data.get("user_id"))
    if user != request.user:
        return _error(request._("Role invitation is not valid."))

    project = (
        request.db.query(Project).filter(Project.id == data.get("project_id")).one()
    )
    desired_role = data.get("desired_role")

    role_invite = (
        request.db.query(RoleInvitation)
        .filter(RoleInvitation.project == project)
        .filter(RoleInvitation.user == user)
        .one_or_none()
    )

    if not role_invite:
        return _error(request._("Role invitation no longer exists."))

    # Use the renderer to bring up a confirmation page
    # before adding as contributor
    if request.method == "GET":
        return {
            "project_name": project.name,
            "desired_role": desired_role,
        }
    elif request.method == "POST" and "decline" in request.POST:
        request.db.delete(role_invite)
        request.session.flash(
            request._(
                "Invitation for '${project_name}' is declined.",
                mapping={"project_name": project.name},
            ),
            queue="success",
        )
        return HTTPSeeOther(request.route_path("manage.projects"))

    request.db.add(Role(user=user, project=project, role_name=desired_role))
    request.db.delete(role_invite)
    request.db.add(
        JournalEntry(
            name=project.name,
            action=f"accepted {desired_role} {user.username}",
            submitted_by=request.user,
            submitted_from=request.remote_addr,
        )
    )
    project.record_event(
        tag="project:role:accepted",
        ip_address=request.remote_addr,
        additional={
            "submitted_by": request.user.username,
            "role_name": desired_role,
            "target_user": user.username,
        },
    )
    user.record_event(
        tag="account:role:accepted",
        ip_address=request.remote_addr,
        additional={
            "submitted_by": request.user.username,
            "project_name": project.name,
            "role_name": desired_role,
        },
    )

    owner_roles = (
        request.db.query(Role)
        .filter(Role.project == project)
        .filter(Role.role_name == "Owner")
        .all()
    )
    owner_users = {owner.user for owner in owner_roles}

    # Don't send email to new user if they are now an owner
    owner_users.discard(user)

    submitter_user = user_service.get_user(data.get("submitter_id"))
    send_collaborator_added_email(
        request,
        owner_users,
        user=user,
        submitter=submitter_user,
        project_name=project.name,
        role=desired_role,
    )

    send_added_as_collaborator_email(
        request,
        user,
        submitter=submitter_user,
        project_name=project.name,
        role=desired_role,
    )

    request.session.flash(
        request._(
            "You are now ${role} of the '${project_name}' project.",
            mapping={"project_name": project.name, "role": desired_role},
        ),
        queue="success",
    )

    if desired_role == "Owner":
        return HTTPSeeOther(
            request.route_path("manage.project.roles", project_name=project.name)
        )
    else:
        return HTTPSeeOther(request.route_path("packaging.project", name=project.name))
Esempio n. 7
0
def control_createfolder_(request):
    form = request.web_input(title="", parentid="")

    folder.create(request.userid, form)
    raise HTTPSeeOther(location="/manage/folders")
Esempio n. 8
0
def signin_post_(request):
    form = request.web_input(username="",
                             password="",
                             referer="",
                             sfwmode="nsfw")
    form.referer = form.referer or '/'

    logid, logerror = login.authenticate_bcrypt(form.username, form.password)

    if logid and logerror == 'unicode-failure':
        raise HTTPSeeOther(location='/signin/unicode-failure')
    elif logid and logerror is None:
        if form.sfwmode == "sfw":
            request.set_cookie_on_response("sfwmode", "sfw", 31536000)
        # Invalidate cached versions of the frontpage to respect the possibly changed SFW settings.
        index.template_fields.invalidate(logid)
        raise HTTPSeeOther(location=form.referer)
    elif logid and logerror == "2fa":
        # Password authentication passed, but user has 2FA set, so verify second factor (Also set SFW mode now)
        if form.sfwmode == "sfw":
            request.set_cookie_on_response("sfwmode", "sfw", 31536000)
        index.template_fields.invalidate(logid)
        # Check if out of recovery codes; this should *never* execute normally, save for crafted
        #   webtests. However, check for it and log an error to Sentry if it happens.
        remaining_recovery_codes = two_factor_auth.get_number_of_recovery_codes(
            logid)
        if remaining_recovery_codes == 0:
            raise RuntimeError(
                "Two-factor Authentication: Count of recovery codes for userid "
                + str(logid) +
                " was zero upon password authentication succeeding, " +
                "which should be impossible.")
        # Store the authenticated userid & password auth time to the session
        sess = define.get_weasyl_session()
        # The timestamp at which password authentication succeeded
        sess.additional_data['2fa_pwd_auth_timestamp'] = arrow.now().timestamp
        # The userid of the user attempting authentication
        sess.additional_data['2fa_pwd_auth_userid'] = logid
        # The number of times the user has attempted to authenticate via 2FA
        sess.additional_data['2fa_pwd_auth_attempts'] = 0
        sess.save = True
        return Response(
            define.webpage(request.userid,
                           "etc/signin_2fa_auth.html", [
                               define.get_display_name(logid), form.referer,
                               remaining_recovery_codes, None
                           ],
                           title="Sign In - 2FA"))
    elif logerror == "invalid":
        return Response(
            define.webpage(request.userid, "etc/signin.html",
                           [True, form.referer]))
    elif logerror == "banned":
        reason = moderation.get_ban_reason(logid)
        return Response(
            define.errorpage(
                request.userid,
                "Your account has been permanently banned and you are no longer allowed "
                "to sign in.\n\n%s\n\nIf you believe this ban is in error, please "
                "contact [email protected] for assistance." % (reason, )))
    elif logerror == "suspended":
        suspension = moderation.get_suspension(logid)
        return Response(
            define.errorpage(
                request.userid,
                "Your account has been temporarily suspended and you are not allowed to "
                "be logged in at this time.\n\n%s\n\nThis suspension will be lifted on "
                "%s.\n\nIf you believe this suspension is in error, please contact "
                "[email protected] for assistance." %
                (suspension.reason, define.convert_date(suspension.release))))
    elif logerror == "address":
        return Response("IP ADDRESS TEMPORARILY BLOCKED")

    return Response(define.errorpage(request.userid))
Esempio n. 9
0
def add_blacklist(request):
    project_name = request.POST.get("project")
    if project_name is None:
        raise HTTPBadRequest("Must have a project to confirm.")
    comment = request.POST.get("comment", "")

    # Verify that the user has confirmed the request to blacklist.
    confirm = request.POST.get("confirm")
    if not confirm:
        request.session.flash(
            "Must confirm the blacklist request.",
            queue="error",
        )
        return HTTPSeeOther(request.current_route_path())
    elif canonicalize_name(confirm) != canonicalize_name(project_name):
        request.session.flash(
            f"{confirm!r} is not the same as {project_name!r}",
            queue="error",
        )
        return HTTPSeeOther(request.current_route_path())

    # Add our requested blacklist.
    request.db.add(
        BlacklistedProject(
            name=project_name,
            comment=comment,
            blacklisted_by=request.user,
        ))

    # Go through and delete anything that we need to delete so that our
    # blacklist actually blocks things and isn't ignored (since the blacklist
    # only takes effect on new project registration).
    # TODO: This should be in a generic function somewhere instead of putting
    #       it here, however this will have to do for now.
    # TODO: We don't actually delete files from the data store. We should add
    #       some kind of garbage collection at some point.
    project = (request.db.query(Project).filter(
        Project.normalized_name == func.normalize_pep426_name(
            project_name)).first())
    if project is not None:
        request.db.add(
            JournalEntry(
                name=project.name,
                action="remove",
                submitted_by=request.user,
                submitted_from=request.remote_addr,
            ))
        request.db.query(Role).filter(Role.project == project).delete()
        request.db.query(File).filter(File.name == project.name).delete()
        (request.db.query(Dependency).filter(
            Dependency.name == project.name).delete())
        (request.db.execute(release_classifiers.delete().where(
            release_classifiers.c.name == project.name)))
        request.db.query(Release).filter(Release.name == project.name).delete()
        request.db.query(Project).filter(Project.name == project.name).delete()

    request.session.flash(
        f"Successfully blacklisted {project_name!r}",
        queue="success",
    )

    return HTTPSeeOther(request.route_path("admin.blacklist.list"))
Esempio n. 10
0
def delete_project(project, request):
    confirm_project(project, request, fail_route="manage.project.settings")
    remove_project(project, request)

    return HTTPSeeOther(request.route_path("manage.projects"))
Esempio n. 11
0
def change_project_role(project, request, _form_class=ChangeRoleForm):
    # TODO: This view was modified to handle deleting multiple roles for a
    # single user and should be updated when fixing GH-2745

    form = _form_class(request.POST)

    if form.validate():
        role_ids = request.POST.getall("role_id")

        if len(role_ids) > 1:
            # This user has more than one role, so just delete all the ones
            # that aren't what we want.
            #
            # TODO: This branch should be removed when fixing GH-2745.
            roles = (request.db.query(Role).filter(
                Role.id.in_(role_ids),
                Role.project == project,
                Role.role_name != form.role_name.data,
            ).all())
            removing_self = any(
                role.role_name == "Owner" and role.user == request.user
                for role in roles)
            if removing_self:
                request.session.flash("Cannot remove yourself as Owner",
                                      queue="error")
            else:
                for role in roles:
                    request.db.delete(role)
                    request.db.add(
                        JournalEntry(
                            name=project.name,
                            action=f"remove {role.role_name} {role.user_name}",
                            submitted_by=request.user,
                            submitted_from=request.remote_addr,
                        ))
                request.session.flash("Changed role", queue="success")
        else:
            # This user only has one role, so get it and change the type.
            try:
                role = (request.db.query(Role).filter(
                    Role.id == request.POST.get("role_id"),
                    Role.project == project).one())
                if role.role_name == "Owner" and role.user == request.user:
                    request.session.flash("Cannot remove yourself as Owner",
                                          queue="error")
                else:
                    request.db.add(
                        JournalEntry(
                            name=project.name,
                            action="change {} {} to {}".format(
                                role.role_name, role.user_name,
                                form.role_name.data),
                            submitted_by=request.user,
                            submitted_from=request.remote_addr,
                        ))
                    role.role_name = form.role_name.data
                    request.session.flash("Changed role", queue="success")
            except NoResultFound:
                request.session.flash("Could not find role", queue="error")

    return HTTPSeeOther(
        request.route_path("manage.project.roles", project_name=project.name))
Esempio n. 12
0
def modcontrol_closereport_(request):
    form = request.web_input(reportid='', action='')
    report.close(request.userid, form)
    raise HTTPSeeOther(location="/modcontrol/report?reportid=%d" %
                       (int(form.reportid), ))
Esempio n. 13
0
def modcontrol_editcatchphrase_(request):
    form = request.web_input(userid="", content="")

    moderation.editcatchphrase(request.userid, define.get_int(form.userid),
                               form.content)
    raise HTTPSeeOther(location="/modcontrol")
Esempio n. 14
0
def modcontrol_removebanner_(request):
    form = request.web_input(userid="")

    moderation.removebanner(request.userid, define.get_int(form.userid))
    raise HTTPSeeOther(location="/modcontrol")
Esempio n. 15
0
 def _error(message):
     request.session.flash(message, queue="error")
     return HTTPSeeOther(request.route_path("accounts.request-password-reset"))
Esempio n. 16
0
def view_wiki(context, request):
    return HTTPSeeOther(location=request.resource_url(context, 'FrontPage'))
Esempio n. 17
0
def verify_email(request):
    token_service = request.find_service(ITokenService, name="email")
    email_limiter = request.find_service(IRateLimiter, name="email.add")

    def _error(message):
        request.session.flash(message, queue="error")
        return HTTPSeeOther(request.route_path("manage.account"))

    try:
        token = request.params.get("token")
        data = token_service.loads(token)
    except TokenExpired:
        return _error(request._("Expired token: request a new email verification link"))
    except TokenInvalid:
        return _error(request._("Invalid token: request a new email verification link"))
    except TokenMissing:
        return _error(request._("Invalid token: no token supplied"))

    # Check whether this token is being used correctly
    if data.get("action") != "email-verify":
        return _error(request._("Invalid token: not an email verification token"))

    try:
        email = (
            request.db.query(Email)
            .filter(Email.id == data["email.id"], Email.user == request.user)
            .one()
        )
    except NoResultFound:
        return _error(request._("Email not found"))

    if email.verified:
        return _error(request._("Email already verified"))

    email.verified = True
    email.unverify_reason = None
    email.transient_bounces = 0
    email.user.record_event(
        tag="account:email:verified",
        ip_address=request.remote_addr,
        additional={"email": email.email, "primary": email.primary},
    )

    # Reset the email-adding rate limiter for this IP address
    email_limiter.clear(request.remote_addr)

    if not email.primary:
        confirm_message = request._(
            "You can now set this email as your primary address"
        )
    else:
        confirm_message = request._("This is your primary address")

    request.user.is_active = True

    request.session.flash(
        request._(
            "Email address ${email_address} verified. ${confirm_message}.",
            mapping={"email_address": email.email, "confirm_message": confirm_message},
        ),
        queue="success",
    )
    return HTTPSeeOther(request.route_path("manage.account"))
Esempio n. 18
0
def control_removecommishclass_(request):
    form = request.web_input(classid="")

    commishinfo.remove_class(request.userid, form.classid)
    raise HTTPSeeOther(location="/control/editcommissionsettings")
Esempio n. 19
0
 def _error(message):
     request.session.flash(message, queue="error")
     return HTTPSeeOther(request.route_path("manage.projects"))
Esempio n. 20
0
def control_removecommishprice_(request):
    form = request.web_input(priceid="")

    commishinfo.remove_price(request.userid, form.priceid)
    raise HTTPSeeOther(location="/control/editcommissionsettings")
Esempio n. 21
0
def control_renamefolder_(request):
    form = request.web_input(folderid="", title="")

    if define.get_int(form.folderid):
        folder.rename(request.userid, form)
    raise HTTPSeeOther(location="/manage/folders")
Esempio n. 22
0
def delete_project(project, request):
    confirm_project(project, request, fail_route="admin.project.detail")
    remove_project(project, request)

    return HTTPSeeOther(request.route_path('admin.project.list'))
Esempio n. 23
0
def control_tagrestrictions_post_(request):
    tags = searchtag.parse_restricted_tags(request.params["tags"])
    searchtag.edit_user_tag_restrictions(request.userid, tags)

    raise HTTPSeeOther(location=request.route_path('control_tagrestrictions'))
Esempio n. 24
0
def view_wiki(request):
    next_url = request.route_url('view_page', pagename='FrontPage')
    return HTTPSeeOther(location=next_url)
Esempio n. 25
0
def manage_banner_post_(request):
    form = request.web_input(image="")

    banner.upload(request.userid, form.image)
    raise HTTPSeeOther(location="/control")
Esempio n. 26
0
def login(request, redirect_field_name=REDIRECT_FIELD_NAME, _form_class=LoginForm):
    # TODO: Logging in should reset request.user
    # TODO: Configure the login view as the default view for not having
    #       permission to view something.
    if request.authenticated_userid is not None:
        return HTTPSeeOther(request.route_path("manage.projects"))

    user_service = request.find_service(IUserService, context=None)
    breach_service = request.find_service(IPasswordBreachedService, context=None)

    redirect_to = request.POST.get(
        redirect_field_name, request.GET.get(redirect_field_name)
    )

    form = _form_class(
        request.POST,
        request=request,
        user_service=user_service,
        breach_service=breach_service,
        check_password_metrics_tags=["method:auth", "auth_method:login_form"],
    )

    if request.method == "POST":
        if form.validate():
            # Get the user id for the given username.
            username = form.username.data
            userid = user_service.find_userid(username)

            # If the user has enabled two factor authentication.
            if user_service.has_two_factor(userid):
                two_factor_data = {"userid": userid}
                if redirect_to:
                    two_factor_data["redirect_to"] = redirect_to

                token_service = request.find_service(ITokenService, name="two_factor")
                token = token_service.dumps(two_factor_data)

                # Stuff our token in the query and redirect to two-factor page.
                resp = HTTPSeeOther(
                    request.route_path("accounts.two-factor", _query=token)
                )
                return resp
            else:
                # If the user-originating redirection url is not safe, then
                # redirect to the index instead.
                if not redirect_to or not is_safe_url(
                    url=redirect_to, host=request.host
                ):
                    redirect_to = request.route_path("manage.projects")

                # Actually perform the login routine for our user.
                headers = _login_user(request, userid)

                # Now that we're logged in we'll want to redirect the user to
                # either where they were trying to go originally, or to the default
                # view.
                resp = HTTPSeeOther(redirect_to, headers=dict(headers))

                # We'll use this cookie so that client side javascript can
                # Determine the actual user ID (not username, user ID). This is
                # *not* a security sensitive context and it *MUST* not be used
                # where security matters.
                #
                # We'll also hash this value just to avoid leaking the actual User
                # IDs here, even though it really shouldn't matter.
                resp.set_cookie(
                    USER_ID_INSECURE_COOKIE,
                    hashlib.blake2b(
                        str(userid).encode("ascii"), person=b"warehouse.userid"
                    )
                    .hexdigest()
                    .lower(),
                )

            return resp

    return {
        "form": form,
        "redirect": {"field": REDIRECT_FIELD_NAME, "data": redirect_to},
    }
Esempio n. 27
0
def home_view(request):
    """The main view on a discussion"""
    user_id = authenticated_userid(request) or Everyone
    context = get_default_context(request)
    discussion = context["discussion"]
    canRead = user_has_permission(discussion.id, user_id, P_READ)
    if not canRead and user_id == Everyone:
        # User isn't logged-in and discussion isn't public:
        # redirect to login page
        # need to pass the route to go to *after* login as well

        # With regards to a next_view, if explicitly stated, then
        # that is the next view. If not stated, the referer takes
        # precedence. In case of failure, login redirects to the
        # discussion which is its context.
        next_view = request.params.get('next', None)
        if not next_view and discussion:
            # If referred here from a post url, want to be able to
            # send the user back. Usually, Assembl will send the user
            # here to login on private discussions.
            referrer = request.url
            next_view = path_qs(referrer)

        login_url = get_social_autologin(request, discussion, next_view)
        if login_url:
            pass
        elif next_view:
            login_url = request.route_url("contextual_login",
                                          discussion_slug=discussion.slug,
                                          _query={"next": next_view})
        else:
            login_url = request.route_url('contextual_login',
                                          discussion_slug=discussion.slug)
        return HTTPTemporaryRedirect(login_url)
    elif not canRead:
        # User is logged-in but doesn't have access to the discussion
        # Would use render_to_response, except for the 401
        from pyramid_jinja2 import IJinja2Environment
        jinja_env = request.registry.queryUtility(IJinja2Environment,
                                                  name='.jinja2')
        template = jinja_env.get_template('cannot_read_discussion.jinja2')
        body = template.render(get_default_context(request))
        return Response(body, 401)

    # if the route asks for a post, get post content (because this is needed for meta tags)
    route_name = request.matched_route.name
    if route_name == "purl_posts":
        post_id = FrontendUrls.getRequestedPostId(request)
        if not post_id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        post = Post.get_instance(post_id)
        if not post or post.discussion_id != discussion.id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        context['post'] = post
    elif route_name == "purl_idea":
        idea_id = FrontendUrls.getRequestedIdeaId(request)
        if not idea_id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        idea = Idea.get_instance(idea_id)
        if not idea or idea.discussion_id != discussion.id:
            return HTTPSeeOther(
                request.route_url('home', discussion_slug=discussion.slug))
        context['idea'] = idea

    canAddExtract = user_has_permission(discussion.id, user_id, P_ADD_EXTRACT)
    context['canAddExtract'] = canAddExtract
    context['canDisplayTabs'] = True
    preferences = discussion.preferences
    session = discussion.db
    if user_id != Everyone:
        from assembl.models import UserPreferenceCollection
        # TODO: user may not exist. Case of session with BD change.
        user = User.get(user_id)
        preferences = UserPreferenceCollection(user_id, discussion)
        target_locale = get_locale_from_request(request, session, user)
        user.is_visiting_discussion(discussion.id)
    else:
        target_locale = get_locale_from_request(request, session)

    translation_service_data = {}
    try:
        service = discussion.translation_service()
        if service:
            translation_service_data = service.serviceData()
    except:
        pass
    context['translation_service_data_json'] = json.dumps(
        translation_service_data)
    locale_labels = json.dumps(
        DummyGoogleTranslationService.target_locale_labels_cls(target_locale))
    context['translation_locale_names_json'] = locale_labels

    context['preferences_json'] = json.dumps(dict(preferences))
    role_names = [x for (x) in session.query(Role.name).all()]
    context['role_names'] = json.dumps(role_names)

    response = render_to_response('../../templates/index.jinja2',
                                  context,
                                  request=request)
    # Prevent caching the home, especially for proper login/logout
    response.cache_control.max_age = 0
    response.cache_control.prevent_auto = True
    return response
Esempio n. 28
0
def reset_password(request, _form_class=ResetPasswordForm):
    if request.authenticated_userid is not None:
        return HTTPSeeOther(request.route_path("index"))

    user_service = request.find_service(IUserService, context=None)
    breach_service = request.find_service(IPasswordBreachedService, context=None)
    token_service = request.find_service(ITokenService, name="password")

    def _error(message):
        request.session.flash(message, queue="error")
        return HTTPSeeOther(request.route_path("accounts.request-password-reset"))

    try:
        token = request.params.get("token")
        data = token_service.loads(token)
    except TokenExpired:
        return _error(request._("Expired token: request a new password reset link"))
    except TokenInvalid:
        return _error(request._("Invalid token: request a new password reset link"))
    except TokenMissing:
        return _error(request._("Invalid token: no token supplied"))

    # Check whether this token is being used correctly
    if data.get("action") != "password-reset":
        return _error(request._("Invalid token: not a password reset token"))

    # Check whether a user with the given user ID exists
    user = user_service.get_user(uuid.UUID(data.get("user.id")))
    if user is None:
        return _error(request._("Invalid token: user not found"))

    # Check whether the user has logged in since the token was created
    last_login = data.get("user.last_login")
    if str(user.last_login) > last_login:
        # TODO: track and audit this, seems alertable
        return _error(
            request._(
                "Invalid token: user has logged in since this token was requested"
            )
        )

    # Check whether the password has been changed since the token was created
    password_date = data.get("user.password_date")
    if str(user.password_date) > password_date:
        return _error(
            request._(
                "Invalid token: password has already been changed since this "
                "token was requested"
            )
        )

    form = _form_class(
        **request.params,
        username=user.username,
        full_name=user.name,
        email=user.email,
        user_service=user_service,
        breach_service=breach_service,
    )

    if request.method == "POST" and form.validate():
        password_reset_limiter = request.find_service(
            IRateLimiter, name="password.reset"
        )
        # Update password.
        user_service.update_user(user.id, password=form.new_password.data)
        user_service.record_event(
            user.id, tag="account:password:reset", ip_address=request.remote_addr
        )
        password_reset_limiter.clear(user.id)

        # Send password change email
        send_password_change_email(request, user)

        # Flash a success message
        request.session.flash(
            request._("You have reset your password"), queue="success"
        )

        # Redirect to account login.
        return HTTPSeeOther(request.route_path("accounts.login"))

    return {"form": form}
Esempio n. 29
0
def client_issue_new(ctx, req):
    loc = req.localizer
    cfg = req.registry.settings
    if not asbool(cfg.get('netprofile.client.ticket.enabled', True)):
        raise HTTPForbidden(detail=_('Issues view is disabled'))
    origin_id = int(cfg.get('netprofile.client.ticket.origin_id', 0))
    user_id = int(cfg.get('netprofile.client.ticket.assign_uid', 0))
    group_id = int(cfg.get('netprofile.client.ticket.assign_gid', 0))
    errors = {}
    sess = DBSession()
    ent = req.user.parent
    states = sess.query(TicketState)\
     .filter(TicketState.is_start == True, TicketState.allow_client == True)
    if 'submit' in req.POST:
        csrf = req.POST.get('csrf', '')
        name = req.POST.get('name', '')
        descr = req.POST.get('descr', '')
        state = int(req.POST.get('state', 0))
        if csrf != req.get_csrf():
            errors['csrf'] = _a('Error submitting form')
        else:
            l = len(name)
            if (l == 0) or (l > 254):
                errors['name'] = _a('Invalid field length')
            for s in states:
                if s.id == state:
                    state = s
                    break
            else:
                errors['state'] = _('Invalid issue type')
        if len(errors) == 0:
            tkt = Ticket()
            tkt.name = name
            tkt.state = state
            tkt.entity = ent
            tkt.show_client = True
            if descr:
                tkt.description = descr
            if origin_id:
                tkt.origin_id = origin_id
            if user_id:
                tkt.assigned_user_id = user_id
            if group_id:
                tkt.assigned_group_id = group_id
            sess.add(tkt)
            sess.flush()

            req.session.flash(
                {'text': loc.translate(_('New issue successfully created'))})
            return HTTPSeeOther(location=req.route_url(
                'tickets.cl.issues', traverse=(tkt.id, 'view')))
    tpldef = {
        'states':
        states,
        'crumbs': [{
            'text': loc.translate(_('My Issues')),
            'url': req.route_url('tickets.cl.issues', traverse=())
        }, {
            'text': loc.translate(_('New Issue'))
        }],
        'errors': {err: loc.translate(errors[err])
                   for err in errors}
    }
    req.run_hook('access.cl.tpldef', tpldef, req)
    req.run_hook('access.cl.tpldef.issue.new', tpldef, req)
    return tpldef
Esempio n. 30
0
def login(request,
          redirect_field_name=REDIRECT_FIELD_NAME,
          _form_class=LoginForm):
    # TODO: Logging in should reset request.user
    # TODO: Configure the login view as the default view for not having
    #       permission to view something.
    if request.authenticated_userid is not None:
        return HTTPSeeOther(request.route_path("manage.projects"))

    user_service = request.find_service(IUserService, context=None)

    redirect_to = request.POST.get(redirect_field_name,
                                   request.GET.get(redirect_field_name))

    form = _form_class(request.POST, user_service=user_service)

    if request.method == "POST":
        request.registry.datadog.increment("warehouse.authentication.start",
                                           tags=["auth_method:login_form"])
        if form.validate():
            # Get the user id for the given username.
            username = form.username.data
            userid = user_service.find_userid(username)

            # If the user-originating redirection url is not safe, then
            # redirect to the index instead.
            if not redirect_to or not is_safe_url(url=redirect_to,
                                                  host=request.host):
                redirect_to = request.route_path("manage.projects")

            # Actually perform the login routine for our user.
            headers = _login_user(request, userid)

            # Now that we're logged in we'll want to redirect the user to
            # either where they were trying to go originally, or to the default
            # view.
            resp = HTTPSeeOther(redirect_to, headers=dict(headers))

            # We'll use this cookie so that client side javascript can
            # Determine the actual user ID (not username, user ID). This is
            # *not* a security sensitive context and it *MUST* not be used
            # where security matters.
            #
            # We'll also hash this value just to avoid leaking the actual User
            # IDs here, even though it really shouldn't matter.
            resp.set_cookie(
                USER_ID_INSECURE_COOKIE,
                hashlib.blake2b(
                    str(userid).encode("ascii"),
                    person=b"warehouse.userid").hexdigest().lower(),
            )

            request.registry.datadog.increment(
                "warehouse.authentication.complete",
                tags=["auth_method:login_form"])
            return resp
        else:
            request.registry.datadog.increment(
                "warehouse.authentication.failure",
                tags=["auth_method:login_form"])

    return {
        "form": form,
        "redirect": {
            "field": REDIRECT_FIELD_NAME,
            "data": redirect_to
        },
    }