Teilnahme am Windows 8 Camp

Heute habe ich am Windows 8 Camp in der deutschen Microsoft-Zentrale in Unterschleißheim bei München teilgenommen.

Der Vortragende erklärte einige Details zum neuen Betriebssystem und insbesondere zu den neuen Metro-Apps aus Entwicklersicht. Obwohl es schon interessant war, hatte ich etwas mehr neue Informationen in so einem Seminar erwartet.

Aber es hat mich gefreut einige Bekannte wieder zu treffen und das Essen war auch gut. ;-)

Waren Sie auch bei dieser Veranstaltung?

MunichJS: Vortrag über Internationalisierung von HTML5-Apps und Verwendung des Encapsulators

Heute fand ein JavaScript-Meetup von MunichJS (English) in Feldkirchen bei München statt. MunichJS ist eine Usergroup in München von Entwicklern, die sich monatlich treffen, um Themen wie JavaScript und ECMAScript zu diskutieren.

Ich war eingeladen dort einen Vortrag über das Thema “Ausführen einer internationalisierten HTML5-App als natives Windows-Programm” zu halten.

MunichJS: Vortrag über Internationalisierung von HTML5-Apps und Verwendung des Encapsulators

Im ersten Teil des Vortrages zeigte ich eine HTML5-App, die eine JavaScript-Bibliothek nutzt, um einfach sämtliche Zeichenketten im HTML- und JavaScript-Teil der Anwendung zu lokalisieren. Am Ende des Vortrages verwendete ich den Intel AppUp Encapsulator zur Generierung einer MSI-Datei für diese App. Damit lief die Anwendung native auf einem Windows-Betriebssystem. Downloaden Sie die PowerPoint-Präsentation (Englisch).

Das in der Präsentation verwendete Beispielprojekt kann in meinem Artikel Internationalisierung: Wie lokalisiert man HTML5-Projekte? herunter geladen werden.

Telefonie-Ereignisbenachrichtigungen von Polycom-Telefonen mittels PHP

Alle aktuellen Polycom-Telefone wie die Polycom SoundPoint IP, die Polycom VVX 500/1500 oder die Polycom SpectraLink Serie unterstützen eine Ereignisbenachrichtigung. Dies ist ein hervorragendes Feature, bei welchem das Telefon eine POST-Anfrage an eine vorher definierte URL für verschiedene Telefonie-Ereignisse sendet.

Bei der Entwicklung einer PHP-Server-Anwendung, die einige dieser Ereignisse behandelt sollte, stieß ich auf das Problem, dass in dem PHP-Datenfeld $_POST keine Daten enthalten waren, obwohl das Skript vom Polycom-Telefon korrekt aufgerufen wurde.

Nach einigen Nachforschungen fand ich heraus, dass die Daten (aus welchem Grund auch immer) nicht als “normales” POST-Key-Value-Paar, sondern also POST-Rohdaten gesendet werden. Somit kann PHP die POST-Rohdaten natürlich auch nicht in das Datenfeld $_POST schreiben.

Hier ist eine Möglichkeit wie man die POST-Rohdaten dennoch erhalten kann:

// Sicherstellen, dass wirklich POST-Rohdaten verfügbar sind
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
	// Nun können wir die POST-Rohdaten von der PHP-Standardeingabe lesen
	$rawPostData = trim(file_get_contents('php://input'));
}

Als Ergebnis erhalten Sie die XML-Daten, die von dem Polycom-Telefon gesendet wurden, in der Variable $rawPostData.

Haben Sie auch bereits Probleme beim Empfang von Polycom Ereignisdaten gehabt?

Erstellen eines beschränkten SSH-Benutzers nur für SSH-Tunneling

Manchmal ist es nötig SSH-Tunneling zu verwenden, um einen Webservice auf einem bestimmten Port zu erreichen, welcher von einer Firewall oder einem Router blockiert wird.

Natürlich könnten Sie einfach einen neuen SSH- Benutzer auf Ihrem Linux-Server einrichten, aber dieser Benutzer kann dann sämtliche Serverbefehle auszuführen, obwohl diese für SSH-Tunneling eigentlich nicht benötigt werden. Genaugenommen muss der Benutzer sich lediglich ein- und wieder ausloggen können – das reicht! Aus diesem Grund möchten wir aus Sicherheitsgründen nicht, dass der Benutzer sonst noch irgendetwas machen kann.

Im Folgenden werde ich zeigen, wie Sie solch einen beschränkten SSH-Benutzer auf einem Linux-Server (getestet auf Debian Linux), nur für die Verwendung von SSH-Tunneling, einrichten können.

Zunächst erstellen wir einen neuen Benutzer (ich nenne ihn nun einfach sshtunnel) mit rbash als Shell:

useradd sshtunnel -m -d /home/sshtunnel -s /bin/rbash
passwd sshtunnel

Die Verwendung von rbash anstatt bash beschränkt den Benutzer bereits, da er insbesondere das Verzeichnis nicht mehr wechseln und auch keine Umgebungsvariablen setzen kann. Jedoch die meisten Bash-Befehle können vom Benutzer weiterhin ausgeführt werden.

Um ihn davon abzuhalten, verwenden wir einen kleinen Trick: Wir setzen die Umgebungsvariable PATH für diesen Benutzer auf nichts. Dadurch wird die Bash keine Befehle zum Ausführen mehr finden. Dies kann ganz einfach dadurch erreicht werden, dass am Ende der Datei .profile im Heimatverzeichnis des Benutzers (in unserem Beispiel /home/sshtunnel/) folgende Zeile eingefügt wird:

PATH=""

Da wir sicherstellen wollen, dass der Benutzer das selbst nicht wieder ändern kann, entfernen wir die Schreibrechte von den Benutzer-Einstellungsdateien sowie vom Heimatverzeichnis des Benutzers selbst:

chmod 555 /home/sshtunnel/
cd /home/sshtunnel/
chmod 444 .bash_logout .bashrc .profile

Jetzt sind wir fertig: Sie können den SSH-Tunnel ganz normal beispielsweise mit PuTTY einrichten und sich mit dem neu angelegten SSH-Benutzer einloggen. Sie werden nichts anderes tun können als sich ein- und wieder auszuloggen, aber das SSH-Tunneling wird einwandfrei funktionieren!

Haben Sie auch schon mal einen so eingeschränkten SSH-Benutzer benötigt?

PHP-Skript für den Zugriff auf die VirusTotal API Version 2.0

Vor kurzem hat VirusTotal (Englisch) ihre API auf Version 2.0 aktualisiert. Da die Version 1.0 nun veraltet ist, habe ich auch mein PHP-Skript für den Zugriff auf die VirusTotal API aktualisiert:

Download des PHP-Skriptes für den Zugriff auf die VirusTotal API Version 2.0

Für eine genaue Beschreibung dieser API-Implementierung, werfen Sie bitte einen Blick auf meinen Artikel zur VirusTotal API Version 1.0.

Lassen Sie mich wissen, wenn Sie Probleme oder Fragen zu diesem PHP-API-Skript haben.

Ports 135, 137 und 445 in AVM Fritz!Box Routern freigeben

Vor einigen Tagen habe ich hier einen neuen Glasfaser-Internetanschluss bekommen, der einwandfrei funktioniert.

Zusammen mit dem neuen Anschlusstyp, bekam ich auch einen neuen, kostenlosen Router von meinem lokalen Internetprovider zur Verfügung gestellt: Eine AVM Fritz!Box 7570 VDSL.

Zunächst möchte ich anmerken, dass dies wirklich ein großartiges Produkt ist: Es hat ein eingebautes VDSL-Modem, aber auch VoIP-Telefonanschlüsse (analog und ISDN), stellt WLAN zur Verfügung und unterstützt sogar DECT, um Ihre Mobilteile zu versorgen.

Ich hatte nur ein Problem: Nachdem dieser neue Router in Betrieb war, konnte ich aus meinem Netzwerk nicht mehr auf unseren Webservice auf Port 445 zugreifen. Es war also keine ausgehende Verbindung auf Port 445 mehr möglich.

Somit prüfte ich die Router-Einstellungen, fand aber keine Option oder wenigstens ein Hinweis auf diese Port-Sperrung. Jedoch, bei einer anschließenden Suche im Internet, stellte sich heraus, dass ich keineswegs der Einzige war, der mit diesem Problem kämpfte.

Natürlich ist Port 445, genauso wie die anderen erwähnten Ports 135 und 137, normalerweise für die NetBIOS- beziehungsweise SMB-Kommunikation reserviert, was wirklich ein Sicherheitsproblem wäre, wenn solche Dienste außerhalb eines sicheren, lokalen Netzwerkes benutzt werden würden. Jedoch, selbst wenn eine Portnummer für einen bestimmten Dienst reserviert ist, so steht es dennoch jedem frei sie für etwas Anderes zu verwenden wie wir: Wir nutzen die Ports 444 und 445, um einige internen SSL-Webseiten zu betreiben, da der Standard-Port 443 bereits anderweitig verwendet wird.

Nachdem ich nicht der Einzige in meinem Unternehmen bin, der diese internen SSL-Webseiten verwendet und ich ganz sicher nicht unsere Port-Verwendung aufgrund eines neuen Routers ändern werde, musste ich einen Weg finden, um die Fritz!Box davon zu überzeugen, ausgehende Verbindungen auf Port 445 zuzulassen.

Nach einiger Recherche kam ich zu folgender Lösung. Hier ist eine schrittweise Anleitung, um ausgehende Verbindungen auf den Ports 135, 137 und 445 mit einer AVM Fritz!Box zum Laufen zu bringen:

  1. Speichern Sie die Einstellungen Ihrer Fritz!Box in eine Datei (Menü “System” / “Einstellungen speichern”).
  2. Öffnen Sie diese Datei in einem einfachen Texteditor.
  3. Ersetzen Sie alle Vorkommen von filter_netbios = yes; durch filter_netbios = no;. (Falls Sie ein älteres Fritz!Box-Modell haben, könnte der Name des Konfigurationseintrag etwas anders lauten. Suchen Sie in diesem Fall einfach nach “netbios”. Damit sollten Sie ihn schnell finden können.)
  4. Fügen Sie eine neue Zeile NoChecks=yes irgendwo am Anfang der Konfigurationsdatei ein (Ich habe Sie nach der Zeile, die mit Language= beginnt, eingefügt). Ohne diese Zeile wird der Import nicht funktionieren, da die Fritz!Box eine manuell geänderte Konfigurationsdatei ablehnen würde.
  5. Stellen Sie zum Schluss die Einstellungen unter Verwendung Ihrer geänderten Konfigurationsdatei wieder her.

Das war’s! Nachdem die geänderte Konfigurationsdatei geladen wurde, startet die Fritz!Box neu und ab jetzt wird der ausgehende Traffic auf den Ports 135, 137 und 445 wieder problemlos funktionieren.

Natürlich kann ich verstehen, dass es sinnvoll ist Ports mit einem potentiellen Sicherheitsrisiko standardmäßig zu sperren, aber ich verstehe absolut nicht, weswegen AVM keine Möglichkeit (irgendwo in den erweiterten Einstellungen) anbietet dies innerhalb deren Benutzer-Interface zu ändern. Ein Router sollte den Benutzer niemals bevormunden: Wenn ein Benutzer einen bestimmten Port aus welchem Grund auch immer nutzen möchte, muss dies mit jedem Router möglich sein!

Sperrt Ihr Router auch ungefragt irgendwelche Ports?

Internationalisierung: Wie lokalisiert man HTML5-Projekte?

Während ich an einem HTML5-Projekt gearbeitet habe, stieß ich auf das Problem, dass das Projekt in mehrere Sprachen übersetzt werden sollte. Hierfür mussten offensichtlich die Zeichenketten der HTML-Tags sowie der JavaScript-Dateien übersetzt werden.

Obwohl ich die Internationalisierung in einer global vernetzten Welt für sehr wichtig erachte, scheint dieses Thema bei der HTML5-Entwicklung komplett vergessen worden zu sein. Ich habe hierzu lediglich einen Vorschlag in der Common-JS-Wiki (Englisch) gefunden, der bereits seit über einem Jahr keinerlei Aktivität zeigt!

Nachdem ich eine Weile gesucht habe, fand ich diesen Post über passive Lokalisierung in JavaScript. Natürlich wäre mir ein offiziell standardisierter Ansatz zur Lokalisierung lieber gewesen, jedoch ist diese JavaScript-Bibliothek in der Zwischenzeit sehr nützlich bis es eine offiziell standardisierter Lösung gibt.

Im Folgenden werde ich erklären, wie ich diese Bibliothek nutze, nicht nur für JavaScript-Dateien, sondern auch um den Inhalt von HTML-Tags zu übersetzen.

HTML5-Test-Page

Zunächst benötigen wird eine HTML5-Test-Seite wie diese hier:

<!doctype html>
<html class="no-js" lang="en">
<head>
	<meta charset="utf-8">
	<title>Internationalization Test</title>

	<link rel="localization" hreflang="de" href="lang/de.json" type="application/vnd.oftn.l10n+json"/>
	<link rel="stylesheet" href="css/style.css">
	<script type="text/javascript" src="js/i18n.js"></script>
	<script type="text/javascript" src="js/script.js"></script>
</head>
<body onload="loaded()">
	<h1 id="headertext">This is an Internationalization Test!</h1>
	<h2 id="subtitletext">With any subtitle.</h2>
	<a id="showinenglish" href="index.html?lang=en">Show in English</a>
	<a id="showingerman" href="index.html?lang=de">Show in German</a>
</body>
</html>

Wie Sie sehen können habe ich allen wichtigen HTML-Tags eine ID zugewiesen. Diese werden wir später für die Übersetzung verwenden.

JavaScript-Hilfsfunktionen

Bevor wir mit der Übersetzung selbst beginnen können, benötigen wir zunächst einige JavaScript-Hilfsfunktionen:

var _ = function (string) {
	return string.toLocaleString();
};

function localizeHTMLTag(tagId)
{
	tag = document.getElementById(tagId);
	tag.innerHTML = _(tag.innerHTML);
}

function getParameterValue(parameter)
{
	parameter = parameter.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
	var regexS = "[\\?&]" + parameter + "=([^&#]*)";
	var regex = new RegExp(regexS);
	var results = regex.exec(window.location.href);
	if(results == null)
		return "";
	else
		return results[1];
}

Hier eine kurze Erklärung was diese Hilfsfunktionen machen:

  • _(): Dies ist nur eine Kurzform des Prototyps string.toLocaleString().
  • localizeHTMLTag(tagId): Diese Funktion holt sich das betreffende HTML-Element vom DOM-Baum basierend auf der übergebenen Tag-ID und macht anschließend direkt die Übersetzung.
  • getParameterValue(parameter): Wir werden diese Funktion benötigen, um den Wert eines URL-Parameters zu erhalten. Dadurch kann die Seitensprache, wenn vom Benutzer gewünscht, manuell geändert werden.

Durchführung der Lokalisierung

Wir haben alle Teile zusammen, um unsere Lokalisierung durchzuführen, was nun sehr einfach ist:

function loaded()
{
	var lang = getParameterValue("lang");
	if (lang != "") String.locale = lang;

	alert(_("Localizing the document title..."));
	document.title = _(document.title);

	alert(_("Localizing other HTML tags..."));
	localizeHTMLTag("headertext");
	localizeHTMLTag("subtitletext");
	localizeHTMLTag("showinenglish");
	localizeHTMLTag("showingerman");

	alert(_("Localizing done!"));
}

Es gibt nur eine Funktion loaded(), die, nachdem das Dokument geladen ist, aufgerufen wird (siehe das Ereignis im Body-Tag der HTML5-Test-Seite oben). Zunächst prüfen wir, ob es einen URL-Parameter lang gibt, falls der Benutzer die Seitensprachen mit den Links geändert hat. Ansonsten müssen wir das Gebietsschema nicht ändern (das Standard-Browser-Gebietsschema des Benutzers wird in diesem Fall automatisch verwendet).

Nun können wir mit der eigentlichen Übersetzung beginnen, entweder, in dem wir eine Zeichenkette direkt mit der Funktion _() übersetzen oder unsere Funktion localizeHTMLTag(tagId) nutzen, um den Inhalt eines HTML-Tags zu übersetzen. Das war’s! :-)

Was ist mit mehreren Sprachen?

Wenn Sie weitere oder andere Sprachen hinzufügen möchten, müssen Sie lediglich einen neuen Lokalisierungslink in den HTML-Bereich head zusammen mit einer JSON-Datei, welche die Übersetzung für die neue Sprache beinhaltet, einfügen.

Warum werden keine kurzen Variablennamen verwendet

Der Autor der JavaScript-Internationalisierungsbibliothek schlägt vor, kurzen Variablennamen anstatt der Standardübersetzungen zu verwenden. Daher möchte ich eine kurze Erklärung geben, warum ich dies in meinem Beispiel nicht mache, denn natürlich hat er recht, dass die Verwendung der Standardübersetzungen dem Projekt einen gewissen Overhead hinzufügt. Jedoch hat die Verwendung von kurzen Variablennamen auch mindestens zwei Nachteile:

  • Ihre HTML5-Seite würde ohne Übersetzung nicht mehr funktionieren, da ansonsten nur die kurzen Variablennamen angezeigt werden würden. In meinem Beispielprojekt würde jedoch einfach die Standardübersetzung (Englisch) angezeigt werden, wenn kein Internationalisierungssystem vorhanden ist.
  • Ich hoffe immer noch, dass es einen standardisierten Weg für die Internationalisierung von HTML5-Projekten geben wird. In diesem wird man wahrscheinlich die Standardübersetzung innerhalb der HTML-Tags benötigen, da der de-facto Standard für die Übersetzung von z. B. PHP-Projekten die Verwendung von gettext-Dateien (.po) ist. Das ist auch die Art und Weise, wie der erwähnte Vorschlag es empfiehlt zu machen. Somit, wenn ich irgendwann in der Zukunft zu dieser Art der Internationalisierung wechseln möchte, will ich nicht sämtliche Standard-Übersetzungen zurück in die HTML-Tags kopieren müssen.

Beispielprojekt downloaden

Wenn Sie möchten, können Sie den Quelltext meines Bespiel-Projektes downloaden.

Update

Ich habe das Beispielprojekt aktualisiert, da in der JSON-Datei ein Komma zu viel war, welches dafür gesorgt hat, dass es nur im Mozilla Firefox (nicht jedoch im Microsoft Internet Explorer und Google Chrome) funktioniert hat. Das ist nun korrigiert – danke an Margaret Wong, die mich auf das Problem aufmerksam gemacht hat!

Denken Sie jedoch daran, dass Sie die Dateien zum Testen auf einen Webserver hochladen müssen, da Sie vermutlich lokal im Internet Explorer und Chrome aufgrund von Browser-Zugriffsbeschränkungen nicht funktionieren werden. Das Beispielprojekt wird nun jedoch korrekt laufen, wenn Sie es auf einen Webserver hochladen.

Welches Konzept verwenden Sie für die Lokalisierung Ihrer HTML5-Projekte?

Zugriff auf die öffentliche VirusTotal API mittels PHP

Aktualisiertes Skript für VirusTotal API Version 2.0!

Nachdem heutzutage sehr viel Spyware und Malware im Umlauf ist, ist es umso wichtiger sicherzustellen, dass der eigene Server stets sauber bleibt.

Aus diesem Grund nutze ich öfters den sehr nützlichen VirusTotal-Dienst (Englisch), um verdächtige Dateien zu überprüfen.

Für ein bestimmtes Projekt wollte ich das gerne automatisieren, um einige Dateien und URLs in definierten Zeitabständen automatisiert prüfen zu können. Dies kann sehr einfach mit der öffentlichen VirusTotal-API realisiert werden.

Leider ist der Link zu einer PHP-Implementierung auf der VirusTotal-Webseite tot. Aus diesem Grund entschied ich mich meine eigene PHP-Implementierung dieser API zu machen.

Sie können eine Kopie meiner Implementierung downloaden. Der Download beinhaltet auch ein kleines Beispielskript, das erklärt, wie sie verwendet werden kann. Gerne können Sie die Implementierung kostenlos in Ihren Projekten verwenden. Natürlich würde ich mich aber über einen kleinen Backlink freuen. :-)

In meiner API-Implementierung sind nicht nur die Standard-API-Funktionen implementiert – diese sind gut dokumentiert und werde daher hier nicht weiter erklärt -, sondern auch einige Hilfsfunktionen, die das Leben einfacher machen sollen. Diese erkläre ich im Folgenden:

  • getScanID($result): Gibt die Scan-ID des Scan-Ergebnisses zurück, die Sie später zur Abfrage eines Scan-Berichtes verwenden können.
  • displayResult($result): Zeigt ein Scan- oder Übermittlungsergebnis in einem lesbaren Format an.
  • getSubmissionDate($report): Gibt den Übermittlungszeitpunkt des Scan-Berichtes zurück.
  • getTotalNumberOfChecks($report): Gibt die Gesamtanzahl der Anti-Virus-Prüfungen des Scan-Berichtes zurück.
  • getNumberHits($report): Gibt die Anzahl der Anti-Virus-Treffer (Malware) des Scan-Berichtes zurück.
  • getReportPermalink($report, $withDate = TRUE): Gibt den Permalink des Scan-Berichtes zurück. Wenn $withDate == TRUE, gibt der Permalink genau den aktuellen Scan-Bericht zurück; ansonsten gibt er immer den neuesten Scan-Bericht zurück.

Diese Hilfsfunktionen sollten die Arbeit mit den API-Ergebnissen einfacher machen, da Sie sich so nicht mehr um die Details des zurückgegebenen JSON-Objekten kümmern müssen. Hier daher nochmals der Download meiner kostenlosen API-Implementierung.

Aktualisiertes Skript für VirusTotal API Version 2.0!

Haben Sie den VirusTotal-Dienst bereits selbst eingesetzt?

Teilnahme bei der Veranstaltung “Die Zukunft ist Ultrabook”

Intel hat mich eingeladen heute die Veranstaltung “Die Zukunft ist Ultrabook” zu besuchen.

Die Zukunft ist Ultrabook

Neben interessanten Vorträgen über Neuigkeiten dieser Laptops der nächsten Generation und einer Podiumsdiskussion, war es sehr spannend viele Leute der Branche zu treffen. Anders als bei anderen Veranstaltungen, nahmen dort nicht nur Softwareentwickler und ISVs (unabhängige Softwarehersteller), sondern auch OEMs (Originalhersteller), IHVs (unabhängige Hardwarehersteller) und natürlich einige Intel-Mitarbeiter teil. Es war sehr interessant sich mit einer ganzen Reihe dieser Leute zu unterhalten.

Nebenbei habe ich auch noch eine Intel X25-M G2 160 GB SSD gewonnen. :-)

Waren Sie auch bei dieser Veranstaltung?

AppLab: Vortrag über “Black Belt und das Accelerator Program”

Heute war ein AppLab von Intel über das Intel AppUp Entwicklerprogramms in Mailand (Italien) mit ungefähr 80 Teilnehmern.

AppLab: Black Belt und das Accelerator Program

Ich war eingeladen dort einen Vortrag zum Thema “Black Belt und das Accelerator Program” zu halten. Dabei habe ich das Reputationssystem des AppUp-Entwicklerprogramms zusammengefasst und aufgezeigt, welche Möglichkeiten das Accelerator Program für Entwickler bereit hält. Downloaden Sie die PowerPoint-Präsentation (Englisch).