Beispiel #1
0
    def clean(self) -> Dict[str, Any]:
        username = self.cleaned_data.get("username")
        password = self.cleaned_data.get("password")

        if username is not None and password:
            subdomain = get_subdomain(self.request)
            realm = get_realm(subdomain)

            return_data: Dict[str, Any] = {}
            try:
                self.user_cache = authenticate(
                    request=self.request,
                    username=username,
                    password=password,
                    realm=realm,
                    return_data=return_data,
                )
            except RateLimited as e:
                assert e.secs_to_freedom is not None
                secs_to_freedom = int(e.secs_to_freedom)
                raise ValidationError(
                    AUTHENTICATION_RATE_LIMITED_ERROR.format(secs_to_freedom))

            if return_data.get("inactive_realm"):
                raise AssertionError(
                    "Programming error: inactive realm in authentication form")

            if return_data.get("password_reset_needed"):
                raise ValidationError(mark_safe(PASSWORD_RESET_NEEDED_ERROR))

            if return_data.get("inactive_user"
                               ) and not return_data.get("is_mirror_dummy"):
                # We exclude mirror dummy accounts here. They should be treated as the
                # user never having had an account, so we let them fall through to the
                # normal invalid_login case below.
                error_message = DEACTIVATED_ACCOUNT_ERROR.format(
                    username=username)
                raise ValidationError(mark_safe(error_message))

            if return_data.get("invalid_subdomain"):
                logging.warning(
                    "User %s attempted password login to wrong subdomain %s",
                    username, subdomain)
                error_message = WRONG_SUBDOMAIN_ERROR.format(username=username)
                raise ValidationError(mark_safe(error_message))

            if self.user_cache is None:
                raise forms.ValidationError(
                    self.error_messages["invalid_login"],
                    code="invalid_login",
                    params={"username": self.username_field.verbose_name},
                )

            self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data
Beispiel #2
0
def remote_installation_stats_link(server_id: int, hostname: str) -> mark_safe:
    from analytics.views.stats import stats_for_remote_installation

    url = reverse(stats_for_remote_installation,
                  kwargs=dict(remote_server_id=server_id))
    stats_link = f'<a href="{escape(url)}"><i class="fa fa-pie-chart"></i>{escape(hostname)}</a>'
    return mark_safe(stats_link)
Beispiel #3
0
def user_activity_link(email: str, user_profile_id: int) -> mark_safe:
    from analytics.views.user_activity import get_user_activity

    url = reverse(get_user_activity,
                  kwargs=dict(user_profile_id=user_profile_id))
    email_link = f'<a href="{escape(url)}">{escape(email)}</a>'
    return mark_safe(email_link)
Beispiel #4
0
    def clean_password(self) -> str:
        password = self.cleaned_data["password"]
        if self.fields["password"].required and not check_password_strength(
                password):
            # The frontend code tries to stop the user from submitting the form with a weak password,
            # but if the user bypasses that protection, this error code path will run.
            raise ValidationError(mark_safe(PASSWORD_TOO_WEAK_ERROR))

        return password
Beispiel #5
0
def email_is_not_mit_mailing_list(email: str) -> None:
    """Prevent MIT mailing lists from signing up for Zulip"""
    if "@mit.edu" in email:
        username = email.rsplit("@", 1)[0]
        # Check whether the user exists and can get mail.
        try:
            DNS.dnslookup(f"{username}.pobox.ns.athena.mit.edu", DNS.Type.TXT)
        except DNS.Base.ServerError as e:
            if e.rcode == DNS.Status.NXDOMAIN:
                raise ValidationError(mark_safe(MIT_VALIDATION_ERROR))
            else:
                raise AssertionError("Unexpected DNS error")
def user_activity_intervals() -> Tuple[mark_safe, Dict[str, float]]:
    day_end = timestamp_to_datetime(time.time())
    day_start = day_end - timedelta(hours=24)

    output = "Per-user online duration for the last 24 hours:\n"
    total_duration = timedelta(0)

    all_intervals = (UserActivityInterval.objects.filter(
        end__gte=day_start,
        start__lte=day_end,
    ).select_related(
        "user_profile",
        "user_profile__realm",
    ).only(
        "start",
        "end",
        "user_profile__delivery_email",
        "user_profile__realm__string_id",
    ).order_by(
        "user_profile__realm__string_id",
        "user_profile__delivery_email",
    ))

    by_string_id = lambda row: row.user_profile.realm.string_id
    by_email = lambda row: row.user_profile.delivery_email

    realm_minutes = {}

    for string_id, realm_intervals in itertools.groupby(
            all_intervals, by_string_id):
        realm_duration = timedelta(0)
        output += f"<hr>{string_id}\n"
        for email, intervals in itertools.groupby(realm_intervals, by_email):
            duration = timedelta(0)
            for interval in intervals:
                start = max(day_start, interval.start)
                end = min(day_end, interval.end)
                duration += end - start

            total_duration += duration
            realm_duration += duration
            output += f"  {email:<37}{duration}\n"

        realm_minutes[string_id] = realm_duration.total_seconds() / 60

    output += f"\nTotal duration:                      {total_duration}\n"
    output += f"\nTotal duration in minutes:           {total_duration.total_seconds() / 60.}\n"
    output += f"Total duration amortized to a month: {total_duration.total_seconds() * 30. / 60.}"
    content = mark_safe("<pre>" + output + "</pre>")
    return content, realm_minutes
Beispiel #7
0
def sanitize_name(value: str) -> str:
    """
    Sanitizes a value to be safe to store in a Linux filesystem, in
    S3, and in a URL.  So Unicode is allowed, but not special
    characters other than ".", "-", and "_".

    This implementation is based on django.utils.text.slugify; it is
    modified by:
    * adding '.' to the list of allowed characters.
    * preserving the case of the value.
    * not stripping trailing dashes and underscores.
    """
    value = unicodedata.normalize("NFKC", value)
    value = re.sub(r"[^\w\s.-]", "", value, flags=re.U).strip()
    value = re.sub(r"[-\s]+", "-", value, flags=re.U)
    assert value not in {"", ".", ".."}
    return mark_safe(value)
Beispiel #8
0
def update_login_page_context(request: HttpRequest, context: Dict[str, Any]) -> None:
    for key in ("email", "already_registered"):
        try:
            context[key] = request.GET[key]
        except KeyError:
            pass

    deactivated_email = request.GET.get("is_deactivated")
    if deactivated_email is None:
        return
    try:
        validate_email(deactivated_email)
        context["deactivated_account_error"] = mark_safe(
            DEACTIVATED_ACCOUNT_ERROR.format(username=escape(deactivated_email))
        )
    except ValidationError:
        logging.info("Invalid email in is_deactivated param to login page: %s", deactivated_email)
Beispiel #9
0
def realm_stats_link(realm_str: str) -> mark_safe:
    from analytics.views.stats import stats_for_realm

    url = reverse(stats_for_realm, kwargs=dict(realm_str=realm_str))
    stats_link = f'<a href="{escape(url)}"><i class="fa fa-pie-chart"></i>{escape(realm_str)}</a>'
    return mark_safe(stats_link)
Beispiel #10
0
def realm_activity_link(realm_str: str) -> mark_safe:
    from analytics.views.realm_activity import get_realm_activity

    url = reverse(get_realm_activity, kwargs=dict(realm_str=realm_str))
    realm_link = f'<a href="{escape(url)}">{escape(realm_str)}</a>'
    return mark_safe(realm_link)