Monitorprofile mit xrandr-mgr

Mehrere Monitore machen Spaß. An meinem Hauptplatz werkeln 4 TFTs an einem Rechner – Mail, Code, Testausgaben, Medien – alles ist irgendwo dauerhaft sichtbar. Was etwas nervig ist sind jedoch Spiele: Diese landen unabhängig von der Primärmonitordefinition immer auf dem linken Monitor. Bisher habe ich hier manuell mit xrandr nachgeholfen und vor Start des Spiels meinen Desktop auf den TFT vor meiner Nase beschränkt. Leider hat xrandr keine undo-Button, das heißt nach dem Spielen musste ich immer wieder per Hand nachhelfen.

Heute ich mir das Tool xrandr-mgr begegnet, welches das anlegen von benannten Profilen erlaubt. Für mich nicht direkt nutzbar, da sich meine Konfiguration häufig ändert, aber für ein temporäres Merken des vorherigen Konfiguration trotzdem Ideal.

BitBastelei #146 – SSH unter Linux

Vom Verbinden bis zum Tunneln
Alle Angaben beziehen sich auf OpenSSH

Befehle:

Verbinden zum Rechner:
ssh evil.server

Verbinden zum Rechner mit Nutzerangabe
ssh anderernutzer@evil.server

Host-Keys anzeigen
ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key
(bzw. passender Key)

Host-Key aus “Adressbuch” löschen
ssh-keygen -R evil.server

Neues Schlüsselpaar erzeugen
ssh-keygen

Key auf Server kopieren
ssh-copy-id username@evil.server

Passwort eines Keys ändern
ssh-keygen -f ~/.ssh/id_rsa -p

Argumente
-p 1234 – Port 1234 statt Port 22 nutzen
-C – Kompression einschalten
-v – verbose – zusätzliche Ausgaben zur Fehlersuche

Lokale Weiterleitung
ssh -L 127.0.0.1:1234:192.168.0.2:80 evil.server
Lokale Verbindungen an Port 1234 werden über evil.server an 192.168.0.2 Port 80 weitergeleitet

Remote Weiterleitung
ssh -R 0.0.0.0:1235:127.0.0.1:80 evil.server
Verbindungen auf eine beliebige IP von evil.server auf Port 1235 werden an Port 80 des lokalen PCs weitergeleitet

SOCKS-Proxy
ssh -D 3128 evil.server
Es wird ein SOCKS-Proxy auf Port 3128 gestartet. Dieser kann z.B. mit Firefox genutzt werden

X11-Forwarding
ssh -XY evil.server
Nun können in der Sitzung grafische Programme gestartet werden. Die Anzeige erfolgt auf dem lokalen PC

Config-Files
Alle Argumente und weitere Optionen können global oder pro Ziel in den Konfigurationen hinterlegt werden. Die Benutzerkonfiguration ist unter ~/.ssh/config zu finden, die Systemweite üblicherweise unter /etc/ssh/ssh_config

Escape-Sequenz
In einer SSH-Sitzung kann man üblicherweise mit der Tilde-Taste (~) ein internes Menü aufrufen. Die Wichtigsten Befehle:
~? Hilfe anzeigen
~. SSH-Verbindung beenden (auch wenn Gegenseite nicht mehr reagiert)
~# Liste der Verbindungen (incl. Tunnel) anzeigen
~C Interne Konsole aufrufen – hier kann man nachträglich Tunnel (-L, -R, -D) aufbauen

Weitere Ideen:
– ssh-agent: Kennwörter für SSH-Keys mussen nur alle X Minuten eingegeben werden
– autossh: SSH-Verbindung bei Abbrüchen neu Aufbauen
– SSH mit Pipes: Pipes lassen sich über SSH auch an entfernte Rechner senden
2-Faktor-Anmeldung, z.B. mit Google Authenticator
Host-Keys in DNS hinterlegen

LUG-MYK

YouTube Watch Later als M3U-Playlist exportieren

Ein großer Teil meines Medienkonsums läuft über YouTube. Bastler, Podcasts, Vorträge – nahezu alles ist hier vorhanden und hat den Fernseher nahezu vollständig abgelöst. Eine der aufwändigsten Arbeiten für mich ist es meine “Wunschliste” an Videos zu verwalten. Welche Videos möchte ich mir noch ansehen. Hierzu nutze ich bereits seit längerem einige Scripte um Posts diverser Channels zu sortieren und Interessantes in die “Watch Later”-Liste, also “Später ansehen”, zu verschieben. Diese kann ich dann einfach auf dem Tablet laufen lassen und so die Videos nach und nach ansehen.

Anders sieht es aus wenn ich am PC arbeite. Zwar kann man auch hier die Liste über die Webseite nutzen, jedoch ist hier ohne Klimmzübe kein Overlay (“Immer im Vordergrund”) möglich. Als Abhilfe nutze ich hier üblicherweise VLC – dort kann man eine YouTube-URL eingeben und direkt abspielen. Leider gibt es keine direkte Unterstützung für Playlisten und die verfügbaren Plugins lassen nur öffentliche Listen abrufen.

Bildschirmfoto-Medien öffnen

Natürlich könnte ich jetzt meine Scripte umschreiben und öffentliche (bzw. “Nicht gelistete”) Listen nutzen, jedoch ist das manuelle Hinzufügen zur Watch-Later-List dank des überall verfügbaren Buttons wesentlich einfacher als das Hinzufügen zu selbst angelegten Listen.

wll

Da ich von LUA, welches in VLC zum Einsatz kommt, keine Ahnung habe und durch meine sonstigen YT-Automationen tonnenweise fertigen PHP-Code zur Verfügung habe ist entsprechend eine Webanwendung daraus geworden. Benötigt wird ein API-Key, welcher in der Dev-Console beantragt werden kann sowie die Installation des Google API PHP-Client. Auch sollte der Webserver die Berechtigung haben key.php im selben Verzeichnis zu beschreiben – dies kann z.B. über “touch key.php ; chmod ugo+w key.php” erfolgen. Der erste Aufruf sollte über den Browser erfolgen, hierbei wird man aufgefordert das Script mit YouTube zu Paaren. Die so abgerufenen Schlüssel werden in den angesprochenen key.php gespeichert, sodass folgende Zugriffe ohne weitere Abfragen erfolgen. Die URL kann nun in VLC eingefügt werden – dieser sollte die so bereitgestellte Playlist laden und die Videos nacheinander abspielen – mit allen Features des VLC wie z.B. Always-on-Top, Abspielgeschwindigkeit, Videoeffekte, etc.

playlist

Den Code zum selbst testen gibts anbei oder – ohne WordPress-Korrekturversuche – im Gist. Eventuell ließ sich das Ganze auch noch mit youtube-dl kombinieren um einen Podcast-kompatiblen Feed zu erstellen.

< ?php
 
/**
 * Youtube Watch Later List To Playlist Script
 * 
 * This script fetches your watch later list and outputs it as an M3U playlist
 *
 * Requirements:
 *   PHP enabled webserver
 *   Google PHP API (https://github.com/google/google-api-php-client)
 *   A YouTube API key (Oauth2, can be registered at https://console.developers.google.com/)
 *   Some kittens to sacrifice
 *
 * Initialization
 *   First ensure your webserver can write a file called "key.php" to the directory
 *   you put this file in. E.g. "touch key.php ; chmod ugo+w key.php"
 *   Next open the appropriate URL in your browser. You will be asked to pair
 *   this script with your YouTube-Account. If you configured everything correctly
 *   it will output the playlist and save your access codes in the key.php mentioned
 *   above. Successive requests do not require additional authentication. You may now
 *   put the URL in your YT-enabled media player like VLC.
 *
 * Based on examples by DomSammut (https://www.domsammut.com/code/php-server-side-youtube-v3-oauth-api-video-upload-guide)
 * 2015 Florian Knodt <yt@adlerweb.info>
 */ 
 
// Set this to the directory of google api php client
set_include_path('./google-api-php-client/src/');
 
$OAUTH2_CLIENT_ID = 'YOURID.apps.googleusercontent.com';
$OAUTH2_CLIENT_SECRET = 'YOURSECRET';
$REDIRECT = 'http://localhost/yt/ytwll2m3u.php';
$APPNAME = 'YouTube WLL Import Test';
 
require_once 'Google/autoload.php';
session_start();
 
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setApplicationName($APPNAME);
$client->setAccessType('offline');
 
if(file_exists('key.php')) {
    require_once 'key.php';
}
 
if(isset($key)) {
    $client->setAccessToken($key);
    $_SESSION['token'] = $key;
}else{
    $client->setScopes('https://www.googleapis.com/auth/youtube');
    $client->setRedirectUri($REDIRECT);
}
 
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
 
if (isset($_GET['code'])) {
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
        die('The session state did not match.');
    }
 
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
 
}
 
if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
    $keydata = '< ?php $key=\''.$_SESSION['token'].'\'; ?>';
    //echo '<code>' . $_SESSION['token'] . '</code>';
   
    if(!is_writable('key.php')) {
        die('key.php can not be written - please put this code into key.php: '.$keydata);
    }
    file_put_contents('key.php', $keydata);
}
 
// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
    try {
        // Call the channels.list method to retrieve information about the
        // currently authenticated user's channel.
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array(
            'mine' => 'true',
        ));
 
        $playlist = '#EXTM3U'."\n";
        foreach ($channelsResponse['items'] as $channel) {
            // Extract the unique playlist ID that identifies the list of videos
            // uploaded to the channel, and then call the playlistItems.list method
            // to retrieve that list.
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['watchLater'];
 
            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                'playlistId' => $uploadsListId,
                'maxResults' => 50
            ));
 
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
                $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n";
            }
            
            while(isset($playlistItemsResponse['nextPageToken'])) {
                $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
                    'playlistId' => $uploadsListId,
                    'maxResults' => 50,
                    'nextPageToken' => $playlistItemsResponse['nextPageToken'],
                ));
                foreach ($playlistItemsResponse['items'] as $playlistItem) {
                    //$htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
                    //$playlistItem['snippet']['resourceId']['videoId']);
                    $playlist .= '#EXTINF:-1,'.$playlistItem['snippet']['title']."\n".'https://www.youtube.com/watch?v='.$playlistItem['snippet']['resourceId']['videoId']."\n";
                }
            }
        }
    } catch (Google_ServiceException $e) {
        echo sprintf('<p>A service error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    } catch (Google_Exception $e) {
        echo sprintf('<p>An client error occurred: <code>%s</code></p>',
            htmlspecialchars($e->getMessage()));
    }
 
    $_SESSION['token'] = $client->getAccessToken();
} else {
    $state = mt_rand();
    $client->setState($state);
    $_SESSION['state'] = $state;
 
    $authUrl = $client->createAuthUrl();
    $htmlBody = < <<END
  <h3>Authorization Required
  <p>You need to <a href="$authUrl">authorise access</a> before proceeding.</p><p>
END;
}
 
if(isset($playlist)) die($playlist);
?>
 
< !doctype html>
<html>
<head>
    <title>My Uploads</title>
</head>
<body>
< ?php echo $htmlBody?>
</body>
</html></p>

Logrotate für Windows-Webserver IIS

Seriously, Microsoft? Der in Windows integrierte Webserver IIS kann problemlos vernünftige Log-Dateien erzeugen und besitzt auch eine Funktion diese bei Erreichen einer Zeitspanne oder eines Größenlimits zu schließen und eine neue beginnen. Was leider fehlt: Alte Dateien löschen. Es kommt was kommen musste: Auf einem Produktivserver durfte ich mehr als 100GB an logtechischen Textkauderwelsch finden. Platte voll.

Zwar kann man hier mit der in NTFS verfügbaren Ordnerkompression gegensteuern, eine Dauerlösung ist das aber sicher nicht. Am Ende habe ich auf Basis eines Powershell-Scriptes von Daniel Schroeder aka deadlydog etwas passendes gebastelt um hier Abhilfe zu schaffen. Regelmäßig über die Aufgabenplanung aufgerufen bleibt so der Ordner auf einem erträglichen Maß.

$limit = 15 #Delete Logs after 15 Days
$path = "C:\inetpub\logs\LogFiles\W3SVC1"
 
# Function to remove all files in the given Path that have not been modified after the given date.
# original written by deadlydog / Daniel Schroeder, http://blog.danskingdom.com/powershell-functions-to-delete-old-files-and-empty-directories/
# Requires Powershell >=2.0
function Remove-FilesNotModifiedAfterDate([parameter(Mandatory)][ValidateScript({Test-Path $_})][string] $Path, [parameter(Mandatory)][DateTime] $DateTime)
{
    Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Remove-Item
    #Get-ChildItem -Path $Path -Recurse -Force -File | Where-Object { $_.LastWriteTime -lt $DateTime } | Format-List BaseName,LastWriteTime
}
 
Remove-FilesNotModifiedAfterDate -Path "$path" -DateTime ((Get-Date).AddDays(1-$limit))

Zum Ausführen wird mindestens PowerShell 2.0 benötigt. Ältere Betriebssysteme wie z.B. 2008R2 bringen nur PowerShell 1 mit, hier muss manuell über das Windows Management Framework aktualisiert werden.

BitNotice #89 – Mit Bauschaum gegen den Luftzug

Der Wind der letzten Zeit hat sich bemerkbar gemacht – schon lange war mir aufgefallen, dass mein Schlafzimmer vergleichsweise kalt war. Bisher hatte ich dies der Nordlage zugeschrieben, bei den jetzigen Windstößen gibt es aber keinen Zweifel mehr: Zwischen Wand und Dach kommt Luft rein. Grob gedämmt ist der Bereich zwar, aber eben nicht Luftdicht. Prinzipiell kein Problem für mich, da auch im Winter ohne Heizung die Temperatur akzeptabel bleibt, aber mit Zug wird es unangenehm. Da eine “richtige” Sanierung eine Menge Arbeit & Dreck verursachen würde kommt die QnD-Lösung zum Einsatz: Bauschaum. Da der nur an den Innenwänden landet kann dahinter weiterhin alles Zirkulieren und über den Hohlraum der Dachkonstruktion abziehen – ohne weg an meinen Wohnbereichen vorbei.

SSH: Fingerprint-Algorithmus ändern

sshmd5Mit einem der letzten Updates scheint OpenSSH einen Schritt in Richtung Gegenwart getätigt zu haben. Nun werden Fingerprints nicht mehr als MD5 sondern mit SHA256 präsentiert. Was auf der einen Seite eine tolle Sache ist kann aber auch zum Problem werden: Eine hiesige Debian-Kiste kann mit dem dort als stable deklarierten OpenSSH 7.0 auch optional keinen SHA256-Hash herausrücken. Manueller Abgeleich mit dem neueren Client des ArchLinux-Systems unmöglich. Um hier wieder auf einen gemeinsamen Nenner zu kommen bleibt nur den neuen Client auf den älteren Hash-Algorithmus zurückzutrimmen. Das funktioniert über die SSH-Config (/etc/ssh/ssh_config or ~/.ssh/config) mit folgenden Zeilen – zum Glück auch für einzelne Hosts:

Host oldserver.org
FingerprintHash md5

Schon erhält man beim Verbinden wieder den gewohnten MD5-Hash und kann sich – bis auch andere Distros sha256 herausrücken – behelfen.

BitBastelei #145 – Dell Laptopnetzteil-DRM

Dell hat sich für seine Laptops etwas ganz tolles ausgedacht: Deren Netzteile kommunizieren mit dem Laptop und handeln den zu erwartenden Ladestrom aus. Das macht es möglich auch Ladegeräte anderer Modelle – ggf. mit längerer Ladezeit – benutzen. Oder auch Ladegeräte von Drittanbietern erkennen und abklemmen. Mit Lötkolben gehts also daran hier Abhilfe zu schaffen.

((Seltsam, was alles so beim Frühjahrsprutz auftaucht – ich hatte echt gedacht, dass da schon online war))

Internet Explorer und die Kompatibilitätsmodi

Auch wenn Microsoft ihn quasi schon beerdigt hat: Immer wieder stößt man noch auf den Internet Explorer. Gerade in Firmen ist er kaum wegzudenken, denn viele Produkte der Industrie haben es auch 2015 noch nicht geschafft auf ActiveX zu verzichten bzw. halbwegs standardisierte Formate zu verwenden. Besonders tückisch hierbei: Während die neueren Versionen des Internet Explorer immerhin halbwegs mit den aktuellen Webstandards klar kommen sind viele Webanwendungen noch auf ältere Inkarnationen zugeschnitten. Um hier den Nutzern keine Angst vor einer Aktualisierung zu bescheren schaltet der Internet Explorer beim kleinsten Anzeichen für Probleme in einen Kompatibilitätsmodus und behandelt die Inhalte wie frühere Versionen. Auch ist es nicht unüblich, dass alle internen Adressen automatisch immer mit den damaligen Vorgaben behandelt werden.

Wer als Webentwickler für Firmen unterwegs ist sollte hier gegensteuern. Natürlich ist es einfach den jeweiligen Administratoren eine Änderung der Einstellungen oder gar einen anderen Browser zu empfehlen, jedoch ist dies häufig nicht mit Policies vereinbar oder aber wird als Ausnahme gehandhabt. Letztere werden gerne auf Grund der Seltenheit nur schlecht gewartet oder gehen mit der Zeit in den Tiefen des Systemmanagements verloren und sogen dann für aufwändige Fehlersuchspiele.

Wer sich sicher ist, dass seine Seite mit aktuellen IE-Versionen läuft kann jedoch auch ganz ohne Firmenadministrator die meisten Probleme vermeiden. Über einen propritären Meta-Tag lässt sich der IE anweisen eine bestimmte Rendering-Art zu verwenden – unabhängig von der globalen Vorlage.

Um beispielsweise explizit als IE11 zu rendern kann folgender Eintrag im head der Seite ergänzt werden:

<meta http-equiv="X-UA-Compatible" content="IE=11"/>

Selbes geht natürlich auch für andere Versionen. Eine Sonderstellung bildet noch “edge” – hiermit wird immer die neueste verfügbare Engine genutzt. Perfekt wenn mann möglichst viele aktuelle Funktionen verfügbar machen will. Identifiziert sich dennnoch ein älterer Browser kann man immernoch per Browserweiche o.Ä. einen abgespeckten Content servieren ohne befürchten zu müssen unbeabsichtigt auch neuere IE-Versionen einzuschränken.

<meta http-equiv="X-UA-Compatible" content="IE=edge"/>

Mehr Infos gibt es in einem Technet-Artikel von Stephanus Schulte, welcher das Thema ausführlich erklärt. Wer sich lieber auf die Fakten beschränkt wird im MSDN fündig.

Hak5 als ASCII-Video

(was posted only on YT before)

You can’t watch Hak5 on text consoles? Challenge accepted…

Downloading Hak5 using lynx and watching as ASCII-Art using mplayer and aalib.
Re for 1808: https://www.youtube.com/watch?v=3RPgd6U2oyc

full command:
mplayer -quiet -vo aa:driver=curses -monitorpixelaspect 0.5 yourfile.mp4

Sorry for the audio, guess the mic-cable must be broken somewhere

It is also possible to use vo=caca to get colored output

Warning: Nerd inside