/
DiscordSignedLink.cs
85 lines (67 loc) · 2.64 KB
/
DiscordSignedLink.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using System.Globalization;
using System.Web;
namespace DisCatSharp.Entities;
/// <summary>
/// Represents a <see cref="DiscordSignedLink"/> used for attachments and other things to improve security
/// and prevent bad actors from abusing Discord's CDN.
/// </summary>
public class DiscordSignedLink : Uri
{
/// <summary>
/// When the signed link expires.
/// </summary>
public DateTimeOffset? ExpiresAt { get; init; }
/// <summary>
/// When the signed link was generated.
/// </summary>
public DateTimeOffset? IssuedAt { get; init; }
/// <summary>
/// The signature of the signed link.
/// </summary>
public string? Signature { get; init; }
/// <summary>
/// Initializes a new instance of the <see cref="Uri"/> class with the specified URI for signed discord links.
/// </summary>
/// <param name="uri">An <see cref="Uri"/>.</param>
public DiscordSignedLink(Uri uri)
: base(uri.AbsoluteUri)
{
ArgumentNullException.ThrowIfNull(uri);
if (string.IsNullOrWhiteSpace(this.Query))
return;
var queries = HttpUtility.ParseQueryString(this.Query);
if (!queries.HasKeys())
return;
if (queries.Get("ex") is { } expiresString && long.TryParse(expiresString, NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out var expiresTimeStamp))
this.ExpiresAt = DateTimeOffset.FromUnixTimeSeconds(expiresTimeStamp);
if (queries.Get("is") is { } issuedString &&
long.TryParse(issuedString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var issuedTimeStamp))
this.IssuedAt = DateTimeOffset.FromUnixTimeSeconds(issuedTimeStamp);
this.Signature = queries.Get("hm");
}
/// <summary>
/// Initializes a new instance of the <see cref="Uri"/> class with the specified URI for signed discord links.
/// </summary>
/// <param name="uriString">A string that identifies the resource to be represented by the <see cref="Uri"/> instance.</param>
public DiscordSignedLink(string uriString)
: base(uriString)
{
ArgumentNullException.ThrowIfNull(uriString);
if (string.IsNullOrWhiteSpace(this.Query))
return;
var queries = HttpUtility.ParseQueryString(this.Query);
if (!queries.HasKeys())
return;
if (queries.Get("ex") is { } expiresString && long.TryParse(expiresString, NumberStyles.HexNumber,
CultureInfo.InvariantCulture,
out var expiresTimeStamp))
this.ExpiresAt = DateTimeOffset.FromUnixTimeSeconds(expiresTimeStamp);
if (queries.Get("is") is { } issuedString &&
long.TryParse(issuedString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var issuedTimeStamp))
this.IssuedAt = DateTimeOffset.FromUnixTimeSeconds(issuedTimeStamp);
this.Signature = queries.Get("hm");
}
}