POST-Daten via Purebasic zu Webseite im Browser schicken

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NicTheQuick »

Hallo Leute,

ich brauchte die Möglichkeit eine Webseite im Standardbrowser aufzurufen und dieser Daten per POST mitzugeben. Da man die Daten nicht einfach an die URL anhängen kann und damit den Standardbrowser mit Runprogram() aufrufen kann, musste ich eine Zwischenschicht bauen, die ich mir ein wenig von Dropbox abgeschaut habe.
Im Grunde wird eine temporäre HTML-Datei erstellt, die die zu übergebenden Daten verschlüsselt enthält und nach dem Entschlüsseln an die eigentliche Webseite weitergibt, indem sie eine HTML-Form submitted. Der Schlüssel zum Entschlüsseln wird als Hash am Ende der URL übergeben und während der Skriptausführung entfernt, sodass in der Browser-History keine Rückstände bleiben.
Damit der Purebasic-Code möglichst kompakt bleibt, habe ich das Template der HTML-Datei möglichst klein gehalten, d.h. auch den JS-Code minimiert.

Um den Code direkt testen zu können, habe ich ein kleines Skript auf meinem Webspace liegen, dass POST- und GET-Daten anzeigt. Hier nun der Code:
Aktuell Windows/Linux only und PB 5.41 beta 2

Code: Alles auswählen

EnableExplicit

DeclareModule BrowserPost
	EnableExplicit
	
	Declare.i openURL(actionUrl.s, Map postData.s(), title.s = "", nojsUrl.s = "", nojsInfo.s = "", keyLength.i = 64)
	
	Declare.i removeTempFiles(deltaTime.i = -1)
EndDeclareModule

Module BrowserPost
	EnableExplicit
	
	Structure TFiles
		time.i
		file.s
	EndStructure
	
	Global NewList tFiles.TFiles()
	Global tfilesLock.i = CreateMutex()
	
	; Konvertiert text.s zu Unicode, verschlüsselt die Rohdaten mit dem Schlüssel und
	; konvertiert die Daten zu einem Hex-String.
	Procedure.s convert2Hex(text.s, *key, keyLength.i, *length.Integer = 0)
		Protected dataSize.i = StringByteLength(text, #PB_Unicode) + SizeOf(Unicode)
		Protected *buffer = AllocateMemory(dataSize)
		PokeS(*buffer, text, -1, #PB_Unicode)
		
		Protected hex.s = "", *i.Unicode = *buffer, *k.Unicode = *key
		
		While *i\u
			hex + RSet(Hex(*i\u ! *k\u, #PB_Unicode), 4, "0")
			*i + SizeOf(Unicode)
			*k + SizeOf(Unicode)
			If (*k - *key) >= keyLength
				*k - keyLength
			EndIf
		Wend
		
		FreeMemory(*buffer)
		
		If *length
			*length\i = dataSize - SizeOf(Unicode)
		EndIf
		
		ProcedureReturn hex
	EndProcedure
	
	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
		; ts-soft: http://www.purebasic.fr/german/viewtopic.php?p=282092#p282092
		Procedure.s FindAssociatedProgram(File.s)
			Protected Result.s = Space(#MAX_PATH)
			Protected Error
			
			Error = FindExecutable_(@File, 0, @Result)
			If Error <= 32
				ProcedureReturn ""
			EndIf
			ProcedureReturn Result
		EndProcedure
	CompilerElse
		Procedure.s FindAssociatedProgram(File.s)
			ProcedureReturn "x-www-browser"
		EndProcedure
	CompilerEndIf
	
	Procedure openURL(actionUrl.s, Map postData.s(), title.s = "", nojsUrl.s = "", nojsInfo.s = "", keyLength.i = 64)
		If Not (keyLength % 2 = 0)
			ProcedureReturn #False
		EndIf
		
		; Erzeuge Schlüssel
		Protected *key = AllocateMemory(keyLength)
		If Not *key
			ProcedureReturn #False
		EndIf
		
		If Not OpenCryptRandom()
			ProcedureReturn #False
		EndIf
		CryptRandomData(*key, keyLength)
		
		Protected i.i, hexKey.s = ""
		For i = 0 To keyLength - 1 Step 2
			hexKey + RSet(Hex(PeekU(*key + i), #PB_Unicode), 4, "0")
		Next
		
		; Wandle Post Data in JSON-String um.
		Protected json.i = CreateJSON(#PB_Any)
	    Protected jsonData.i = SetJSONObject(JSONValue(json))
	    ForEach postData()
	    	SetJSONString(AddJSONMember(jsonData, MapKey(postData())), postData())
	    Next
		Protected jsonStr.s = ComposeJSON(json)
		FreeJSON(json)
		
		; Wandle JSON-String in Hex-String um.
		Protected jsonLength.i, jsonHex.s = convert2Hex(jsonStr, *key, keyLength, @jsonLength)
		; Wandle Länge des JSON-String in HEX um.
		Protected.s hexLength = RSet(Hex(jsonLength * 2, #PB_Long), 8, "0")
		
		; Gib Schlüssel wieder frei
		FillMemory(*key, keyLength, 0)
		FreeMemory(*key)
		
		; Erstelle Mark of the Web
		Protected motw.s = GetURLPart(actionUrl, #PB_URL_Protocol) + "://" + GetURLPart(actionUrl, #PB_URL_Site)
		
		; Lies HTML-Template aus Datasection aus.
		Protected template.s = PeekS(?template_begin2, -1, #PB_Unicode) ;PeekS(?template_begin, -1, #PB_UTF8)
		
		; Ersetze Variablen in Template.
		template = ReplaceString(template, "%MOTW%", "(" + RSet(Str(Len(motw)), 4, "0") + ")" + motw)
		template = ReplaceString(template, "%TITLE%", title)
		template = ReplaceString(template, "%ACTION%", actionUrl)
		template = ReplaceString(template, "%POSTDATA%", jsonHex)
		template = ReplaceString(template, "%NOJSACTION%", nojsUrl)
		template = ReplaceString(template, "%NOJSINFO%", nojsinfo)
		
		; Suche zufälligen nicht existenten Dateinamen im temporären Verzeichnis
		Repeat
			Protected tempFile.s = GetTemporaryDirectory() + "_post" + Hex(Random(2147483647), #PB_Long) + "-" + Hex(Random(2147483647), #PB_Long) + ".html"
		Until FileSize(tempFile) = -1
		
		; Schreibe Template in Datei
		Protected fileId.i = CreateFile(#PB_Any, tempFile)
		If Not fileId
			ProcedureReturn #False
		EndIf
		WriteString(fileId, template, #PB_UTF8)
		CloseFile(fileId)
		LockMutex(tfilesLock)
		If AddElement(tFiles())
			tFiles()\file = tempFile
			tfiles()\time = Date()
		EndIf
		UnlockMutex(tfilesLock)
		
		; Suche Standardprogramm zum Öffnen von HTML-Dateien.
		Protected browser.s = FindAssociatedProgram(tempFile)
		If browser = ""
			ProcedureReturn #False
		EndIf
		
		; Setze URL für den Browser zusammen
		Protected call.s = ~"\"file://" + tempFile + "#" + hexLength + hexKey + #DQUOTE$
		
		ProcedureReturn RunProgram(browser, call, "")
		
		DataSection
			template_begin:
				;IncludeBinary "OpenBrowserWithPostData.html"
				;Data.u 0
			template_begin2:
				Data.s ~"<!DOCTYPE html>\r\n<!-- saved from url=%MOTW% -->\r\n<html><head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" +
				       ~"<script type=\"text/javascript\">\r\n" +
				       "!function(){'use strict';function t(t,e){if(void 0==t||void 0==e||t.length%4!==0||e.length%4!==0||t.length<12)return null;" +
				       "var n=parseInt(t.slice(0,8),16);if(n!==e.length)return null;t=t.substr(8);for(var r=0,i='',o=0;o!==e.length;o+=4)i+=String." +
				       "fromCharCode(parseInt(t.slice(r,r+4),16)^parseInt(e.slice(o,o+4),16)),r=(r+4)%t.length;return i}function e(){var e=window." +
				       "location.hash.substr(1);window.location.hash='';var n=document.getElementsByName('data')[0],r=t(e,n.getAttribute('post-data'));" +
				       "if(document.submitPost.removeChild(n),null!=r){var i=JSON.parse(r);for(var o in i)if(i.hasOwnProperty(o)){var s=document." +
				       "createElement('input');s.setAttribute('type','hidden'),s.setAttribute('name',o),s.setAttribute('value',i[o]),document.submitPost." +
				       ~"appendChild(s)}document.submitPost.submit()}}window.onload=e}();\r\n" +
				       "</script><title>%TITLE%</title></head><body><form id='submitPost' name='submitPost' action='%ACTION%' method='post'>" +
				       "<input type='hidden' name='data' value='' post-Data='%POSTDATA%'><noscript><div class='center'>" +
				       ~"<meta id=\"meta-refresh\" http-equiv=\"refresh\" content=\"2;URL=%NOJSACTION%\"><p>%NOJSINFO%</p>" +
				       ~"<a href=\"%NOJSACTION%\">Link</a></div></noscript></form></body></html>"
				Data.u 0
				       
		EndDataSection
	EndProcedure
	
	Procedure.i removeTempFiles(deltaTime.i = -1)
		If deltaTime < 0
			ProcedureReturn ListSize(tFiles())
		EndIf
		LockMutex(tfilesLock)
		ResetList(tFiles())
		While NextElement(tFiles())
			If tFiles()\time + deltaTime <= Date()
				DeleteFile(tFiles()\file)
				DeleteElement(tFiles())
			EndIf
		Wend
		UnlockMutex(tfilesLock)
		
		ProcedureReturn ListSize(tFiles())
	EndProcedure
EndModule

NewMap postData.s()

postData("__ac_name") = "admin"
postData("__ac_password") = "herein"
postData("form.submitted") = "1"
postData("pwd_empty") = "0"
postData("js_enabled") = "0"

BrowserPost::openURL("http://freakscorner.de/test.php?bla=normales+GET", postData(), "Bastelkeller Weiterleitung", "http://freakscorner.de/", "Da in ihrem Browser Skripte deaktiviert wurden, können die Daten nicht automatisch übertragen werden.")

Delay(5000)
BrowserPost::removeTempFiles(0)
TODO:
  • Mac-Version
  • Automatisches Löschen der temporären Datei nach einer bestimmten Zeit.
test.php:

Code: Alles auswählen

<html>
	<body>
		<h3>POST</h3>
		<? var_dump($_POST); ?>
		<h3>GET</h3>
		<? var_dump($_GET); ?>
		<h3>REQUEST</h3>
		<? var_dump($_REQUEST); ?>
	</body>
</html>
Nicht minimiertes Template:

Code: Alles auswählen

<!DOCTYPE html>
<!-- saved from url=%MOTW% -->
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <script type="text/javascript">
        (function () {
            "use strict";
            function decryptData(key, data) {
                if (key == undefined || data == undefined || (key.length % 4) !== 0 || (data.length % 4) !== 0 || key.length < 12) {
                    return null;
                }
				var dataLength = parseInt(key.slice(0, 8), 16);
				if (dataLength !== data.length) {
					return null;
				}
				key = key.substr(8);

                var j = 0, out = '';
                for (var i = 0; i !== data.length; i += 4) {
                    out += String.fromCharCode(parseInt(key.slice(j, j + 4), 16) ^ parseInt(data.slice(i, i + 4), 16));
					j = (j + 4) % key.length;
                }
                return out;
            }
            function go() {
                var hashKey = window.location.hash.substr(1);
                window.location.hash = '';
                var inputs = document.getElementsByName('data')[0];
				var jsonStr = decryptData(hashKey, inputs.getAttribute('post-data'));
				document.submitPost.removeChild(inputs);
				if (jsonStr == null) {
					return;
				}
				var jsonObj = JSON.parse(jsonStr);
				for (var key in jsonObj) {
					if (jsonObj.hasOwnProperty(key)) {
						var hiddenInput = document.createElement("input");
						hiddenInput.setAttribute("type", "hidden");
						hiddenInput.setAttribute("name", key);
						hiddenInput.setAttribute("value", jsonObj[key]);
						document.submitPost.appendChild(hiddenInput);
					}
				}
				document.submitPost.submit();
			}
            window.onload = go;
        })();
    </script>
    <title>%TITLE%</title>
</head>
<body>
<form id="submitPost" name="submitPost" action="%ACTION%" method="post">
    <input type="hidden" name="data" value="" post-data="%POSTDATA%">
    <noscript>
        <div class="center">
            <meta id="meta-refresh" http-equiv="refresh" content="2;URL=%NOJSACTION%">
            <p>%NOJSINFO%</p>
            <a href="%NOJSACTION%">Link</a>
        </div>
    </noscript>
</form>
</body>
</html>
Edit:
  • Linux-Version hinzugefügt
  • In Modul gepackt
  • Löschmöglichkeit eingebaut.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von ts-soft »

Kleiner Hinweis: Falls das "EnableExplicit" für das Module sein soll, würde ich es auch dort plazieren,
weil so wirkt es nur Ausserhalb :wink:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NicTheQuick »

ts-soft hat geschrieben:Kleiner Hinweis: Falls das "EnableExplicit" für das Module sein soll, würde ich es auch dort plazieren,
weil so wirkt es nur Ausserhalb :wink:
Das hast du mir in irgendeinem anderen Thread auch schonmal gesagt. :lol: Aber mir war es bewusst. Falsch kann momentan nichts mehr sein, weil ich den vorhandenen Code nur noch ins Modul kopiert habe. Ich könnte es aber natürlich der Vollständigkeit halber gleich mal einbauen.
NeoChris
Beiträge: 205
Registriert: 21.11.2013 21:17
Wohnort: Schweiz
Kontaktdaten:

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NeoChris »

Is das nicht doppelt gemoppelt?! Einfach oben einmalig einfügen und gut is.

Wen jemand meint EnableExplicit nicht zu nutzen selbst schuld!
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NicTheQuick »

Eben nicht. Ein "EnableExplicit" oben reicht nicht. Innerhalb eines Modules musst du nochmal "EnableExplicit" nutzen, sonst wirkt es nicht.

Code: Alles auswählen

EnableExplicit
DeclareModule bla
	a.s = "hi"
EndDeclareModule
Module bla
EndModule
NeoChris
Beiträge: 205
Registriert: 21.11.2013 21:17
Wohnort: Schweiz
Kontaktdaten:

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NeoChris »

thx für die Info die mir nicht bekannt war. Nich gewusst.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von ts-soft »

PureBasic.chm - Module hat geschrieben:Wenn die Anweisungen Define, EnableExplicit, EnableASM in einem Modul verwendet werden, haben sie keine Wirkung außerhalb des jeweiligen Moduls, und umgekehrt.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
NeoChris
Beiträge: 205
Registriert: 21.11.2013 21:17
Wohnort: Schweiz
Kontaktdaten:

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von NeoChris »

Du bist zu langsam, Nic hats mir grad eben erzählt! ;)
funkheld
Beiträge: 647
Registriert: 31.12.2009 11:58

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von funkheld »

Das liest sich ja wunderbar, was dein Programm macht.

So etwas suche ich hier schon seit einpaar Tagen für meinem Yun.
Habe mir soeben das neueste Purebasic geladen.
Dein Programm funktioniert bei mir.

Nun möchte ich Daten damit zur http-seite senden zum Arduino Yun über http.
------------------------------------------------------------
text holen : "192.168.240.1/data/get/analog0"
Hier liegen Daten vom Arduino Yun.

text senden : "192.168.240.1/data/put/ledhigh/1"
hier wird eine 1 zum Arduino Yun gesendet.
-------------------------------------------------------------

Wo kann ich das bitte bei dir einsetzen , das ich Daten empfangen kann (get) und Daten senden kann (post) ?


Danke.
Gruss
Zuletzt geändert von funkheld am 09.12.2015 15:08, insgesamt 1-mal geändert.
Nino
Beiträge: 1300
Registriert: 13.05.2010 09:26
Wohnort: Berlin

Re: POST-Daten via Purebasic zu Webseite im Browser schicken

Beitrag von Nino »

Sehr interessantes Modul!
Zum Testen wollte ich mich automatisch hier im Forum anmelden.
Code:

Code: Alles auswählen

NewMap postData.s()

postData("username") = "Nino"
postData("password") = "<richtiges Passwort>"

BrowserPost::openURL("http://www.purebasic.fr/german/ucp.php?mode=login", postData(), "PureBoard-Anmeldung")

Delay(5000)
BrowserPost::removeTempFiles(0)
Die Feldnamen "username" und "password" habe ich mit Hilfe von Firefox' 42.0 "Inspektor" ermittelt.

Zwar wird die Anmeldeseite aufgerufen, aber mehr passiert nicht, alle Felder bleiben leer.
Geht das nicht mit diesem Modul, oder habe ich etwas falsch gemacht?
Antworten