From b5326b4cbb6f0c89cfc8d0ed7d2584ef2164cc7a Mon Sep 17 00:00:00 2001 From: danogentili Date: Thu, 23 Jun 2016 23:51:08 +0200 Subject: [PATCH] Let the madness begin! --- AES.class.php | 554 ++++++++++++++++++++++++++++++++++++ README.md | 73 +---- TL.php | Bin 0 -> 6745 bytes classes/__init__.php | 4 + classes/chat.php | 11 + classes/contact.php | 5 + classes/file.php | 43 +++ classes/message.php | 6 + classes/shell.php | 339 +++++++++++++++++++++++ classes/telepy.php | 26 ++ classes/user.php | 12 + crypt.php | 58 ++++ libpy2php/libpy2php.php | 486 ++++++++++++++++++++++++++++++++ libpy2php/os.php | 570 ++++++++++++++++++++++++++++++++++++++ libpy2php/os_path.php | 214 ++++++++++++++ libpy2php/strict_mode.php | 134 +++++++++ mtproto.php | Bin 0 -> 12431 bytes prime.php | 171 ++++++++++++ telepy.php | 14 + testing.php | 22 ++ tests/SHA.php.tmp | 24 ++ tests/Serialization | 4 + 22 files changed, 2701 insertions(+), 69 deletions(-) create mode 100644 AES.class.php create mode 100644 TL.php create mode 100644 classes/__init__.php create mode 100644 classes/chat.php create mode 100644 classes/contact.php create mode 100644 classes/file.php create mode 100644 classes/message.php create mode 100644 classes/shell.php create mode 100644 classes/telepy.php create mode 100644 classes/user.php create mode 100644 crypt.php create mode 100644 libpy2php/libpy2php.php create mode 100644 libpy2php/os.php create mode 100644 libpy2php/os_path.php create mode 100644 libpy2php/strict_mode.php create mode 100755 mtproto.php create mode 100644 prime.php create mode 100644 telepy.php create mode 100644 testing.php create mode 100644 tests/SHA.php.tmp create mode 100644 tests/Serialization diff --git a/AES.class.php b/AES.class.php new file mode 100644 index 000000000..007710f3d --- /dev/null +++ b/AES.class.php @@ -0,0 +1,554 @@ +Nk = strlen($z)/4; + $this->Nr = $this->Nk + self::$Nb + 2; + + if ($this->Nk != 4 && $this->Nk != 6 && $this->Nk != 8) + die("Key is " . ($this->Nk*32) . " bits long. *not* 128, 192, or 256."); + + $this->Nr = $this->Nk+self::$Nb+2; + $this->w = array(); // Nb*(Nr+1) 32-bit words + $this->s = array(array()); // 2-D array of Nb colums and 4 rows + + $this->KeyExpansion($z); // places expanded key in w + } + + /** Encrypts an aribtrary length String. + * @params plaintext string + * @returns ciphertext string + * Whenever possible you should stream your plaintext through the + * encryptBlock() function directly, as the amount of time required + * to encrypt is linear to the size of the ciphertext. + **/ + public function encrypt($x) { + $t = ""; // 16-byte block + $y = ""; // returned cipher text; + + // put a 16-byte block into t + $xsize = strlen($x); + for ($i=0; $i<$xsize; $i+=16) { + for ($j=0; $j<16; $j++) { + if (($i+$j)<$xsize) { + $t[$j] = $x[$i+$j]; + } + else + $t[$j] = chr(0); + } + + $y .= $this->encryptBlock($t); + } + return $y; + } + + /** Decrypts an aribtrary length String. + * @params ciphertext string + * @returns plaintext string + * Whenever possible you should stream your ciphertext through the + * decryptBlock() function directly, as the amount of time required + * to decrypt is linear to the size of the ciphertext. + **/ + public function decrypt($y) { + $t = ""; // 16-byte block + $x = ""; // returned plain text; + + // put a 16-byte block into t + $ysize = strlen($y); + for ($i=0; $i<$ysize; $i+=16) { + for ($j=0; $j<16; $j++) { + if (($i+$j)<$ysize) + $t[$j] = $y[$i+$j]; + else + $t[$j] = chr(0); + } + $x .= $this->decryptBlock($t); + } + return $x; + } + + /** Encrypts the 16-byte plain text. + * @params 16-byte plaintext string + * @returns 16-byte ciphertext string + **/ + public function encryptBlock($x) { + $y = ""; // 16-byte string + + // place input x into the initial state matrix in column order + for ($i=0; $i<4*self::$Nb; $i++) { + // we want integerger division for the second index + $this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] = ord($x[$i]); + } + + // add round key + $this->addRoundKey(0); + + for ($i=1; $i<$this->Nr; $i++) { + // substitute bytes + $this->subBytes(); + + // shift rows + $this->shiftRows(); + + // mix columns + $this->mixColumns(); + + // add round key + $this->addRoundKey($i); + } + + // substitute bytes + $this->subBytes(); + + // shift rows + $this->shiftRows(); + + // add round key + $this->addRoundKey($i); + + // place state matrix s into y in column order + for ($i=0; $i<4*self::$Nb; $i++) + $y .= chr($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb]); + return $y; + } + + /** Decrypts the 16-byte cipher text. + * @params 16-byte ciphertext string + * @returns 16-byte plaintext string + **/ + public function decryptBlock($y) { + $x = ""; // 16-byte string + + // place input y into the initial state matrix in column order + for ($i=0; $i<4*self::$Nb; $i++) + $this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] = ord($y[$i]); + + // add round key + $this->addRoundKey($this->Nr); + + for ($i=$this->Nr-1; $i>0; $i--) { + // inverse shift rows + $this->invShiftRows(); + + // inverse sub bytes + $this->invSubBytes(); + + // add round key + $this->addRoundKey($i); + + // inverse mix columns + $this->invMixColumns(); + } + + // inverse shift rows + $this->invShiftRows(); + + // inverse sub bytes + $this->invSubBytes(); + + // add round key + $this->addRoundKey($i); + + // place state matrix s into x in column order + for ($i=0; $i<4*self::$Nb; $i++) { + // Used to remove filled null characters. + $x .= ($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb] == chr(0) ? "" : chr($this->s[$i%4][($i-$i%self::$Nb)/self::$Nb])); + } + + return $x; + } + + public function __destruct() { + unset($this->w); + unset($this->s); + } + + /** makes a big key out of a small one + * @returns void + **/ + private function KeyExpansion($z) { + // Rcon is the round constant + static $Rcon = array( + 0x00000000, + 0x01000000, + 0x02000000, + 0x04000000, + 0x08000000, + 0x10000000, + 0x20000000, + 0x40000000, + 0x80000000, + 0x1b000000, + 0x36000000, + 0x6c000000, + 0xd8000000, + 0xab000000, + 0x4d000000, + 0x9a000000, + 0x2f000000 + ); + + $temp = 0; // temporary 32-bit word + + // the first Nk words of w are the cipher key z + for ($i=0; $i<$this->Nk; $i++) { + $this->w[$i] = 0; + // fill an entire word of expanded key w + // by pushing 4 bytes into the w[i] word + $this->w[$i] = ord($z[4*$i]); // add a byte in + $this->w[$i] <<= 8; // make room for the next byte + $this->w[$i] += ord($z[4*$i+1]); + $this->w[$i] <<= 8; + $this->w[$i] += ord($z[4*$i+2]); + $this->w[$i] <<= 8; + $this->w[$i] += ord($z[4*$i+3]); + } + + + for (; $iNr+1); $i++) { + $temp = $this->w[$i-1]; + + if ($i%$this->Nk == 0) + $temp = $this->subWord($this->rotWord($temp)) ^ $Rcon[$i/$this->Nk]; + else if ($this->Nk > 6 && $i%$this->Nk == 4) + $temp = $this->subWord($temp); + + $this->w[$i] = $this->w[$i-$this->Nk] ^ $temp; + + self::make32BitWord($this->w[$i]); + } + } + + /** adds the key schedule for a round to a state matrix. + * @returns void + **/ + private function addRoundKey($round) { + $temp = ""; + + for ($i=0; $i<4; $i++) { + for ($j=0; $jw[$round*self::$Nb+$j] >> (3-$i)*8; + // Cast temp from a 32-bit word into an 8-bit byte. + $temp %= 256; + // Can't do unsigned shifts, so we need to make this temp positive + $temp = ($temp < 0 ? (256 + $temp) : $temp); + + $this->s[$i][$j] ^= $temp; // xor temp with the byte at location (i,j) of the state + } + } + } + + /** unmixes each column of a state matrix. + * @returns void + **/ + private function invMixColumns() { + $s0 = $s1 = $s2 = $s3= ''; + + // There are Nb columns + for ($i=0; $is[0][$i]; $s1 = $this->s[1][$i]; $s2 = $this->s[2][$i]; $s3 = $this->s[3][$i]; + + $this->s[0][$i] = $this->mult(0x0e, $s0) ^ $this->mult(0x0b, $s1) ^ $this->mult(0x0d, $s2) ^ $this->mult(0x09, $s3); + $this->s[1][$i] = $this->mult(0x09, $s0) ^ $this->mult(0x0e, $s1) ^ $this->mult(0x0b, $s2) ^ $this->mult(0x0d, $s3); + $this->s[2][$i] = $this->mult(0x0d, $s0) ^ $this->mult(0x09, $s1) ^ $this->mult(0x0e, $s2) ^ $this->mult(0x0b, $s3); + $this->s[3][$i] = $this->mult(0x0b, $s0) ^ $this->mult(0x0d, $s1) ^ $this->mult(0x09, $s2) ^ $this->mult(0x0e, $s3); + + } + } + + /** applies an inverse cyclic shift to the last 3 rows of a state matrix. + * @returns void + **/ + private function invShiftRows() { + $temp = ""; + for ($i=1; $i<4; $i++) { + for ($j=0; $js[$i][$j]; + for ($j=0; $js[$i][$j] = $temp[$j]; + } + } + + /** applies inverse S-Box substitution to each byte of a state matrix. + * @returns void + **/ + private function invSubBytes() { + for ($i=0; $i<4; $i++) + for ($j=0; $js[$i][$j] = self::$invSBox[$this->s[$i][$j]]; + } + + /** mixes each column of a state matrix. + * @returns void + **/ + private function mixColumns() { + $s0 = $s1 = $s2 = $s3= ''; + + // There are Nb columns + for ($i=0; $is[0][$i]; $s1 = $this->s[1][$i]; $s2 = $this->s[2][$i]; $s3 = $this->s[3][$i]; + + $this->s[0][$i] = $this->mult(0x02, $s0) ^ $this->mult(0x03, $s1) ^ $this->mult(0x01, $s2) ^ $this->mult(0x01, $s3); + $this->s[1][$i] = $this->mult(0x01, $s0) ^ $this->mult(0x02, $s1) ^ $this->mult(0x03, $s2) ^ $this->mult(0x01, $s3); + $this->s[2][$i] = $this->mult(0x01, $s0) ^ $this->mult(0x01, $s1) ^ $this->mult(0x02, $s2) ^ $this->mult(0x03, $s3); + $this->s[3][$i] = $this->mult(0x03, $s0) ^ $this->mult(0x01, $s1) ^ $this->mult(0x01, $s2) ^ $this->mult(0x02, $s3); + } + } + + /** applies a cyclic shift to the last 3 rows of a state matrix. + * @returns void + **/ + private function shiftRows() { + $temp = ""; + for ($i=1; $i<4; $i++) { + for ($j=0; $js[$i][($j+$i)%self::$Nb]; + for ($j=0; $js[$i][$j] = $temp[$j]; + } + } + /** applies S-Box substitution to each byte of a state matrix. + * @returns void + **/ + private function subBytes() { + + for ($i=0; $i<4; $i++) { + for ($j=0; $js[$i][$j] = self::$sBox[$this->s[$i][$j]]; + } + } + + /** multiplies two polynomials a(x), b(x) in GF(2^8) modulo the irreducible polynomial m(x) = x^8+x^4+x^3+x+1 + * @returns 8-bit value + **/ + private static function mult($a, $b) { + $sum = self::$ltable[$a] + self::$ltable[$b]; + $sum %= 255; + // Get the antilog + $sum = self::$atable[$sum]; + return ($a == 0 ? 0 : ($b == 0 ? 0 : $sum)); + } + + /** applies a cyclic permutation to a 4-byte word. + * @returns 32-bit int + **/ + private static function rotWord($w) { + $temp = $w >> 24; // put the first 8-bits into temp + $w <<= 8; // make room for temp to fill the lower end of the word + self::make32BitWord($w); + // Can't do unsigned shifts, so we need to make this temp positive + $temp = ($temp < 0 ? (256 + $temp) : $temp); + $w += $temp; + + return $w; + } + + /** applies S-box substitution to each byte of a 4-byte word. + * @returns 32-bit int + **/ + private static function subWord($w) { + $temp = 0; + // loop through 4 bytes of a word + for ($i=0; $i<4; $i++) { + $temp = $w >> 24; // put the first 8-bits into temp + // Can't do unsigned shifts, so we need to make this temp positive + $temp = ($temp < 0 ? (256 + $temp) : $temp); + $w <<= 8; // make room for the substituted byte in w; + self::make32BitWord($w); + $w += self::$sBox[$temp]; // add the substituted byte back + } + + self::make32BitWord($w); + + return $w; + } + + /** reduces a 64-bit word to a 32-bit word + * @returns void + **/ + private static function make32BitWord(&$w) { + // Reduce this 64-bit word to 32-bits on 64-bit machines + $w &= 0x00000000FFFFFFFF; + } +} +?> \ No newline at end of file diff --git a/README.md b/README.md index bcc4b254c..8dd7f778c 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,7 @@ -[![Join the chat at https://gitter.im/griganton/telepy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/griganton/telepy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +# MadelineProto -# About this repo -This is Telegram API for python. -Main aim is to implement MTProto protocol Telegram API on pure Python (not wrapped CLI) +PHP implementation of MTProto, converted from [telepy](https://github.com/griganton/telepy) using [py2php](https://github.com/dan-da/py2php). -### Plan -- [ ] Make it work on Python 2 as well as 3. -- [ ] Follow up the same functionality of CLI API. - - [x] Serialize/Deserialize - - [x] Send and receive PQ authorization with server [[doc]](https://core.telegram.org/mtproto/samples-auth_key) - - [ ] Send and receive service messages with server like logging in to server [[doc]](https://core.telegram.org/mtproto/service_messages) +This is a WIP. -### Useful start points to join -Detailed description of API and protocol can be found here: -* https://core.telegram.org/api -* https://core.telegram.org/mtproto - -API registration is needed to be done by yourself at http://my.telegram.org -Follow Structure - Credentials for provide it your API information. - -# Structure - -- tests - - Serialization and SHA.py -- mtproto.py -- testing.py -- prime.py -- credentials -- rsa.pub - -## Credentials -Repo doesn't contain any credentials to connect Telegram servers. -You can get yours from http://my.telegram.org - -You should place 2 files in the root of your repo: -- credentials -- rsa.pub - -Config example for "credentials" file: - -``` -[App data] -api_id: 12345 -api_hash: 1234567890abcdef1234567890abcdef -ip_address: 112.134.156.178 -port: 443 -``` -rsa.pub contains your RSA key. - -## mtproto.py - -Contains functions to work with MTproto protocol: -- TL schema parsing -- serializing and deserializing -- manage connections to server -- send and receive messages - -## testing.py - -testing.py is used to test functionality of modules. -Now it makes steps from https://core.telegram.org/mtproto/samples-auth_key: -- sends PQ request to server -- parses the result -- factorizes PQ - -## prime.py -prime.py is used in PQ factorization. It has been copied from https://stackoverflow.com/questions/4643647/fast-prime-factorization-module - -## TL schema -We use JSON format TL Shema. TL Schema file contains information about objects and methods, it is located in TL_schema.JSON file in the root of repo. It is fully equivalent to JSON TL Schema from -https://core.telegram.org/schema/mtproto-json +The name of this project is inspired by [this person](https://s-media-cache-ak0.pinimg.com/736x/f0/a1/70/f0a170718baeb0e3817c612d96f5d1cf.jpg), due to the obvious signs of madness this project has in common with her. diff --git a/TL.php b/TL.php new file mode 100644 index 0000000000000000000000000000000000000000..5696308ed365d940cf6c494a47bc39a172be5915 GIT binary patch literal 6745 zcmds5ZExE)5Z-713NBM2Ig67eU5mm?JoF{QvZYPY1_K5o5M+sonaYw&QH`B8e{Em( z$9BgTiIQkL9Xeo}J|vcSJl-9jdw9pgALr9~ub?7iS)7&$4d;=V23PG5eX>hlKRy3B ze0%)*>6@qLXK&y`!gvHCs# z8s=F{Nl=gN>Txd&qf$(B9){$I_|X+-S21|ds5DGiEc#juMLjWP#bCq|aAdx`E+7sN zX<796lCDa9^&~Tg2-s;9 zuphHRQBG7K5F4nxC3{C`TF{kNeNa|Ccu9*Qx}x{COwDVph4wk^nknrq@%x!}S&9;} zqli-R4_Rle;I>fVd{gwZGEJNNbl2E5jbw$O@dct;{;uaJ`Mcg-&t%(63W=ZmI}>fD zY-=W^`nWE|>=ah9Fw&Oer)QIEKqjFJL9?U)ZiN@M4Q{#-X-HE#v(rk)8#x(cttAGd ziU?HT?N!${b}i_Ea31b7UOv z{8ZB9*tZ8vNMuGS(zJ#{NuV}Yb#;fDF>R@u(K;#%Noeg5%H?mt%8cGLxj*ovY>nNO zmX5t!WPFMD+l}&QwVYAyQhQ>ZRN83;xn?Z&H%A!N$jS)nVGWvf!86O^L9iiiFJ-2z z3t45==4e?KN@4ZxjuK)UfNwVNG{}qL5KEfj@H%Ii^=gV2C^iu1P`&IBAD~&pQ#y-w ze|dZM3J$FwdR6unl(Q&hw@|lCt^*JEE!-jAyPJq#6(&Wz$x_fFWI0&C^5O6qzMh-~ z`g|9B*(eUux`2S{LgwsXWaD0;L$0L{YJ~I^IzY4G1bgfe+07|ihh4hPbqphAvGEBG(*W00;2XStQKV21o`*2&O-P%Z*iFla#{ z=#~PdV28XaXA{aziebuVSuHUbO_&Jb_`ZT}u1^k+$io9$y0UFuPAg*#7uaQWZL=)E z8^!(S7`@4i_ed?P%wSmheH=Ati_8;L-ODtI_gJftp~TQrmv# ztj?-VslflrC)?1}4ZM^L$bO$ZAYhUP0#4D5OzoLdkN@W%*zV()c{+Z`9Sor_25`I1 zl@yL;>@#-AL)!q<*U|NP-l20Hzx1(p*W26P?m-NOh;(8O^&y<;yZT5cPz6B24nlkN zQIOE;aO$Q%?7i~D(=Dw2U=ZR+9JBC_T}+rbY@`ow0V|lGmYIEA8^wbWwERhcfE#~j zDhxNaziD!lTlop%@NX#Z(uiBXB!rg!C-*Qu$;(Mf@8dz@@ZdfxXzFQXuJoZDj{V2$ z8C5gaW<|j0D!Cfh3NsW9^v*R@0EgKQf&$MRG#zf}83vv)UUA{98|x zCbfVX3`btQYP_N?6E( zs=)7UH?IX!R){#C%^Md3K$XhnPE4D9k<_YhFEGv`-P9D}j5>yEnN^0mGAw$Wx3`eKb8D#NF?q5kDfqJoB#d_fa=r6O;M^<^$x z%tCE-0(C0Q}gG;9Gq^SNn~#8_h6Y zqQLE(x{AkJl~xyw6Y%jC%{~>@`Xc@}o8yM#a!7xH&bUQvHCWUy_184a3+#^n0z+P+ A{{R30 literal 0 HcmV?d00001 diff --git a/classes/__init__.php b/classes/__init__.php new file mode 100644 index 000000000..48b4106ee --- /dev/null +++ b/classes/__init__.php @@ -0,0 +1,4 @@ +_users = []; + } + function add_user($user) { + $this->_users+= $user; + } +} diff --git a/classes/contact.php b/classes/contact.php new file mode 100644 index 000000000..482ac9126 --- /dev/null +++ b/classes/contact.php @@ -0,0 +1,5 @@ +_path = $path; + } + /** + * truncates the file and create new with :param bytes. + * :return number of bytes written + */ + function write_bytes($bytes) { + // py2php.fixme "with" unsupported. + + } + /** + * read the file as bytes. :return b'' on file not exist + */ + function read_bytes() { + if (!(new exists($this->_path))) { + return ''; + } + // py2php.fixme "with" unsupported. + + } + /** + * tries to open with os default viewer + */ + function open() { + new call((os::name == 'nt') ? 'cmd /c start "" "' . $this->_path . '"' : [platform::startswith('darwin') ? 'open' : 'xdg-open', $this->_path]); + } + /** + * try to remove the file + */ + function remove() { + try { + os::remove($this->_path); + } + catch(FileNotFoundError $e) { + } + } +} diff --git a/classes/message.php b/classes/message.php new file mode 100644 index 000000000..a621e2795 --- /dev/null +++ b/classes/message.php @@ -0,0 +1,6 @@ +'; + function preloop() { + require_once ('classes.telepy.php'); + $this->_telepy = new Telepy(); + } + function precmd($line) { + $line = $line->lstrip(); + $blank_pos = $line->find(' '); + if (($blank_pos < 0)) { + return $line->lower(); + } + return array_slice($line, null, $blank_pos)->lower() . ' ' . array_slice($line, ($blank_pos + 1), null); + } + function completedefault( . . . $ignored) { + pyjslib_printnl($ignored); + } + function complete($text, $state) { + $this->super()->complete($text, $state); + pyjslib_printnl('completing'); + } + /** + * shell + * lets you use external shell. ! for short-hand. + */ + function do_shell($line) { + pyjslib_printnl(os::popen($line)->read()); + } + /** + * msg + * sends message to this peer + */ + function do_msg($arg) { + } + /** + * fwd + * forward message to user. You can see message numbers starting client with -N + */ + function do_fwd($arg) { + } + /** + * chat_with_peer + * starts one on one chat session with this peer. /exit or /quit to end this mode. + */ + function do_chat_with_peer($arg) { + } + /** + * add_contact + * tries to add contact to contact-list by phone + */ + function do_add_contact($arg) { + } + /** + * rename_contact + * tries to rename contact. If you have another device it will be a fight + */ + function do_rename_contact($arg) { + } + /** + * mark_read + * mark read all received messages with peer + */ + function do_mark_read($arg) { + } + /** + * delete_msg + * deletes message (not completly, though) + */ + function do_delete_msg($arg) { + } + /** + * restore_msg + * restores delete message. Impossible for secret chats. Only possible short time (one hour, I think) after deletion + */ + function do_restore_msg($arg) { + } + /** + * send_photo + * sends photo to peer + */ + function do_send_photo($arg) { + } + /** + * send_video + * sends video to peer + */ + function do_send_video($arg) { + } + /** + * send_text + * sends text file as plain messages + */ + function do_send_text($arg) { + } + /** + * load_photo + * loads photo to download dir + */ + function do_load_photo($arg) { + } + /** + * load_video + * loads video to download dir + */ + function do_load_video($arg) { + } + /** + * load_video_thumb + * loads video thumbnail to download dir + */ + function do_load_video_thumb($arg) { + } + /** + * load_audio + * loads audio to download dir + */ + function do_load_audio($arg) { + } + /** + * load_document + * loads document to download dir + */ + function do_load_document($arg) { + } + /** + * load_document_thumb + * loads document thumbnail to download dir + */ + function do_load_document_thumb($arg) { + } + /** + * view_photo + * loads photo/video to download dir and starts system default viewer + */ + function do_view_photo($arg) { + } + /** + * view_video + */ + function do_view_video($arg) { + } + /** + * view_video_thumb + */ + function do_view_video_thumb($arg) { + } + /** + * view_audio + */ + function do_view_audio($arg) { + } + /** + * view_document + */ + function do_view_document($arg) { + } + /** + * view_document_thumb + */ + function do_view_document_thumb($arg) { + } + /** + * fwd_media + * send media in your message. Use this to prevent sharing info about author of media (though, it is possible to determine user_id from media itself, it is not possible get access_hash of this user) + */ + function do_fwd_media($arg) { + } + /** + * set_profile_photo + * sets userpic. Photo should be square, or server will cut biggest central square part + */ + function do_set_profile_photo($arg) { + } + /** + * chat_info + * prints info about chat + */ + function do_chat_info($arg) { + $arg = $arg->split(); + if ((count($arg) == 1)) { + pyjslib_printnl(['chat_info called with ', $arg[0]]); + } + } + /** + * chat_add_user + * add user to chat + */ + function do_chat_add_user($arg) { + pyjslib_printnl($arg); + } + /** + * chat_del_user + * remove user from chat + */ + function do_chat_del_user($arg) { + } + /** + * chat_rename + * rename chat room + */ + function do_chat_rename($arg) { + $arg = $arg->split(); + } + /** + * create_group_chat ... + * creates a groupchat with users, use chat_add_user to add more users + */ + function do_create_group_chat($chat_topic, $user1, $user2, $user3) { + pyjslib_printnl($chat_topic); + pyjslib_printnl([$user1, $user2, $user3]); + } + /** + * chat_set_photo + * sets group chat photo. Same limits as for profile photos. + */ + function do_chat_set_photo($chat, $photo) { + } + /** + * search + * searches pattern in messages with peer + */ + function do_search($pattern) { + } + /** + * global_search + * searches pattern in all messages + */ + function do_global_search($pattern) { + } + /** + * create_secret_chat + * creates secret chat with this user + */ + function do_create_secret_chat($user) { + } + /** + * visualize_key + * prints visualization of encryption key. You should compare it to your partner's one + */ + function do_visualize_key($secret_chat) { + } + /** + * set_ttl + * sets ttl to secret chat. Though client does ignore it, client on other end can make use of it + */ + function do_set_ttl($secret_chat, $ttl) { + } + /** + * accept_secret_chat + * manually accept secret chat (only useful when starting with -E key) + */ + function do_accept_secret_chat($secret_chat) { + } + /** + * user_info + * prints info about user + */ + function do_user_info($user) { + } + /** + * history [limit] + * prints history (and marks it as read). Default limit = 40 + */ + function do_history($peer, $limit = 40) { + if (($peer == '')) { + pyjslib_printnl('no peer have specified'); + return; + } + $args = $peer->split(); + if (!in_array(count($args), [1, 2])) { + pyjslib_printnl(['not appropriate number of arguments : ', $peer]); + return; + } + if ((count($args) == 2)) { + if (!($args[1]->isdecimal()) || (pyjslib_int($args[1]) < 1)) { + pyjslib_printnl(['not a valid limit:', $args[1]]); + } + $limit = pyjslib_int($args[1]); + } + pyjslib_printnl($peer); + pyjslib_printnl($limit); + } + /** + * dialog_list + * prints info about your dialogs + */ + function do_dialog_list($ignored) { + } + /** + * contact_list + * prints info about users in your contact list + */ + function do_contact_list($ignored) { + } + /** + * suggested_contacts + * print info about contacts, you have max common friends + */ + function do_suggested_contacts($ignored) { + } + /** + * stats + * just for debugging + */ + function do_stats($ignored) { + } + /** + * export_card + * print your 'card' that anyone can later use to import your contact + */ + function do_export_card($card) { + } + /** + * import_card + * gets user by card. You can write messages to him after that. + */ + function do_import_card($card) { + } + /** + * quit_force + * quit without waiting for query ends + */ + function do_quit_force($ignored) { + return true; + } + /** + * quit + * wait for all queries to end then quit + */ + function do_quit($ignored) { + return true; + } +} diff --git a/classes/telepy.php b/classes/telepy.php new file mode 100644 index 000000000..b3d172188 --- /dev/null +++ b/classes/telepy.php @@ -0,0 +1,26 @@ +_config = $configparser->ConfigParser(); + if (!($this->_config->read('credentials'))) { + pyjslib_printnl('File \'credentials\' seems to not exist.'); + $exit(-1); + } + $ip = $this->_config->get('App data', 'ip_address'); + $port = $this->_config->getint('App data', 'port'); + $this->_session = $mtproto->Session($ip, $port); + $this->_session->create_auth_key(); + $__temp22 = py2php_kwargs_method_call($this->_session, 'method_call', ['get_future_salts'], ["num" => 3]); + $this->_salt = $__temp22; + $future_salts = $__temp22; + } +} diff --git a/classes/user.php b/classes/user.php new file mode 100644 index 000000000..cb62cb960 --- /dev/null +++ b/classes/user.php @@ -0,0 +1,12 @@ +uid = $uid; + } +} diff --git a/crypt.php b/crypt.php new file mode 100644 index 000000000..80e7dd4bb --- /dev/null +++ b/crypt.php @@ -0,0 +1,58 @@ + 'encrypt']); +} +function ige_decrypt($message, $key, $iv) { + return py2php_kwargs_function_call('_ige', [$message, $key, $iv], ["operation" => 'decrypt']); +} +/** + * Given a key, given an iv, and message + * do whatever operation asked in the operation field. + * Operation will be checked for: "decrypt" and "encrypt" strings. + * Returns the message encrypted/decrypted. + * message must be a multiple by 16 bytes (for division in 16 byte blocks) + * key must be 32 byte + * iv must be 32 byte (it's not internally used in AES 256 ECB, but it's + * needed for IGE) + */ +function _ige($message, $key, $iv, $operation = 'decrypt') { + $message = $bytes($message); + if ((count($key) != 32)) { + throw new $ValueError('key must be 32 bytes long (was ' . pyjslib_str(count($key)) . ' bytes)'); + } + if ((count($iv) != 32)) { + throw new $ValueError('iv must be 32 bytes long (was ' . pyjslib_str(count($iv)) . ' bytes)'); + } + $cipher = new AES($key); + $cipher = $cipher->encrypt($iv); + $blocksize = $cipher->block_size; + if (((count($message) % $blocksize) != 0)) { + throw new $ValueError('message must be a multiple of 16 bytes (try adding ' . pyjslib_str((16 - (count($message) % 16))) . ' bytes of padding)'); + } + $ivp = array_slice($iv, 0, $blocksize - 0); + $ivp2 = array_slice($iv, $blocksize, null); + $ciphered = $bytes(); + foreach (pyjslib_range(0, count($message), $blocksize) as $i) { + $indata = array_slice($message, $i, ($i + $blocksize) - $i); + if (($operation == 'decrypt')) { + $xored = new strxor($indata, $ivp2); + $decrypt_xored = $cipher->decrypt($xored); + $outdata = new strxor($decrypt_xored, $ivp); + $ivp = $indata; + $ivp2 = $outdata; + } else if (($operation == 'encrypt')) { + $xored = new strxor($indata, $ivp); + $encrypt_xored = $cipher->encrypt($xored); + $outdata = new strxor($encrypt_xored, $ivp2); + $ivp = $outdata; + $ivp2 = $indata; + } else { + throw new $ValueError('operation must be either \'decrypt\' or \'encrypt\''); + } + $ciphered+= $outdata; + } + return $ciphered; +} diff --git a/libpy2php/libpy2php.php b/libpy2php/libpy2php.php new file mode 100644 index 000000000..c18ce77d5 --- /dev/null +++ b/libpy2php/libpy2php.php @@ -0,0 +1,486 @@ + $call_cnt + 1 ) { + $found = true; + } + } + if( !$found ) { + $done = true; + } + $results[] = call_user_func_array($callable, $func_args); + $call_cnt ++; + } + return $results; +} + +function pyjslib_zip() { + $params = func_get_args(); + if (count($params) === 1){ // this case could be probably cleaner + // single iterable passed + $result = array(); + foreach ($params[0] as $item){ + $result[] = array($item); + }; + return $result; + }; + $result = call_user_func_array('array_map',array_merge(array(null),$params)); + $length = min(array_map('count', $params)); + return array_slice($result, 0, $length); +} + +function pyjslib_is_assoc($arr) +{ + return array_keys($arr) !== range(0, count($arr) - 1); +} + +function pyjslib_dict($arg=null) { + if( $arg === null ) { + return []; + } + if( pyjslib_is_assoc( $arg )) { + return $arg; + } + $dict = []; + foreach( $arg as $a ) { + if( count($a) == 2 ) { + $dict[$a[0]] = $a[1]; + } + } + return $dict; +} + +function pyjslib_printWorker($objs, $nl, $multi_arg, $depth=1) { + $buf = ''; + if( is_array( $objs ) && $multi_arg && $depth == 1) { + $cnt = 0; + foreach( $objs as $obj ) { + if( $cnt ++ > 0 ) { + $buf .= " "; + } + $buf .= pyjslib_printWorker( $obj, $nl, $multi_arg, $depth + 1 ); + } + } + else if( is_bool( $objs )) { + $buf = $objs ? "True" : "False"; + } + else if( is_null( $objs )) { + $buf = 'None'; + } + else if( is_float( $objs )) { + $buf = (int)$objs; + } + else if( is_string( $objs ) && ($multi_arg && $depth > 2 || (!$multi_arg && $depth > 1) ) ) { + $buf = "'$objs'"; + } + elseif( is_array( $objs )) { + $buf = '['; + $cnt = 0; + foreach( $objs as $obj ) { + $val = pyjslib_printWorker($obj, $nl, false, $depth + 1); + if( $cnt ++ > 0 ) { + $buf .= ', '; + } + $buf .= $val; + } + $buf .= "]"; +// $buf = '[' . implode( ", ", $objs ) . ']'; + } + else { + $buf = $objs; + } + if( $depth == 1 && (!strlen($buf) || $buf[strlen($buf)-1] != "\n") ) { + $buf .= $nl ? "\n" : " "; + } + return $buf; +} + +function pyjslib_repr($obj) { + return pyjslib_printWorker($obj, false, false); +} + +function pyjslib_print($objs, $multi_arg=false) { + echo pyjslib_printWorker($objs, false, $multi_arg); +} + +function pyjslib_printnl($objs, $multi_arg=false) { + echo pyjslib_printWorker($objs, true, $multi_arg); +} + +function py2php_kwargs_function_call($funcname, $ordered, $named) { + + if( $funcname == 'array' || $funcname == 'pyjslib_dict' ) { + return $named; + } + + $num_ordered = count($ordered); + $count = 1; + + $refFunc = new ReflectionFunction($funcname); + foreach( $refFunc->getParameters() as $param ){ + if( $param->isVariadic() ) { + $ordered[$count-1] = $named; + break; + } + //invokes ReflectionParameter::__toString + if( $count > $num_ordered ) { + $name = $param->name; + $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; + $ordered[] = @$named[$name] ?: $default; + } + + $count ++; + } + //var_dump($ordered); + return call_user_func_array($funcname, $ordered); +} + +function py2php_kwargs_method_call( $obj, $method, $ordered, $named ) { + + $num_ordered = count($ordered); + $count = 1; + + $refFunc = new ReflectionMethod($obj, $method); + foreach( $refFunc->getParameters() as $param ){ + //invokes ReflectionParameter::__toString + if( $count > $num_ordered ) { + $name = $param->name; + $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; + $ordered[] = @$named[$name] ?: $default; + } + + $count ++; + } + + $callable = [$obj, $method]; + return call_user_func_array($callable, $ordered); +} + +class IOError extends Exception{ +} + +class ValueError extends Exception{ +} + + +function pyjslib_open( $name, $mode="r", $buffering=null ) { + return new pyjslib_file( $name, $mode, $buffering ); +} + +class pyjslib_file implements Iterator { + + private $fh = false; + private $current_line = null; + + // public attributes of python file class. + public $closed = true; + public $encoding = null; + public $errors = []; + public $mode = null; + public $newlines = null; + public $softspace = false; + + function __construct($name_or_fd, $mode="r", $buffering=null) { + if( is_resource($name_or_fd) ) { + $this->fh = $name_or_fd; + $this->closed = false; + $meta = stream_get_meta_data( $name_or_df ); + $this->mode = $meta['mode']; + return; + } + $name = $name_or_fd; + try { + $this->fh = fopen($name, $mode); + if( !$this->fh ) { + throw new Exception("Could not open $name"); + } + $this->closed = false; + $this->mode = $mode; + } + catch( Exception $e ) { + throw new IOError( $e->getMessage(), $e->getCode() ); + } + } + + + + function close() { + if( $this->fh ) { + fclose( $this->fh ); + $this->fh = null; + $this->closed = true; + } + } + + function flush() { + if( !$this->fh ) { + throw new ValueError("File is closed."); + } + fflush( $this->fh ); + } + + function fileno() { + if( !$this->fh ) { + throw new ValueError("File is closed."); + } + return $this->fh; + } + + function isatty() { + if( !$this->fh ) { + throw new ValueError("File is closed."); + } + return posix_isatty( $this->fh ); + } + + /* --- + * Begin PHP Iterator implementation + * --- + */ + function rewind() { + fseek( $this->fh, 0 ); + $this->line = 0; + } + + function current() { + if( !$this->current_line ) { + $this->current_line = fgets( $this->fh ); + } + return $this->current_line; + } + + function key() { + return $this->line; + } + + function next() { + $this->current(); // ensure current line has been retrieved. + $this->current_line = fgets( $this->fh ); + $this->line ++; + return $this->current_line; + } + + function valid() { + return $this->fh != false && !feof( $this->fh ); + } + /* --- + * End PHP Iterator implementation + * --- + */ + + function read($size=null) { + if( $size !== null) { + return fread( $this->fh, $size); + } + return stream_get_contents( $this->fh ); + } + + function readline($size=null) { + return fgets( $this->fh, $size ); + } + + function readlines($sizehint=null) { + $len = 0; + $lines = array(); + while( $line = fgets( $this->fh ) ) { + $len += strlen( $line ); + $lines[] = $line; + if( $sizehint && $len >= $sizehint ) { + break; + } + } + return $lines; + } + + function seek($offset, $whence=SEEK_SET) { + return fseek( $this->fh, $offset, $whence); + } + + function tell() { + return ftell($this->fh); + } + + function truncate( $size ) { + $rc = ftruncate( $this->fh, $size ); + } + + function write( $str ) { + fwrite( $this->fh, $str ); + } + + function writelines($sequence) { + foreach($sequence as $line) { + $this->write( $line ); + } + } +} + diff --git a/libpy2php/os.php b/libpy2php/os.php new file mode 100644 index 000000000..4f9bbc4f1 --- /dev/null +++ b/libpy2php/os.php @@ -0,0 +1,570 @@ + $v) { + $attr = "st_" . $key; + $obj->$attr = $v; + } + return $obj; + } + + static public function fstatvfs($fd) { + self::_unimplemented(); + } + + static public function fsync($fd) { + fsync($fd); + } + + static public function ftruncate($fd, $length) { + ftruncate($fd, $length); + } + + static public function isatty($fd) { + return posix_isatty( $fd ); + } + + static public function lseek($fd, $pos, $how) { + lseek($fd, $pos, $how); + } + + static public function open($file, $flags, $mode=0777) { + // todo: define and map flag constants. See list at: + // https://docs.python.org/2/library/os.html#open-flag-constants + + $fl = ''; + if( $flags & self::O_RDONLY ) { + $fl .= 'r'; + } + if( $flags & self::O_WRONLY ) { + $fl .= 'w'; + } + if( $flags & self::O_RDWR ) { + $fl .= 'rw'; + } + if( $flags & self::O_APPEND ) { + $fl .= 'a'; + } + if( $flags & self::O_CREAT ) { + $fl .= 'c'; + } + if( $flags & self::O_EXCL ) { + $fl .= 'x'; + } + if( $flags & self::O_TRUNC ) { + $fl .= 'w'; + } + + return fopen($file, $fl, false ); + } + + static public function pipe() { + self::_unimplemented(); + } + + static public function read($fd, $n) { + return fread( $fd, $n ); + } + + static public function tcgetpgrp($fd) { + self::_unimplemented(); + } + + static public function tcsetpgrp($fd, $pg) { + self::_unimplemented(); + } + + static public function ttyname($fd) { + return posix_ttyname($fd); + } + + static public function write($fd, $str) { + return fwrite( $fd, $str ); + } + + static function access($path, $mode) { + return posix_access($path, $mode); + } + + static function chdir($path) { + chdir( $path ); + } + + static function fchdir($path) { + fchdir( $path ); + } + + static function getcwd() { + return getcwd(); + } + + static function getcwdu() { + return getcwd(); + } + + static function chflags($path, $flags) { + self::_unimplemented(); + } + + static function chroot($path) { + chroot($path); + } + + static function chmode($path, $mode) { + self::_unimplemented(); + } + + static function chown($path, $uid, $gid) { + chown($path, $uid, $gid); + } + + static function lchflags($path, $flags) { + self::_unimplemented(); + } + + static function lchmod($path, $mode) { + self::_unimplemented(); + } + + static function lchown($path, $uid, $gid) { + self::_unimplemented(); + } + + static function link($source, $link_name) { + link($source, $link_name); + } + + static function listdir($path) { + self::_unimplemented(); + } + + static function lstat($path) { + self::_unimplemented(); + } + + static function mkfifo($path, $mode=0666) { + posix_mkfifo($path, $mode); + } + + static function mknod($filename, $mode=0666, $device=0) { + return posix_mknod( $filename, $mode ); + } + + static function major($path, $flags) { + self::_unimplemented(); + } + + static function minor($path, $flags) { + self::_unimplemented(); + } + + static function makedev($major, $minor) { + self::_unimplemented(); + } + + static function mkdir($path, $mode=0777) { + mkdir($path, $mode, $recursive=false); + } + + static function makedirs($path, $mode=0777) { + mkdir($path, $mode, $recursive=true); + } + + static function pathconf($path, $name) { + self::_unimplemented(); + } + + static function readlink($path) { + return readlink($path); + } + + static function remove($path) { + if( !is_file( $path ) ) { + throw new OSError("Path is not a file. $path"); + } + try { + unlink( $path ); + } + catch( Exception $e ) { + throw new OSError( $e->getMessage(), $e->getCode() ); + } + } + + static function removedirs($path) { + self::_unimplemented(); + } + + static function rename($src, $dst) { + if( is_dir($dst)) { + throw new OSError("Destination is a directory. $dst"); + } + rename($src, $dst); + } + + static function renames($old, $new) { + self::makedirs( dirname($new) ); + self::rename($old, $new); + } + + static function rmdir($path) { + rmdir($pat); + } + + static function stat($path) { + $arr = stat($path); + if(!$arr) { + throw new OSError("Path does not exist. $path"); + } + $obj = new stdClass; + foreach($arr as $key => $v) { + $attr = "st_" . $key; + $obj->$attr = $v; + } + return $obj; + } + + static function stat_float_times($newvalue=null) { + self::_unimplemented(); + } + + static function statvfs() { + self::_unimplemented(); + } + + static function symlink($source, $link_name) { + symlink($source, $link_name); + } + + static function tempnam($dir=null, $prefix='') { + if( !$dir ) { + $dir = sys_get_temp_dir() ; + } + $name = tempnam($dir, $prefix); + unlink($name); + return $name; + } + + static function tmpnam() { + return self::tempnam(); + } + + static function unlink($path) { + unlink($path); + } + + static function utime($path, $times) { + self::_unimplemented(); + } + + static function walk($top, $topdown=true, $onerror=null, $followlinks=false) { + self::_unimplemented(); + } + + /** + * Begin Process Management + */ + + static function abort() { + self::_unimplemented(); + } + + static function execl($path, $arg0, $arg1) { + self::_unimplemented(); + } + + static function execle($path, $arg0, $arg1, $env) { + self::_unimplemented(); + } + + static function execlp($file, $arg0, $arg1) { + self::_unimplemented(); + } + + static function execlpe($file, $arg0, $arg1, $env) { + self::_unimplemented(); + } + + static function execv($path, $args) { + self::_unimplemented(); + } + + static function execve($path, $args, $env) { + self::_unimplemented(); + } + + static function execvp($file, $args) { + self::_unimplemented(); + } + + static function execvpe($file, $args, $env) { + self::_unimplemented(); + } + + static function _exit($n) { + exit($n); + } + + static function fork() { + return pcntl_fork(); + } + + static function forkpty() { + self::_unimplemented(); + } + + static function kill($pid, $sig) { + posix_kill($pid, $sig); + } + + static function killpg($pgid, $sig) { + self::_unimplemented(); + } + + static function nice($increment) { + proc_nice($increment); + } + + static function plock($op) { + self::_unimplemented(); + } + + + + private static function _unimplemented() { + throw new Exception( "Unimplemented. Please consider submitting a patch to py2php project on github."); + } +} + diff --git a/libpy2php/os_path.php b/libpy2php/os_path.php new file mode 100644 index 000000000..a937bfefd --- /dev/null +++ b/libpy2php/os_path.php @@ -0,0 +1,214 @@ + $v ) { + if( !is_scalar( $v )) { + continue; + } + $map['$' . $k] = $v; + $map['${' . $k . '}'] = $v; + } + return strtr($path, $map); + } + + static function getatime($path) { + try { + $rc = fileatime($path); + return $rc; + } + catch( Exception $e ) { + throw new OSError($e->getMessage, $e->getCode()); + } + } + + static function getmtime($path) { + try { + $rc = filemtime($path); + return $rc; + } + catch( Exception $e ) { + throw new OSError($e->getMessage, $e->getCode()); + } + } + + static function getctime($path) { + try { + $rc = filectime($path); + return $rc; + } + catch( Exception $e ) { + throw new OSError($e->getMessage, $e->getCode()); + } + } + + static function getsize($path) { + try { + $rc = filesize($path); + return $rc; + } + catch( Exception $e ) { + throw new OSError($e->getMessage, $e->getCode()); + } + } + + static function isabs($path) { + // fixme: implement check for windows. + return $path[0] == '/'; + } + + static function isfile($path) { + return is_file($path); + } + + static function isdir($path) { + return is_dir($path); + } + + static function islink($path) { + return is_link($path); + } + + static function ismount($path) { + self::_unimplemented(); + } + + static function split($path) { + $parts = explode(DIRECTORY_SEPARATOR, $path); + $first = implode(DIRECTORY_SEPARATOR, array_slice($parts, 0, count($parts)-1 )); + $last = $parts[count($parts)-1]; + return array($first, $last); + } + + static function join($path, ...$paths) { + $buf = rtrim($path, '/'); + foreach( $paths as $p ) { + $i = 0; + $p = trim( $p, '/'); + $buf .= DIRECTORY_SEPARATOR . $p; + } + return $buf; + } + + static function normcase($path) { + // fixme: different behavior on windows. + return $path; + } + + static function normpath($path) { + return realpath($path); + } + + static function realpath($path) { + return realpath($path); + } + + static function relpath($path, $start) { + self::_unimplemented(); + } + + static function samefile($path1, $path2) { + return fileinode($path1) == fileinode($path2); + } + + static function sameopenfile($fd1, $fd2) { + $s1 = fstat( $fd1 ); + $s2 = fstat( $fd2 ); + return $s1['ino'] == $s2['ino']; + } + + static function samestat($stat1, $stat2) { + return $stat1 == $stat2; + } + + static function splitdrive($path) { + //fixme: implement windows case. + return array('', $path); + } + + static function splitext($path) { + $first = $path; + $second = ''; + + $pos = strrpos( $path, '.'); + if( $pos !== false ) { + $first = substr($path, 0, $pos); + $second = substr($path, $pos); + } + + return array($first, $second); + } + + static function splitunc($path) { + self::_unimplemented(); + } + + static function walk($path, $visit, $arg) { + // Note: deprecated in python 3 in favor of os.walk() + self::_unimplemented(); + } + + private static function _unimplemented() { + throw new Exception( "Unimplemented. Please consider submitting a patch to py2php project on github."); + } + +} \ No newline at end of file diff --git a/libpy2php/strict_mode.php b/libpy2php/strict_mode.php new file mode 100644 index 000000000..7549d442d --- /dev/null +++ b/libpy2php/strict_mode.php @@ -0,0 +1,134 @@ +getCode(), $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString() ); + while( ( $e = $e->getPrevious() ) ) { + $msg .= sprintf( "\nPrevious Exception. code: %s, message: %s\n%s : %s\n\nStack Trace:\n%s\n", $e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString() ); + } + echo $msg; + // error_log( $msg ); + strict_mode_mail_admin( 'Uncaught exception!', $msg ); + echo "\n\nNow exiting. Please report this problem to the software author\n\n"; + exit(1); +} + +/** + * This shutdown handler callback prints a message and sends email on any PHP fatal error + */ +function shutdown_handler() { + + $error = error_get_last(); + + $ignore = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_STRICT | E_DEPRECATED | E_USER_DEPRECATED; + if ( $error && ($error['type'] & $ignore) == 0) { + + // error keys: type, file, line, message + $msg = "Ouch! Encountered PHP Fatal Error. Shutting down.\n" . print_r( $error, true ); + echo $msg; + strict_mode_mail_admin( 'PHP Fatal Error!', $msg ); + } +} + +/** + * email admin if defined + */ +function strict_mode_mail_admin( $subject, $msg ) { + $subject = sprintf( '[%s] [%s] %s [pid: %s]', gethostname(), basename($_SERVER['PHP_SELF']), $subject, getmypid() ); + if( defined('ALERTS_MAIL_TO') ) { + mail( ALERTS_MAIL_TO, $subject, $msg ); + } + else { + echo "\nWARNING: ALERTS_MAIL_TO not defined in environment. alert not sent with subject: $subject\n"; + } +} diff --git a/mtproto.php b/mtproto.php new file mode 100755 index 0000000000000000000000000000000000000000..f58402e351389bc890419ea748d9ab9ea3474084 GIT binary patch literal 12431 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 Q4fhu-Z;|QqJ-uA~e^!)(rvLx| literal 0 HcmV?d00001 diff --git a/prime.php b/prime.php new file mode 100644 index 000000000..af5b670d1 --- /dev/null +++ b/prime.php @@ -0,0 +1,171 @@ + 1); + $N = [0 => $N, 1 => ($N - 1), 2 => ($N + 4), 3 => ($N + 3), 4 => ($N + 2), 5 => ($N + 1) ][($N % 6) ]; + $sieve = ([true] * ($N / 3)); + $sieve[0] = false; + foreach (pyjslib_range(((pyjslib_int(pow($N, 0.5)) / 3) + 1)) as $i) { + if ($sieve[$i]) { + $k = ((3 * $i) + 1) | 1; + $sieve[(($k * $k) / 3), null, (2 * $k) ] = // finish this + ([false] * ((((($N / 6) - (($k * $k) / 6)) - 1) / $k) + 1)); + $sieve[(((($k * $k) + (4 * $k)) - ((2 * $k) * ($i % 2))) / 3), null, (2 * $k) ] = ([false] * ((((($N / 6) - (((($k * $k) + (4 * $k)) - ((2 * $k) * ($i % 2))) / 6)) - 1) / $k) + 1)); + } + } + // finish this + return ([2, 3] + [(3 * $i + 1) | 1 for $i in range(1, floor($N/3) - $correction) if $sieve[$i]] + ); +} +$smallprimeset = set(primesbelow(100000)); +$_smallprimeset = 100000; +function isprime($n, $precision = 7) { + if (($n == 1) || (($n % 2) == 0)) { + return false; + } else if (($n < 1)) { + throw new $ValueError('Out of bounds, first argument must be > 0'); + } else if (($n < $_smallprimeset)) { + return in_array($n, $smallprimeset); + } + $d = ($n - 1); + $s = 0; + while ((($d % 2) == 0)) { + $d + //= 2; + $s+= 1; + } + foreach (pyjslib_range($precision) as $repeat) { + $a = random::randrange(2, ($n - 2)); + $x = pow($a, $d, $n); + if (($x == 1) || ($x == ($n - 1))) { + continue; + } + foreach (pyjslib_range(($s - 1)) as $r) { + $x = pow($x, 2, $n); + if (($x == 1)) { + return false; + } + if (($x == ($n - 1))) { + break; + } + } + } + return true; +} +function pollard_brent($n) { + if ((($n % 2) == 0)) { + return 2; + } + if ((($n % 3) == 0)) { + return 3; + } + list($y, $c, $m) = [random::randint(1, ($n - 1)), random::randint(1, ($n - 1)), random::randint(1, ($n - 1)) ]; + list($g, $r, $q) = [1, 1, 1]; + while (($g == 1)) { + $x = $y; + foreach (pyjslib_range($r) as $i) { + $y = ((pow($y, 2, $n) + $c) % $n); + } + $k = 0; + while (($k < $r) && ($g == 1)) { + $ys = $y; + foreach (pyjslib_range(min($m, ($r - $k))) as $i) { + $y = ((pow($y, 2, $n) + $c) % $n); + $q = (($q * abs(($x - $y))) % $n); + } + $g = gcd($q, $n); + $k+= $m; + } + $r*= 2; + } + if (($g == $n)) { + while (true) { + $ys = ((pow($ys, 2, $n) + $c) % $n); + $g = gcd(abs(($x - $ys)), $n); + if (($g > 1)) { + break; + } + } + } + return $g; +} +$smallprimes = primesbelow(10000); +function primefactors($n, $sort = false) { + $factors = []; + $limit = (pyjslib_int(pow($n, 0.5)) + 1); + foreach ($smallprimes as $checker) { + if (($checker > $limit)) { + break; + } + while ((($n % $checker) == 0)) { + $factors[] = $checker; + $n + //= $checker; + $limit = (pyjslib_int(pow($n, 0.5)) + 1); + if (($checker > $limit)) { + break; + } + } + } + if (($n < 2)) { + return $factors; + } + while (($n > 1)) { + if (isprime($n)) { + $factors[] = $n; + break; + } + $factor = pollard_brent($n); + $factors->extend(primefactors($factor)); + $n + //= $factor; + + } + if ($sort) { + $factors->sort(); + } + return $factors; +} +function factorization($n) { + $factors = []; + foreach (primefactors($n) as $p1) { + try { + $factors[$p1]+= 1; + } + catch(KeyError $e) { + $factors[$p1] = 1; + } + } + return $factors; +} +$totients = []; +function totient($n) { + if (($n == 0)) { + return 1; + } + try { + return $totients[$n]; + } + catch(KeyError $e) { + } + $tot = 1; + foreach (factorization($n)->items() as list($p, $exp)) { + $tot*= (($p - 1) * pow($p, ($exp - 1))); + } + $totients[$n] = $tot; + return $tot; +} +function gcd($a, $b) { + if (($a == $b)) { + return $a; + } + while (($b > 0)) { + list($a, $b) = [$b, ($a % $b) ]; + } + return $a; +} +function lcm($a, $b) { + return (abs(($a * $b)) / gcd($a, $b)); +} diff --git a/telepy.php b/telepy.php new file mode 100644 index 000000000..41a1168cd --- /dev/null +++ b/telepy.php @@ -0,0 +1,14 @@ + 'Python implementation of telegram API.']); + py2php_kwargs_method_call($parser, 'add_argument', ['command'], ["nargs" => '?', "choices" => (['cmd', 'dialog_list', 'contact_list'] + /* py2php.fixme listcomp unsupported. */ + ) ]); + py2php_kwargs_method_call($parser, 'add_argument', ['args'], ["nargs" => '*']); + $args = $parser->parse_args(); + if (($args->command == null)) { + new TelepyShell()->cmdloop(); + } +} diff --git a/testing.php b/testing.php new file mode 100644 index 000000000..4edf589a4 --- /dev/null +++ b/testing.php @@ -0,0 +1,22 @@ +ConfigParser(); +if (!($config->read('credentials'))) { + pyjslib_printnl('File \'credentials\' seems to not exist.'); + $exit(-1); +} +$ip = $config->get('App data', 'ip_address'); +$port = $config->getint('App data', 'port'); +$Session = mtproto::Session($ip, $port); +Session::create_auth_key(); +$future_salts = py2php_kwargs_function_call('Session::method_call', ['get_future_salts'], ["num" => 3]); +pyjslib_printnl($future_salts); diff --git a/tests/SHA.php.tmp b/tests/SHA.php.tmp new file mode 100644 index 000000000..fb920bc29 --- /dev/null +++ b/tests/SHA.php.tmp @@ -0,0 +1,24 @@ +-------------------------- +- BEGIN OF Serialization - +-------------------------- + +