Skip to content

Instantly share code, notes, and snippets.

@clochix
Last active May 29, 2021 16:43
Show Gist options
  • Save clochix/48a7537b248f4272fc2513cd9722817f to your computer and use it in GitHub Desktop.
Save clochix/48a7537b248f4272fc2513cd9722817f to your computer and use it in GitHub Desktop.
Export data from Cozy Bank
#!/usr/bin/env bash
#########
#
# Export bank operations
#
# Syntax: bankexport claude.mycozy.cloud
#
# Requirements:
# - curl
# - socat
# - jq
#
########
bankexport ()
(
server=''
token=''
verbose='-s'
#
# Check if required applications are available
#
if [ "$(type -t curl)" != "file" ]; then
echo "Please install curl"
return 1
fi
if [ "$(type -t jq)" != "file" ]; then
echo "Please install jq"
return 1
fi
if [ "$(type -t socat)" != "file" ]; then
echo "Please install socat"
return 1
fi
if [ "$#" != "1" ]; then
echo "Syntax bankexport server"
return 1
fi
#
# Step 1: register app and get token
#
server=$(echo "$1" | sed 's/https:\/\///g')
if [ "$server" = "" ]; then
echo "Usage: ${FUNCNAME[0]} URL"
return 1
fi
scope="io.cozy.bank.accounts:GET%20io.cozy.bank.operations:GET"
#echo "Getting token for $server with scope $scope"
registration=$(curl -s -X POST -H "Host: ${server}" -H "Content-Type: application/json" -H "Accept: application/json" -d '{"redirect_uris": ["http://localhost:8080"],"client_name": "cozycli","software_id": "cozycli"}' https://${server}/auth/register | jq ".server=\"${server}\"")
state="$(cat /proc/sys/kernel/random/uuid)"
clientid="$(echo "$registration" | jq -r '.client_id')"
clientsecret="$(echo "$registration" | jq -r '.client_secret')"
registrationtoken="$(echo "$registration" | jq -r '.registration_access_token')"
url="$(curl -s -L -w "%{url_effective}" -o /dev/null "https://${server}/auth/authorize?client_id={$clientid}&response_type=code&scope=${scope}&state=${state}&redirect_uri=http%3A%2F%2Flocalhost:8080")"
echo "Open this URL in your browser"
echo "$url"
answer=$(mktemp)
chmod 600 "$answer"
answer=$(socat -v TCP-LISTEN:8080,crlf,reuseaddr SYSTEM:'echo "OK"' 2>&1 | grep "^GET")
#nc -l -p 8080 -i 1 -c 'while read -r request remaining;do echo $request $remaining >> '${answer}';if [ "$remaining" = "" ];then break;fi;done;echo "HTTP/1.1 200 OK\n\nOK"';
IFS=";" read -r code state2<<< $(echo "$answer" | sed -E "s/^.*&code=([^&]*)&state=(.*) .*$/\1;\2/")
rm -f $answer
if [ "$state2" != "$state" ]; then
echo "Wrong state! Expected ${state}, got ${state2}"
fi
token=$(curl -s -X POST -H "Host: ${server}" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: application/json" -d "grant_type=authorization_code&code=${code}&client_id=${clientid}&client_secret=${clientsecret}" https://${server}/auth/access_token | jq -r '.access_token')
#
# Step 2: export the data
#
curl $verbose -H "Origin: https://${server}" -H "Authorization: Bearer ${token}" -H "Accept: application/json" "https://${server}/data/io.cozy.bank.accounts/_all_docs?include_docs=true" > bank_accounts.json
curl $verbose -H "Origin: https://${server}" -H "Authorization: Bearer ${token}" -H "Accept: application/json" "https://${server}/data/io.cozy.bank.operations/_all_docs?include_docs=true" > bank_operations.json
echo 'Compte;Établissement;Libellé du compte' > bank_accounts.csv
echo 'Compte;Date;Montant;Libellé de l’opération' > bank_operations.csv
jq -r '.rows[].doc | select(.institutionLabel) | [._id, .institutionLabel, .label] | join(";")' bank_accounts.json | sort >> bank_accounts.csv
jq -r '.rows[].doc | select(.amount) | [.account, .date, (.amount|tostring), .label] | join(";")' bank_operations.json | sort >> bank_operations.csv
join --header -t';' -j1 bank_accounts.csv bank_operations.csv > bank_data.csv
#
# Step 3: revoke the tocken
#
res=$(curl $verbose -H "Origin: https://${server}" -H "Authorization: Bearer ${registrationtoken}" -X DELETE "https://${server}/auth/register/${clientid}")
echo "$res"
)
@xavgra2
Copy link

xavgra2 commented Apr 13, 2020

Hello,
Après avoir utilisé ce script sur une instance officiellement hébergée, j'ai rencontré 2 problèmes:
1- "minime": j'ai dû ajouter bankexport $1 à la fin du script pour que la fonction s'instancie, ce qui est sans doute lié à mon usage.
2- plus étonnant:
J'ai du modifier les scopes de la sorte
scope="io.cozy.bank.accounts:GET%20io.cozy.bank.operations:GET"
( et non io.cozy.bank-accounts) , à 2 endroits pour chaque occurence.

D'ailleurs, ce n'est probablemnt pas l'endroit, mais je m'interroge: où sont gérées les "consentements" que je fais via browser ? combien de temps sont-ils valides ?

En tout cas merci pour ce scripts qui comble avantageusement le manque d'export CSV.

@bolikahult
Copy link

Salut,
Moi aussi cet export csv m'intéresse bien, mais pas moyen de le faire marcher.
J'ai appliqué les 2 solutions de xavgra2 (la première était clairement utile, la 2nde je ne sais pas encore).
Maintenant je bute sur le message "Syntax bankexport server", sans comprendre le problème.
J'ai bien ajouté le domaine de mon cozy-cloud à l'intérieur du script, mais pas de résultat...
Avez-vous une idée de ce que je dois faire ?
(je ne suis pas du métier, comme vous devez le deviner... je peux juste reproduire quelques commandes !)

@xavgra2
Copy link

xavgra2 commented May 2, 2020

En fait, il ne faut pas ajouter le nom de l'instance dans le script.
Il suffit de la passer en paramètre (si version modifiée pour être lancée comme un script bash):
./bankexport.sh monInstance.mycozy.cloud

@bolikahult
Copy link

Ok. ç'a a marché, puisque j'obtiens un "bank_operations.csv"... !
Par contre les fichiers "bank_data.csv" et "bank_accounts.csv" n'ont pas de données (seulement les en-têtes), et j'ai obtenu cet erreur sur le terminal :
jq: error (at bank_accounts.json:1): Cannot iterate over null (null)
En tout cas merci beaucoup, je vais pouvoir intégrer ça dans homebank :)

@captain053
Copy link

Hello,

Merci pour ce script qui comble un vrai manque comme ça a été dit. De mon côté, je suis sur MacOS et j'utilise zsh donc j'ai du faire quelques ajustements pour qu'il fonctionne correctement, voici la liste :

Sur la vérification des dépendances, type avec zsh fonctionne différemment et ne dispose pas du paramètre -t, j'ai donc utilisé -w et modifié le test par "type -w {exec} != "exec: command". Exemple : if [ "$(type -w jq)" != "jq: command" ]; then

J'ai du modifier la variable state state="$(cat /proc/sys/kernel/random/uuid)" en state="$(uuidgen)"
car /proc/sys/kernel/random/uuid n'existe pas sous MacOS donc j'ai remplacé par uuidgen qui fait le job.

J'ai eu des erreurs sur la dernière commande join (ligne 81), sur les paramètres --header et -j qui n'existent pas chez moi. Du coup, j'ai modifié en : join -t';' -1 1 -2 1 bank_accounts.csv bank_operations.csv > bank_data.csv

J'ai aussi utilisé la méthode de @xavgra2 avec bankexport $1 à la fin

Et dernier point, plutôt que d'afficher l'url dans le terminal et de la copier/coller, j'ai modifié le script pour la lancer directement dans le navigateur par défaut avec un simple open $url.

Encore merci !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment