Example #1
0
    public static async Task VerifyAvatarOrThrow(HttpClient client, string url, bool isFullSizeImage = false)
    {
        if (url.Length > Limits.MaxUriLength)
        {
            throw Errors.UrlTooLong(url);
        }

        // List of MIME types we consider acceptable
        var acceptableMimeTypes = new[]
        {
            "image/jpeg", "image/gif", "image/png"
            // TODO: add image/webp once ImageSharp supports this
        };

        if (!PluralKit.Core.MiscUtils.TryMatchUri(url, out var uri))
        {
            throw Errors.InvalidUrl(url);
        }

        url = TryRewriteCdnUrl(url);

        var response = await client.GetAsync(url);

        if (!response.IsSuccessStatusCode) // Check status code
        {
            throw Errors.AvatarServerError(response.StatusCode);
        }
        if (response.Content.Headers.ContentLength == null) // Check presence of content length
        {
            throw Errors.AvatarNotAnImage(null);
        }
        if (!acceptableMimeTypes.Contains(response.Content.Headers.ContentType.MediaType)) // Check MIME type
        {
            throw Errors.AvatarNotAnImage(response.Content.Headers.ContentType.MediaType);
        }

        if (isFullSizeImage)
        {
            // no need to do size checking on banners
            return;
        }

        if (response.Content.Headers.ContentLength > Limits.AvatarFileSizeLimit) // Check content length
        {
            throw Errors.AvatarFileSizeLimit(response.Content.Headers.ContentLength.Value);
        }

        // Parse the image header in a worker
        var stream = await response.Content.ReadAsStreamAsync();

        var image = await Task.Run(() => Image.Identify(stream));

        if (image == null)
        {
            throw Errors.AvatarInvalid;
        }
        if (image.Width > Limits.AvatarDimensionLimit ||
            image.Height > Limits.AvatarDimensionLimit) // Check image size
        {
            throw Errors.AvatarDimensionsTooLarge(image.Width, image.Height);
        }
    }