@@ -111,19 +111,145 @@ export function formatDaysCount(days: number): string {
111111 return `${ days } дней` ;
112112}
113113
114- // Simple MD5 implementation for Gravatar
114+ // Generate a Gravatar URL using the proper MD5 email hash
115115export async function generateGravatarUrl ( username : string , size : number = 200 ) : Promise < string > {
116- const email = `${ username . toLowerCase ( ) } @gravatar.local` ;
117- const hash = await md5 ( email . trim ( ) . toLowerCase ( ) ) ;
116+ const email = `${ username . toLowerCase ( ) } @gravatar.local` . trim ( ) . toLowerCase ( ) ;
117+ const hash = md5 ( email ) ;
118118 return `https://www.gravatar.com/avatar/${ hash } ?d=identicon&s=${ size } ` ;
119119}
120120
121- // Simplified MD5 hash function
122- async function md5 ( str : string ) : Promise < string > {
123- const msgBuffer = new TextEncoder ( ) . encode ( str ) ;
124- const hashBuffer = await crypto . subtle . digest ( 'SHA-256' , msgBuffer ) ;
125- const hashArray = Array . from ( new Uint8Array ( hashBuffer ) ) ;
126- return hashArray . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
121+ // Minimal MD5 implementation for browser use
122+ function md5 ( inputString : string ) : string {
123+ const rotateLeft = ( lValue : number , iShiftBits : number ) => ( lValue << iShiftBits ) | ( lValue >>> ( 32 - iShiftBits ) ) ;
124+ const addUnsigned = ( lX : number , lY : number ) => {
125+ const lX4 = lX & 0x40000000 ;
126+ const lY4 = lY & 0x40000000 ;
127+ const lX8 = lX & 0x80000000 ;
128+ const lY8 = lY & 0x80000000 ;
129+ const lResult = ( lX & 0x3fffffff ) + ( lY & 0x3fffffff ) ;
130+ if ( lX4 & lY4 ) return lResult ^ 0x80000000 ^ lX8 ^ lY8 ;
131+ if ( lX4 | lY4 ) {
132+ if ( lResult & 0x40000000 ) return lResult ^ 0xc0000000 ^ lX8 ^ lY8 ;
133+ return lResult ^ 0x40000000 ^ lX8 ^ lY8 ;
134+ }
135+ return lResult ^ lX8 ^ lY8 ;
136+ } ;
137+ const _F = ( x : number , y : number , z : number ) => ( x & y ) | ( ~ x & z ) ;
138+ const _G = ( x : number , y : number , z : number ) => ( x & z ) | ( y & ~ z ) ;
139+ const _H = ( x : number , y : number , z : number ) => x ^ y ^ z ;
140+ const _I = ( x : number , y : number , z : number ) => y ^ ( x | ~ z ) ;
141+ const _FF = ( a : number , b : number , c : number , d : number , x : number , s : number , ac : number ) => addUnsigned ( rotateLeft ( addUnsigned ( addUnsigned ( a , _F ( b , c , d ) ) , addUnsigned ( x , ac ) ) , s ) , b ) ;
142+ const _GG = ( a : number , b : number , c : number , d : number , x : number , s : number , ac : number ) => addUnsigned ( rotateLeft ( addUnsigned ( addUnsigned ( a , _G ( b , c , d ) ) , addUnsigned ( x , ac ) ) , s ) , b ) ;
143+ const _HH = ( a : number , b : number , c : number , d : number , x : number , s : number , ac : number ) => addUnsigned ( rotateLeft ( addUnsigned ( addUnsigned ( a , _H ( b , c , d ) ) , addUnsigned ( x , ac ) ) , s ) , b ) ;
144+ const _II = ( a : number , b : number , c : number , d : number , x : number , s : number , ac : number ) => addUnsigned ( rotateLeft ( addUnsigned ( addUnsigned ( a , _I ( b , c , d ) ) , addUnsigned ( x , ac ) ) , s ) , b ) ;
145+ const convertToWordArray = ( str : string ) => {
146+ const lMessageLength = str . length ;
147+ const lNumberOfWordsTemp1 = lMessageLength + 8 ;
148+ const lNumberOfWordsTemp2 = ( lNumberOfWordsTemp1 - ( lNumberOfWordsTemp1 % 64 ) ) / 64 ;
149+ const lNumberOfWords = ( lNumberOfWordsTemp2 + 1 ) * 16 ;
150+ const wordArray = new Array < number > ( lNumberOfWords - 1 ) ;
151+ let lBytePosition = 0 ;
152+ let lByteCount = 0 ;
153+ while ( lByteCount < lMessageLength ) {
154+ const lWordCount = ( lByteCount - ( lByteCount % 4 ) ) / 4 ;
155+ lBytePosition = ( lByteCount % 4 ) * 8 ;
156+ wordArray [ lWordCount ] = ( wordArray [ lWordCount ] || 0 ) | ( inputString . charCodeAt ( lByteCount ) << lBytePosition ) ;
157+ lByteCount ++ ;
158+ }
159+ const lWordCount = ( lByteCount - ( lByteCount % 4 ) ) / 4 ;
160+ lBytePosition = ( lByteCount % 4 ) * 8 ;
161+ wordArray [ lWordCount ] = wordArray [ lWordCount ] || 0 ;
162+ wordArray [ lWordCount ] |= 0x80 << lBytePosition ;
163+ wordArray [ lNumberOfWords - 2 ] = lMessageLength << 3 ;
164+ wordArray [ lNumberOfWords - 1 ] = lMessageLength >>> 29 ;
165+ return wordArray ;
166+ } ;
167+ const wordToHex = ( lValue : number ) => {
168+ let wordToHexValue = '' ;
169+ let wordToHexValueTemp = '' ;
170+ for ( let lCount = 0 ; lCount <= 3 ; lCount ++ ) {
171+ wordToHexValueTemp = ( lValue >>> ( lCount * 8 ) & 255 ) . toString ( 16 ) ;
172+ wordToHexValue += wordToHexValueTemp . padStart ( 2 , '0' ) ;
173+ }
174+ return wordToHexValue ;
175+ } ;
176+ const x = convertToWordArray ( inputString ) ;
177+ let a = 0x67452301 ;
178+ let b = 0xefcdab89 ;
179+ let c = 0x98badcfe ;
180+ let d = 0x10325476 ;
181+ const xl = x . length ;
182+ for ( let k = 0 ; k < xl ; k += 16 ) {
183+ const AA = a ;
184+ const BB = b ;
185+ const CC = c ;
186+ const DD = d ;
187+ a = _FF ( a , b , c , d , x [ k + 0 ] , 7 , 0xd76aa478 ) ;
188+ d = _FF ( d , a , b , c , x [ k + 1 ] , 12 , 0xe8c7b756 ) ;
189+ c = _FF ( c , d , a , b , x [ k + 2 ] , 17 , 0x242070db ) ;
190+ b = _FF ( b , c , d , a , x [ k + 3 ] , 22 , 0xc1bdceee ) ;
191+ a = _FF ( a , b , c , d , x [ k + 4 ] , 7 , 0xf57c0faf ) ;
192+ d = _FF ( d , a , b , c , x [ k + 5 ] , 12 , 0x4787c62a ) ;
193+ c = _FF ( c , d , a , b , x [ k + 6 ] , 17 , 0xa8304613 ) ;
194+ b = _FF ( b , c , d , a , x [ k + 7 ] , 22 , 0xfd469501 ) ;
195+ a = _FF ( a , b , c , d , x [ k + 8 ] , 7 , 0x698098d8 ) ;
196+ d = _FF ( d , a , b , c , x [ k + 9 ] , 12 , 0x8b44f7af ) ;
197+ c = _FF ( c , d , a , b , x [ k + 10 ] , 17 , 0xffff5bb1 ) ;
198+ b = _FF ( b , c , d , a , x [ k + 11 ] , 22 , 0x895cd7be ) ;
199+ a = _FF ( a , b , c , d , x [ k + 12 ] , 7 , 0x6b901122 ) ;
200+ d = _FF ( d , a , b , c , x [ k + 13 ] , 12 , 0xfd987193 ) ;
201+ c = _FF ( c , d , a , b , x [ k + 14 ] , 17 , 0xa679438e ) ;
202+ b = _FF ( b , c , d , a , x [ k + 15 ] , 22 , 0x49b40821 ) ;
203+ a = _GG ( a , b , c , d , x [ k + 1 ] , 5 , 0xf61e2562 ) ;
204+ d = _GG ( d , a , b , c , x [ k + 6 ] , 9 , 0xc040b340 ) ;
205+ c = _GG ( c , d , a , b , x [ k + 11 ] , 14 , 0x265e5a51 ) ;
206+ b = _GG ( b , c , d , a , x [ k + 0 ] , 20 , 0xe9b6c7aa ) ;
207+ a = _GG ( a , b , c , d , x [ k + 5 ] , 5 , 0xd62f105d ) ;
208+ d = _GG ( d , a , b , c , x [ k + 10 ] , 9 , 0x02441453 ) ;
209+ c = _GG ( c , d , a , b , x [ k + 15 ] , 14 , 0xd8a1e681 ) ;
210+ b = _GG ( b , c , d , a , x [ k + 4 ] , 20 , 0xe7d3fbc8 ) ;
211+ a = _GG ( a , b , c , d , x [ k + 9 ] , 5 , 0x21e1cde6 ) ;
212+ d = _GG ( d , a , b , c , x [ k + 14 ] , 9 , 0xc33707d6 ) ;
213+ c = _GG ( c , d , a , b , x [ k + 3 ] , 14 , 0xf4d50d87 ) ;
214+ b = _GG ( b , c , d , a , x [ k + 8 ] , 20 , 0x455a14ed ) ;
215+ a = _GG ( a , b , c , d , x [ k + 13 ] , 5 , 0xa9e3e905 ) ;
216+ d = _GG ( d , a , b , c , x [ k + 2 ] , 9 , 0xfcefa3f8 ) ;
217+ c = _GG ( c , d , a , b , x [ k + 7 ] , 14 , 0x676f02d9 ) ;
218+ b = _GG ( b , c , d , a , x [ k + 12 ] , 20 , 0x8d2a4c8a ) ;
219+ a = _HH ( a , b , c , d , x [ k + 5 ] , 4 , 0xfffa3942 ) ;
220+ d = _HH ( d , a , b , c , x [ k + 8 ] , 11 , 0x8771f681 ) ;
221+ c = _HH ( c , d , a , b , x [ k + 11 ] , 16 , 0x6d9d6122 ) ;
222+ b = _HH ( b , c , d , a , x [ k + 14 ] , 23 , 0xfde5380c ) ;
223+ a = _HH ( a , b , c , d , x [ k + 1 ] , 4 , 0xa4beea44 ) ;
224+ d = _HH ( d , a , b , c , x [ k + 4 ] , 11 , 0x4bdecfa9 ) ;
225+ c = _HH ( c , d , a , b , x [ k + 7 ] , 16 , 0xf6bb4b60 ) ;
226+ b = _HH ( b , c , d , a , x [ k + 10 ] , 23 , 0xbdc7be42 ) ;
227+ a = _HH ( a , b , c , d , x [ k + 13 ] , 4 , 0x289b7ec6 ) ;
228+ d = _HH ( d , a , b , c , x [ k + 0 ] , 11 , 0xeaa127fa ) ;
229+ c = _HH ( c , d , a , b , x [ k + 3 ] , 16 , 0xd4ef3085 ) ;
230+ b = _HH ( b , c , d , a , x [ k + 6 ] , 23 , 0x04881d05 ) ;
231+ a = _HH ( a , b , c , d , x [ k + 11 ] , 4 , 0xd9d4d039 ) ;
232+ d = _HH ( d , a , b , c , x [ k + 2 ] , 11 , 0xe6db99e5 ) ;
233+ c = _HH ( c , d , a , b , x [ k + 5 ] , 16 , 0x1fa27cf8 ) ;
234+ b = _HH ( b , c , d , a , x [ k + 8 ] , 23 , 0xc4ac5665 ) ;
235+ a = _II ( a , b , c , d , x [ k + 0 ] , 6 , 0xf4292244 ) ;
236+ d = _II ( d , a , b , c , x [ k + 7 ] , 10 , 0x432aff97 ) ;
237+ c = _II ( c , d , a , b , x [ k + 14 ] , 15 , 0xab9423a7 ) ;
238+ b = _II ( b , c , d , a , x [ k + 5 ] , 21 , 0xfc93a039 ) ;
239+ a = _II ( a , b , c , d , x [ k + 12 ] , 6 , 0x655b59c3 ) ;
240+ d = _II ( d , a , b , c , x [ k + 3 ] , 10 , 0x8f0ccc92 ) ;
241+ c = _II ( c , d , a , b , x [ k + 10 ] , 15 , 0xffeff47d ) ;
242+ b = _II ( b , c , d , a , x [ k + 1 ] , 21 , 0x85845dd1 ) ;
243+ a = _II ( a , b , c , d , x [ k + 8 ] , 6 , 0x6fa87e4f ) ;
244+ d = _II ( d , a , b , c , x [ k + 15 ] , 10 , 0xfe2ce6e0 ) ;
245+ c = _II ( c , d , a , b , x [ k + 6 ] , 15 , 0xa3014314 ) ;
246+ b = _II ( b , c , d , a , x [ k + 13 ] , 21 , 0x4e0811a1 ) ;
247+ a = addUnsigned ( a , AA ) ;
248+ b = addUnsigned ( b , BB ) ;
249+ c = addUnsigned ( c , CC ) ;
250+ d = addUnsigned ( d , DD ) ;
251+ }
252+ return wordToHex ( a ) + wordToHex ( b ) + wordToHex ( c ) + wordToHex ( d ) ;
127253}
128254
129255// Safe error logging that prevents token leakage
0 commit comments