بدأ Google App Script و Mikrotik و Telegram و VPNBook في تشغيل الرباعية

اليوم في البرنامج: أين يمكنك تطبيق Google Apps Script إذا انتهت الأفكار العادية. أتمتة العمل مع VPNBook من خلال سلسلة من البرامج النصية بلغات مختلفة لا أعرفها. Nedo-cURL بواسطة Mikrotik. برقية عبر مكان واحد ، حتى لا تكون في مكان آخر ، يسمح بالإشراف الذاتي.

الجزء 1. بلا عنوان


منذ عام ، كتبت ملاحظة " تقريبا OCR للحصول على كلمة مرور VPNBook. PHP + Mikrotik " حول كيفية إعداد استرداد كلمة المرور التلقائي في جهاز توجيه Mikrotik للوصول المجاني إلى VPN عبر VPNBook. بداية القصة هناك.

منذ ذلك الحين ، تدفقت الكثير من المياه ، وفي روسيا قاموا بحظر موقع VPNBook ، ولكن ليس خوادم VPN العامة نفسها ، والتي يتم نشرها على هذا الموقع. سيناريو PHP هذا لفك تشفير صورة PNG لكلمة مرور في سلسلة نصية يجب أن يعمل الآن أيضًا عند تشغيله على خادم لا تمر مرورته عبر نظام الحظر. ولكن منذ بعض الوقت ، من خلال تجربة script.google.com لخدمة Google Apps Script (GAS) ، قررت التخلي عن البرنامج النصي PHP على خادم ويب خارجي ، واستبداله جزئيًا أو كليًا ببرنامج نصي GAS يعمل كتطبيق ويب (تطبيق ويب). لم أفهم سياسة التنفيذ وقيود GAS ، لكن كل ما فعلته يعمل في حساب Google مجاني ولا يطلب المال حتى الآن. ليس لدي هدف لوصف Google Apps Script بالتفصيل. تعتمد GAS على لغة JavaScript ، ويمكنك استخدام مكتبات JS التابعة لجهات خارجية ، ويمكنك نشر البرنامج النصي كتطبيق ويب ، والذي يمكن إتاحته للجميع دون إذن. لم تكن إمكانات تطبيق GAS الحالي كافية بالنسبة لي ، لذلك اضطررت إلى الخروج والبحث عن حلول.

في البداية قررت أن أكتب وكيلًا لصور PNG. كان من المفترض أن يطلب برنامج الويب النصي صورة كلمة مرور من موقع VPNBook (أذكر أنه تم نشر كلمة المرور هناك في PNG) ومنحها للعميل الذي دعا هذا البرنامج النصي لفك تشفيره. هذه طريقة للالتفاف حول القفل. هنا التقى أول قيود الغاز. اتضح أن البرنامج النصي لا يمكنه عرض صورة MIME / png ، ولكن فقط تنسيقات النص ، JSON ، TEXT ، XML ، إلخ. ولكن كان هناك طريقة للالتفاف حول هذا. يمكنك تشفير PNG إلى Base64 وإرجاع سلسلة نصية إلى العميل. هناك نصوص مشابهة على الإنترنت ، على سبيل المثال techslides.com/image-proxy-with-google-app-scripts . أنا فقط تبسيط واحد منهم. كنت بحاجة إلى صورة واحدة فقط وإخراج سلاسل Base64 فقط. والنتيجة هي برنامج نصي يتكون من دالة doGet واحدة فقط - معالج طلب GET يقوم بإرجاع سلسلة استجابة.

function doGet() { var response = UrlFetchApp.fetch('https://www.vpnbook.com/password.php'); var b64 = Utilities.base64Encode(response.getContent()); //var data = 'data:'+type+';base64,'+b64; return ContentService.createTextOutput(b64); } 

مثال على إخراج المتصفح:

 iVBORw0KGgoAAAANSUhEUgAAAGQAAAANAQMAAABl11mFAAAABlBMVEX29vZMTExY89ZbAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAVUlEQVQImWNgIBrwSzCw/2ZgOADhSc5gYJCG8wxQedLdCcYFNXcgPHOZsxuSZxx7BuFZzsjdcJi34TBU5Y3cjc3IvM3McJ7kjNxtzDwwffwSIB7UTACt/h52C5DFqQAAAABJRU5ErkJggg== 

بعد ذلك يأتي البرنامج النصي PHP ، والذي يمكن وضعه على الخادم داخل المنطقة مع قفل الموارد. إنه مشابه جدًا للبرنامج النصي من المقال السابق ، باستثناء تغيير بسيط في معلمات استدعاء cURL. أنت بحاجة إلى السماح لـ cURL بتجاوز HTTP / 1.1 302 تم النقل مؤقتًا ، لأن عند استدعاء GAS ، تتم إعادة التوجيه من عنوان البرنامج النصي على الويب إلى عنوان مؤقت ديناميكي:

 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 

و Base64 فك:

 $imgOCR = imagecreatefromstring(base64_decode($output)); 

النصي نفسه
 <?php //   $wchar = 9; $hchar = 13; $strDict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '; $imgDict = imagecreatetruecolor(2 + strlen($strDict)* $wchar, $hchar); $bg = imagecolorallocate($imgDict, 0xF6, 0xF6, 0xF6); $textcolor = imagecolorallocate($imgDict, 0x4C, 0x4C, 0x4C); imagefill($imgDict, 0, 0, $bg); imagestring($imgDict, 5, 2, 0, $strDict, $textcolor); //  cURL $ch = curl_init(); //  url,      //curl_setopt($ch, CURLOPT_URL, 'https://www.vpnbook.com/password.php'); curl_setopt($ch, CURLOPT_URL, 'https://script.google.com/macros/s/AKfycbwYPfaZobtjbFv0mSYI8U4NIXPh1Sft_DkGH8QKgg/exec'); //  ,      string curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); // also, this seems wise considering output is image. //   $output = curl_exec($ch); //  cURL curl_close($ch); // echo $output; $imgOCR = imagecreatefromstring(base64_decode($output)); //$imgOCR = imageCreateFromPng('password.png'); //      10  . 2 + 10*9 = 92 < 100 $maxchar = floor((imagesx($imgOCR) - 2) / 9); $imgBox = imagecreatetruecolor($wchar, $hchar); $hashDict = Array(); //   for ($k = 0; $k < strlen($strDict) ; $k++) { imagecopy($imgBox, $imgDict, 0, 0, 2 + $k * $wchar, 0, $wchar, $hchar); $hashStr = ""; for($y = 0; $y < $hchar ; $y++) for($x = 0; $x < $wchar; $x++) $hashStr .= (imagecolorat($imgBox, $x, $y) != 0xF6F6F6)? '1': '0'; $hashDict[$hashStr] = $strDict[$k]; } //     for ($k = 0; $k < $maxchar ; $k++) { imagecopy($imgBox, $imgOCR, 0, 0, 2 + $k * $wchar, 0, $wchar, $hchar); $hashStr = ""; for($y = 0; $y < $hchar ; $y++) for($x = 0; $x < $wchar; $x++) $hashStr .= (imagecolorat($imgBox, $x, $y) != 0xF6F6F6)? '1': '0'; $tempchar = $hashDict[$hashStr]; if ($tempchar=='u' || $tempchar=='y') //    $tempchar = (mt_rand(0, 1))? 'u': 'y'; //$tempchar = (time() / 60 % 60 % 2)? 'u': 'y'; elseif ($tempchar==' ') break; print($tempchar); } /* header('Content-type: image/png'); imagepng($imgDict); */ //var_dump($hashDict); imagedestroy($imgDict); imagedestroy($imgOCR); imagedestroy($imgBox); ?> 


يقوم برنامج PHP النصي بفك تشفير كلمة مرور PNG وإرجاعها كسلسلة نصية. علاوة على ذلك ، كما في المقالة الأولى في الجزء حول Mikrotik. يلتقط الموجه كلمة المرور باستخدام الجلب.
وكانت النتيجة مثل هذا المخطط للعمل من 2 الخدمات الوسيطة أمام Mikrotik.

الجزء 2. دفع على الغاز. تخلص من PHP النصي فك


أثناء التجارب مع GAS ، نشأت فكرة التخلي عن وحدة فك ترميز كلمة المرور في PHP ، وإعادة كتابتها في GAS. وهنا تم اكتشاف مشكلة كبيرة: لا يحتوي البرنامج النصي لـ Google على وظائف معالجة PNG ، الشيء الوحيد الذي يمكن القيام به هو تحويل PNG إلى صفيف بايت. لم يكن هناك أي شك في أي تلاعب مع أجزاء الصورة وبكسل. حصلت على Github أبحث عن مكتبة JS للعمل مع PNG ، لقد وجدت الكثير منها: PNG.js ، UPNG.js ، pngjs. لا يدعم البعض عمق ألوان 1 بت لوحدة بكسل PNG (صورة بكلمة مرور). سحبوا على طول مكتبات ضغط zlib. بشكل عام ، بدا لي كل هذا مرهقًا بعض الشيء ، وقررت أن أكتب بمفردي محولًا بدائيًا فقط لصورتي PNG إلى صورة نقطية مع وظيفة الوصول إلى البكسل بواسطة إحداثيات XY. ثم جاء الانغماس الكامل في تنسيق PNG: محرر سداسي عشرية ، معايير القراءة ، أكوام من الأوصاف على الشبكة. وأخيرًا ، صادفت قسم بابوا نيو غينيا من ملف IDAT ، معبأًا بـ zlib ، والذي تضمن مجموعة من البكسلات.

كانت تتطلب وظيفة لتفريغ zlib ، والتي بالطبع لم تكن في GAS. والمثير للدهشة أن لديهم gzip / ungzip و zip / unzip ، لكن لا يوجد zlib. بعد أن قرأت عن gzip (المستوى الثاني من الانغماس بعد تنسيق PNG) ، توصلت إلى استنتاج أنه لن يكون من الممكن تجميع "دراجة" على شكل أرشيف gzip من قسم IDAT ، على الرغم من استخدام ضغط zlib هناك وهناك. لأن لإنشاء أرشيف gzip صالح ، يلزمك معرفة طول البيانات التي تم فك حزمتها ، والتي لم أستطع الحصول عليها دون تفريغها :) وبالطول الخطأ ، اعتبرت GAS أن الأرشيف تالف. في النهاية ، التفتت إلى Github ووجدت حلاً رائعًا: zlib.js لمكتبة تطبيقات Google Apps (https://github.com/hinimub/zlib.js/blob/develop/README.en.md). الذي تم إعداده خصيصًا للاندماج في مشاريع GAS من خلال مكتبات المشروع الرئيسية. ثم بدأ اللغز يتلاقى. بعد كتابة إلغاء ضغط صفيف البكسل ووظيفة الوصول إلى إحداثيات XY بكسل ، كان من الممكن نقل برنامج فك التشفير من PHP إلى GAS.

بشكل منفصل حساب جدول تجزئة قاموس من أحرف كلمة المرور المحتملة. هذا إجراء لمرة واحدة قمت به في برنامج تابع لجهة خارجية (في LabVIEW ، مرحبًا ، زملاء). يمكن تخصيص كل حرف في الصورة على شكل 8 بتات (بدون مسافة بادئة) × 10 خطوط. 1 بايت يكفي لترميز 8 بكسل لسطر حرف واحد. يمكنك تخزين سلسلة من البيكسلات في عدد صحيح (بايت) ، والحرف بأكمله كتسلسل من 10 بايت. اتضح 10 أرقام عرافة لكل حرف. بعد ذلك ، يكرر وحدة فك ترميز GAS السلف PHP الخاص به.

والنتيجة هي برنامج نصي يعمل بالكامل في GAS.
 function doGet() { //var file = DriveApp.getFilesByName("password2.png").next(); //var image = file.getBlob(); var image = UrlFetchApp.fetch('https://www.vpnbook.com/password.php').getBlob(); var imageString = image.getDataAsString(); var imageArray = image.getBytes().map(function(e) { return e & 0xff; }); // imageArray = blobToUint8(imageArray); var chunkIDATStart = imageString.indexOf("IDAT") + 4; //   IDAT var chunkIDATLen = bytesToUint32(imageArray, imageString.indexOf("IDAT") - 4); //   IDAT var IDATArray = imageArray.slice(chunkIDATStart, chunkIDATStart + chunkIDATLen) var inflate = new zlibjs.Inflate(IDATArray); //  IDAT   zlib var plain = inflate.decompress(); const Width = 100; //   const Height = 13; //   const wchar = 9; //   const hchar = 13; //   //Logger.log(typeof(plain)); //Logger.log(plain); rowlen = (Width / 8) >> 0; //   ,    if ((Width - rowlen * 8) > 0) { //    rowlen+=2; // +1 filter byte at the beginning of each row.    PNG } else { rowlen++; } function getXY(x, y) { //  : 0/1 var xbyte = (x / 8 >> 0); //  ,   //Logger.log("xbyte: " + xbyte); var xbit = x - xbyte * 8; //  ,    //Logger.log("xbit: " + xbit); return (plain[xbyte + 1 + y * rowlen] << xbit & 0x80) >> 7; // +1 filter byte at the beginning of each row } // Logger.log("getXY: " + getXY(4, 3)); // - .        8  (  ) x 10 ,        (byte),      10  . //  10 hex   . var hashDict = {'183C66C3C3C3FFC3C3C3':'A','FCC6C3C6FCC6C3C3C6FC':'B','3E63C1C0C0C0C0C1633E':'C','FCC6C3C3C3C3C3C3C6FC':'D', 'FEC0C0C0FCC0C0C0C0FE':'E','FFC0C0C0FCC0C0C0C0C0':'F','3E63C0C0C0C7C3C3633E':'G','C3C3C3C3FFC3C3C3C3C3':'H', '7E18181818181818187E':'I','1E666666466C38':'J','C3C6CCD8F0F0D8CCC6C3':'K','C0C0C0C0C0C0C0C0C0FE':'L', 'C3E7FFDBDBDBC3C3C3C3':'M','C3E3F3F3DBDBCFC7C7C3':'N','3C66C3C3C3C3C3C3663C':'O','FEC3C3C3FEC0C0C0C0C0':'P', '3C66C3C3C3C3DBCF663D':'Q','FEC3C3C3FEF8CCC6C3C3':'R','7EC3C0C07E333C37E':'S','FF181818181818181818':'T', 'C3C3C3C3C3C3C3C3663C':'U','C3C3C36666663C3C1818':'V','C3C3C3C3DBDBDBFFE7C3':'W','C3C3663C18183C66C3C3':'X', 'C3C3663C181818181818':'Y','FE66C183060C0C0FE':'Z','0003E6337FC3C77B':'a','C0C0C0DCE6C3C3C3E6DC':'b', '0003E63C0C0C0633E':'c','3333B67C3C3C3673B':'d','0003C66C3FFC0633E':'e','1E33333030FC30303030':'f', '0007DC7C6C67CC07E':'g','C0C0C0DCE6C3C3C3C3C3':'h','181803818181818187E':'i','660E66666C6':'j', '606060666C78786C6663':'k','3818181818181818183C':'l','000B6DBDBDBDBDBDB':'m','000DCE6C3C3C3C3C3':'n', '0003C66C3C3C3663C':'o','000DCE6C3C3C3E6DC':'p','0003B67C3C3C3673B':'q','000DE736060606060':'r', '0007EC3C07E3C37E':'s','03030FC30303030331E':'t','000C3C3C3C3C3673B':'u','000C3C366663C3C18':'v', '000C3C3DBDBDBFF66':'w','000C3663C183C66C3':'x','000C3C3C3C3C3673B':'y','0007E6C1830607E':'z', '183C66C3C3C3C3663C18':'0','1838781818181818187E':'1','3C66C336C183060FF':'2','7CC6361C633C67C':'3', '6E1E3666C6FF666':'4','FEC0C0DCE633C3663C':'5','3C66C2C0DCE6C3C3663C':'6','FF336C183060C0C0':'7', '3C66C3663C66C3C3663C':'8','3C66C3C3673B343663C':'9','0000000000':' '}; //      10  . 2 + 10*9 = 92 < 100 const maxchar = (Width - 2) / wchar >> 0; var password = ''; for (var charX = 2; charX < maxchar * wchar + 2; charX+=wchar) { //    var hash = ''; //   for (var charY = 3; charY < hchar; charY++) { //   Y- var charrow = 0; //   -  8   for (var charXbit = 0; charXbit < 8; charXbit++) { //   X- charrow <<= 1; charrow |= getXY(charX + charXbit, charY); } hash += charrow.toString(16).toUpperCase(); //Logger.log("charrow: " + charrow.toString(2)); //Logger.log("charrow: " + charrow.toString(16).toUpperCase()); } var tempChar = hashDict[hash]; if (tempChar === 'u' || tempChar === 'y') { //     tempChar = (Date.now() % 2) ? 'u': 'y'; } if (tempChar !== ' ') { password += tempChar; // Logger.log("hash: " + hash); // Logger.log("Char: " + tempChar); } } Logger.log("password: " + password); return ContentService.createTextOutput(password); } function blobToUint8(blob) { return blob.map(function(e){ return e & 0xff; }); } function bytesToUint32(byteArray, start) { var value = 0; for (var i = start; i < start + 4; i++) { value = (value * 256) + (byteArray[i] & 0xff); } return value; } function my2() { var file = DriveApp.getFilesByName("password2.png").next(); // var file = DriveApp.getFilesByName("test.bin").next(); var image = file.getBlob(); //var imageArray = image.getBytes(); //var img = UrlFetchApp.fetch('http://example.com/image.png'); var reader = new pngjs.PNGReader(image.getBytes()); var png = reader.parse(function(err, png){ if (err) throw err; return png; }); Logger.log(png); } 'A'، 'FCC6C3C6FCC6C3C3C6FC': 'B'، '3E63C1C0C0C0C0C1633E': 'C'، 'FCC6C3C3C3C3C3C3C6FC': 'D'، 'FEC0C0C0FCC0C0C0C0FE': 'E'، 'FFC0C0C0FCC0C0C0C0C0': 'F function doGet() { //var file = DriveApp.getFilesByName("password2.png").next(); //var image = file.getBlob(); var image = UrlFetchApp.fetch('https://www.vpnbook.com/password.php').getBlob(); var imageString = image.getDataAsString(); var imageArray = image.getBytes().map(function(e) { return e & 0xff; }); // imageArray = blobToUint8(imageArray); var chunkIDATStart = imageString.indexOf("IDAT") + 4; //   IDAT var chunkIDATLen = bytesToUint32(imageArray, imageString.indexOf("IDAT") - 4); //   IDAT var IDATArray = imageArray.slice(chunkIDATStart, chunkIDATStart + chunkIDATLen) var inflate = new zlibjs.Inflate(IDATArray); //  IDAT   zlib var plain = inflate.decompress(); const Width = 100; //   const Height = 13; //   const wchar = 9; //   const hchar = 13; //   //Logger.log(typeof(plain)); //Logger.log(plain); rowlen = (Width / 8) >> 0; //   ,    if ((Width - rowlen * 8) > 0) { //    rowlen+=2; // +1 filter byte at the beginning of each row.    PNG } else { rowlen++; } function getXY(x, y) { //  : 0/1 var xbyte = (x / 8 >> 0); //  ,   //Logger.log("xbyte: " + xbyte); var xbit = x - xbyte * 8; //  ,    //Logger.log("xbit: " + xbit); return (plain[xbyte + 1 + y * rowlen] << xbit & 0x80) >> 7; // +1 filter byte at the beginning of each row } // Logger.log("getXY: " + getXY(4, 3)); // - .        8  (  ) x 10 ,        (byte),      10  . //  10 hex   . var hashDict = {'183C66C3C3C3FFC3C3C3':'A','FCC6C3C6FCC6C3C3C6FC':'B','3E63C1C0C0C0C0C1633E':'C','FCC6C3C3C3C3C3C3C6FC':'D', 'FEC0C0C0FCC0C0C0C0FE':'E','FFC0C0C0FCC0C0C0C0C0':'F','3E63C0C0C0C7C3C3633E':'G','C3C3C3C3FFC3C3C3C3C3':'H', '7E18181818181818187E':'I','1E666666466C38':'J','C3C6CCD8F0F0D8CCC6C3':'K','C0C0C0C0C0C0C0C0C0FE':'L', 'C3E7FFDBDBDBC3C3C3C3':'M','C3E3F3F3DBDBCFC7C7C3':'N','3C66C3C3C3C3C3C3663C':'O','FEC3C3C3FEC0C0C0C0C0':'P', '3C66C3C3C3C3DBCF663D':'Q','FEC3C3C3FEF8CCC6C3C3':'R','7EC3C0C07E333C37E':'S','FF181818181818181818':'T', 'C3C3C3C3C3C3C3C3663C':'U','C3C3C36666663C3C1818':'V','C3C3C3C3DBDBDBFFE7C3':'W','C3C3663C18183C66C3C3':'X', 'C3C3663C181818181818':'Y','FE66C183060C0C0FE':'Z','0003E6337FC3C77B':'a','C0C0C0DCE6C3C3C3E6DC':'b', '0003E63C0C0C0633E':'c','3333B67C3C3C3673B':'d','0003C66C3FFC0633E':'e','1E33333030FC30303030':'f', '0007DC7C6C67CC07E':'g','C0C0C0DCE6C3C3C3C3C3':'h','181803818181818187E':'i','660E66666C6':'j', '606060666C78786C6663':'k','3818181818181818183C':'l','000B6DBDBDBDBDBDB':'m','000DCE6C3C3C3C3C3':'n', '0003C66C3C3C3663C':'o','000DCE6C3C3C3E6DC':'p','0003B67C3C3C3673B':'q','000DE736060606060':'r', '0007EC3C07E3C37E':'s','03030FC30303030331E':'t','000C3C3C3C3C3673B':'u','000C3C366663C3C18':'v', '000C3C3DBDBDBFF66':'w','000C3663C183C66C3':'x','000C3C3C3C3C3673B':'y','0007E6C1830607E':'z', '183C66C3C3C3C3663C18':'0','1838781818181818187E':'1','3C66C336C183060FF':'2','7CC6361C633C67C':'3', '6E1E3666C6FF666':'4','FEC0C0DCE633C3663C':'5','3C66C2C0DCE6C3C3663C':'6','FF336C183060C0C0':'7', '3C66C3663C66C3C3663C':'8','3C66C3C3673B343663C':'9','0000000000':' '}; //      10  . 2 + 10*9 = 92 < 100 const maxchar = (Width - 2) / wchar >> 0; var password = ''; for (var charX = 2; charX < maxchar * wchar + 2; charX+=wchar) { //    var hash = ''; //   for (var charY = 3; charY < hchar; charY++) { //   Y- var charrow = 0; //   -  8   for (var charXbit = 0; charXbit < 8; charXbit++) { //   X- charrow <<= 1; charrow |= getXY(charX + charXbit, charY); } hash += charrow.toString(16).toUpperCase(); //Logger.log("charrow: " + charrow.toString(2)); //Logger.log("charrow: " + charrow.toString(16).toUpperCase()); } var tempChar = hashDict[hash]; if (tempChar === 'u' || tempChar === 'y') { //     tempChar = (Date.now() % 2) ? 'u': 'y'; } if (tempChar !== ' ') { password += tempChar; // Logger.log("hash: " + hash); // Logger.log("Char: " + tempChar); } } Logger.log("password: " + password); return ContentService.createTextOutput(password); } function blobToUint8(blob) { return blob.map(function(e){ return e & 0xff; }); } function bytesToUint32(byteArray, start) { var value = 0; for (var i = start; i < start + 4; i++) { value = (value * 256) + (byteArray[i] & 0xff); } return value; } function my2() { var file = DriveApp.getFilesByName("password2.png").next(); // var file = DriveApp.getFilesByName("test.bin").next(); var image = file.getBlob(); //var imageArray = image.getBytes(); //var img = UrlFetchApp.fetch('http://example.com/image.png'); var reader = new pngjs.PNGReader(image.getBytes()); var png = reader.parse(function(err, png){ if (err) throw err; return png; }); Logger.log(png); } '،' C3C3C3C3FFC3C3C3C3C3 ':' H '،' 7E18181818181818187E ':' I '،' 1E666666466C38 ':' J '،' C3C6CCD8F0F0D8CCC6C3 ':' K '،' C0C0C0C0C0C0C0C0C0FE ':' L '، function doGet() { //var file = DriveApp.getFilesByName("password2.png").next(); //var image = file.getBlob(); var image = UrlFetchApp.fetch('https://www.vpnbook.com/password.php').getBlob(); var imageString = image.getDataAsString(); var imageArray = image.getBytes().map(function(e) { return e & 0xff; }); // imageArray = blobToUint8(imageArray); var chunkIDATStart = imageString.indexOf("IDAT") + 4; //   IDAT var chunkIDATLen = bytesToUint32(imageArray, imageString.indexOf("IDAT") - 4); //   IDAT var IDATArray = imageArray.slice(chunkIDATStart, chunkIDATStart + chunkIDATLen) var inflate = new zlibjs.Inflate(IDATArray); //  IDAT   zlib var plain = inflate.decompress(); const Width = 100; //   const Height = 13; //   const wchar = 9; //   const hchar = 13; //   //Logger.log(typeof(plain)); //Logger.log(plain); rowlen = (Width / 8) >> 0; //   ,    if ((Width - rowlen * 8) > 0) { //    rowlen+=2; // +1 filter byte at the beginning of each row.    PNG } else { rowlen++; } function getXY(x, y) { //  : 0/1 var xbyte = (x / 8 >> 0); //  ,   //Logger.log("xbyte: " + xbyte); var xbit = x - xbyte * 8; //  ,    //Logger.log("xbit: " + xbit); return (plain[xbyte + 1 + y * rowlen] << xbit & 0x80) >> 7; // +1 filter byte at the beginning of each row } // Logger.log("getXY: " + getXY(4, 3)); // - .        8  (  ) x 10 ,        (byte),      10  . //  10 hex   . var hashDict = {'183C66C3C3C3FFC3C3C3':'A','FCC6C3C6FCC6C3C3C6FC':'B','3E63C1C0C0C0C0C1633E':'C','FCC6C3C3C3C3C3C3C6FC':'D', 'FEC0C0C0FCC0C0C0C0FE':'E','FFC0C0C0FCC0C0C0C0C0':'F','3E63C0C0C0C7C3C3633E':'G','C3C3C3C3FFC3C3C3C3C3':'H', '7E18181818181818187E':'I','1E666666466C38':'J','C3C6CCD8F0F0D8CCC6C3':'K','C0C0C0C0C0C0C0C0C0FE':'L', 'C3E7FFDBDBDBC3C3C3C3':'M','C3E3F3F3DBDBCFC7C7C3':'N','3C66C3C3C3C3C3C3663C':'O','FEC3C3C3FEC0C0C0C0C0':'P', '3C66C3C3C3C3DBCF663D':'Q','FEC3C3C3FEF8CCC6C3C3':'R','7EC3C0C07E333C37E':'S','FF181818181818181818':'T', 'C3C3C3C3C3C3C3C3663C':'U','C3C3C36666663C3C1818':'V','C3C3C3C3DBDBDBFFE7C3':'W','C3C3663C18183C66C3C3':'X', 'C3C3663C181818181818':'Y','FE66C183060C0C0FE':'Z','0003E6337FC3C77B':'a','C0C0C0DCE6C3C3C3E6DC':'b', '0003E63C0C0C0633E':'c','3333B67C3C3C3673B':'d','0003C66C3FFC0633E':'e','1E33333030FC30303030':'f', '0007DC7C6C67CC07E':'g','C0C0C0DCE6C3C3C3C3C3':'h','181803818181818187E':'i','660E66666C6':'j', '606060666C78786C6663':'k','3818181818181818183C':'l','000B6DBDBDBDBDBDB':'m','000DCE6C3C3C3C3C3':'n', '0003C66C3C3C3663C':'o','000DCE6C3C3C3E6DC':'p','0003B67C3C3C3673B':'q','000DE736060606060':'r', '0007EC3C07E3C37E':'s','03030FC30303030331E':'t','000C3C3C3C3C3673B':'u','000C3C366663C3C18':'v', '000C3C3DBDBDBFF66':'w','000C3663C183C66C3':'x','000C3C3C3C3C3673B':'y','0007E6C1830607E':'z', '183C66C3C3C3C3663C18':'0','1838781818181818187E':'1','3C66C336C183060FF':'2','7CC6361C633C67C':'3', '6E1E3666C6FF666':'4','FEC0C0DCE633C3663C':'5','3C66C2C0DCE6C3C3663C':'6','FF336C183060C0C0':'7', '3C66C3663C66C3C3663C':'8','3C66C3C3673B343663C':'9','0000000000':' '}; //      10  . 2 + 10*9 = 92 < 100 const maxchar = (Width - 2) / wchar >> 0; var password = ''; for (var charX = 2; charX < maxchar * wchar + 2; charX+=wchar) { //    var hash = ''; //   for (var charY = 3; charY < hchar; charY++) { //   Y- var charrow = 0; //   -  8   for (var charXbit = 0; charXbit < 8; charXbit++) { //   X- charrow <<= 1; charrow |= getXY(charX + charXbit, charY); } hash += charrow.toString(16).toUpperCase(); //Logger.log("charrow: " + charrow.toString(2)); //Logger.log("charrow: " + charrow.toString(16).toUpperCase()); } var tempChar = hashDict[hash]; if (tempChar === 'u' || tempChar === 'y') { //     tempChar = (Date.now() % 2) ? 'u': 'y'; } if (tempChar !== ' ') { password += tempChar; // Logger.log("hash: " + hash); // Logger.log("Char: " + tempChar); } } Logger.log("password: " + password); return ContentService.createTextOutput(password); } function blobToUint8(blob) { return blob.map(function(e){ return e & 0xff; }); } function bytesToUint32(byteArray, start) { var value = 0; for (var i = start; i < start + 4; i++) { value = (value * 256) + (byteArray[i] & 0xff); } return value; } function my2() { var file = DriveApp.getFilesByName("password2.png").next(); // var file = DriveApp.getFilesByName("test.bin").next(); var image = file.getBlob(); //var imageArray = image.getBytes(); //var img = UrlFetchApp.fetch('http://example.com/image.png'); var reader = new pngjs.PNGReader(image.getBytes()); var png = reader.parse(function(err, png){ if (err) throw err; return png; }); Logger.log(png); } ' C3E3F3F3DBDBCFC7C7C3 ':' N '،' 3C66C3C3C3C3C3C3663C ':' O '،' FEC3C3C3FEC0C0C0C0C0 ':' P '،' 3C66C3C3C3C3DBCF663D ':' Q '،' FEC3C3C3FEF8CCC6C3C3 ':' R '،' 7EC3C0C07E333C37E function doGet() { //var file = DriveApp.getFilesByName("password2.png").next(); //var image = file.getBlob(); var image = UrlFetchApp.fetch('https://www.vpnbook.com/password.php').getBlob(); var imageString = image.getDataAsString(); var imageArray = image.getBytes().map(function(e) { return e & 0xff; }); // imageArray = blobToUint8(imageArray); var chunkIDATStart = imageString.indexOf("IDAT") + 4; //   IDAT var chunkIDATLen = bytesToUint32(imageArray, imageString.indexOf("IDAT") - 4); //   IDAT var IDATArray = imageArray.slice(chunkIDATStart, chunkIDATStart + chunkIDATLen) var inflate = new zlibjs.Inflate(IDATArray); //  IDAT   zlib var plain = inflate.decompress(); const Width = 100; //   const Height = 13; //   const wchar = 9; //   const hchar = 13; //   //Logger.log(typeof(plain)); //Logger.log(plain); rowlen = (Width / 8) >> 0; //   ,    if ((Width - rowlen * 8) > 0) { //    rowlen+=2; // +1 filter byte at the beginning of each row.    PNG } else { rowlen++; } function getXY(x, y) { //  : 0/1 var xbyte = (x / 8 >> 0); //  ,   //Logger.log("xbyte: " + xbyte); var xbit = x - xbyte * 8; //  ,    //Logger.log("xbit: " + xbit); return (plain[xbyte + 1 + y * rowlen] << xbit & 0x80) >> 7; // +1 filter byte at the beginning of each row } // Logger.log("getXY: " + getXY(4, 3)); // - .        8  (  ) x 10 ,        (byte),      10  . //  10 hex   . var hashDict = {'183C66C3C3C3FFC3C3C3':'A','FCC6C3C6FCC6C3C3C6FC':'B','3E63C1C0C0C0C0C1633E':'C','FCC6C3C3C3C3C3C3C6FC':'D', 'FEC0C0C0FCC0C0C0C0FE':'E','FFC0C0C0FCC0C0C0C0C0':'F','3E63C0C0C0C7C3C3633E':'G','C3C3C3C3FFC3C3C3C3C3':'H', '7E18181818181818187E':'I','1E666666466C38':'J','C3C6CCD8F0F0D8CCC6C3':'K','C0C0C0C0C0C0C0C0C0FE':'L', 'C3E7FFDBDBDBC3C3C3C3':'M','C3E3F3F3DBDBCFC7C7C3':'N','3C66C3C3C3C3C3C3663C':'O','FEC3C3C3FEC0C0C0C0C0':'P', '3C66C3C3C3C3DBCF663D':'Q','FEC3C3C3FEF8CCC6C3C3':'R','7EC3C0C07E333C37E':'S','FF181818181818181818':'T', 'C3C3C3C3C3C3C3C3663C':'U','C3C3C36666663C3C1818':'V','C3C3C3C3DBDBDBFFE7C3':'W','C3C3663C18183C66C3C3':'X', 'C3C3663C181818181818':'Y','FE66C183060C0C0FE':'Z','0003E6337FC3C77B':'a','C0C0C0DCE6C3C3C3E6DC':'b', '0003E63C0C0C0633E':'c','3333B67C3C3C3673B':'d','0003C66C3FFC0633E':'e','1E33333030FC30303030':'f', '0007DC7C6C67CC07E':'g','C0C0C0DCE6C3C3C3C3C3':'h','181803818181818187E':'i','660E66666C6':'j', '606060666C78786C6663':'k','3818181818181818183C':'l','000B6DBDBDBDBDBDB':'m','000DCE6C3C3C3C3C3':'n', '0003C66C3C3C3663C':'o','000DCE6C3C3C3E6DC':'p','0003B67C3C3C3673B':'q','000DE736060606060':'r', '0007EC3C07E3C37E':'s','03030FC30303030331E':'t','000C3C3C3C3C3673B':'u','000C3C366663C3C18':'v', '000C3C3DBDBDBFF66':'w','000C3663C183C66C3':'x','000C3C3C3C3C3673B':'y','0007E6C1830607E':'z', '183C66C3C3C3C3663C18':'0','1838781818181818187E':'1','3C66C336C183060FF':'2','7CC6361C633C67C':'3', '6E1E3666C6FF666':'4','FEC0C0DCE633C3663C':'5','3C66C2C0DCE6C3C3663C':'6','FF336C183060C0C0':'7', '3C66C3663C66C3C3663C':'8','3C66C3C3673B343663C':'9','0000000000':' '}; //      10  . 2 + 10*9 = 92 < 100 const maxchar = (Width - 2) / wchar >> 0; var password = ''; for (var charX = 2; charX < maxchar * wchar + 2; charX+=wchar) { //    var hash = ''; //   for (var charY = 3; charY < hchar; charY++) { //   Y- var charrow = 0; //   -  8   for (var charXbit = 0; charXbit < 8; charXbit++) { //   X- charrow <<= 1; charrow |= getXY(charX + charXbit, charY); } hash += charrow.toString(16).toUpperCase(); //Logger.log("charrow: " + charrow.toString(2)); //Logger.log("charrow: " + charrow.toString(16).toUpperCase()); } var tempChar = hashDict[hash]; if (tempChar === 'u' || tempChar === 'y') { //     tempChar = (Date.now() % 2) ? 'u': 'y'; } if (tempChar !== ' ') { password += tempChar; // Logger.log("hash: " + hash); // Logger.log("Char: " + tempChar); } } Logger.log("password: " + password); return ContentService.createTextOutput(password); } function blobToUint8(blob) { return blob.map(function(e){ return e & 0xff; }); } function bytesToUint32(byteArray, start) { var value = 0; for (var i = start; i < start + 4; i++) { value = (value * 256) + (byteArray[i] & 0xff); } return value; } function my2() { var file = DriveApp.getFilesByName("password2.png").next(); // var file = DriveApp.getFilesByName("test.bin").next(); var image = file.getBlob(); //var imageArray = image.getBytes(); //var img = UrlFetchApp.fetch('http://example.com/image.png'); var reader = new pngjs.PNGReader(image.getBytes()); var png = reader.parse(function(err, png){ if (err) throw err; return png; }); Logger.log(png); } 000B6DBDBDBDBDBDB ':' م '،' 000DCE6C3C3C3C3C3 ':' ن '،' 0003C66C3C3C3663C ':' س '،' 000DCE6C3C3C3E6DC ':' ع '،' 0003B67C3C3C3673B ':' ف '،' 000DE736060606060 " function doGet() { //var file = DriveApp.getFilesByName("password2.png").next(); //var image = file.getBlob(); var image = UrlFetchApp.fetch('https://www.vpnbook.com/password.php').getBlob(); var imageString = image.getDataAsString(); var imageArray = image.getBytes().map(function(e) { return e & 0xff; }); // imageArray = blobToUint8(imageArray); var chunkIDATStart = imageString.indexOf("IDAT") + 4; //   IDAT var chunkIDATLen = bytesToUint32(imageArray, imageString.indexOf("IDAT") - 4); //   IDAT var IDATArray = imageArray.slice(chunkIDATStart, chunkIDATStart + chunkIDATLen) var inflate = new zlibjs.Inflate(IDATArray); //  IDAT   zlib var plain = inflate.decompress(); const Width = 100; //   const Height = 13; //   const wchar = 9; //   const hchar = 13; //   //Logger.log(typeof(plain)); //Logger.log(plain); rowlen = (Width / 8) >> 0; //   ,    if ((Width - rowlen * 8) > 0) { //    rowlen+=2; // +1 filter byte at the beginning of each row.    PNG } else { rowlen++; } function getXY(x, y) { //  : 0/1 var xbyte = (x / 8 >> 0); //  ,   //Logger.log("xbyte: " + xbyte); var xbit = x - xbyte * 8; //  ,    //Logger.log("xbit: " + xbit); return (plain[xbyte + 1 + y * rowlen] << xbit & 0x80) >> 7; // +1 filter byte at the beginning of each row } // Logger.log("getXY: " + getXY(4, 3)); // - .        8  (  ) x 10 ,        (byte),      10  . //  10 hex   . var hashDict = {'183C66C3C3C3FFC3C3C3':'A','FCC6C3C6FCC6C3C3C6FC':'B','3E63C1C0C0C0C0C1633E':'C','FCC6C3C3C3C3C3C3C6FC':'D', 'FEC0C0C0FCC0C0C0C0FE':'E','FFC0C0C0FCC0C0C0C0C0':'F','3E63C0C0C0C7C3C3633E':'G','C3C3C3C3FFC3C3C3C3C3':'H', '7E18181818181818187E':'I','1E666666466C38':'J','C3C6CCD8F0F0D8CCC6C3':'K','C0C0C0C0C0C0C0C0C0FE':'L', 'C3E7FFDBDBDBC3C3C3C3':'M','C3E3F3F3DBDBCFC7C7C3':'N','3C66C3C3C3C3C3C3663C':'O','FEC3C3C3FEC0C0C0C0C0':'P', '3C66C3C3C3C3DBCF663D':'Q','FEC3C3C3FEF8CCC6C3C3':'R','7EC3C0C07E333C37E':'S','FF181818181818181818':'T', 'C3C3C3C3C3C3C3C3663C':'U','C3C3C36666663C3C1818':'V','C3C3C3C3DBDBDBFFE7C3':'W','C3C3663C18183C66C3C3':'X', 'C3C3663C181818181818':'Y','FE66C183060C0C0FE':'Z','0003E6337FC3C77B':'a','C0C0C0DCE6C3C3C3E6DC':'b', '0003E63C0C0C0633E':'c','3333B67C3C3C3673B':'d','0003C66C3FFC0633E':'e','1E33333030FC30303030':'f', '0007DC7C6C67CC07E':'g','C0C0C0DCE6C3C3C3C3C3':'h','181803818181818187E':'i','660E66666C6':'j', '606060666C78786C6663':'k','3818181818181818183C':'l','000B6DBDBDBDBDBDB':'m','000DCE6C3C3C3C3C3':'n', '0003C66C3C3C3663C':'o','000DCE6C3C3C3E6DC':'p','0003B67C3C3C3673B':'q','000DE736060606060':'r', '0007EC3C07E3C37E':'s','03030FC30303030331E':'t','000C3C3C3C3C3673B':'u','000C3C366663C3C18':'v', '000C3C3DBDBDBFF66':'w','000C3663C183C66C3':'x','000C3C3C3C3C3673B':'y','0007E6C1830607E':'z', '183C66C3C3C3C3663C18':'0','1838781818181818187E':'1','3C66C336C183060FF':'2','7CC6361C633C67C':'3', '6E1E3666C6FF666':'4','FEC0C0DCE633C3663C':'5','3C66C2C0DCE6C3C3663C':'6','FF336C183060C0C0':'7', '3C66C3663C66C3C3663C':'8','3C66C3C3673B343663C':'9','0000000000':' '}; //      10  . 2 + 10*9 = 92 < 100 const maxchar = (Width - 2) / wchar >> 0; var password = ''; for (var charX = 2; charX < maxchar * wchar + 2; charX+=wchar) { //    var hash = ''; //   for (var charY = 3; charY < hchar; charY++) { //   Y- var charrow = 0; //   -  8   for (var charXbit = 0; charXbit < 8; charXbit++) { //   X- charrow <<= 1; charrow |= getXY(charX + charXbit, charY); } hash += charrow.toString(16).toUpperCase(); //Logger.log("charrow: " + charrow.toString(2)); //Logger.log("charrow: " + charrow.toString(16).toUpperCase()); } var tempChar = hashDict[hash]; if (tempChar === 'u' || tempChar === 'y') { //     tempChar = (Date.now() % 2) ? 'u': 'y'; } if (tempChar !== ' ') { password += tempChar; // Logger.log("hash: " + hash); // Logger.log("Char: " + tempChar); } } Logger.log("password: " + password); return ContentService.createTextOutput(password); } function blobToUint8(blob) { return blob.map(function(e){ return e & 0xff; }); } function bytesToUint32(byteArray, start) { var value = 0; for (var i = start; i < start + 4; i++) { value = (value * 256) + (byteArray[i] & 0xff); } return value; } function my2() { var file = DriveApp.getFilesByName("password2.png").next(); // var file = DriveApp.getFilesByName("test.bin").next(); var image = file.getBlob(); //var imageArray = image.getBytes(); //var img = UrlFetchApp.fetch('http://example.com/image.png'); var reader = new pngjs.PNGReader(image.getBytes()); var png = reader.parse(function(err, png){ if (err) throw err; return png; }); Logger.log(png); } 


ينفذ البرنامج النصي أسلوب GET فقط. عند تنفيذ طلب GET لهذا البرنامج النصي ، الذي تم نشره كتطبيق ويب ، ستحتوي الاستجابة على الفور على كلمة المرور التي تم فك شفرتها في شكل سلسلة.

الجزء 3. Mikrotik وانتقلت مؤقتا 302


لذلك ، لدينا برنامج نصي يعمل على خوادم Web App الخارجية ، وهو مستقل عن الأقفال ويعيد كلمة مرور نص عادي. ويبدو أنه لا يوجد شيء أسهل من طلب ذلك باستخدام أمر الجلب في RouterOS Mikrotik. ولكن بعد ذلك انتظرني مفاجأة أخرى. استجابةً للطلب (تم تغيير العناوين الحقيقية) ، يُرجع إحضار "302 تم نقله مؤقتًا".

 [admin@MikroTik] /environment> :put ([/tool fetch url="https://script.google.com/macros/s/A.....A/exec" http-method=get output=user as-value]->"data") failure: closing connection: <302 Moved Temporarily "https://script.googleusercontent.com/macros/echo?user_content_key=....."> 173.194.222.138:443 (4) [admin@MikroTik] /environment> 

في بداية المقال ، كتبت بالفعل عن هذا. عند الوصول إلى عنوان URL الثابت والمعروف في البرنامج النصي لتطبيق الويب ، تعيد Google التوجيه إلى عنوان URL المؤقت ، والذي بدوره يُرجع استجابة للطلب. ولكن على عكس PHP cURL ، فإن إحضار RouterOS لا يعرف كيفية إجراء عمليات إعادة التوجيه ، بل إنه يعيد الفشل. لكن forum.mikrotik.com لم يحدث على الفور ، ولكن كان هناك حل بديل. يمكنك إعادة توجيه إخراج الجلب القياسي من وحدة التحكم إلى ملف عن طريق استدعاء التنفيذ غير المتزامن في مهمة منفصلة عن طريق الالتفاف: التنفيذ. يمكنك بعد ذلك استرداد عنوان URL المعاد توجيهه وإعادة جلبه بالفعل باستخدام العنوان الجديد. الذي يتم أدناه.

 #  . Moved Temporarily 302.  fetch  gasfetchout.txt :local jobid [:execute script={/tool fetch url="https://script.google.com/macros/s/A.....A/exec" output=user as-value} file=gasfetchout.txt] #    ,     :while ([:len [/system script job find .id=$jobid ]] > 0) do={ delay 1s } #  gasfetchout.txt,  URL  :local fetchOut [/file get gasfetchout.txt contents] :local startURL [:find $fetchOut "http" -1] :local endURL [:find $fetchOut "\"> " startURL] :local moveURL [:pick $fetchOut $startURL $endURL] :global VPNBookPass2 ([/tool fetch url=$moveURL output=user as-value]->"data") 

فيما يلي النص الكامل لبرنامج نصي Mikrotik للعمل مع تطبيق GAS Web App
 # VPNBookScript v4 :local VPNBookpIfName "pptp-out1" :local VPNBookServerAddresses {"PL226.vpnbook.com";"de4.vpnbook.com";"us1.vpnbook.com";"us2.vpnbook.com";"fr1.vpnbook.com ";"fr8.vpnbook.com ";"ca222.vpnbook.com ";"ca198.vpnbook.com"} :local VPNBookErr false :global VPNBookPass :global VPNBookRun :global VPNBookServerIndex :if ([:typeof $VPNBookServerIndex] != "num") do={:set VPNBookServerIndex 0} :if ([/interface pptp-client get $VPNBookpIfName running]) do={ :set VPNBookRun true } else { :if (!$VPNBookRun) do={ :set VPNBookServerIndex ($VPNBookServerIndex + 1) :if ($VPNBookServerIndex>=[:len $VPNBookServerAddresses]) do={:set VPNBookServerIndex 0} } else { :set VPNBookRun false } :if (![/interface pptp-client get $VPNBookpIfName disabled]) do={/interface pptp-client set $VPNBookpIfName disabled=yes} # :do {:set VPNBookPass ([/tool fetch url="http://serv/vpnbookpass_googlescript.php" output=user as-value]->"data")} on-error={:set VPNBookErr true} :do { # First request with Moved Temporarily. Fetch out to gasfetchout.txt :local jobid [:execute script={/tool fetch url="https://script.google.com/macros/s/A.....g/exec" output=user as-value} file=gasfetchout.txt] # Wait end job :while ([:len [/system script job find .id=$jobid ]] > 0) do={ delay 1s } # parse new URL for second fetch :local fetchOut [/file get gasfetchout.txt contents] :local startURL [:find $fetchOut "http" -1] :local endURL [:find $fetchOut "\"> " startURL] :local moveURL [:pick $fetchOut $startURL $endURL] :set VPNBookPass ([/tool fetch url=$moveURL output=user as-value]->"data") } on-error={:set VPNBookErr true} :if (!$VPNBookErr) do={ :if ([/interface pptp-client get $VPNBookpIfName password] != $VPNBookPass) do={/interface pptp-client set $VPNBookpIfName password=$VPNBookPass} :if ([/interface pptp-client get $VPNBookpIfName connect-to] != $VPNBookServerAddresses->$VPNBookServerIndex) do={/interface pptp-client set $VPNBookpIfName connect-to=($VPNBookServerAddresses->$VPNBookServerIndex)} :log info "VPNBook: Attempt to connect to: $($VPNBookServerAddresses->$VPNBookServerIndex). Password: $VPNBookPass" /interface pptp-client set $VPNBookpIfName disabled=no } } 


الجزء 4. وكيل Telegram الغاز


قررت أن أخصص هذا الجزء للتكرار التالي لدمج خدمة Telegram في Mikrotik. سيكون استخدام GAS هنا ذا أهمية أكاديمية بحتة إذا لم يكن الأمر واقعًا لحظر خدمة Telegram ، بما في ذلك api.telegram.org ، والتي تعمل من خلالها برامج الروبوت مع الخدمة. تكرر الفكرة الفكرة في بداية المقالة حول بروكسي طلب صور PNG.
في هذه الحالة ، تتم كتابة GAS Web App لطلبات الوكيل من Mikrtotik إلى api.telegram.org. كأساس ، أخذت نصيًا جاهزًا من manzoorwanijk ، WPTelegram Google Script gist.github.com/manzoorwanijk/ee9ed032caedf2bb0c83dea73bc9a28e . يمكن لهذا البرنامج النصي تعيين العديد من طرق Telegram API (ولكن ليس كلها). في args ، يمكنك تمرير كائن JSON يحتوي على معلمات الطلب ، على سبيل المثال {"chat_id":"123","text":"HelloWorld"} . ولكن بالنسبة لمهمتي المتمثلة في إرسال رسائل نصية من RouterOS Mikrtotik ، بدا أن التنفيذ معقد وبسطته. في النهاية ، يمكنك عمومًا كتابة العديد من البرامج النصية لتطبيقات الويب للتعبير عن طرق Telegram API المختلفة. إليكم تطبيقي لأسلوب sendMessage. يمكن تبسيطه بشكل أكبر عن طريق تضمين اسم أسلوب sendMessage الذي يتم استدعاؤه ، وحتى bot_token و chat_id في نص الدالة requestHandler.

 function doGet(e) { if(typeof e !== 'undefined'){ return ContentService.createTextOutput(requestHandler(e)); } } function doPost(e) { if(typeof e !== 'undefined'){ return ContentService.createTextOutput(requestHandler(e)); } } function requestHandler(e){ if (typeof e.parameter.bot_token === 'undefined'){ return 'Error! Bot token not provided'; } else if (typeof e.parameter.method === 'undefined') { return 'Error! Method name not provided'; } else if (typeof e.parameter.chat_id === 'undefined') { return 'Error! Chat id not provide'; } else if (typeof e.parameter.text === 'undefined') { return 'Error! Text not provide'; } /* if(typeof e.parameter.args !== 'undefined'){ var args = e.parameter.args; data.payload = JSON.parse(args); } */ if (e.parameter.method === 'sendMessage') { var data = { "method": "post", "muteHttpExceptions": true, payload : 'chat_id=' + e.parameter.chat_id + '&text=' + e.parameter.text } return UrlFetchApp.fetch('https://api.telegram.org/bot' + e.parameter.bot_token + '/' + e.parameter.method, data).getContentText(); } } 

بعد نشر البرنامج النصي في تطبيق الويب ، يمكنك تنفيذ طلب في متصفح GET للتحقق:

 https://script.google.com/macros/s/A.....A/exec?bot_token=3.....3&method=sendMessage&chat_id=2.....3&text=testtext123 

أو في طلب RouterOS POST:

 :do { /tool fetch url=("https://script.google.com/macros/s/A.....A/exec") keep-result=no http-method=post http-data=("bot_token=3.....3&method=sendMessage&chat_id=2.....3&text=testtext123") } on-error={ } 

يتم لف الطلب في حالة خطأ ، لأنه ، كما هو موضح أعلاه ، ستلقي المكالمة الأولى لجلب استثناء "Moved مؤقتًا 302" وسيوقف البرنامج النصي بدون معالج الخطأ عند هذه النقطة. مكالمة واحدة للجلب دون إعادة توجيه كافية لإرسال الرسالة ، وبالتالي فإن المكالمة الثانية لإحضارها ليست ضرورية إذا كنت لا تحتاج إلى كائن JSON الذي تم إرجاعه بواسطة Telegram API.

الجزء 5. النهائي


أحضرت تطبيقاتي الحقيقية عند تقاطع Google Apps Script مع خدمات أخرى. يمكنك الخروج مع الكثير. على سبيل المثال ، اكتب روبوت Telegram في GAS ، والذي سوف يستجيب بكلمة مرور VPNBook مع طلبات التخزين المؤقت لتقليل الحمل على VPNBook (خدمة ذاكرة التخزين المؤقت) ، وكل هذا سيكون في برنامج نصي GAS واحد. يمكنك الكتابة على GAS على نظام تسجيل أو تكوينات احتياطية لـ Mikrtotik ، والتي سيتم وضعها في ملفات محرّر مستندات Google وجداول بيانات Google ، وغير ذلك الكثير.

Source: https://habr.com/ru/post/ar475856/


All Articles