Brother QL-570 auf ArchLinux

Ich habe mir einen Etikettendrucker zugelegt und habe mich bin dabei für de QL-570 von Brother entschieden. Den gab es gerade günstig bei Amazon zu kaufen und kommt mit Einzeletiketten und Endlospapier klar.

Bei Brother kann man sich die Treiber herunterladen. Ich habe mich für deb entschieden. Entpacken muss man sie so oder so:

# ar xv ql570cupswrapper-1.0.1-0.i386.deb
# ar xv ql570lpr-1.0.1-0.i386.deb

Den Inhalt von der data.tar.gz kann man dann nach “/” kopieren. Anschließend muss man nur noch einen Befehl ausführen damit der Treiber auch im cups konfiguriert wird:

# /opt/brother/PTouch/ql570/cupswrapper/cupswrapperql570pt1

Leider hat das bei mir nicht ganz gereicht. Ich musste die größe des Papiers noch mit angeben. Das mitgelieferte Papier hat eine Breite von 62mm. Den Befehl bastelt man am besten mit der Ausgabe von dem cupswrapper Befehl (wegen der Seriennumber):

# lpadmin -p QL-570 -E -v usb://Brother/QL-570?serial=<SERIAL> -P /usr/share/cups/model/Brother/brother_ql570_printer_en.ppd -o PageSize=62x29

Anschließend kann man in der angegebenen Größe mittels gLabels auch direkt losdrucken :) Die passenden Optionen kann man sich einfach anzeigen lassen:

# lpoptions -pQL-570 -l

Bitcoin Geldautomat in Hong Kong

Als ich letztens in Hong Kong war musste ich einfach einen Bitcoin ATM besuchen und schnell und einfach Geld tauschen. Ich habe mir dazu den HK Bitcoin ATM ausgesucht. Es war ein bisschen schwer zu finden, aber wenn man erst einmal im richtigen Gebäude ist finde man es schnell.

Der Lamassu Automat ist einfach super zu bedienen. QR Code einscannen vom Wallet, Geld rein schieben und Bestätigen. Ein paar Sekunden später waren die Bitcoins auf meinem Wallet. Warum gibt es davon nicht schon viel mehr?

Mojolicious mit Facebook OAuth2

Ich wollte mich einmal ein bisschen mit dem Graphen von Facebook und Authentifizierung mittels OAuth2 per Facebook schlau machen und bin dabei über den Blog Eintrag bei tudorconstantin.com gestoßen. Genaueres steht auf der Seite, jedoch ist der Code nicht sofort einsetzbar und habe ich ein mal korrigiert:

#!/usr/bin/env perl
use Mojolicious::Lite;
use Net::Facebook::Oauth2;

my $config = {
  facebook => {
      app_id => '',
      secret => '',
      redirect_url => 'http://mojo.dev:3000/redirect_from_fb',
    },
};

plugin 'o_auth2', {
  facebook => {
    key    => $config->{facebook}->{app_id},
    secret => $config->{facebook}->{secret},
}};

get '/' => sub {
  my $self = shift;

  $self->redirect_to('authenticate') unless $self->session->{user}->{fb_username};
  return $self->render('index_authenticated');
  
} => 'index';

get authenticate => sub {
  my $self = shift;

  my $url = $self->get_authorize_url(
    'facebook',
    scope => 'offline_access publish_stream user_likes email',
    redirect_uri => $config->{facebook}->{redirect_url},
  );

  $self->redirect_to( $url->to_abs->to_string );
} => 'authenticate';

get redirect_from_fb => sub {
  my $self = shift;
  my $token = $self->param('code');

  my $fb = Net::Facebook::Oauth2->new(
    application_id     => $config->{facebook}->{app_id},
    application_secret => $config->{facebook}->{secret},
    access_token       => $token,
    callback           => $config->{facebook}->{redirect_url}
  );

	my $access_token = $fb->get_access_token(code => $token);

	$fb = Net::Facebook::Oauth2->new(
		access_token => $access_token
  );

	my $info = $fb->get(
		'https://graph.facebook.com/me'
  );
							    
  print $info->as_json;

  $self->session->{user} = {
	    fb_username   => $info->as_hash->{name},
  };

  $self->redirect_to('index');
} => 'redirect_from_fb';

app->start;
__DATA__

@@ index_unauthenticated.html.ep
% layout 'default';

<%= link_to 'Click here to authenticate with FB' => 'authenticate'; %>

@@ index_authenticated.html.ep
% layout 'default';

Hello <%= session->{user}->{fb_username} %>

<%= link_to 'Click here to authenticate with FB' => 'authenticate'; %>

@@ layouts/default.html.ep
<%= content %>

oder auf gist.github.com.

Multi Room Entertainment mit dem Squeeze Box Server (Teil 2)

Nachdem im ersten Teil das Projekt mit Mopidy und Icecast fehlgeschlagen ist, musste eine neue Lösung her. Entschlossen wurde sich dann für die Squeezebox von Logitech. Die hat ein relativ offenes System mit Servern und Clients. Die lässt sich auch ohne deren Hardware betreiben. Es gibt ein Third-Party Modul mit dem man seinen Soundcloud Account einbinden kann und das war für mich das wichtigste. Der andere wichtige Teil ist, dass alle Clients auch Synchron sind und die Lieder nicht von verschiedenen Stellen abspielt. Auch daran hat Logitech gedacht und ins Protokoll eingebaut. Also eigentlich eine viel umfangreichere Lösung als mit Mopidy.

Als erstes müssen wir ein paar Abhängigkeiten installieren:

# apt-get install libjpeg8 libpng12-0 libgif4 libexif12 libswscale2 libavcodec53

Auf dem Raspberry Pi werde ich Server und Client betreiben und als erstes beginnen wir mit dem Server:

# wget http://downloads.slimdevices.com/LogitechMediaServer_v7.8.0/logitechmediaserver_7.8.0_all.deb
# dpkg -i logitechmediaserver_7.8.0_all.deb
# service logitechmediaserver stop

Das sollte ohne Probleme durchlaufen. Wir muessen jedoch noch ein paar Libs und Symlinks anlegen, die der Server benoetigt. Dabei greife ich auf das Fantastische Howto von All Things Pi zurück:

# wget http://itbert.de/pub/lms-rpi-raspbian.tar.gz
# tar -xzf lms-rpi-raspbian.tar.gz

In dem LMS Howto sind noch ein paar Schritte mehr beschrieben, die waren jetzt bei v7.8.0 nicht nötig:

# mv libmediascan.so.0.0.0 libfaad.so.2.0.0 /usr/local/lib
# mv /usr/share/squeezeboxserver/Bin/arm-linux/faad /usr/share/squeezeboxserver/Bin/arm-linux/faad.old
# mv faad /usr/share/squeezeboxserver/Bin/arm-linux
# ln -s /usr/local/lib/libmediascan.so.0.0.0 /usr/local/lib/libmediascan.so
# ln -s /usr/local/lib/libmediascan.so.0.0.0 /usr/local/lib/libmediascan.so.0
# ln -s /usr/local/lib/libfaad.so.2.0.0 /usr/local/lib/libfaad.so
# ln -s /usr/local/lib/libfaad.so.2.0.0 /usr/local/lib/libfaad.so.2
# ldconfig
# chown -R squeezeboxserver:nogroup /usr/share/squeezeboxserver/

Anschließend kann man den Dienst wieder starten:

# service logitechmediaserver start

Auf dem RaspberryPi dauert das Starten bei mir ungefähr 20 Sekunden und erst dann kann man auf das Webinterface http://DEINSERVER:9000/ zugreifen.
Der Server läuft und wer will kann sich noch das SqueezeCloud Modul aktivieren. Den erstellten API Key aus Teil 1 kann man ruhig weiterverwenden.

Wir wollen jedoch auch Musik hören und nicht nur abspielen. Als Client benutze ich den SqueezeLite und habe bis jetzt keine Probleme gehabt. Zum Glück gibt es auch Binaries und man muss nichts weiter auf dem RasPi kompilieren:

# wget http://squeezelite-downloads.googlecode.com/git/squeezelite-armv6
# chmod +x squeezelite-armv6

Der Client hat selber viele Einstellungen, aber auf dem Server selber kann man ihn ohne Optionen starten. Nach ein paar Sekunden sollte der Client in dem Webinterface von dem Server angezeigt werden und man kann Musik abspielen.

Mein Setup umfasst momentan, den Server und einen Client auf dem Raspi und einen weiteren Client auf dem Computer. Beide laufen ohne Probleme und ich kann endlich in der ganzen Wohnung Soundcloud streamen und das auch noch Synchron :) Demnächst kommt noch ein zweiter RasPi dazu und ich bin mal gespannt.
Auf dem Android benutze ich die Squeeze Controller App. Damit kann man den Server steuern. Leider kann es nicht direkt auf das Soundcloud Modul zugreifen, sondern nur auf die Lieder die momentan in der Playlist sind. Funktioniert jedoch auch super. Soweit bin ich sehr zufrieden und man hat ein paar Hundert Euro gespart die man ansonsten mit Sonos oder Raumfeld ausgegeben hätte.

Multi Room Entertainment mit Mopidy und Icecast (Teil 1)

Ein kleines Projekt um das Heim ein bisschen mehr Musikalisch zu machen. Das Ziel ist es in jedem Raum und auf der Dachterrasse ein paar Boxen zu haben die die gleiche Musik spielen. Eigentlich ganz einfach mit DLNA zu realisieren. Das Problem ist nur, dass ich auch unbedingt Soundcloud hören möchte.

Nach ein bisschen Recherche bin ich auf Mopidy gestoßen. Das ist ein Musikserver der auch von Soundcloud, Spotify und Streams Musik abspielen kann. Wenn man dazu noch Icecast benutzt kann man es sogar in das Netzwerk streamen. Hört sich super an – also installieren. Eine andere Anforderung ist noch das es auf einem RasperryPi laufen muss. Das Projekt sagt sogar das es auf dem laufen soll, also weiter installieren. SPOILER ALERT: Mopidy als Musikdaemon läuft auch einwandfrei und kann ich empfehlen. Wer jedoch auch noch Icecast benutzen will kann dieses leider vergessen, weil der kleine Pi einfach nicht mit dem decodieren der Lieder mitkommt und somit die CPU total überlastet und die Streams nur hackelig ankommen. Es ist also nicht zu empfehlen das folgende Howto auf einem RasperryPi zu installieren sondern auf einem Rechner mit mehr CPU Power zum dekodieren.

Die Installationanleitung von docs.mopidy.com kann man eigentlich getrosst folgen. Man sollte nur gleich seine Plugins mit installieren:

# apt-get install mopidy mopidy-alsamixer mopidy-soundcloud

Es werden alle möglichen python Abhängigkeiten installiert und kann schon ein paar Minütchen dauern auf dem Pi. Unter Debian liegt die Konfiguration unter /etc/mopidy/ und sollte auch dort angepasst werden, wenn man die init script benutzen will. Die Konfiguration kann man eigentlich minimal belassen und man muss nur noch folgendes hinzufügen um den HTTP Server, MPD Server und Soundcloud Anbindung zu aktivieren:


[http]
enabled = true
hostname = ::
port = 6680
static_dir = /var/www/Mopidy-MusicBox-Webclient/webclient
zeroconf = Mopidy HTTP server on $hostname

[mpd]
enabled = true
hostname = ::
port = 6600
password =
max_connections = 20
connection_timeout = 60
zeroconf = Mopidy MPD server on $hostname

[soundcloud]
enabled = true
explore_songs = 100
auth_token = <DEIN-KEY>

[alsamixer]
enabled = true
card = 1
control = PCM

Bevor wir den Dienst starten sollten, brauchen wir noch den API Key für Soundcloud und die Dateien für das Webfrontend.

# cd /var/www/
# git clone https://github.com/woutervanwijk/Mopidy-MusicBox-Webclient.git

Anschließend nur noch Mopidy starten:

# service mopidy start

Jetzt ist es möglich sich mit dem Webfrontend zu verbinden: http://<DEINSERVER>:6680

Die Konfiguration für Mopidy ist jetzt eigentlich abgeschlossen und man kann auf dem Computer auf dem Mopidy läuft (falls nicht: modprobe snd_bcm2835) Musik hören. Wir wollen jedoch Streamen! Also muss erst einmal Icecast2 installiert werden:


# apt-get install icecast2
# sed -i s/false/true/ /etc/default/icecast2

Damit Mopidy einen eigenen Mountpoint bekommt, müssen wie die Konfiguration von Icecast in /etc/icecast2/icecast.xml anpassen bzw. hinzufügen:


<mount>
<mount-name>/mopidy</mount-name>
<fallback-mount>/silence.mp3</fallback-mount>
<fallback-override>1</fallback-override>
</mount>

Woher kommt die silence.mp3 und was macht diese? Es gibt leider noch einen Bug mit Mopidy und Icecast, dass bei einem Songwechsel Icecast die Verbindung verliert. Deswegen muss man den Workaround einbauen und eine leere Datei abspielen. Diese muss im webroot von Icecast liegen und kann folgendermaßen erstellt werden:


# ffmpeg -f lavfi -i aevalsrc=0 -t 5 silence.mp3
# mv silence.mp3 /usr/share/icecast2/web/

Damit Icecast von Mopidy benutzt werden kann, müssen wir den output channel von Mopidy anpassen:


mixer = software
mixer_volume = 100
# output = autoaudiosink
output = lame ! shout2send mount=mopidy ip=<DEINSERVER> port=8000 password=askme
# output = audioresample ! audioconvert ! vorbisenc ! oggmux ! shout2send mount=mopidy ip=<DEINSERVER> port=8000 password=askme
visualizer =

Anschließend muss man Icecast starten und Mopidy neu starten. Bitte beachten, Icecast muss immer vor Mopidy gestartet werden. Wenn alles korrekt konfiguriert ist muss man in Mopidy ein Lied startet und man kann im Icecast Webinterface einen aktiven /mopidy Mountpunkt sehen. Und schon kann man überall Musik hören:


# mplayer http://DEINSERVER:8000/mopidy

[UPDATE] Blockieren von XMLRPC Attacken

Seit ein paar Tagen bin ich in irgend einer Liste für XML-RPC Brute Force Attacken gelandet und die müllen meine limitierten Apache Slots zu. Lösung:

#!/bin/bash
# script: block xmlrpc attacks
# author: Steffen Wirth <s.wirth@itbert.de>
 
LOGFILE="/var/log/apache2/access.log"
LASTLINES="20"
MAXCOUNT="5"
 
LIST=$(tail -n$LASTLINES $LOGFILE |grep "xmlrpc.php" | awk '{print $1}' | sort -n | uniq -c)
 
if [ -n "$LIST" ]; then
        while read -r count ip ; do
                if [ $count -ge $MAXCOUNT ]; then
                        iptables -A INPUT -s $ip -j DROP
                        logger -t "XMLRPC" "blocked ip $ip"
                fi
        done <<< "$LIST"
fi

wie immer auch im gist.github.com

Wie Sebastian korrekt darauf hinwies, wenn man fail2ban installiert hat ist es viel einfacher:

# grep -v "^#" /etc/fail2ban/filter.d/apache-xmlrpc.conf 

[INCLUDES]

before = apache-common.conf

[Definition]

failregex = ^ .*POST .*xmlrpc\.php.*

ignoreregex = 
# grep apache-xmlrpc /etc/fail2ban/jail.conf -A3
[apache-xmlrpc]
enabled = true
port    = http,https
filter  = apache-xmlrpc
logpath = /var/log/apache*/*access.log
maxretry = 5

Soundcloud Favorite Downloader

Früher sammelte man noch MP3 Dateien wie wild, aber das ist längst Vergangenheit. Heutzutage kann man (oder ich) gemütlich neue und alte Musik auf Soundcloud oder ähnlichen hören. Ich höre eigentlich fast ausschließlich Musik auf Soundcloud. Es gibt einfach sehr gute Musik, gerade Remixe von Liedern auf der Platform.

Leider kann man die Lieder nicht in der Soundcloud App cachen bzw. Offline hören. Deswegen ist es für das Handy eigentlich gänzlich ungeeignet, wenn man nicht seinen Traffic dafür verbrauchen will. Zum Glück bieten manche Künstler ihre Lieder zum kostenlosen Download an und das kann man sich ja zunutze machen. Dafür habe ich ein kleines Script zusammen gebastelt, das die favorisierten Lieder herunterlädt.

#!/usr/bin/perl
# script: download favorite songs from your soundcloud stream
# author: Steffen Wirth <s.wirth@itbert.de>

use WebService::Soundcloud;
use XML::Simple;
no warnings 'utf8';

# create a new app -> soundcloud.com/you/apps/new
my $client_id = "YOUR_CLIEND_ID";
my $client_secret = "YOUR_CLIENT_SECRET";
# soundcloud username and password
my $username = "YOUR_USERNAME";
my $password = "YOUR_PASSWORD";
# download path
my $file_path = "/tmp/";
    
my $scloud = WebService::Soundcloud->new($client_id, $client_secret,
	{ username => $username, password => $password, response_format => 'xml' }
);
    
# get access token
my $access_token = $scloud->get_access_token();
my $oauth_token = $access_token->{access_token};

# get favorites tracks
my $followings = $scloud->get('/users/' . $username . '/favorites');

$xml = XML::Simple->new;
$xml = XMLin($followings->content);

foreach my $item (@{$xml->{track}}) {
	my $id = $item->{id}->{content};
	my $title = $item->{title};
	my $downloadable = $item->{downloadable}->{content};
	my $downloadurl = $item->{'download-url'};

	# only download songs that are downloadable
	if ($downloadable eq "true") {

		# download track
		$title =~ s/\ /_/g;
		my $dest_file = $file_path . $id . "_" . $title . ".mp3";

		unless (-e $dest_file) {
			print "DOWNLOAD: $title ($id)" . "\n"; 
			#my $path = $scloud->download($id, $file_path);

			# verrrrrrry ugly way, but $scloud->download(); is not working.
			# have fun with big files :)
			my $track = $scloud->get($downloadurl);
			my $sound = $track->content;
			open (TRACK, ">>$dest_file");
				print TRACK $sound;
			close(TRACK);

		} else {
			print "IGNORING TRACK $title ($id)" . "\n";
		}
	}
	
}

oder auf gist.github.com

Update: ABER ABER, was machen wir mit den Liedern die wir nicht offiziell herunterladen dürfen? Dafuer gibt es Dienste wie zum Beispiel anything2mp3.com. Damit kann man auch “diese” Lieder herunterladen. Wir sind Faul, also los:

#!/usr/bin/perl
# script: download favorite songs from your soundcloud stream
# author: Steffen Wirth 

use WebService::Soundcloud;
use XML::Simple;
use HTTP::Cookies;
use LWP::Simple;
use Encode qw(encode_utf8);
no warnings 'utf8';

### settings ###

# create a new app -> soundcloud.com/you/apps/new
my $client_id = "YOUR_CLIEND_ID";
my $client_secret = "YOUR_CLIENT_SECRET";
# soundcloud username and password
my $username = "YOUR_USERNAME";
my $password = "YOUR_PASSWORD";
# download path
my $file_path = "/tmp/";
# download service
my $url = "http://anything2mp3.com/de";

### script ###

my $cookie_jar = HTTP::Cookies->new( 
    file => 'lwp_cookies.txt',
    autosave => 1,
    ignore_discard => 1,
);

my $ua = LWP::UserAgent->new;
	$ua->agent("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0");
	$ua->timeout(30);
	$ua->cookie_jar($cookie_jar);

my $scloud = WebService::Soundcloud->new($client_id, $client_secret,
	{ username => $username, password => $password, response_format => 'xml' }
);

# get access token
my $access_token = $scloud->get_access_token();
my $oauth_token = $access_token->{access_token};

# get favorites tracks
my $followings = $scloud->get('/users/' . $username . '/favorites');

$xml = XML::Simple->new;
$xml = XMLin($followings->content);

foreach my $item (@{$xml->{track}}) {
	my $id = $item->{id}->{content};
	my $title = $item->{title};
	my $downloadable = $item->{downloadable}->{content};
	my $downloadurl = $item->{'download-url'};
	my $permalink = $item->{'permalink-url'};

	# title and file 
	$title =~ s/\ /_/g;
	my $dest_file = $file_path . $id . "_" . $title . ".mp3";
	$dest_file = encode_utf8($dest_file);

	# only download songs that are downloadable
	if ($downloadable eq "true") {

		unless (-e $dest_file) {
			print "DOWNLOAD: $title" . "\n"; 
			#my $path = $scloud->download($id, $file_path);

			# verrrrrrry ugly way, but $scloud->download(); is not working.
			# have fun with big files :)
			my $track = $scloud->get($downloadurl);
			my $sound = $track->content;
			open (TRACK, ">>$dest_file");
				print TRACK $sound;
			close(TRACK);

		} else {
			print "IGNORING TRACK $title" . "\n";
		}
	} else {
		# lets download tracks that we are not supposed to

		unless (-e $dest_file) {
			print "D0WNL04D $title" . "\n";
			my $request = $ua->post($url,
				{
					url => $permalink,
					op => 'Convert',
					form_build_id => 'form-iKcdS_GJM5mRuRicuFJKS7wGB8oR7zbY6YbVeV4cjtM', # not sure how long this is valid
					form_id => 'videoconverter_form',
			});

			my $html = $ua->get($url . '/kostenlose-online-soundcloud-youtube-mp3-converter');
			$html = $html->content;

			while ($html =~ m@(((http://anything2mp3.com/de/system/temporary/mp3/))\S+[^.,!? ])@g) {
				$dl = $1;
				$dl =~ s/\>\Click//g;
			}

			($file) = $dl =~ m!([^/]+)$!;
			$file =~ s/\?download=1//g;

			my $track = $ua->get($dl);
			my $sound = $track->content;
			open (TRACK, ">>$dest_file");
				print TRACK $sound;
			close(TRACK);
		} else {
			print "IGNORING TRACK $title" . "\n";
		}

	}
	
}

auch auf gist.github.com

Videos auf dem Chromebook

Leider ist AC3 nur mit einer Lizenz zu genießen und kein Chromebook wird es möglich sein AC3 in einem Video abzuspielen. Das einzige was einem bleibt ist AC3 aus dem Video zu entfernen und durch ein anderes Format zu ersetzen.

Folgendes Script habe ich erfolgreich für MKV Dateien eingesetzt. Als erstes wird das AC3 extrahiert, in MP3 umgewandelt und wieder in die MKV Datei integriert. Anschließend AC3 entfernt. (gist)

#!/bin/bash
# script: convert AC3 to MP3 in MKV container
# author: bert2002 <s.wirth@itbert.de>

FILE=$1
FILENAME=$(basename $FILE mkv)
AC3AUDIO=$(mkvmerge --identify $FILE |grep "AC3" | awk -F':' '{print $1}' | awk '{print $3}')

mkvextract tracks $FILE $AC3AUDIO:${FILENAME}ac3
ffmpeg -i ${FILENAME}ac3 -acodec libmp3lame -ab 160k -ac 2 ${FILENAME}mp3

mkvmerge -o ${FILENAME}NEW.mkv $FILE ${FILENAME}mp3

MP3AUDIO=$(mkvmerge --identify ${FILENAME}NEW.mkv |grep MP3 | awk -F':' '{print $1}' | awk '{print $3}')
mkvmerge -o ${FILENAME}NEW.mkv.tmp -a $MP3AUDIO ${FILENAME}NEW.mkv && mv ${FILENAME}NEW.mkv.tmp ${FILENAME}NEW.mkv

Debian Wheezy auf einem Chromebook

Seit ein paar Tagen spiele ich mit einem HP Chromebook 11 herum und muss sagen, soweit bin ich eigentlich zufrieden. Nichtsdestotrotz darf man das Chromebook nicht als Notebook Ersatz sehen, sondern eher als Tablet Ersatz mit Tastatur und grösserem Bildschirm. Genau darin ist es gut. Es ist super einfach und schnell einzurichten und alle Daten fliesen zu Google. Wunderbar.

Nach ein paar Minuten herum spielen fehlte mir jedoch schon die bash und es musste eine Lösung her. Zum glück kann man Debian/Ubuntu als chroot installieren und beides parallel betreiben. Also als erstes das Chromebook in den Entwickler Modus packen:

 Esc + Refresh + Power Off

Dann kommt man zu einer schrecklichen Nachricht. Diese kann man jedoch getrost ignorieren und “Strg + D” drücken. Anschließend wird das Chromebook neu gestartet und ein neues Image wird aus dem Internet gezogen und installiert. Sobald man eingeloggt ist, braucht man eine Shell. Die “crosh” Shell bekommt man mittels “Strg + Alt + t”. Damit man aber in die richtige Shell kommt, muss man noch “shell” eingeben. Endlich!

Jetzt können wir unserer Chroot installieren. Ich habe dafür crouton benutzt und funktionierte einwandfrei:

# wget http://goo.gl/fd3zc
# sudo su -c crouton -r wheezy -t xfce

Den Anweisungen folgen und in ein paar Minuten hat man ein vollständiges Debian Wheezy in der Chroot mit XFCE4 installiert. Das kann man entweder über “sudo startxfce4″ starten oder einfach in die chroot mittels “sudo enter-chroot”. Fertig!

Bitpay integration in PHP

Die letzten Wochen wollte ich in ein Projekt Bitcoins als bezahl Option einbauen und musste mich für einen Payment Anbieter entscheiden. Ich hatte Coinbase und Bitpay in meine engere Wahl genommen und am Ende fuer Bitpay entschlossen. Warum? Weil Bitpay Auszahlungen in die EU macht und Coinbase nur auf Amerikanische Konten. Diese Entscheidung wurde einem also relativ einfach genommen.

Jetzt ging es um die Integration der Bitpay API in den Shop. Die Seite benutzt keine Shop Software und somit musste ich die API selber in der Seite einbauen. Die Dokumentation ist eigentlich recht gut. Diese beinhaltet sehr gut wie man eine Rechnung erstellt. Ich finde die “callback” Funktion wird nicht gut beschrieben und ich musste erst einmal ein bisschen ausprobieren. Als erstes, es gibt keine Testumgebung und somit muss man mit echten Bitcoins seine Implementierung testen. Irgendwie schreckt das eigentlich schon direkt ab.

Zum glück bietet Bitpay eine eigene library für PHP an. Somit musste man sich nicht um wirklich alles kümmern. Die Konfiguration in bp_options.php sollte verständlich sein und ich gehe hier nicht auf diese ein.

Erstellen einer Rechnung:

 <?php
// bitpay
require 'bp_lib.php';


$post_data = array(
 'product' => $product
);

$addl_options = array(
 'itemDesc' => $description,
 'itemCode' => $product,
 'currency' => $currency
);

$response = bpCreateInvoice(null, $price, $post_data, $addl_options);
if(!empty($response)){
 $bitpay = $response["url"];
 if ($bitpay) {
 header("Location: $bitpay");
 }

?>

Die $post_data können später im callback verarbeitet werden, die anderen Werte sind nur für die Rechnung oder um die Umrechnung korrekt durchzuführen.

Verarbeiten des Callbacks:

Es hat also jemand ein Produkt gekauft und wir werden über dieses wunderbare Event informiert. Die Callback URL musste man vorher in den Optionen festlegen:

 <?php
// bitpay
require 'bp_lib.php';
$BITPAY_KEY = "YOUR_BITPAY_KEY";

$response = bpVerifyNotification( $BITPAY_KEY );
$id = $response['id'];
$url = $response['url'];

$product = $response['posData']['product'];
$status = $response['status'];
$btcPrice = $response['btcPrice'];
$price = $response['price'];
$currency = $response['currency'];
$btcPaid = $response['btcPaid'];
$rate = $response['rate'];

?>

Eigentlich sehr einfach und man kann die Daten weiter verarbeiten. Die Hürde war an der stelle vorhanden, das man echte Bitcoins benutzen musste. Ich hoffe das Bitpay das bald ändern wird und ggf. werden dann mehr Shops auf Bitpay setzen. Wenn die Tests ordentlich verlaufen wird es bald einen Shop mehr geben der Bitcoins als Option anbietet.

SSH Tunnel trotz /bin/false

Ein interessantes Feature von SSH ist das man trotz einer Shell wie /bin/false oder /bin/nologin einen SSH Tunnel aufbauen kann. Normalerweise setzt man einer der genannten Shells gerade für (s)/FTP Benutzer ein, damit sich diese nicht auf dem Server mit einer Shell einloggen dürfen. Leider interessiert dieses SSH absolut gar nicht und für einen Tunnel braucht man eben keine Shell (channel!).

Viele Anbieter bieten FTP für ihre Dienste an und falls dann noch SSH läuft wäre es somit möglich die Firewalls zu umgehen und einen direkten Zugang auf das System und den dahinterliegenden zu erhaschen. Das ganze funktioniert leider auch wenn man den Benutzer in einer Match Gruppe nur SFTP erlaubt hat.

Ein SSH Tunnel ist schnell aufgebaut und schon kann man loslegen:

# ssh -N -L 1337:localhost:80 $ftpuser@$server

Viel mehr Spaß macht es dann eigentlich nur noch die File Descriptor auf dem Server bequem und schnell zu verbrauchen:

# ssh -N -L 1337:localhost:80 $ftpuser@$server
# ssh -N -R 1337:localhost:80 $ftpuser@$server
# telnet localhost 1337

Das einzige was man dagegen machen kann ist den Zugriff auf SSH nur für bestimmte Benutzer zu erlauben (AllowUsers, AllowGroups) und Tunnel, Forwarding zu verbieten (AllowTcpForwarding, X11Forwarding, PermitTunnel)

Wunderbar beschrieben im Jahr 2005 auf semicomplete.com und immer noch möglich.