Skip to content

Commit 3fdf6a7

Browse files
Merge branch 'dev' into dev-v10
2 parents f4307b1 + 840e14b commit 3fdf6a7

File tree

2 files changed

+43
-19
lines changed

2 files changed

+43
-19
lines changed

src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ protected override async Task<OAuthTokenResponse> ExchangeCodeAsync([NotNull] OA
7373
using var document = await JsonDocument.ParseAsync(stream);
7474

7575
var mainElement = document.RootElement;
76+
7677
if (!ValidateReturnCode(mainElement, out var code))
7778
{
7879
return OAuthTokenResponse.Failed(new Exception($"An error (Code:{code}) occurred while retrieving an access token."));
@@ -86,21 +87,26 @@ private static string ComputeHmacSHA256(string key, string data)
8687
{
8788
var keyBytes = Encoding.UTF8.GetBytes(key);
8889
var dataBytes = Encoding.UTF8.GetBytes(data);
90+
8991
var hash = HMACSHA256.HashData(keyBytes, dataBytes);
92+
9093
return Convert.ToHexStringLower(hash);
9194
}
9295

93-
private static string BuildSignatureString(HttpRequestMessage request, string appSecret)
96+
private static string BuildSignatureString(SortedList<string, string> xbiliHeaders, string key)
9497
{
95-
var headers = request.Headers
96-
.Where(h => h.Key.StartsWith("x-bili-", StringComparison.OrdinalIgnoreCase))
97-
.OrderBy(h => h.Key)
98-
.Select(h => $"{h.Key}:{string.Join(",", h.Value)}")
99-
.ToList();
98+
var builder = new StringBuilder(256); // 256 is an estimated size for the plain text
10099

101-
var signature = string.Join('\n', headers);
100+
foreach ((var name, var value) in xbiliHeaders)
101+
{
102+
builder.Append(name)
103+
.Append(':')
104+
.Append(value)
105+
.Append('\n');
106+
}
102107

103-
return ComputeHmacSHA256(appSecret, signature);
108+
var data = builder.ToString(0, builder.Length - 1); // Ignore the last '\n'
109+
return ComputeHmacSHA256(key, data);
104110
}
105111

106112
protected override async Task<AuthenticationTicket> CreateTicketAsync(
@@ -110,19 +116,21 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
110116
{
111117
using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
112118
request.Headers.Add("access-token", tokens.AccessToken);
113-
request.Headers.Add("x-bili-accesskeyid", Options.ClientId);
114-
request.Headers.Add("x-bili-content-md5", "d41d8cd98f00b204e9800998ecf8427e"); // It's a GET request so there's no content, so we send the MD5 hash of an empty string
115-
request.Headers.Add("x-bili-signature-method", "HMAC-SHA256");
116-
request.Headers.Add("x-bili-signature-nonce", Base64Url.EncodeToString(RandomNumberGenerator.GetBytes(256 / 8)));
117-
request.Headers.Add("x-bili-signature-version", "2.0");
118-
request.Headers.Add("x-bili-timestamp", TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture));
119-
120-
var signature = BuildSignatureString(request, Options.ClientSecret);
119+
120+
var xbiliHeaders = BuildXBiliHeaders();
121+
122+
foreach ((var name, var value) in xbiliHeaders)
123+
{
124+
request.Headers.Add(name, value);
125+
}
126+
127+
var signature = BuildSignatureString(xbiliHeaders, Options.ClientSecret);
121128
request.Headers.Add("Authorization", signature);
122129

123130
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
124131

125132
using var response = await Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, Context.RequestAborted);
133+
126134
if (!response.IsSuccessStatusCode)
127135
{
128136
await Log.UserProfileErrorAsync(Logger, response, Context.RequestAborted);
@@ -132,6 +140,7 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
132140
using var payload = JsonDocument.Parse(await response.Content.ReadAsStringAsync(Context.RequestAborted));
133141

134142
var mainElement = payload.RootElement;
143+
135144
if (!ValidateReturnCode(mainElement, out var code))
136145
{
137146
throw new AuthenticationFailureException($"An error (ErrorCode:{code}) occurred while retrieving user information.");
@@ -145,6 +154,23 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
145154
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
146155
}
147156

157+
private SortedList<string, string> BuildXBiliHeaders() => new(6, StringComparer.OrdinalIgnoreCase)
158+
{
159+
{ "x-bili-accesskeyid", Options.ClientId },
160+
{ "x-bili-content-md5", "d41d8cd98f00b204e9800998ecf8427e" }, // It's a GET request so there's no content, so we send the MD5 hash of an empty string
161+
{ "x-bili-signature-method", "HMAC-SHA256" },
162+
{ "x-bili-signature-nonce", GenerateNonce() },
163+
{ "x-bili-signature-version", "2.0" },
164+
{ "x-bili-timestamp", TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture) }
165+
};
166+
167+
private static string GenerateNonce()
168+
{
169+
Span<byte> bytes = stackalloc byte[256 / 8];
170+
RandomNumberGenerator.Fill(bytes);
171+
return Base64Url.EncodeToString(bytes);
172+
}
173+
148174
/// <summary>
149175
/// Check the code sent back by server for potential server errors.
150176
/// </summary>
@@ -154,14 +180,13 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
154180
/// <returns>True if succeed, otherwise false.</returns>
155181
private static bool ValidateReturnCode(JsonElement element, out int code)
156182
{
157-
code = 0;
158183
if (!element.TryGetProperty("code", out JsonElement errorCodeElement))
159184
{
185+
code = 0;
160186
return true;
161187
}
162188

163189
code = errorCodeElement.GetInt32();
164-
165190
return code == 0;
166191
}
167192

test/AspNet.Security.OAuth.Providers.Tests/Bilibili/BilibiliTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
* for more information concerning the license and the contributors participating to this project.
55
*/
66

7-
using System.Web;
87
using Microsoft.AspNetCore.WebUtilities;
98

109
namespace AspNet.Security.OAuth.Bilibili;

0 commit comments

Comments
 (0)