Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 37 additions & 19 deletions src/AspNet.Security.OAuth.Bilibili/BilibiliAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,19 @@ private static string ComputeHmacSHA256(string key, string data)
return Convert.ToHexStringLower(hash);
}

private static string BuildSignatureString(HttpRequestMessage request, string appSecret)
private static string BuildSignatureString(SortedList<string, string> xbiliHeaders, string appSecret)
{
var headers = request.Headers
.Where(h => h.Key.StartsWith("x-bili-", StringComparison.OrdinalIgnoreCase))
.OrderBy(h => h.Key)
.Select(h => $"{h.Key}:{string.Join(",", h.Value)}")
.ToList();

var signature = string.Join('\n', headers);
var sb = new StringBuilder(256); // 256 is an estimated size for the plain text
foreach ((var name, var value) in xbiliHeaders)
{
sb.Append(name)
.Append(':')
.Append(value)
.Append('\n');
}

return ComputeHmacSHA256(appSecret, signature);
var signSrcText = sb.ToString(0, sb.Length - 1); // Ignore the last '\n'
return ComputeHmacSHA256(appSecret, signSrcText);
}

protected override async Task<AuthenticationTicket> CreateTicketAsync(
Expand All @@ -110,14 +112,14 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
{
using var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint);
request.Headers.Add("access-token", tokens.AccessToken);
request.Headers.Add("x-bili-accesskeyid", Options.ClientId);
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
request.Headers.Add("x-bili-signature-method", "HMAC-SHA256");
request.Headers.Add("x-bili-signature-nonce", Base64Url.EncodeToString(RandomNumberGenerator.GetBytes(256 / 8)));
request.Headers.Add("x-bili-signature-version", "2.0");
request.Headers.Add("x-bili-timestamp", TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture));

var signature = BuildSignatureString(request, Options.ClientSecret);

var xbiliHeaders = BuildXBiliHeaders();
foreach ((var name, var value) in xbiliHeaders)
{
request.Headers.Add(name, value);
}

var signature = BuildSignatureString(xbiliHeaders, Options.ClientSecret);
request.Headers.Add("Authorization", signature);

request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Expand Down Expand Up @@ -145,6 +147,23 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
return new AuthenticationTicket(context.Principal!, context.Properties, Scheme.Name);
}

private SortedList<string, string> BuildXBiliHeaders() => new(6, StringComparer.OrdinalIgnoreCase)
{
{ "x-bili-accesskeyid", Options.ClientId },
{ "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
{ "x-bili-signature-method", "HMAC-SHA256" },
{ "x-bili-signature-nonce", GenerateNonce() },
{ "x-bili-signature-version", "2.0" },
{ "x-bili-timestamp", TimeProvider.GetUtcNow().ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture) }
};

private static string GenerateNonce()
{
Span<byte> bytes = stackalloc byte[256 / 8];
RandomNumberGenerator.Fill(bytes);
return Base64Url.EncodeToString(bytes);
}

/// <summary>
/// Check the code sent back by server for potential server errors.
/// </summary>
Expand All @@ -154,14 +173,13 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
/// <returns>True if succeed, otherwise false.</returns>
private static bool ValidateReturnCode(JsonElement element, out int code)
{
code = 0;
if (!element.TryGetProperty("code", out JsonElement errorCodeElement))
{
code = 0;
return true;
}

code = errorCodeElement.GetInt32();

return code == 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* for more information concerning the license and the contributors participating to this project.
*/

using System.Web;
using Microsoft.AspNetCore.WebUtilities;

namespace AspNet.Security.OAuth.Bilibili;
Expand Down