Selbstregistrierung für Piratenpad.de Team

EtherPad ist eine nützliche Open-Source Software, die es einem ermöglicht, mit mehreren Leuten live an einem Text zu arbeiten und parallel zu chatten. Dass dieses Tool sehr nützlich für die Online-Kolaboration ist, dachte sich wohl auch die Piratenpartei und betreibt deshalb gleich mehrere Instanzen: Zum einen Piratepad.net (schwedische Piratenpartei) und zum anderen Piratenpad.de (deutsche Piratenpartei).

Im Gegensatz zum schwedischen Piratepad bietet das deutsche Piratenpad auch die Möglichkeit, Teampads anzulegen. Dabei wird eine eigene Subdomain für das Team angelegt, unter der sich dann mehrere Pads befinden können. Diese Möglichkeit ist interessant, da man dadurch leichter Pads mit sprechenden Namen nutzen und später (wenn sie nicht mehr benötigt werden) Pads auch entsorgen kann. Darüber hinaus kann man auch private Pads anlegen, die nur von Mitgliedern des Teams eingesehen werden können. Diese Teampads haben jedoch ein gravierendes Problem: Der Administrator des Teampads muss die Mitglieder händisch verwalten.

Das kann ganz schön nervig sein, wenn man für jeden einzelnen den Account anlegen muss. Besonders nervig ist es dann, wenn man sowieso schon irgendwo eine Teamliste hat - da dann eine doppelte Verwaltung notwendig wird.
Um genau dieses Problem für ein von mir administriertes Teampad zu lösen, habe ich eine Selbstregistrierungsfunktion für das Piratenpad entwickelt. Damit ist es Leuten möglich, sich selbst einen Account für ein Teampad auf Piratenpad.de anzulegen.

Um in meinem Fall zu prüfen, ob die Person, die einen Account anlegen will, dazu berechtigt ist, habe ich die letztes Jahr vorgestellte SMTP-Authentifizierung genutzt. In meinem Team hat jedes Mitglied einen E-Mail-Account mit einer bestimmten Domain - dadurch kann ich alle Leute herausfiltern, die nicht zum Team gehören.

Als nächstes habe ich mir eine kleine Bibliothek mit Funktionen geschrieben, um das Piratenpad fernzusteuern. Den Quelltext seht ihr hier:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
<?php
  /* THESE SETTINGS ARE FREE TO EDIT */

  define("PIRATENPAD_MAIL",      "[BOT_ADDRESS]");
  define("PIRATENPAD_PASS",      "[BOT_PASSWORD]");

  define("PIRATENPAD_SERVER",    "http://[PAD_NAME].piratenpad.de");
  define("PIRATENPAD_PORT",      80);

  /* STOP EDITING HERE IF YOU DO NOT KNOW WHAT YOU ARE DOING */

  // PIRATENPAD_TEMP = ./temp/.
  define("PIRATENPAD_TEMPPART",  dirname(__FILE__) . "/temp");
  define("PIRATENPAD_TEMP",      PIRATENPAD_TEMPPART . "/.");

  define("PIRATENPAD_ACCOUNTS",  "/ep/admin/account-manager/");
  define("PIRATENPAD_LOGIN",     "/ep/account/sign-in");
  define("PIRATENPAD_LOGOUT",    "/ep/account/sign-out");
  define("PIRATENPAD_NEW",       "/ep/admin/account-manager/new");
  define("PIRATENPAD_TIMEOUT",   5);
  define("PIRATENPAD_USERAGENT", "Piratenpad-Bot");

  /* STOP EDITING HERE */

  function callPage($url, $post, $cookie) {
    $options = array(
      CURLOPT_FOLLOWLOCATION => true,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_SSL_VERIFYHOST => false,
      CURLOPT_SSL_VERIFYPEER => false,
      CURLOPT_USERAGENT      => PIRATENPAD_USERAGENT,
      CURLOPT_VERBOSE        => 1
    );

    if ($post != null) {
      $options[CURLOPT_POST]       = true;
      $options[CURLOPT_POSTFIELDS] = $post;
    }

    if ($cookie != null) {
      $options[CURLOPT_COOKIEFILE] = $cookie;
      $options[CURLOPT_COOKIEJAR]  = $cookie;
    }

    $curl = curl_init($url);
    curl_setopt_array($curl, $options);
    $output = curl_exec($curl);
    curl_close($curl);  

    return $output;
  }
 
  function checkTempPath($mail) {
    return (dirname(PIRATENPAD_TEMP . $mail) === PIRATENPAD_TEMPPART);
  }

  function piratenpadAddAccount($mail, $name, $password) {
    $test = "Account " . $name . " (" . $mail . ") created successfully.";
 
    $output = callPage(PIRATENPAD_SERVER . PIRATENPAD_NEW,
                       "email=" . urlencode($mail) . "&fullName=" . urlencode($name) . "&tempPass=" . urlencode($password) . "&btn=Create%20Account",
                       PIRATENPAD_TEMP . $mail);

    return ((strpos($output, PIRATENPAD_MAIL) !== false) &&
            (strpos($output, PIRATENPAD_LOGOUT) !== false) &&
            (strpos($output, $test) !== false));
  }

  function piratenpadCheckAccount($mail) {
    $output = callPage(PIRATENPAD_SERVER . PIRATENPAD_ACCOUNTS,
                       null,
                       PIRATENPAD_TEMP . $mail);

    return ((strpos($output, PIRATENPAD_MAIL) !== false) &&
            (strpos($output, PIRATENPAD_LOGOUT) !== false) &&
            (strpos($output, $mail) === false));
  }

  function piratenpadFinit($mail) {
    $result = false;
 
    if (file_exists(PIRATENPAD_TEMP . $mail)) {
      unlink(PIRATENPAD_TEMP . $mail);

      $result = (!file_exists(PIRATENPAD_TEMP . $mail));
    }

    return $result;
  }

  function piratenpadInit($mail) {
    $result = false;

    if (!file_exists(PIRATENPAD_TEMP . $mail)) {
      callPage(PIRATENPAD_SERVER,
               null,
               PIRATENPAD_TEMP . $mail);

      $result = file_exists(PIRATENPAD_TEMP . $mail);
    }

    return $result;
  }

  function piratenpadLogin($mail) {
    $output = callPage(PIRATENPAD_SERVER . PIRATENPAD_LOGIN,
                       "email=" . urlencode(PIRATENPAD_MAIL) . "&password=" . urlencode(PIRATENPAD_PASS),
                       PIRATENPAD_TEMP . $mail);

    return ((strpos($output, PIRATENPAD_MAIL) !== false) &&
            (strpos($output, PIRATENPAD_LOGOUT) !== false));
  }

  function piratenpadLogout($mail) {
    $output = callPage(PIRATENPAD_SERVER . PIRATENPAD_LOGOUT,
                       null,
                       PIRATENPAD_TEMP . $mail);

    return ((strpos($output, PIRATENPAD_MAIL) !== false) &&
            (strpos($output, PIRATENPAD_LOGIN) !== false));
  }
?>

Nun zur Erklärung: Um die Selbstregistrierung nutzen zu können, wird hier das Piratenpad ferngesteuert. Hierfür habe ich einen Administrator-Account zum Teampad hinzugefügt, der für das Steuern der Seite verwendet wird. Als PIRATENPAD_MAIL wird die E-Mail-Adresse des Bots angegeben, so, wie sie im Teampad hinterlegt ist. PIRATENPAD_PASS ist dann entsprechend das Passwort des Bots. Zudem muss unter PIRATENPAD_SERVER die URL zum Teampad (ohne abschließendes Slash!) angegeben werden, damit die ganzen Aktions-URLs generiert werden können.

Piratenpad-Bot in Mitgliederverwaltung

Das Piratenpad lässt sich leider nur mit Hilfe von Cookies nutzen. Aus diesem Grund werden im Unterordner "./temp" (der vorher angelegt werden muss) Dateien abgelegt und nach Beenden des Vorganges gelöscht. Die Dateinamen beginnen standardmäßig mit einem "." und sollten (da es sich um Sessioninformationen handelt) nicht von außen zugänglich sein. Wie ihr euren Apache-Server via .htaccess-Datei dazu bringen könnt, versteckte Dateien (beginnen immer mit einem Punkt) nicht auszuliefern, hatte ich euch letztes Jahr bereits gezeigt.

Die Erzeugung des Accounts erfolgt in mehreren Schritten. Zuerst wird die Session gestartet; anschließend loggt sich der Bot ein; überprüft, ob der Account mit der entsprechenden E-Mail-Adresse bereits existiert; legt den Account an (ohne Admin-Rechte); loggt sich aus und löscht anschließend die Sessiondatei. Vom Teampad-Nutzer werden lediglich die Informationen E-Mail-Adresse, voller Name (kann auch ein Nickname sein) und sein gewünschtes Passwort benötigt. Quelltextseitig sieht das ganze dann in etwa so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
  $address  = "[MAIL_ADDRESS]";
  $name     = "[FULL_NAME]";
  $password = "[PASSWORD]";

  $done = false;

  // check if temp file name is harmful
  if (checkTempPath($address)) {
    // initialize session
    if (piratenpadInit($address)) {
      // log in to piratenpad
      if (piratenpadLogin($address)) {
        // does account already exist?
        if (piratenpadCheckAccount($address)) {
          // create account
          if (piratenpadAddAccount($address, $name, $password)) {
            $done = true;
          } else {
            print("account creation failed");
          }
        } else {
          print("account already exists");
        }

        // log out of piratenpad
        if (!piratenpadLogout($address)) {
          print("logout failed");
        }

        // finalize session
        if (!piratenpadFinit($address)) {
          print("finit failed");
        }
      } else {
        print("login failed");
      }
    } else {
      print("init failed");
    }
  } else {
    print("harmful temp path");
  }
 
  if ($done) {
    // show some message or so
  }
?>

Mit ein paar Anpassungen der Bibliothek lässt sich das ganze sicherlich auch für andere EtherPad-Instanzen nutzen. Aufpassen muss man wahrscheinlich in der Funktion piratenpadAddAccount() da hier anhand der Meldung "Account [NAME] ([ADRESSE]) created successfully." überprüft wird, ob die Erzeugung erfolgreich war. Alternativ könnte man sicherlich auch einfach nochmal testen, ob der Account nun existiert. 😉

Sooo... ich hoffe, dieser Code wird für einige hilfreich sein. Ich freue mich wie immer über Feedback, Anregungen, Kritik, Fehlermeldungen, etc.! 🙂

Zum Schluss noch etwas Rechtliches:
Der Autor dieses Programms haftet nicht für Schäden an Soft- oder Hardware oder Vermögensschäden, die durch das Benutzen des Programms entstehen, es sei denn, diese beruhen auf einem grob fahrlässigen oder vorsätzlichen Handeln des Autors, seiner Erfüllungsgehilfen oder seiner gesetzlichen Vertreter.
Selbstregistrierende Grüße, Kenny

3 Kommentare » Schreibe einen Kommentar

  1. Hallo Kenny, vielen Dank für die Selbstregistrierung, die einiges an Arbeit abnimmt, als weiteren Vorteil des Piratenpad gegenüber einer Wiki oder google wave würde ich das anonymisierte Arbeiten gegenüber dritten sehen.

  2. Interessante Software, kannte ich noch gar nicht. Aber wo liegt da der Vorteil zu einem Wiki? Damit kann man ja auch gemeinsam an Texten arbeiten und über die Kommentarfunktion quasi chatten.

    • Der erste Vorteil ist zuerst einmal, dass es - soweit ich weiß - keine unthematischen Wikis gibt. Der Vorteil vom Piratenpad ist, dass jeder eins eröffnen kann, egal zu welchem Thema. Wenn man ein Teampad hat, kann man dieses zudem auch privat machen, damit nur Teammitglieder es einsehen können. Abschließend sind die Änderungen im Pad live - das heißt, jeder sieht sofort, was ein anderer schreibt oder am bereits Geschriebenen ändert. Bei einem Wiki geht das nicht - dort sehen zwei Leute, die eine Seite gleichzeitig bearbeiten, nicht, dass jemand anderes auch gerade aktiv ist. Das gleiche gilt übrigens auch für die Diskussionsseiten eines Wikis, deshalb sind sie mit einem Chat nicht vergleichbar.

      Pads sind also eher für die synchrone Kollaboration gedacht, während Wikis eher auf Asynchronität ausgelegt sind.

Schreibe einen Kommentar

Um Ihnen beim weiteren Kommentieren auf dieser Webseite die erneute Eingabe Ihrer Daten zu ersparen, wird beim Absenden Ihres Kommentars ein Cookie an Ihren Browser gesendet und von diesem gespeichert. Mit dem Absenden eines Kommentars auf dieser Webseite stimmen Sie der Speicherung und Übertragung dieses Cookies explizit zu.

Pflichtfelder sind mit * markiert.