import * as crypto from 'crypto' ; const itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ; const DIGEST_ENCODING = 'binary' ; export default class ApacheMd5 { static to64 ( index , count ) { let result = '' ; while ( -- count >= 0 ) { result += itoa64 [ index & 63 ] ; index = index >> 6 ; } return result ; } static getSalt ( inputSalt ) { let salt = '' ; if ( inputSalt ) { salt = inputSalt . split ( '$' ) [ 2 ] ; } else { while ( salt . length < 8 ) { const rchIndex = Math . floor ( Math . random ( ) * 64 ) ; salt += itoa64 [ rchIndex ] ; } } return salt ; } static getPassword ( final ) { let epass = '' ; epass += ApacheMd5 . to64 ( ( final . charCodeAt ( 0 ) << 16 ) | ( final . charCodeAt ( 6 ) << 8 ) | final . charCodeAt ( 12 ) , 4 ) ; epass += ApacheMd5 . to64 ( ( final . charCodeAt ( 1 ) << 16 ) | ( final . charCodeAt ( 7 ) << 8 ) | final . charCodeAt ( 13 ) , 4 ) ; epass += ApacheMd5 . to64 ( ( final . charCodeAt ( 2 ) << 16 ) | ( final . charCodeAt ( 8 ) << 8 ) | final . charCodeAt ( 14 ) , 4 ) ; epass += ApacheMd5 . to64 ( ( final . charCodeAt ( 3 ) << 16 ) | ( final . charCodeAt ( 9 ) << 8 ) | final . charCodeAt ( 15 ) , 4 ) ; epass += ApacheMd5 . to64 ( ( final . charCodeAt ( 4 ) << 16 ) | ( final . charCodeAt ( 10 ) << 8 ) | final . charCodeAt ( 5 ) , 4 ) ; epass += ApacheMd5 . to64 ( final . charCodeAt ( 11 ) , 2 ) ; return epass ; } static createApacheHash ( password , salt ? ) { let magic = '' ; if ( salt && salt . split ( '$' ) [ 1 ] === '1' ) { magic = '$1$' ; } else { magic = '$apr1$' ; } salt = ApacheMd5 . getSalt ( salt ) ; let ctx = password + magic + salt ; let final = crypto . createHash ( 'md5' ) . update ( password + salt + password , 'ascii' ) . digest ( DIGEST_ENCODING ) ; for ( let pl = password . length ; pl > 0 ; pl -= 16 ) { ctx += final . substr ( 0 , pl > 16 ? 16 : pl ) ; } for ( let i = password . length ; i ; i >>= 1 ) { if ( i % 2 ) { ctx += String . fromCharCode ( 0 ) ; } else { ctx += password . charAt ( 0 ) ; } } final = crypto . createHash ( 'md5' ) . update ( ctx , 'ascii' ) . digest ( DIGEST_ENCODING ) ; for ( let i = 0 ; i < 1000 ; ++ i ) { let ctxl = '' ; if ( i % 2 ) { ctxl += password ; } else { ctxl += final . substr ( 0 , 16 ) ; } if ( i % 3 ) { ctxl += salt ; } if ( i % 7 ) { ctxl += password ; } if ( i % 2 ) { ctxl += final . substr ( 0 , 16 ) ; } else { ctxl += password ; } final = crypto . createHash ( 'md5' ) . update ( ctxl , 'ascii' ) . digest ( DIGEST_ENCODING ) ; } return `${ magic + salt }$${ ApacheMd5 . getPassword ( final ) }` ; } }