@@ -90,17 +90,19 @@ private static string ComputeHmacSHA256(string key, string data)
9090 return Convert . ToHexStringLower ( hash ) ;
9191 }
9292
93- private static string BuildSignatureString ( HttpRequestMessage request , string appSecret )
93+ private static string BuildSignatureString ( SortedList < string , string > xbiliHeaders , string appSecret )
9494 {
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 ( ) ;
100-
101- var signature = string . Join ( '\n ' , headers ) ;
95+ var sb = new StringBuilder ( 256 ) ; // 256 is an estimated size for the plain text
96+ foreach ( ( var name , var value ) in xbiliHeaders )
97+ {
98+ sb . Append ( name )
99+ . Append ( ':' )
100+ . Append ( value )
101+ . Append ( '\n ' ) ;
102+ }
102103
103- return ComputeHmacSHA256 ( appSecret , signature ) ;
104+ var signSrcText = sb . ToString ( 0 , sb . Length - 1 ) ; // Ignore the last '\n'
105+ return ComputeHmacSHA256 ( appSecret , signSrcText ) ;
104106 }
105107
106108 protected override async Task < AuthenticationTicket > CreateTicketAsync (
@@ -110,14 +112,14 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
110112 {
111113 using var request = new HttpRequestMessage ( HttpMethod . Get , Options . UserInformationEndpoint ) ;
112114 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 ) ;
115+
116+ var xbiliHeaders = BuildXBiliHeaders ( ) ;
117+ foreach ( ( var name , var value ) in xbiliHeaders )
118+ {
119+ request . Headers . Add ( name , value ) ;
120+ }
121+
122+ var signature = BuildSignatureString ( xbiliHeaders , Options . ClientSecret ) ;
121123 request . Headers . Add ( "Authorization" , signature ) ;
122124
123125 request . Headers . Accept . Add ( new MediaTypeWithQualityHeaderValue ( "application/json" ) ) ;
@@ -145,6 +147,23 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
145147 return new AuthenticationTicket ( context . Principal ! , context . Properties , Scheme . Name ) ;
146148 }
147149
150+ private SortedList < string , string > BuildXBiliHeaders ( ) => new ( 6 , StringComparer . OrdinalIgnoreCase )
151+ {
152+ { "x-bili-accesskeyid" , Options . ClientId } ,
153+ { "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
154+ { "x-bili-signature-method" , "HMAC-SHA256" } ,
155+ { "x-bili-signature-nonce" , GenerateNonce ( ) } ,
156+ { "x-bili-signature-version" , "2.0" } ,
157+ { "x-bili-timestamp" , TimeProvider . GetUtcNow ( ) . ToUnixTimeSeconds ( ) . ToString ( CultureInfo . InvariantCulture ) }
158+ } ;
159+
160+ private static string GenerateNonce ( )
161+ {
162+ Span < byte > bytes = stackalloc byte [ 256 / 8 ] ;
163+ RandomNumberGenerator . Fill ( bytes ) ;
164+ return Base64Url . EncodeToString ( bytes ) ;
165+ }
166+
148167 /// <summary>
149168 /// Check the code sent back by server for potential server errors.
150169 /// </summary>
@@ -154,14 +173,13 @@ protected override async Task<AuthenticationTicket> CreateTicketAsync(
154173 /// <returns>True if succeed, otherwise false.</returns>
155174 private static bool ValidateReturnCode ( JsonElement element , out int code )
156175 {
157- code = 0 ;
158176 if ( ! element . TryGetProperty ( "code" , out JsonElement errorCodeElement ) )
159177 {
178+ code = 0 ;
160179 return true ;
161180 }
162181
163182 code = errorCodeElement . GetInt32 ( ) ;
164-
165183 return code == 0 ;
166184 }
167185
0 commit comments