Vor einer ganzen Weile habe ich mich schon einmal darüber ausgelassen, dass das so mit den Backups unter OneNote nicht schön ist. Eine Art Versionierung wollte ich haben, damit ich cloud-unabhängig auch bei versehentlichen Löschungen nichts verliere. Bisher gab es also eine Liste mit Abschnitten, die aus dem Notizbuch auf OneDrive geglaubt wurden, heruntergeladen und anschließend archiviert. Das wurde spätestens beim zweiten Notizbuch unübersichtlich, und ein neuer Ansatz musste her; skalierbar bitte:
Ein neues Microsoftkonto, mit dem die zu sichernden Notizbücher geteilt werden, wird über die API benutzt. Sinn dahinter: alle Notizbücher, die mit diesem Konto geteilt sind, werden heruntergeladen. Und weil ich mich nun einmal aufraffen konnte, das ganze neu zu entwickeln, ist jetzt auch die Liste mit den Abschnitten hinfällig, sondern es werden einfach alle Abschnitte gesichert, die nicht in einer Unterkategorie gelandet sind. Letzteres nicht mit zu sichern ist dann primär meine Faulheit, hier noch eine Iteration einzubauen.
Jede Nacht wird das Backup ausgeführt, anschließend auf einen entfernten Webspace per rsync über SSH hochgeladen und in Folge dessen noch aufgeräumt, was sich angestaut hat. Das meint: Backups älter als drei Wochen werden auf dem entfernten Webspace gelöscht, Backups älter als drei Tage auf dem Server selbst. Wie das Ganze nun funktioniert, versuche ich, schrittweise aufzuzeigen:
Server vorbereiten
Wir brauchen einen Linux-Server, auf dem ein paar Tools installiert sind. Im folgenden Schritt hilft selbiger auch bei der API-Key-Erstellung. Ich gehe von Debian Jessie aus; andere Systeme benötigen hier vermutlich andere Befehlsketten, die aber ähnlich sein dürften.
benötigte Pakete installieren
(rsync und sshpass können entfallen, wenn nach dem Download kein erneuter Upload auf ein SSH-rsync-Ziel geplant ist)
sudo apt-get install jq curl rsync sshpass
Microsoft-Konto erstellen und API-Token anfordern
- Zu Beginn ist ein normales Microsoft-Konto vonnöten, wie es bei “Winzigweich” an allen Ecken und Enden angelegt werden kann. Dies darf aber nicht das gleiche Konto sein, in welchem die zu sichernden Notizbücher liegen, da meine Skripte erwarten, dass die zu sichernden Notizbücher mit dem neuen Konto geteilt wurden, und nicht im kontoeigenen OneDrive-Speicher des neuen Kontos liegen.
- Um einen API-Zugang zu bekommen, muss eine “App” erstellt werden. Das geht in den Microsoft Developer Resources, hinter dem Button “Registrieren Sie Ihre App”. Anschließend klicken wir auf ein unscheinbares “Skip quickstart” rechts oben in der Ecke, anschließend können wir über einer leeren App-Liste auf “App hinzufügen” klicken und einen x-beliebigen Namen (“OneNoteBackup”, “Hundekuchen”, “MuttisLiebling”) für unsere neue “App” vergeben. Der Name spielt keine tiefere Rolle.
- Wichtig: Die Anwendungs-ID irgendwo notieren. Die wird später noch relevant.
- Ein “Anwendungsgeheimnis” in generieren. Dazu gibts den Button “Neues Kennwort generieren”. Kleine Herausforderung: dieses Kennwort bitte notieren und anschließend URL-kodieren. Sowas geht zum Beispiel hier, oder mit jeder beliebigen Skriptsprache. Bitte wenn möglich keine Webservices dafür benutzen, damit dieses Kennwort Eure Privatsphäre nicht verlässt.
- Auf der Seite der App-Eigenschaften nun den Button “Plattform hinzufügen” suchen und finden, dann klicken. Anschließend “Web” wählen und als Umleitungs-URL https://login.microsoftonline.com/oauth20_desktop.srf hinterlegen. Alles Weitere spielt keine Rolle, wir brauchen keine lustigen Logos oder Homepage-URLs für den Betrieb. Ganz unten “Speichern”.
- Nun wirds ein bisschen speziell: in irgendeinem Browser muss die URL https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=<ANWENDUNGS-ID>&scope=Files.Read.All user.read offline_access&response_type=code&redirect_uri=https://login.microsoftonline.com/oauth20_desktop.srf aufgerufen werden, wobei <ANWENDUNGS-ID> gegen die in Schritt 2.1 notierte Anwendungs-ID ersetzt werden muss. Im Browser wird man nun nach der Berechtigung für die eigene App gefragt, auf OneDrive bzw. Dateien zugreifen zu dürfen. Diese muss natürlich gewährt werden.
- Theoretisch dürfte nun nur eine weiße Seite erscheinen. Das ist soweit normal, aber die URL hat sich geändert. Die aktuelle Adresse in der Adresszeile muss nun rauskopiert werden, oder genauer der Teil nach ?code= bis zum nächsten & .
- Nun müssen wir den Code relativ zeitnah an Microsoft schicken, und zwar nicht etwa per Einschreiben, sondern per POST-Request. Hier bietet sich CURL an: curl -X POST -d “client_id=<ANWENDUNGS-ID>&redirect_uri=https://login.microsoftonline.com/oauth20_desktop.srf&code=<CODE_VON_EBEN>&grant_type=authorization_code&client_secret=<URL-KENNWORT>” https://login.microsoftonline.com/common/oauth2/v2.0/token – Bitte <ANWENDUNGS-ID> durch die Anwendungs-ID und <CODE_VON_EBEN> durch den gerade in Schritt 4 erhaltenen Code ersetzen. <URL-KENNWORT> muss durch das URL-kodierte Kennwort (“Anwendungsgeheimnis”) aus Schritt 2.1 ersetzt werden.
- Als Antwort bekommen wir JSON, worin irgendein Feld “refresh_token” heißt. Diesen Token brauchen wir. Microsoft selbst gibt da für die Antwort auf den POST folgendes Beispiel:
{ "token_type":"bearer", "expires_in": 3600, "scope":"wl.basic onedrive.readwrite", "access_token":"EwCo...AA==", "refresh_token":"eyJh...9323" }
Uns interessiert also nur der Inhalt des letzten Feldes.
- Jetzt sollten wir drei Informationen haben, die wir notieren, falls noch nicht geschehen:
- die Anwendungs-ID
- den refresh_token
- das URL-kodierte client_secret, auch “Anwendungsgeheimnis” auf Microsoft-Deutsch.
Geskripte auf dem Server
Es ist jetzt an der Zeit, alles zusammenzuführen – den Server, die Notizbücher, die IDs. Dazu gibt’s von mir folgendes kleines Skript:
(in der dritten Zeile <ANWENDUNGS-ID> , <URL-KENNWORT> und <REFRESH-TOKEN> entsprechend ersetzen)
#!/bin/bash KEY=`curl -s -X POST -d 'client_id=<ANWENDUNGS-ID>&redirect_uri=https://login.microsoftonline.com/oauth20_desktop.srf&client_secret=<URL-KENNWORT>&refresh_token=<REFRESH-TOKEN>&grant_type=refresh_token' https://login.microsoftonline.com/common/oauth2/v2.0/token | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["access_token"]'` ROOT="/home/$USER" AUTH="Authorization: bearer $KEY" DATE=`date +%Y--%m--%d-00` mkdir "$DATE" cd "$DATE" function download { curl -H "$AUTH" -s https://graph.microsoft.com/v1.0/drives/${drive}/items/{$id}/children | jq -r '.value[] | select(.name | contains(".one")) | .["@microsoft.graph.downloadUrl"] + " " + .name' | while read url name; do curl -o "$name" --retry 3 "$url" done } curl -H "$AUTH" -s https://graph.microsoft.com/v1.0/me/drive/sharedWithMe/ | jq -r '.value[] | .remoteItem | select(.package.type | . and contains("oneNote")) | .parentReference.driveId + " " + .id' | while read drive id; do mkdir "$id" cd "$id" download $drive $id curl -H "$AUTH" -s https://graph.microsoft.com/v1.0/drives/${drive}/items/{$id}/children | jq -r '.value[] | select(.folder) | .parentReference.driveId + " " + .id + " " + .name' | while read drive id name; do mkdir $name cd $name download $drive $id cd .. done cd .. done cd .. ./post-dl.sh
Das ganze als backup.sh im zukünftigen Backup-Verzeichnis speichern und mit chmod +x backup.sh ausführbar machen. Jetzt können wir immerhin die Dateien schon herunterladen, aber noch nicht wieder hochladen. Diese Funktion habe ich in ein zweites Skript ausgegliedert, um die Backups zu komprimieren und per rsync wieder hochzuladen:
#!/bin/bash DATE=`date +%Y--%m--%d-00` LASTDATE=`date --date='-3 week' +%Y--%m--%d-00` USR="webspace_user" PW="webspace_pw" HOST="web.space.speicher.tld" tar cfvj $DATE.tar.bz2 $DATE/ sshpass -p $PW rsync -arv --progress ${DATE}.tar.bz2 ${USR}@${HOST}:/$USR/ sshpass -p $PW sftp -oBatchMode=no -b - ${USR}@${HOST} << EOF cd $USR rm $LASTDATE.tar.bz2 bye EOF rm $DATE.tar.bz2
Gleiches Spiel: als post-dl.sh im zukünftigen Backup-Verzeichnis speichern und mit chmod +x post-dl.sh ausführbar machen. Während der ersten Durchführungen wird natürlich ein Fehler angezeigt werden, da noch kein Backup von vor 3 Wochen existiert. Der kann getrost ignoriert werden.
Eine Lösung, um die lokalen Backups nach drei Tagen zu löschen, habe ich hier jetzt nicht aufgezeigt – das kann analog zur post-dl.sh als Cronjob geschehen, indem einfach die LASTDATE -Variable modifiziert wird und entsprechend dem die alten Backups gelöscht.
Bei Fragen, Kritik und Anregungen einfach kurz unten drunter oder per Kontaktformular melden – vielleicht hats ja jemandem geholfen.
Aktualisierung vom 19.03.2019: Habe ein bisschen gebastelt, Anmeldung funktioniert nun wieder.
One Responses
[…] Es gibt eine verbesserte und aktualisierte Fassung der hier aufgezeigten […]