Google App Script, Mikrotik, Telegram und VPNBook haben begonnen, ein Quartett zu spielen

Heute im Programm: Wo sonst können Sie Google Apps Script anwenden, wenn die normalen Ideen vorbei sind. Automatisierung der Arbeit mit VPNBook durch eine Reihe von Skripten in verschiedenen Sprachen, die ich nicht kenne. Nedo-cURL von Mikrotik. Telegramm durch einen Ort, um nicht in einem anderen zu sein, erlaubt Selbstüberwachung.

Teil 1. Ohne Titel


Vor einem Jahr schrieb ich einen Hinweis „ Fast OCR, um ein VPNBook-Passwort zu erhalten. PHP + Mikrotik “ darüber, wie die automatische Passwortabfrage im Mikrotik-Router für den kostenlosen VPN-Zugang über VPNBook eingerichtet wird. Der Anfang der Geschichte ist da.

Seitdem ist viel Wasser geflossen, in Russland haben sie die VPNBook-Site blockiert, aber nicht die öffentlichen VPN-Server selbst, die darauf veröffentlicht werden. Das PHP-Skript zum Dekodieren eines PNG-Bildes eines Kennworts in eine Textzeichenfolge sollte jetzt auch funktionieren, wenn es auf einem Server gestartet wird, dessen Datenverkehr nicht durch das Blockierungssystem geleitet wird. Als ich vor einiger Zeit mit dem Google Apps Script (GAS) -Dienst script.google.com experimentierte , entschied ich mich, das PHP-Skript auf einem externen Webserver aufzugeben und es teilweise oder vollständig durch ein GAS-Skript zu ersetzen, das als Web App (Webanwendung) ausgeführt wird. Ich habe die Ausführungsrichtlinien und die GAS-Einschränkungen nicht verstanden, aber alles, was ich getan habe, funktioniert in einem kostenlosen Google-Konto und verlangt noch kein Geld. Ich habe nicht das Ziel, Google Apps Script detailliert zu beschreiben. GAS basiert auf der JavaScript-Sprache, Sie können JS-Bibliotheken von Drittanbietern verwenden, Sie können das Skript als Webanwendung veröffentlichen, die jedem ohne Autorisierung zur Verfügung gestellt werden kann. Die Möglichkeiten der aktuellen GAS-Implementierung reichten mir nicht aus, sodass ich nach Lösungen suchen musste.

Zuerst habe ich beschlossen, einen Proxy für PNG-Bilder zu schreiben. Das Web-Skript musste ein Passwort-Image von der VPNBook-Website anfordern (ich erinnere mich, dass das Passwort dort in PNG veröffentlicht wurde) und es dem Client geben, der dieses Skript zum Dekodieren aufrief. So kommen Sie um das Schloss herum. Hier traf die erste Einschränkung von GAS ein. Es stellt sich heraus, dass das Skript kein MIME-Bild / PNG rendern kann, sondern nur Textformate, JSON, TEXT, XML usw. Aber es gab einen Weg, dies zu umgehen. Sie können PNG in Base64 codieren und eine Textzeichenfolge an den Client zurückgeben. Es gibt ähnliche Skripte im Internet, zum Beispiel techslides.com/image-proxy-with-google-app-scripts . Ich habe nur einen von ihnen vereinfacht. Ich brauchte nur ein Bild und gab nur Base64-Strings aus. Das Ergebnis ist ein Skript, das nur aus einer doGet-Funktion besteht - einem GET-Anforderungshandler, der als Antwort eine Zeichenfolge zurückgibt.

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); } 

Beispiel für eine Browserausgabe:

 iVBORw0KGgoAAAANSUhEUgAAAGQAAAANAQMAAABl11mFAAAABlBMVEX29vZMTExY89ZbAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAVUlEQVQImWNgIBrwSzCw/2ZgOADhSc5gYJCG8wxQedLdCcYFNXcgPHOZsxuSZxx7BuFZzsjdcJi34TBU5Y3cjc3IvM3McJ7kjNxtzDwwffwSIB7UTACt/h52C5DFqQAAAABJRU5ErkJggg== 

Als nächstes kommt das PHP-Skript, das mit Resource Locking auf dem Server innerhalb der Zone platziert werden kann. Es ist dem Skript aus dem vorherigen Artikel sehr ähnlich, abgesehen von einer kleinen Änderung der Parameter des cURL-Aufrufs. Sie müssen zulassen, dass cURL vorübergehend über HTTP / 1.1 verschoben wird, da Wenn GAS aufgerufen wird, wird es von der Web-Skript-Adresse zu einer dynamischen temporären Adresse umgeleitet:

 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 

Und Base64-Dekodierung:

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

Skript selbst
 <?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); ?> 


Dieses PHP-Skript decodiert das PNG-Passwort und gibt es als Textzeichenfolge zurück. Weiter wie im ersten Artikel im Teil über Mikrotik. Der Router ermittelt das Passwort mit fetch.
Das Ergebnis war ein solches Arbeitsschema von 2 Zwischendiensten vor Mikrotik.

Teil 2. Drücken Sie auf GAS. Befreien Sie sich von PHP-Decoder-Skript


Während der Experimente mit GAS entstand die Idee, den Passwortdecoder in PHP ganz aufzugeben und in GAS umzuschreiben. Und hier wurde ein großes Problem entdeckt: Google-Skript verfügt nicht über PNG-Verarbeitungsfunktionen. Das einzige, was getan werden kann, ist, PNG in ein Byte-Array zu konvertieren. Manipulationen mit Bildteilen und Pixeln waren ausgeschlossen. Ich bin auf der Suche nach der JS-Bibliothek für die Arbeit mit PNG auf Github gestiegen und habe viele gefunden: PNG.js, UPNG.js, pngjs. Einige unterstützen die 1-Bit-Farbtiefe eines PNG-Pixels (Bild mit Passwort) nicht. Sie zogen verschiedene zlib-Komprimierungsbibliotheken mit. Im Allgemeinen schien mir alles etwas umständlich zu sein, und ich beschloss, selbst einen primitiven Konverter nur für mein PNG-Bild in eine Bitmap mit der Funktion zu schreiben, auf Pixel über XY-Koordinaten zuzugreifen. Dann kam ein komplettes Eintauchen in das PNG-Format: Hex-Editor, Lesestandards, jede Menge Beschreibungen im Netzwerk. Und schließlich stieß ich auf den PNG-Abschnitt der IDAT-Datei, der mit zlib gepackt war und eine Reihe von Pixeln enthielt.

Es wurde eine Funktion zum Entpacken von zlib benötigt, die natürlich nicht in GAS enthalten war. Überraschenderweise haben sie gzip / ungzip und zip / unzip, aber keine zlib. Nachdem ich über gzip gelesen hatte (die zweite Stufe des Eintauchens nach dem PNG-Format), kam ich zu dem Schluss, dass es nicht möglich sein würde, ein „Fahrrad“ in Form eines gzip-Quasi-Archivs aus der IDAT-Sektion zusammenzustellen, obwohl hier und da ZLIB-Komprimierung verwendet wird. Weil Um ein gültiges gzip-Archiv zu erstellen, müssen Sie die Länge der entpackten Daten kennen, die ich nicht bekommen könnte, ohne sie zu entpacken :) Und mit der falschen Länge betrachtete GAS das Archiv als beschädigt. Am Ende habe ich mich an Github gewandt und eine großartige Lösung gefunden: die Skriptbibliothek zlib.js für Google Apps (https://github.com/hinimub/zlib.js/blob/develop/README.en.md). Das speziell für die Integration in GAS-Projekte durch Projektschlüsselbibliotheken vorbereitet wurde. Dann begann das Rätsel zu konvergieren. Nach dem Schreiben der Dekomprimierung des Pixelarrays und der Funktion zum Zugreifen auf die Koordinaten des XY-Pixels konnte das Decoderskript von PHP nach GAS übertragen werden.

Separat berechnete Hash-Tabelle eines Wörterbuchs mit möglichen Kennwortzeichen. Dies ist eine einmalige Aktion, die ich in einem Drittanbieterprogramm durchgeführt habe (in LabVIEW, hallo, Kollegen). Jedes Zeichen im Bild kann mit 8 Bit (ohne Einrückung) x 10 Zeilen belegt werden. Ein Byte reicht aus, um 8 Pixel einer Zeile eines Zeichens zu codieren. Sie können eine Folge von Pixeln in einer ganzen Zahl (Byte) und das gesamte Zeichen als Folge von 10 Byte speichern. Es werden 10 Hexadezimalzahlen pro Zeichen ausgegeben. Als nächstes wiederholt der GAS-Decoder seinen PHP-Vorgänger.

Das Ergebnis ist ein Skript, das vollständig in GAS funktioniert.
 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 ':' m '' 000DCE6C3C3C3C3C3 ':' n '' 0003C66C3C3C3663C ':' o '' 000DCE6C3C3C3E6DC ':' p '' 0003B67C3C3C3673B ':' q '' 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); } 


Das Skript implementiert nur die GET-Methode. Wenn Sie eine GET-Anforderung für dieses als Web App veröffentlichte Skript ausführen, enthält die Antwort sofort das dekodierte Kennwort in Form einer Zeichenfolge.

Teil 3. Mikrotik und vorübergehend umgezogen 302


Wir haben also ein Skript, das auf externen Web-App-Servern ausgeführt wird, das unabhängig von Sperren ist und ein Nur-Text-Kennwort zurückgibt. Und es scheint, dass es nichts Einfacheres gibt, als es mit dem Abrufbefehl in RouterOS Mikrotik anzufordern. Aber dann erwartete mich eine weitere Überraschung. Als Antwort auf die Anforderung (reale Adressen geändert) gibt der Abruf "302 Vorübergehend verschoben" zurück.

 [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> 

Zu Beginn des Artikels habe ich bereits darüber geschrieben. Beim Zugriff auf die persistente bekannte URL des Web App-Skripts leitet Google zu einer temporären URL weiter, die wiederum eine Antwort auf die Anforderung zurückgibt. Im Gegensatz zu PHP cURL weiß fetch RouterOS jedoch nicht, wie man Weiterleitungen durchläuft, sondern gibt einen Fehler zurück. Aber forum.mikrotik.com hat nicht sofort, aber es gab eine Problemumgehung. Sie können die Standardabrufausgabe von der Konsole in eine Datei umleiten, indem Sie die asynchrone Ausführung in einer separaten Task mit dem folgenden Befehl aufrufen: execute. Sie können dann die Weiterleitungs-URL abrufen und bereits mit der neuen Adresse erneut abrufen. Welches wird unten getan.

 #  . 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") 

Hier finden Sie den vollständigen Text des Mikrotik-Skripts für die Arbeit mit der 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 } } 


Teil 4. Telegramm-GAS-Proxy


Ich beschloss, diesen Teil der nächsten Iteration der Integration des Telegrammdienstes in Mikrotik zu widmen. Die Verwendung von GAS wäre hier von rein akademischem Interesse, wenn nicht der Telegrammdienst, einschließlich api.telegram.org, blockiert würde, über den Bots mit dem Dienst arbeiten. Die Idee wiederholt die Idee am Anfang des Artikels über das Proxying der Anforderung von PNG-Bildern.
In diesem Fall wird die GAS-Web-App auf Proxy-Anfragen von Mikrtotik an api.telegram.org geschrieben. Als Grundlage nahm ich ein fertiges Skript von manzoorwanijk, WPTelegram Google Script gist.github.com/manzoorwanijk/ee9ed032caedf2bb0c83dea73bc9a28e . Dieses Skript kann viele (aber nicht alle) Telegramm-API-Methoden als Proxy verwenden. In args können Sie ein JSON-Objekt übergeben, das die Anforderungsparameter enthält, z. B. {"chat_id":"123","text":"HelloWorld"} . Für meine Aufgabe, Textnachrichten von RouterOS Mikrtotik zu senden, schien die Implementierung jedoch kompliziert und ich habe sie vereinfacht. Letztendlich können Sie im Allgemeinen mehrere Web-App-Skripts schreiben, um verschiedene Telegramm-API-Methoden zu vertreten. Hier ist meine Implementierung für die sendMessage-Methode. Sie können dies weiter vereinfachen, indem Sie den Namen der aufgerufenen sendMessage-Methode und sogar bot_token und chat_id in den Hauptteil der requestHandler-Funktion einbetten.

 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(); } } 

Nach dem Veröffentlichen des Skripts in der Web App können Sie im GET-Browser eine Anforderung ausführen, um Folgendes zu überprüfen:

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

Oder in RouterOS POST Anfrage:

 :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={ } 

Die Anforderung wird in do-on-error eingeschlossen, da der erste Aufruf zum Abrufen, wie oben gezeigt, die Ausnahme "Vorübergehend verschoben 302" auslöst und das Skript ohne den On-Error-Handler an dieser Stelle stoppt. Ein Aufruf zum Abrufen ohne Weiterleitung reicht aus, damit die Nachricht gesendet wird. Ein zweiter Aufruf zum Abrufen ist daher nicht erforderlich, wenn Sie das von der Telegramm-API zurückgegebene JSON-Objekt nicht benötigen.

Teil 5. Schluss


Ich habe meine echten Anwendungen an die Schnittstelle von Google Apps Script mit anderen Diensten gebracht. Sie können sich viel mehr einfallen lassen. Schreiben Sie beispielsweise einen Telegramm-Bot in GAS, der mit einem VPNBook-Kennwort mit Caching-Anforderungen antwortet, um die Belastung des VPNBook (Cache-Dienst) zu verringern. Dies alles wird in einem GAS-Skript ausgeführt. Sie können auf GAS ein Protokollierungssystem oder Sicherungskonfigurationen für Mikrtotik schreiben, die in Google Text & Tabellen- und Google Sheets-Dateien gespeichert werden, und vieles mehr.

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


All Articles