gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated: cleanup


From: gnunet
Subject: [libeufin] branch master updated: cleanup
Date: Fri, 06 Oct 2023 02:11:49 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new a2e68259 cleanup
a2e68259 is described below

commit a2e6825908e6fb0271bbc58d849fd6480d013316
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Oct 6 02:11:55 2023 +0200

    cleanup
---
 build.gradle                                    |   35 -
 cli/bin/libeufin-cli                            | 2004 -----------------------
 cli/tests/add-incoming-client.sh                |    7 -
 cli/tests/circuit_test.sh                       |  118 --
 cli/tests/circuit_test_email_tan.sh             |   83 -
 cli/tests/circuit_test_file_tan.sh              |  126 --
 cli/tests/debit_test.sh                         |   77 -
 cli/tests/launch_services_with_ebics.sh         |  106 --
 cli/tests/launch_services_with_xlibeufinbank.sh |  118 --
 cli/tests/libeufin-cli                          |    1 -
 cli/tests/registration_test.sh                  |   43 -
 cli/tests/twg-history-loop.sh                   |   21 -
 cli/tests/wire-transfer.sh                      |   14 -
 cli/tests/wirewatch.conf                        |   11 -
 14 files changed, 2764 deletions(-)

diff --git a/build.gradle b/build.gradle
index c248edf6..5d5873d7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -48,41 +48,6 @@ task libeufinVersion {
     }
 }
 
-task replaceVersionCli(type: Copy) {
-    from file("cli/bin/libeufin-cli")
-    into file("${project.buildDir}/generated/python")
-    filter(ReplaceTokens, tokens: [version: getRootProject().version])
-}
-
 classes {
     dependsOn versionFile
-    dependsOn replaceVersionCli
-}
-
-task execArch(type: Zip) {
-    dependsOn versionFile
-    dependsOn replaceVersionCli
-    // evaluationDependsOn("nexus")
-    evaluationDependsOn("bank")
-    def topDir = "${getRootProject().name}-${getRootProject().version}"
-    archiveFileName = "${topDir}.zip"
-    subprojects.each {
-        if (it.name == "nexus" || it.name == "bank") {
-            Task t = it.tasks.getByName("installShadowDist")
-            dependsOn(t) // invokes the task 't'
-        }
-    }
-    //from("nexus/build/install/nexus-shadow") {
-    //  include("**/libeufin-nexus")
-    //  include("**/*.jar")
-    //}
-    from("bank/build/install/bank-shadow") {
-        include("**/libeufin-bank")
-        include("**/*.jar")
-    }
-    from("${project.buildDir}/generated/python") {
-      include("libeufin-cli")
-      rename { "bin/libeufin-cli" }
-    }
-    into(topDir)
 }
diff --git a/cli/bin/libeufin-cli b/cli/bin/libeufin-cli
deleted file mode 100755
index 9a7471ab..00000000
--- a/cli/bin/libeufin-cli
+++ /dev/null
@@ -1,2004 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-import sys
-import click
-import json
-import hashlib
-import errno
-from datetime import datetime
-import requests
-
-# FIXME: always use qualified name
-from requests import post, get, auth, delete, patch
-from urllib.parse import urljoin
-from getpass import getpass
-
-# Prepares the 'auth' option to pass to requests.
-def maybe_auth(sandbox_ctx):
-    if (sandbox_ctx.credentials_found):
-        return dict(
-            auth=auth.HTTPBasicAuth(
-                sandbox_ctx.username,
-                sandbox_ctx.password
-            )
-        )
-    return dict()
-
-
-# Gets the account name to use in a request.  It gives
-# precedence to the account name passed along the CLI options,
-# and falls back to the account name found in the environment.
-# It returns None if no account was found, or that was 'admin'.
-# Admin is excluded because it isn't modeled like ordinary
-# customers and would therefore very likely hit != 2xx response
-# statuses.
-def get_account_name(accountNameCli, usernameEnv):
-    maybeUsername = accountNameCli
-    if not maybeUsername:
-        maybeUsername = usernameEnv
-    if not maybeUsername:
-        print("No username was found", file=sys.stderr)
-        return None
-    if maybeUsername == "admin":
-        print("admin username not suitable", file=sys.stderr)
-        return None
-    return maybeUsername
-
-# Exit the program according to the HTTP status code that
-# was received.
-def check_response_status(resp, expected_status_code=200):
-    if resp.status_code != expected_status_code:
-        print("Unexpected response status: {}".format(resp.status_code), 
file=sys.stderr)
-        print("Response: {}".format(resp.text), file=sys.stderr)
-        sys.exit(1)
-
-# Prints the response body.
-def tell_user(resp):
-    print(resp.content.decode("utf-8"))
-
-# Normalize the two components to "x/" and "y" and pass them
-# to urljoin().  This avoids drop-policies from plain urljoin().
-def urljoin_nodrop(a, b):
-    a = a + "/" # urljoin will drop extra trailing slashes.
-    b = "/".join([x for x in b.split("/") if x != ""]) # remove leading 
slashes.
-    return urljoin(a, b)
-
-# FIXME: deprecate this in favor of NexusContext
-def fetch_env():
-    if "--help" in sys.argv:
-        return []
-    try:
-        nexus_base_url = os.environ["LIBEUFIN_NEXUS_URL"]
-        nexus_username = os.environ["LIBEUFIN_NEXUS_USERNAME"]
-        nexus_password = os.environ["LIBEUFIN_NEXUS_PASSWORD"]
-    except KeyError:
-        print(
-            "Please ensure that LIBEUFIN_NEXUS_URL,"
-            " LIBEUFIN_NEXUS_USERNAME, LIBEUFIN_NEXUS_PASSWORD exist"
-            " in the environment"
-        )
-        sys.exit(1)
-    return nexus_base_url, nexus_username, nexus_password
-
-
-# FIXME: deprecate this in favor of NexusContext
-class NexusAccess:
-    def __init__(self, nexus_base_url=None, username=None, password=None):
-        self.nexus_base_url = nexus_base_url
-        self.username = username
-        self.password = password
-
-
-@click.group(help="General utility to invoke HTTP REST services offered by 
Nexus.")
-@click.version_option(version="0.0.1-dev.1")
-def cli():
-    pass
-
-
-@cli.group()
-@click.pass_context
-def facades(ctx):
-    ctx.obj = NexusAccess(*fetch_env())
-
-
-@cli.group()
-@click.pass_context
-def connections(ctx):
-    ctx.obj = NexusAccess(*fetch_env())
-
-
-@cli.group()
-@click.pass_context
-def users(ctx):
-    ctx.obj = NexusContext()
-
-
-@cli.group()
-@click.pass_context
-def permissions(ctx):
-    ctx.obj = NexusContext()
-
-@users.command("self", help="Show information about authenticated user.")
-@click.pass_obj
-def users_self(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/user")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.nexus_username, 
obj.nexus_password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-@users.command("list", help="List users")
-@click.pass_obj
-def list_users(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/users")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.nexus_username, 
obj.nexus_password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@users.command(help="Change user's password (as superuser)")
-@click.argument("username")
-@click.option(
-    "--new-password",
-    help="New password",
-    prompt=True,
-    hide_input=True,
-    confirmation_prompt=True,
-)
-@click.pass_obj
-def change_password(obj, username, new_password):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/users/{username}/password")
-    try:
-        body = dict(newPassword=new_password)
-        resp = post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.nexus_username, obj.nexus_password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@users.command("create", help="Create a new user without superuser privileges")
-@click.argument("username")
-@click.option(
-    "--password",
-    help="Provide password instead of prompting interactively.",
-    prompt=True,
-    hide_input=True,
-    confirmation_prompt=True,
-)
-@click.pass_obj
-def create_user(obj, username, password):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/users")
-    try:
-        body = dict(
-            username=username,
-            password=password,
-        )
-        resp = post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.nexus_username, obj.nexus_password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    print(resp.content.decode("utf-8"))
-    check_response_status(resp)
-
-
-@permissions.command("list", help="Show permissions")
-@click.pass_obj
-def list_permission(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/permissions")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.nexus_username, 
obj.nexus_password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    print(resp.content.decode("utf-8"))
-    check_response_status(resp)
-
-
-@permissions.command("grant", help="Grant permission to a subject")
-@click.pass_obj
-@click.argument("subject-type")
-@click.argument("subject-id")
-@click.argument("resource-type")
-@click.argument("resource-id")
-@click.argument("permission-name")
-def grant_permission(
-    obj, subject_type, subject_id, resource_type, resource_id, permission_name
-):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/permissions")
-    try:
-        permission = dict(
-            subjectType=subject_type,
-            subjectId=subject_id,
-            resourceType=resource_type,
-            resourceId=resource_id,
-            permissionName=permission_name,
-        )
-        body = dict(
-            permission=permission,
-            action="grant",
-        )
-        resp = post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.nexus_username, obj.nexus_password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    print(resp.content.decode("utf-8"))
-    check_response_status(resp)
-
-
-@permissions.command("revoke", help="Revoke permission from a subject")
-@click.pass_obj
-@click.argument("subject-type")
-@click.argument("subject-id")
-@click.argument("resource-type")
-@click.argument("resource-id")
-@click.argument("permission-name")
-def revoke_permission(
-    obj, subject_type, subject_id, resource_type, resource_id, permission_name
-):
-    url = urljoin_nodrop(obj.nexus_base_url, f"/permissions")
-    try:
-        permission = dict(
-            subjectType=subject_type,
-            subjectId=subject_id,
-            resourceType=resource_type,
-            resourceId=resource_id,
-            permissionName=permission_name,
-        )
-        body = dict(
-            permission=permission,
-            action="revoke",
-        )
-        resp = post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.nexus_username, obj.nexus_password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    print(resp.content.decode("utf-8"))
-    check_response_status(resp)
-
-
-@cli.group()
-@click.pass_context
-def accounts(ctx):
-    ctx.obj = NexusAccess(*fetch_env())
-
-
-class SandboxContext:
-    def __init__(self):
-        self.sandbox_base_url = None
-        self.demobank_name = None
-        self.init_sandbox_credentials()
-        if not self.credentials_found:
-            print("""INFO: LIBEUFIN_SANDBOX_USERNAME or 
LIBEUFIN_SANDBOX_PASSWORD
-not found in the environment.  Won't authenticate"""
-            )
-
-    def init_sandbox_credentials(self):
-        self.username = os.environ.get("LIBEUFIN_SANDBOX_USERNAME")
-        self.password = os.environ.get("LIBEUFIN_SANDBOX_PASSWORD")
-        self.credentials_found = False
-        if self.username and self.password:
-            self.credentials_found = True 
-
-    def require_sandbox_base_url(self):
-        if self.sandbox_base_url:
-            return self.sandbox_base_url
-        sandbox_base_url = os.environ.get("LIBEUFIN_SANDBOX_URL")
-        if not sandbox_base_url:
-            raise click.UsageError(
-                "sandbox URL must be given as an argument or in 
LIBEUFIN_SANDBOX_URL"
-            )
-        return sandbox_base_url
-
-    def access_api_url(self, upath):
-        base = self.require_sandbox_base_url()
-        # return urljoin_nodrop(demobank_base, "/access-api" + upath)
-        return urljoin_nodrop(self.demobank_base_url(), "/access-api" + upath)
-
-    # Empty upath gets just the slash-ended circuit API URL initial segment.
-    def circuit_api_url(self, upath):
-        circuit_base_url = urljoin_nodrop(self.demobank_base_url(), 
"/circuit-api")
-        return urljoin_nodrop(circuit_base_url, upath)
-
-    def demobank_base_url(self):
-        base = self.require_sandbox_base_url()
-        return  urljoin_nodrop(base, f"demobanks/{self.demobank_name}")
-
-class NexusContext:
-    def __init__(self):
-        self._nexus_base_url = None
-        self._nexus_password = None
-        self._nexus_username = None
-
-    @property
-    def nexus_base_url(self):
-        if self._nexus_base_url:
-            return self._nexus_base_url
-        val = os.environ.get("LIBEUFIN_NEXUS_URL")
-        if not val:
-            raise click.UsageError(
-                "nexus URL not found in LIBEUFIN_NEXUS_URL"
-            )
-        self._nexus_base_url = val
-        return val
-
-    @property
-    def nexus_username(self):
-        if self._nexus_username:
-            return self._nexus_username
-        val = os.environ.get("LIBEUFIN_NEXUS_USERNAME")
-        if not val:
-            raise click.UsageError(
-                "Could not find the username in LIBEUFIN_NEXUS_USERNAME"
-            )
-        self._nexus_username = val
-        return val
-
-    @property
-    def nexus_password(self):
-        if self._nexus_password:
-            return self._nexus_password
-        val = os.environ.get("LIBEUFIN_NEXUS_PASSWORD")
-        if not val:
-            raise click.UsageError(
-                "Could not find the password in LIBEUFIN_NEXUS_PASSWORD"
-            )
-        self._nexus_password = val
-        return val
-
-
-@cli.group()
-@click.option("--sandbox-url", help="URL for the sandbox", required=False)
-@click.pass_context
-def sandbox(ctx, sandbox_url):
-    ctx.obj = SandboxContext()
-    ctx.obj.sandbox_base_url = sandbox_url
-
-
-@connections.command(help="Get key letter (typically PDF).")
-@click.argument("connection-name")
-@click.argument("output_file")
-@click.pass_obj
-def get_key_letter(obj, connection_name, output_file):
-    url = urljoin_nodrop(obj.nexus_base_url, 
f"/bank-connections/{connection_name}/keyletter")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-    output = open(output_file, "wb")
-    output.write(resp.content)
-    output.close()
-
-@connections.command(help="export backup")
-@click.option("--passphrase", help="Passphrase for locking the backup", 
required=True)
-@click.option("--output-file", help="Where to store the backup", required=True)
-@click.argument("connection-name")
-@click.pass_obj
-def export_backup(obj, connection_name, passphrase, output_file):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
"/bank-connections/{}/export-backup".format(connection_name)
-    )
-    try:
-        resp = post(
-            url,
-            json=dict(passphrase=passphrase),
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    # Will exit upon errors.
-    check_response_status(resp)
-
-    output = open(output_file, "w+")
-    output.write(resp.content.decode("utf-8"))
-    output.close()
-
-    print("Backup stored in {}".format(output_file))
-
-
-@connections.command(help="delete bank connection")
-@click.argument("connection-name")
-@click.pass_obj
-def delete_connection(obj, connection_name):
-
-    url = urljoin_nodrop(obj.nexus_base_url, 
"/bank-connections/delete-connection")
-    try:
-        resp = post(
-            url,
-            json=dict(bankConnectionId=connection_name),
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@connections.command(help="restore backup")
-@click.option("--backup-file", help="Back file", required=True)
-@click.option("--passphrase", help="Passphrase for locking the backup", 
required=True)
-@click.argument("connection-name")
-@click.pass_obj
-def restore_backup(obj, backup_file, passphrase, connection_name):
-    url = urljoin_nodrop(obj.nexus_base_url, "/bank-connections")
-    try:
-        backup = open(backup_file, "r")
-    except Exception as e:
-        print(e)
-        print("Could not open the backup at {}".format(backup_file))
-        exit(1)
-    backup_json = json.loads(backup.read())
-    backup.close()
-
-    try:
-        resp = post(
-            url,
-            json=dict(
-                name=connection_name,
-                data=backup_json,
-                passphrase=passphrase,
-                source="backup",
-            ),
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@connections.command(help="make a new x-libeufin-bank connection")
-@click.option(
-    "--bank-url",
-    help="Bank base URL, typically ending with 
'../demobanks/default/access-api'",
-    required=True
-)
-@click.option(
-    "--username",
-    help="Username at the bank, that this connection impersonates.",
-    required=True
-)
-@click.password_option()
-@click.argument("connection-name")
-@click.pass_obj
-def new_xlibeufinbank_connection(obj, bank_url, username, password, 
connection_name):
-    url = urljoin_nodrop(obj.nexus_base_url, "/bank-connections")
-    body = dict(
-        name=connection_name,
-        source="new",
-        type="x-libeufin-bank",
-        data=dict(
-            baseUrl=bank_url,
-            username=username,
-            password=password
-        ),
-    )
-    try:
-        resp = post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.username, obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print(f"Could not reach nexus at {url}")
-        exit(1)
-
-    check_response_status(resp)
-
-@connections.command(help="make new EBICS bank connection")
-@click.option("--ebics-url", help="EBICS URL", required=True)
-@click.option("--host-id", help="Host ID", required=True)
-@click.option("--partner-id", help="Partner ID", required=True)
-@click.option("--ebics-user-id", help="Ebics user ID", required=True)
-@click.option(
-  "--dialect",
-  help="EBICS dialect of this connection",
-  required=False
-)
-@click.argument("connection-name")
-@click.pass_obj
-def new_ebics_connection(
-    obj, connection_name, ebics_url, host_id, partner_id, ebics_user_id, 
dialect
-):
-    url = urljoin_nodrop(obj.nexus_base_url, "/bank-connections")
-    body = dict(
-        name=connection_name,
-        source="new",
-        type="ebics",
-        data=dict(
-            ebicsURL=ebics_url,
-            hostID=host_id,
-            partnerID=partner_id,
-            userID=ebics_user_id,
-            dialect=dialect
-        ),
-    )
-    try:
-        resp = post(url, json=body, auth=auth.HTTPBasicAuth(obj.username, 
obj.password))
-    except Exception as e:
-        print(e)
-        print(f"Could not reach nexus at {url}")
-        exit(1)
-
-    check_response_status(resp)
-
-@connections.command(help="Initialize the bank connection.")
-@click.argument("connection-name")
-@click.pass_obj
-def connect(obj, connection_name):
-    url = urljoin_nodrop(obj.nexus_base_url, 
f"/bank-connections/{connection_name}/connect")
-    try:
-        resp = post(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print(f"Could not reach nexus at {url}")
-        exit(1)
-
-    check_response_status(resp)
-
-@connections.command(help="Import one bank account, chosen from the downloaded 
ones.")
-@click.option(
-    "--offered-account-id", help="Name of the account to import", required=True
-)
-@click.option(
-    "--nexus-bank-account-id",
-    help="Name to give to the imported account",
-    required=True,
-)
-@click.argument("connection-name")
-@click.pass_obj
-def import_bank_account(
-    obj, connection_name, offered_account_id, nexus_bank_account_id
-):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        "/bank-connections/{}/import-account".format(connection_name),
-    )
-    try:
-        resp = post(
-            url,
-            json=dict(
-                offeredAccountId=offered_account_id,
-                nexusBankAccountId=nexus_bank_account_id,
-            ),
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-        )
-    except Exception as e:
-        print(f"Could not reach nexus at {url}: {e}")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@connections.command(
-    help="Update list of bank accounts available through this connection."
-)
-@click.argument("connection-name")
-@click.pass_obj
-def download_bank_accounts(obj, connection_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        "/bank-connections/{}/fetch-accounts".format(connection_name),
-    )
-    try:
-        resp = post(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@connections.command(help="List the connections.")
-@click.pass_obj
-def list_connections(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, "/bank-connections")
-    try:
-        resp = get(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@connections.command(help="Show the status of a bank connection.")
-@click.argument("connection-name")
-@click.pass_obj
-def show_connection(obj, connection_name):
-    url = urljoin_nodrop(obj.nexus_base_url, 
f"/bank-connections/{connection_name}")
-    try:
-        resp = get(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@connections.command(help="list bank accounts hosted at one connection")
-@click.argument("connection-name")
-@click.pass_obj
-def list_offered_bank_accounts(obj, connection_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
"/bank-connections/{}/accounts".format(connection_name)
-    )
-    try:
-        resp = get(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="Schedules a new task")
-@click.argument("account-name")
-@click.option("--task-name", help="Name of the task", required=True)
-@click.option("--task-cronspec", help="Cronspec string", required=True)
-@click.option(
-    "--task-type",
-    help="'fetch' (downloads transactions histories) or 'submit' (uploads 
payments instructions)",
-    required=True,
-)
-@click.option(
-    "--task-param-range-type",
-    help="Only needed for 'fetch'.  (FIXME: link to documentation here!)",
-    required=False,
-)
-@click.option(
-    "--task-param-level",
-    help="Only needed for 'fetch'.  (FIXME: link to documentation here!)",
-    required=False,
-)
-@click.pass_obj
-def task_schedule(
-    obj,
-    account_name,
-    task_name,
-    task_cronspec,
-    task_type,
-    task_param_range_type,
-    task_param_level,
-):
-
-    url = urljoin_nodrop(obj.nexus_base_url, 
"/bank-accounts/{}/schedule".format(account_name))
-    body = dict(name=task_name, cronspec=task_cronspec, type=task_type)
-    if task_type == "fetch" and not (task_param_range_type or 
task_param_level):
-        print("'fetch' type requires --task-param-range-type and 
--task-param-level")
-        return
-
-    body.update(
-        dict(params=dict(rangeType=task_param_range_type, 
level=task_param_level))
-    )
-    try:
-        resp = post(url, json=body, auth=auth.HTTPBasicAuth(obj.username, 
obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@accounts.command(help="Show the status of a task")
-@click.argument("account-name")
-@click.option("--task-name", help="Name of the task", required=True)
-@click.pass_obj
-def task_status(obj, account_name, task_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        "/bank-accounts/{}/schedule/{}".format(account_name, task_name),
-    )
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="Delete a task")
-@click.argument("account-name")
-@click.option("--task-name", help="Name of the task", required=True)
-@click.pass_obj
-def task_delete(obj, account_name, task_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        "/bank-accounts/{}/schedule/{}".format(account_name, task_name),
-    )
-    try:
-        resp = delete(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@accounts.command("list-tasks", help="List all the configured tasks")
-@click.argument("account-name")
-@click.pass_obj
-def tasks_show(obj, account_name):
-    url = urljoin_nodrop(obj.nexus_base_url, 
"/bank-accounts/{}/schedule".format(account_name))
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="Show accounts belonging to calling user")
-@click.pass_obj
-def show(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, "/bank-accounts")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(f"Could not reach nexus at {url}, error: {e}")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="Prepare payment initiation debiting the account.")
-@click.option(
-    "--creditor-iban", help="IBAN that will receive the payment", required=True
-)
-@click.option(
-    "--creditor-bic", help="BIC that will receive the payment", required=False
-)
-@click.option(
-    "--creditor-name", help="Legal name that will receive the payment", 
required=True
-)
-@click.option(
-    "--payment-amount", help="Amount to be paid (<currency>:X.Y)", 
required=True
-)
-@click.option("--payment-subject", help="Subject of this payment", 
required=True)
-@click.argument("account-name")
-@click.pass_obj
-def prepare_payment(
-    obj,
-    account_name,
-    creditor_iban,
-    creditor_bic,
-    creditor_name,
-    payment_amount,
-    payment_subject,
-):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
"/bank-accounts/{}/payment-initiations".format(account_name)
-    )
-    body = dict(
-        iban=creditor_iban,
-        bic=creditor_bic,
-        name=creditor_name,
-        subject=payment_subject,
-        amount=payment_amount,
-    )
-
-    try:
-        resp = post(url, json=body, auth=auth.HTTPBasicAuth(obj.username, 
obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@accounts.command(help="Submit a payment initiation.  Submit every new payment 
if invoked without options.")
-@click.option("--payment-uuid", help="Payment unique identifier.  Submits only 
this payment.")
-@click.argument("account-name")
-@click.pass_obj
-def submit_payments(obj, account_name, payment_uuid):
-    if payment_uuid:
-        url = urljoin_nodrop(
-            obj.nexus_base_url,
-            "/bank-accounts/{}/payment-initiations/{}/submit".format(
-                account_name, payment_uuid
-            ),
-        )
-    else:
-        url = urljoin_nodrop(
-            obj.nexus_base_url,
-            "/bank-accounts/{}/submit-all-payment-initiations".format(
-                account_name
-            ),
-        )
-    try:
-        resp = post(
-            url, json=dict(), auth=auth.HTTPBasicAuth(obj.username, 
obj.password)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at" + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@accounts.command(help="Show status of a payment initiation")
-@click.option("--payment-uuid", help="payment unique identifier", 
required=True)
-@click.argument("account-name")
-@click.pass_obj
-def show_payment(obj, account_name, payment_uuid):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        f"/bank-accounts/{account_name}/payment-initiations/{payment_uuid}",
-    )
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at" + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="List payment initiations")
-@click.argument("account-name")
-@click.pass_obj
-def list_payments(obj, account_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
f"/bank-accounts/{account_name}/payment-initiations"
-    )
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at" + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@accounts.command(help="Delete a payment initiation")
-@click.argument("account-name")
-@click.option("--payment-uuid", help="payment unique identifier", 
required=True)
-@click.pass_obj
-def delete_payment(obj, account_name, payment_uuid):
-    url = urljoin_nodrop(
-        obj.nexus_base_url,
-        f"/bank-accounts/{account_name}/payment-initiations/{payment_uuid}",
-    )
-    try:
-        resp = delete(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus at" + url)
-        exit(1)
-
-    check_response_status(resp)
-
-
-@accounts.command(help="Fetch transactions from the bank")
-@click.option(
-    "--range-type",
-    default="all",
-    help="Admitted values: all, latest, previous-days, since-last, time-range",
-)
-@click.option("--level", default="all", help="Admitted values: report, 
statement, all")
-@click.option("--start", help="If --range-type is 'time-range', this option 
holds the (inclusive) starting date in the format YYYY-MM-DD.  If missing, it 
defaults to 1970-01-01.")
-@click.option("--end", help="If --range-type is 'time-range', this option 
holds the (inclusive) ending date in the format YYYY-MM-DD.  If missing, it 
defaults to the present date.")
-@click.argument("account-name")
-@click.pass_obj
-def fetch_transactions(obj, account_name, range_type, level, start, end):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
"/bank-accounts/{}/fetch-transactions".format(account_name)
-    )
-    body = dict(rangeType=range_type, level=level)
-    if range_type == "time-range":
-        start_value = start if start else "1970-01-01"
-        end_value = end if end else datetime.today().strftime("%Y-%m-%d")
-        body.update(dict(start=start_value, end=end_value))
-    try:
-        resp = requests.post(
-            url,
-            json=body,
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-@accounts.command(help="Get transactions from the simplified nexus JSON API")
-@click.option(
-    "--compact/--no-compact",
-    help="Tells only amount/subject for each payment",
-    required=False,
-    default=False,
-)
-@click.argument("account-name")
-@click.pass_obj
-def transactions(obj, compact, account_name):
-    url = urljoin_nodrop(
-        obj.nexus_base_url, 
"/bank-accounts/{}/transactions".format(account_name)
-    )
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(e)
-        print("Could not reach nexus " + url)
-        exit(1)
-
-    if compact and resp.status_code == 200:
-        for payment in resp.json()["transactions"]:
-            for entry in payment["batches"]:
-                for expected_singleton in entry["batchTransactions"]:
-                    print(
-                        "{}, {}".format(
-                            expected_singleton["details"][
-                                "unstructuredRemittanceInformation"
-                            ],
-                            expected_singleton["amount"],
-                        )
-                    )
-    else:
-        tell_user(resp)
-    check_response_status(resp)
-
-
-@facades.command("list", help="List active facades in the Nexus")
-@click.pass_obj
-def list_facades(obj):
-    url = urljoin_nodrop(obj.nexus_base_url, "/facades")
-    try:
-        resp = get(url, auth=auth.HTTPBasicAuth(obj.username, obj.password))
-    except Exception as e:
-        print(f"Could not reach nexus (at {obj.nexus_base_url}): {e}")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@facades.command(
-    "new-anastasis-facade", help="create a new Anastasis facade"
-)
-@click.option("--facade-name", help="Name of the facade", required=True)
-@click.option("--currency", help="Facade's currency", required=True)
-@click.argument("connection-name")
-@click.argument("account-name")
-@click.pass_obj
-def new_anastasis_facade(obj, facade_name, connection_name, account_name, 
currency):
-    url = urljoin_nodrop(obj.nexus_base_url, "/facades")
-    try:
-        resp = post(
-            url,
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-            json=dict(
-                name=facade_name,
-                type="anastasis",
-                config=dict(
-                    currency=currency,
-                    bankAccount=account_name,
-                    bankConnection=connection_name,
-                    reserveTransferLevel="UNUSED",
-                    intervalIncremental="UNUSED",
-                ),
-            ),
-        )
-    except Exception as e:
-        print(f"Could not reach nexus (at {obj.nexus_base_url}): {e}")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@facades.command(
-    "new-taler-wire-gateway-facade", help="create a new Taler Wire Gateway 
facade"
-)
-@click.option("--facade-name", help="Name of the facade", required=True)
-@click.option("--currency", help="Facade's currency", required=True)
-@click.argument("connection-name")
-@click.argument("account-name")
-@click.pass_obj
-def new_twg_facade(obj, facade_name, connection_name, account_name, currency):
-    url = urljoin_nodrop(obj.nexus_base_url, "/facades")
-    try:
-        resp = post(
-            url,
-            auth=auth.HTTPBasicAuth(obj.username, obj.password),
-            json=dict(
-                name=facade_name,
-                type="taler-wire-gateway",
-                config=dict(
-                    currency=currency,
-                    bankAccount=account_name,
-                    bankConnection=connection_name,
-                    reserveTransferLevel="UNUSED",
-                    intervalIncremental="UNUSED",
-                ),
-            ),
-        )
-    except Exception as e:
-        print(f"Could not reach nexus (at {obj.nexus_base_url}): {e}")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@sandbox.group("ebicshost", help="manage EBICS hosts")
-@click.pass_context
-def sandbox_ebicshost(ctx):
-    pass
-
-
-@sandbox.command("check", help="check sandbox status")
-@click.pass_obj
-def check_sandbox_status(obj):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/")
-    try:
-        resp = get(url)
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_ebicshost.command("create", help="Create an EBICS host")
-@click.option("--host-id", help="EBICS host ID", required=True, prompt=True)
-@click.pass_obj
-def make_ebics_host(obj, host_id):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/admin/ebics/hosts")
-    try:
-        resp = post(
-            url,
-            json=dict(hostID=host_id, ebicsVersion="2.5"),
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@sandbox_ebicshost.command("list", help="List EBICS hosts.")
-@click.pass_obj
-def list_ebics_host(obj):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/admin/ebics/hosts")
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox.group("ebicssubscriber", help="manage EBICS subscribers")
-@click.pass_context
-def sandbox_ebicssubscriber(ctx):
-    pass
-
-
-@sandbox_ebicssubscriber.command("create", help="Create an EBICS subscriber.")
-@click.option("--host-id", help="Ebics host ID", required=True, prompt=True)
-@click.option("--partner-id", help="Ebics partner ID", required=True, 
prompt=True)
-@click.option("--user-id", help="Ebics user ID", required=True, prompt=True)
-@click.pass_obj
-def create_ebics_subscriber(obj, host_id, partner_id, user_id):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/admin/ebics/subscribers")
-    try:
-        resp = post(
-            url,
-            json=dict(hostID=host_id, partnerID=partner_id, userID=user_id),
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@sandbox_ebicssubscriber.command("list", help="List EBICS subscribers.")
-@click.pass_obj
-def list_ebics_subscriber(obj):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/admin/ebics/subscribers")
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox.group("ebicsbankaccount", help="manage EBICS bank accounts")
-@click.pass_context
-def sandbox_ebicsbankaccount(ctx):
-    pass
-
-
-@sandbox_ebicsbankaccount.command(
-    "create",
-    help="Create a bank account for an existing EBICS subscriber.  This 
operation is deprecated because it doesn't associate any user profile to the 
bank account being created."
-)
-@click.option("--iban", help="IBAN", required=True)
-@click.option("--bic", help="BIC", required=True)
-@click.option("--person-name", help="bank account owner name", required=True)
-@click.option("--account-name", help="label of this bank account", 
required=True)
-@click.option("--ebics-user-id", help="user ID of the Ebics subscriber", 
required=True)
-@click.option("--ebics-host-id", help="host ID of the Ebics subscriber", 
required=True)
-@click.option(
-    "--ebics-partner-id", help="partner ID of the Ebics subscriber", 
required=True
-)
-@click.pass_obj
-def associate_bank_account(
-    obj,
-    iban,
-    bic,
-    person_name,
-    account_name,
-    ebics_user_id,
-    ebics_host_id,
-    ebics_partner_id,
-):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, "/admin/ebics/bank-accounts")
-    body = dict(
-        subscriber=dict(
-            userID=ebics_user_id, partnerID=ebics_partner_id, 
hostID=ebics_host_id
-        ),
-        iban=iban,
-        bic=bic,
-        name=person_name,
-        label=account_name,
-    )
-
-    try:
-        resp = post(
-            url, json=body,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@sandbox.group("bankaccount", help="manage bank accounts")
-@click.pass_context
-def sandbox_bankaccount(ctx):
-    pass
-
-
-# This group deals with the new Access API
-# and the 'demobank' model.
-@sandbox.group(
-    "demobank",
-    help="Subcommands for the 'demobank' model and the Access API."
-)
-@click.option(
-    "--demobank-name",
-    help="Defaults to 'default'",
-    required=False,
-    default="default"
-    )
-@click.pass_context
-def sandbox_demobank(ctx, demobank_name):
-    ctx.obj.demobank_name = demobank_name
-    pass
-
-@sandbox_demobank.command("list-transactions", help="List transactions.")
-@click.option(
-    "--bank-account",
-    help="Label of the bank account to be debited for the transaction.",
-    required=True
-)
-@click.pass_obj
-def sandbox_demobank_list_transactions(obj, bank_account):
-    url = obj.access_api_url (f"/accounts/{bank_account}/transactions")
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + url)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_demobank.command("new-transaction", help="Initiate a new 
transaction.")
-@click.option(
-    "--bank-account",
-    help="Label of the bank account to be debited for the transaction.",
-    required=True
-)
-# Including the subject in the payto to match the
-# payto returned by the merchant backend helper program
-# to create tip reserves.
-@click.option(
-    "--payto-with-subject",
-    help="Payto address including the subject as a query parameter.",
-    required=True
-)
-@click.option(
-    "--amount",
-    help="Amount to transfer, in the CUR:X.Y format.",
-    required=True
-)
-@click.pass_obj
-def sandbox_demobank_new_transaction(obj, bank_account, payto_with_subject, 
amount):
-    url = obj.access_api_url (f"/accounts/{bank_account}/transactions")
-    try:
-        body = dict(paytoUri=payto_with_subject, amount=amount)
-        resp = post(
-            url,
-            json=body,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + url)
-        exit(1)
-
-    check_response_status(resp)
-
-@sandbox_demobank.command("info", help="Return basic information of a bank 
account")
-@click.option(
-    "--bank-account",
-    help="Label of the bank account whose information should be returned.",
-    required=True
-)
-@click.pass_obj
-def sandbox_demobank_info(obj, bank_account):
-    url = obj.access_api_url (f"/accounts/{bank_account}")
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-@sandbox_demobank.command(
-  "debug-url",
-  help="Prints the base URL for the demobank to address, according to the 
related values passed via the environment or the command line."
-)
-@click.pass_obj
-def debug_url(obj):
-    print("demobank URL", obj.demobank_base_url())
-    print("access API registration URL", 
obj.access_api_url("/testing/register"))
-
-@sandbox_demobank.command("delete",
-    help="""delete bank account"""
-)
-@click.option(
-    "--bank-account",
-    help="Label of the bank account to delete.",
-    required=True
-)
-@click.pass_obj
-def sandbox_demobank_delete(obj, bank_account):
-    url = obj.access_api_url (f"/accounts/{bank_account}")
-    try:
-        resp = delete(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + url)
-        exit(1)
-    check_response_status(resp)
-
-@sandbox_demobank.command("register",
-    help="""register a new bank account.  Credentials will be taken
-    from the LIBEUFIN_SANDBOX_{USERNAME, PASSWORD} env variables.  Note
-    that the username will be both the username to login at the bank
-    and the bank account label"""
-)
-@click.option(
-    "--public/--no-public",
-    default=False,
-    help="Decides whether a bank account is public.",
-)
-@click.option(
-    "--name",
-    default="",
-    help="Person name",
-)
-@click.option(
-    "--iban",
-    help="Uses this IBAN, instead of a random one.",
-)
-@click.pass_obj
-def sandbox_demobank_register(obj, public, name, iban):
-    url = obj.access_api_url ("/testing/register")
-    if not obj.credentials_found:
-        print("WARNING: registering with unset credentials in the 
environment!!")
-    req = dict(username=obj.username, password=obj.password, isPublic=public)
-    if name != "":
-        req.update(name=name)
-    if iban:
-        req.update(iban=iban)
-    try:
-        resp = post(url, json=req)
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + url)
-        exit(1)
-    check_response_status(resp)
-
-@sandbox_demobank.command("new-ebicssubscriber",
-    help="Associate a new Ebics subscriber to an existing bank account."
-)
-@click.option("--host-id", help="Ebics host ID", required=True)
-@click.option("--partner-id", help="Ebics partner ID", required=True)
-@click.option("--user-id", help="Ebics user ID", required=True)
-@click.option(
-    "--bank-account",
-    help="Label of the bank account to associate with this Ebics subscriber",
-    required=True
-)
-@click.pass_obj
-def sandbox_demobank_ebicssubscriber(obj, host_id, partner_id, user_id, 
bank_account):
-    demobank_url = obj.demobank_base_url()
-    url = urljoin_nodrop(demobank_url, "/ebics/subscribers")
-    try:
-        resp = post(url,
-            json=dict(
-                hostID=host_id,
-                partnerID=partner_id,
-                userID=user_id,
-                demobankAccountLabel=bank_account
-            ),
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-    check_response_status(resp)
-
-@sandbox_bankaccount.command("list", help="List accounts")
-@click.pass_obj
-def bankaccount_list(obj):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(sandbox_base_url, f"/admin/bank-accounts")
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_bankaccount.command("transactions", help="List transactions")
-@click.argument("account-label")
-@click.pass_obj
-def transactions_list(obj, account_label):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(
-        sandbox_base_url, f"/admin/bank-accounts/{account_label}/transactions"
-    )
-    try:
-        resp = get(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_bankaccount.command("generate-transactions", help="Generate test 
transactions")
-@click.argument("account-label")
-@click.pass_obj
-def bankaccount_generate_transactions(obj, account_label):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(
-        sandbox_base_url,
-        f"/admin/bank-accounts/{account_label}/generate-transactions"
-    )
-    try:
-        resp = post(url, **maybe_auth(obj))
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-
-
-@sandbox_bankaccount.command(help="Book an incoming payment in the sandbox")
-@click.argument("account-name")
-@click.option("--debtor-iban", help="IBAN sending the payment", prompt=True)
-@click.option("--debtor-bic", help="BIC sending the payment", prompt=True)
-@click.option(
-    "--debtor-name", help="name of the person who is sending the payment", 
prompt=True
-)
-@click.option("--amount", help="amount with currency (currency:x.y)", 
prompt=True)
-@click.option("--subject", help="payment subject", prompt=True)
-@click.pass_obj
-def simulate_incoming_transaction(
-    obj,
-    account_name,
-    debtor_iban,
-    debtor_bic,
-    debtor_name,
-    amount,
-    subject,
-):
-    sandbox_base_url = obj.require_sandbox_base_url()
-    url = urljoin_nodrop(
-        sandbox_base_url,
-        f"/admin/bank-accounts/{account_name}/simulate-incoming-transaction",
-    )
-    body = dict(
-        debtorIban=debtor_iban,
-        debtorBic=debtor_bic,
-        debtorName=debtor_name,
-        amount=amount,
-        subject=subject,
-    )
-    try:
-        resp = post(
-            url,
-            json=body,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox")
-        exit(1)
-
-    check_response_status(resp)
-
-
-# The commands below request to the latest CIRCUIT API.
-
-@sandbox_demobank.command(
-  "circuit-cashout-confirm",
-  help="Confirm a cash-out operation.  Only the author is allowed (no admin)."
-)
-@click.option(
-    "--tan",
-    help="TAN that authorizes the cash-out operaion.",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--uuid",
-    help="UUID of the cash-out operation to confirm.",
-    required=True,
-    prompt=True
-)
-@click.pass_obj
-def circuit_cashout_confirm(obj, tan, uuid):
-    cashout_confirm_endpoint = obj.circuit_api_url(f"cashouts/{uuid}/confirm")
-    req = dict(tan=tan)
-    try:
-        resp = post(
-            cashout_confirm_endpoint,
-            json=req,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + cashout_confirm_endpoint)
-        exit(1)
-
-    check_response_status(resp, 204)
-    
-
-@sandbox_demobank.command(
-  "circuit-cashout-abort",
-  help="Abort a cash-out operation.  Admin and author are allowed to request."
-)
-@click.option(
-    "--uuid",
-    help="UUID of the cash-out operation to abort.",
-    required=True,
-    prompt=True
-)
-@click.pass_obj
-def circuit_cashout_abort(obj, uuid):
-    cashout_abort_endpoint = obj.circuit_api_url(f"cashouts/{uuid}/abort")
-    try:
-        resp = post(
-            cashout_abort_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + cashout_abort_endpoint)
-        exit(1)
-
-    check_response_status(resp, 204)
-
-@sandbox_demobank.command(
-  "circuit-cashout-details",
-  help="Retrieve status information about one cash-out operation.  Admin and 
author are allowed to request."
-)
-@click.option(
-    "--uuid",
-    help="UUID of the cash-out operation to retrieve.",
-    required=True,
-    prompt=True
-)
-@click.pass_obj
-def circuit_cashout_info(obj, uuid):
-    cashout_info_endpoint = obj.circuit_api_url(f"cashouts/{uuid}")
-    try:
-        resp = get(
-            cashout_info_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + cashout_info_endpoint)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-@sandbox_demobank.command(
-  "circuit-delete-account",
-  help="Delete one account.  Only available to the administrator and for 
accounts with zero balance."
-)
-@click.option(
-    "--username",
-    help="account to delete",
-    required=True,
-    prompt=True
-)
-@click.pass_obj
-def circuit_delete(obj, username):
-
-    # Check that admin wasn't specified.
-    # Note: even if 'admin' gets through here,
-    # the bank can't delete it because its profile
-    # doesn't get a ordinary entry into the database.
-    if username == "admin":
-        print("Won't delete 'admin'", file=sys.stderr)
-        exit(1)
-
-    # Do not check credentials to let the --no-auth case
-    # function, in case the bank allows it.
-    account_deletion_endpoint = obj.circuit_api_url(f"accounts/{username}")
-    try:
-        resp = delete(
-            account_deletion_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + account_deletion_endpoint)
-        exit(1)
-  
-    check_response_status(resp, expected_status_code=204)
-
-
-@sandbox_demobank.command(
-  "circuit-register",
-  help="Register a new account with cash-out capabilities.  It needs 
administrator credentials, and the new account password exported in 
LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD."
-)
-@click.option(
-    "--username",
-    help="new account username",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--cashout-address",
-    help="Payto address where to send fiat payments on cash-outs",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--name",
-    help="Legal name associated to the account.",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--phone",
-    help="SMS where to send the cash-out TAN.",
-)
-@click.option(
-    "--email",
-    help="E-mail address where to send the cash-out TAN.",
-)
-@click.option(
-    "--internal-iban",
-    help="Which IBAN to associate to this account.  The IBAN participates only 
in the local currency circuit.  If missing, the bank generates one.",
-)
-@click.pass_obj
-def circuit_register(
-    obj,
-    username,
-    cashout_address,
-    name,
-    phone,
-    email,
-    internal_iban
-):
-    # Check admin is requesting.
-    if (obj.username != "admin"):
-        print("Not running as 'admin'.  Won't request", file=sys.stderr)
-        exit(1)
-    new_account_password = 
os.environ.get("LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD")
-    # Check that the new account password got
-    # exported into the environment.
-    if not new_account_password:
-        print("LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD not found in the 
environment", file=sys.stderr)
-        exit(1)
-
-    # Get the bank base URL.
-    registration_endpoint = obj.circuit_api_url("accounts")
-
-    contact_data = dict()
-    if (phone):
-        contact_data.update(phone=phone)
-    if (email):
-        contact_data.update(email=email)
-    req = dict(
-        contact_data=contact_data,
-        username=username,
-        password=new_account_password,
-        name=name,
-        cashout_address=cashout_address
-    )
-    if internal_iban:
-        req.update(internal_iban=internal_iban)
-    try:
-        resp = post(
-            registration_endpoint,
-            json=req,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + registration_endpoint)
-        exit(1)
-
-    check_response_status(resp, expected_status_code=204)
-
-
-@sandbox_demobank.command(
-  "circuit-reconfig",
-  help="Reconfigure an account with cash-out capabilities.  It needs 
administrator or owner credentials"
-)
-@click.option(
-    "--phone",
-    help="Phone number for the SMS TAN",
-)
-@click.option(
-    "--email",
-    help="E-mail address for receiving the TAN",
-)
-@click.option(
-    "--cashout-address",
-    help="Payto address where to send fiat payments on cash-outs",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--username",
-    help="Username associated with the account to reconfigure.  It defaults to 
LIBEUFIN_SANDBOX_USERNAME and doesn't accept 'admin'.",
-)
-@click.pass_obj
-def circuit_reconfig(
-  obj,
-  phone,
-  email,
-  cashout_address,
-  username
-):
-    resource_name = get_account_name(username, obj.username)
-    if not resource_name:
-        print("Could not find any username to reconfigure.", file=sys.stderr)
-    reconfig_endpoint = obj.circuit_api_url(f"accounts/{resource_name}")
-    contact_data = dict()
-    if (phone):
-        contact_data.update(phone=phone)
-    if (email):
-        contact_data.update(email=email)
-    req = dict(contact_data=contact_data, cashout_address=cashout_address)
-
-    try:
-        resp = patch(
-            reconfig_endpoint,
-            json=req,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + reconfig_endpoint)
-        exit(1)
-
-    check_response_status(resp, expected_status_code=204)
-
-
-@sandbox_demobank.command(
-  "circuit-password-reconfig",
-  help="Ask interactively to change the password. It needs administrator or 
owner credentials"
-)
-@click.option(
-    "--username",
-    help="Username whose password will change.  Defaults to 
LIBEUFIN_SANDBOX_USERNAME and doesn't accept 'admin' as a value.",
-    required=False
-)
-@click.pass_obj
-def password_reconfig(obj, username):
-    resource_name = get_account_name(username, obj.username)
-    if not resource_name:
-        print(
-            "Couldn't find the username whose password should change.",
-            file=sys.stderr
-        )
-        exit(1)
-    print(f"Change password for account: {resource_name}.")
-    new_password = click.prompt(
-        "Enter the new password",
-        hide_input=True,
-        type=str
-    )
-    confirm_new_password = click.prompt(
-        "Enter the new password again",
-        hide_input=True,
-        type=str
-    )
-    if (new_password != confirm_new_password):
-        print("The password entered the second time didn't match.", 
file=sys.stderr)
-        exit(1)
-    password_reconfig_endpoint = 
obj.circuit_api_url(f"accounts/{resource_name}/auth")
-    req = dict(new_password=confirm_new_password)
-    try:
-        resp = patch(
-            password_reconfig_endpoint,
-            json=req,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + password_reconfig_endpoint)
-        exit(1)
-
-    check_response_status(resp, expected_status_code=204)
-
-
-@sandbox_demobank.command(
-  "circuit-cashout",
-  help="Create a cash-out operation.  If successful, the user gets a TAN."
-)
-@click.option(
-    "--subject",
-    help="Payment subject to associate to the outgoing and incoming payments 
that are associated with this cash-out operation.",
-    required=False
-)
-@click.option(
-    "--amount-debit",
-    help="Amount that will debited to the local currency account, in the 
<currency>:X.Y format.",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--amount-credit",
-    help="Amount that will credited to the fiat currency account, in the 
<currency>:X.Y format.",
-    required=True,
-    prompt=True
-)
-@click.option(
-    "--tan-channel",
-    help="Indicates how to send the TAN to the user: 'sms', 'email' and 'file' 
are valid values.  If missing, the bank defaults to SMS.  'file' makes the 
server write the TAN to /tmp/libeufin-cashout-tan.txt, normally used for 
testing.",
-    required=False,
-)
-@click.pass_obj
-def circuit_cashout(obj, subject, amount_debit, amount_credit, tan_channel):
-    req = dict(
-        amount_debit=amount_debit,
-        amount_credit=amount_credit
-    )
-    if subject:
-        req.update(subject=subject)
-    if tan_channel:
-        req.update(tan_channel=tan_channel)
-    cashout_creation_endpoint = obj.circuit_api_url("cashouts")
-    try:
-        resp = post(
-            cashout_creation_endpoint,
-            json=req,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach sandbox at " + cashout_creation_endpoint)
-        exit(1)
-  
-    check_response_status(resp, expected_status_code=202)
-    tell_user(resp) # Communicates back the operation UUID.
-
-@sandbox_demobank.command(
-  "circuit-account-info",
-  help="Retrieve Circuit information about one account.  Useful to get 
cash-out address and contact details."
-)
-@click.option(
-    "--username",
-    help="Username of the account to retrieve.  It defaults to 
LIBEUFIN_SANDBOX_USERNAME and doesn't accept 'admin'.",
-)
-@click.pass_obj
-def circuit_account_info(obj, username):
-    resource_name = get_account_name(username, obj.username)
-    if not resource_name:
-        print(
-            "Couldn't find the username whose account is being retrieved.",
-            file=sys.stderr
-        )
-        exit(1)
-    # resource_name != admin
-    account_info_endpoint = obj.circuit_api_url(f"accounts/{resource_name}")
-    try:
-        resp = get(
-            account_info_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + account_info_endpoint)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_demobank.command(
-  "circuit-accounts",
-  help="Gets the list of all the accounts managed by the Circuit.  Only 
'admin' allowed"
-)
-@click.pass_obj
-def circuit_accounts(obj):
-    # Check admin is requesting.
-    if (obj.username != "admin"):
-        print("Not running as 'admin'.  Won't request", file=sys.stderr)
-        exit(1)
-    accounts_endpoint = obj.circuit_api_url(f"accounts")
-    try:
-        resp = get(
-            accounts_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + accounts_endpoint)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-
-@sandbox_demobank.command(
-  "circuit-cashouts",
-  help="Gets the list of all the pending and confirmed cash-out operations."
-)
-@click.pass_obj
-def circuit_cashouts(obj):
-    # Check admin is requesting.
-    if (obj.username != "admin"):
-        print("Not running as 'admin'.  Won't request", file=sys.stderr)
-        exit(1)
-    cashouts_endpoint = obj.circuit_api_url(f"cashouts")
-    try:
-        resp = get(
-            cashouts_endpoint,
-            **maybe_auth(obj)
-        )
-    except Exception as e:
-        print(e)
-        print("Could not reach the bank at " + cashouts_endpoint)
-        exit(1)
-
-    check_response_status(resp)
-    tell_user(resp)
-
-cli()
diff --git a/cli/tests/add-incoming-client.sh b/cli/tests/add-incoming-client.sh
deleted file mode 100755
index 36314b74..00000000
--- a/cli/tests/add-incoming-client.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-curl -v -s \
-  -XPOST \
-  -H "Content-Type: application/json" \
-  -d'{"amount": "MANA:3.00", "reservePub": "re:publica"}' \
-  
http://localhost:5001/facades/test-facade/taler-wire-gateway/admin/add-incoming
diff --git a/cli/tests/circuit_test.sh b/cli/tests/circuit_test.sh
deleted file mode 100755
index 971e664d..00000000
--- a/cli/tests/circuit_test.sh
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/bin/bash
-
-# Tests successful cases of the CLI acting
-# as the client of the Circuit API.
-
-set -eu
-
-echo TESTING THE CLI SIDE OF THE CIRCUIT API
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/circuit-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-# NOTE: unset this variable to test the SMS or e-mail TAN.
-export LIBEUFIN_CASHOUT_TEST_TAN=secret-tan
-
-echo -n Delete previous data..
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank...
-libeufin-sandbox config default
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=circuit
-libeufin-sandbox serve &> sandbox.log &
-SANDBOX_PID=$!
-trap "echo -n 'killing the bank (pid $SANDBOX_PID)...'; kill $SANDBOX_PID; 
wait; echo DONE" EXIT
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-echo Ask Circuit API /config...
-curl http://localhost:5000/demobanks/default/circuit-api/config &> /dev/null
-echo DONE
-echo -n "Register new account..."
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-export LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD=foo
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-register --name eee --username www \
-    --cashout-address payto://iban/FIAT --internal-iban LOCAL 
-echo DONE
-echo -n Reconfigure account specifying a phone number..
-# Give phone number.
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-reconfig --cashout-address payto://iban/WWW --phone +999
-echo DONE
-echo -n Create a cash-out operation...
-CASHOUT_RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout --tan-channel file --amount-debit=EUR:1 
--amount-credit=CHF:0.95)
-echo DONE
-echo -n Extract the cash-out UUID...
-CASHOUT_UUID=$(echo ${CASHOUT_RESP} | jq --raw-output '.uuid')
-echo DONE
-echo -n Get cash-out details...
-RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-details \
-  --uuid $CASHOUT_UUID
-)
-OPERATION_STATUS=$(echo $RESP | jq --raw-output '.status')
-if ! test "$OPERATION_STATUS" = "PENDING"; then
-    echo Unexpected cash-out operation status found: $OPERATION_STATUS
-    exit 1
-fi
-echo DONE
-echo -n Delete the cash-out operation...
-RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-abort \
-  --uuid $CASHOUT_UUID
-)
-echo DONE
-echo -n Create another cash-out operation...
-CASHOUT_RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout --tan-channel file --amount-debit=EUR:1 
--amount-credit=CHF:0.95)
-CASHOUT_UUID=$(echo ${CASHOUT_RESP} | jq --raw-output '.uuid')
-echo DONE
-echo -n Confirm the last cash-out operation...
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-confirm --uuid $CASHOUT_UUID --tan secret-tan
-echo DONE
-# The user now has -1 balance.  Let the bank
-# award EUR:1 to them, in order to bring their
-# balance to zero.
-echo -n Bring the account to 0 balance...
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  new-transaction \
-  --bank-account admin \
-  --payto-with-subject "payto://iban/SANDBOXX/LOCAL?message=bring-to-zero" \
-  --amount EUR:1
-echo DONE
-echo -n Delete the account...
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-delete-account --username www
-echo DONE
diff --git a/cli/tests/circuit_test_email_tan.sh 
b/cli/tests/circuit_test_email_tan.sh
deleted file mode 100755
index e1b61d9d..00000000
--- a/cli/tests/circuit_test_email_tan.sh
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/bash
-
-# Tests successful cases of the CLI acting
-# as the client of the Circuit API.
-
-set -eu
-
-echo TESTING THE EMAIL TAN
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/circuit-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-
-echo -n Delete previous data..
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank...
-libeufin-sandbox config default
-echo DONE
-echo -n Starting the bank passing the e-mail TAN option...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=circuit
-libeufin-sandbox serve \
-  --email-tan "../../contrib/libeufin-tan-email.sh" &> sandbox.log &
-SANDBOX_PID=$!
-# Cleaner:
-trap "echo -n 'killing the bank (pid $SANDBOX_PID)...'; kill $SANDBOX_PID; 
wait; echo DONE" EXIT
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-echo Ask Circuit API /config...
-curl http://localhost:5000/demobanks/default/circuit-api/config &> /dev/null
-echo DONE
-echo -n "Register new account..."
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-export LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD=foo
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-register --name eee --username www --email $LIBEUFIN_EMAIL_ADDRESS \
-    --cashout-address payto://iban/FIAT --internal-iban LOCAL 
-echo DONE
-echo -n Create the cash-out operation with the e-mail TAN...
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-CASHOUT_RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout \
-    --tan-channel=email \
-    --amount-debit=EUR:1 \
-    --amount-credit=CHF:0.95
-)
-CASHOUT_UUID=$(echo ${CASHOUT_RESP} | jq --raw-output '.uuid')
-echo DONE
-echo -n Checking that cash-out status is 'pending'...
-RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-details \
-  --uuid $CASHOUT_UUID
-)
-OPERATION_STATUS=$(echo $RESP | jq --raw-output '.status')
-if ! test "$OPERATION_STATUS" = "PENDING"; then
-    echo Unexpected cash-out operation status found: $OPERATION_STATUS
-    exit 1
-fi
-echo DONE
-read -p "Enter the TAN received via e-mail:" INPUT_TAN
-echo -n Confirming the last cash-out operation...
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-confirm --uuid $CASHOUT_UUID --tan $INPUT_TAN
-echo DONE
-echo -n Checking the balance...
-RESP=$(libeufin-cli sandbox --sandbox-url http://localhost:5000/ demobank info 
--bank-account www)
-BALANCE=$(echo $RESP | jq -r '.balance.amount')
-INDICATOR=$(echo $RESP | jq -r '.balance.credit_debit_indicator')
-echo $BALANCE $INDICATOR
-echo DONE
diff --git a/cli/tests/circuit_test_file_tan.sh 
b/cli/tests/circuit_test_file_tan.sh
deleted file mode 100755
index f98a436a..00000000
--- a/cli/tests/circuit_test_file_tan.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/bin/bash
-
-# Tests successful cases of the CLI acting
-# as the client of the Circuit API.
-
-set -eu
-
-echo TESTING THE CLI SIDE OF THE CIRCUIT API
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/circuit-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-
-echo -n Delete previous data..
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank...
-libeufin-sandbox config default
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=circuit
-libeufin-sandbox serve &> sandbox.log &
-SANDBOX_PID=$!
-trap "echo -n 'killing the bank (pid $SANDBOX_PID)...'; kill $SANDBOX_PID; 
wait; echo DONE" EXIT
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-echo Ask Circuit API /config...
-curl http://localhost:5000/demobanks/default/circuit-api/config &> /dev/null
-echo DONE
-echo -n "Register new account..."
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-export LIBEUFIN_NEW_CIRCUIT_ACCOUNT_PASSWORD=foo
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-register --name eee --username www \
-    --cashout-address payto://iban/FIAT --internal-iban LOCAL 
-echo DONE
-echo -n Reconfigure account specifying a phone number..
-# Give phone number.
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-reconfig --cashout-address payto://iban/WWW --phone +999
-echo DONE
-echo -n Create a cash-out operation...
-CASHOUT_RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout \
-    --tan-channel=file \
-    --amount-debit=EUR:1 \
-    --amount-credit=CHF:0.95
-)
-echo DONE
-echo -n "Extract the cash-out UUID..."
-CASHOUT_UUID=$(echo ${CASHOUT_RESP} | jq --raw-output '.uuid')
-echo DONE
-echo -n Get cash-out details...
-RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-details \
-  --uuid $CASHOUT_UUID
-)
-OPERATION_STATUS=$(echo $RESP | jq --raw-output '.status')
-if ! test "$OPERATION_STATUS" = "PENDING"; then
-    echo Unexpected cash-out operation status found: $OPERATION_STATUS
-    exit 1
-fi
-echo DONE
-echo -n Abort the cash-out operation...
-RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-abort \
-  --uuid $CASHOUT_UUID
-)
-echo DONE
-echo -n Create another cash-out operation...
-CASHOUT_RESP=$(./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout \
-    --tan-channel=file \
-    --amount-debit=EUR:1 \
-    --amount-credit=CHF:0.95
-)
-CASHOUT_UUID=$(echo ${CASHOUT_RESP} | jq --raw-output '.uuid')
-echo DONE
-echo Reading the TAN from /tmp/libeufin-cashout-tan.txt
-INPUT_TAN=$(cat /tmp/libeufin-cashout-tan.txt)
-echo -n Confirm the last cash-out operation...
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-cashout-confirm --uuid $CASHOUT_UUID --tan $INPUT_TAN
-echo DONE
-# The user now has -1 balance.  Let the bank
-# award EUR:1 to them, in order to bring their
-# balance to zero.
-echo -n Bring the account to 0 balance...
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  new-transaction \
-  --bank-account admin \
-  --payto-with-subject "payto://iban/SANDBOXX/LOCAL?message=bring-to-zero" \
-  --amount EUR:1
-echo DONE
-echo -n Delete the account...
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=circuit
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  circuit-delete-account --username www
-echo DONE
diff --git a/cli/tests/debit_test.sh b/cli/tests/debit_test.sh
deleted file mode 100755
index 9e1ad97e..00000000
--- a/cli/tests/debit_test.sh
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/bash
-
-# Tests successful cases of the CLI acting
-# as the client of the Circuit API.
-
-set -eu
-
-echo TESTING DEBIT THRESHOLD
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/debit-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-
-echo -n Delete previous data..
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank, with users limit 0...
-libeufin-sandbox config --currency MANA default --users-debt-limit=0
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=circuit
-libeufin-sandbox serve &> sandbox.log &
-SANDBOX_PID=$!
-trap "echo -n 'killing the bank (pid $SANDBOX_PID)...'; kill $SANDBOX_PID; 
wait; echo DONE" EXIT
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-
-echo -n "Register new account..."
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  register
-echo DONE
-echo -n "Get the admin's IBAN..."
-ADMIN_IBAN=$(echo "SELECT iban FROM BankAccounts WHERE label='admin'" | 
sqlite3 $DB_PATH)
-echo "DONE ($ADMIN_IBAN)"
-echo -n "Try to surpass the debit threshold (user pays admin)..."
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  new-transaction \
-  --bank-account www \
-  --payto-with-subject "payto://iban/SANDBOXX/${ADMIN_IBAN}?message=go-debit" \
-  --amount MANA:99999 &> /dev/null || true
-echo DONE
-
-echo -n Check the amount is still the initial zero...
-RESP=$(libeufin-cli sandbox --sandbox-url http://localhost:5000/ demobank info 
--bank-account www)
-BALANCE=$(echo $RESP | jq -r '.balance.amount')
-if [ "$BALANCE" != "MANA:0" ]; then
-  echo Debit threshold of MANA:0 not respected.
-  exit 1
-fi
-echo DONE
-
-echo -n "Try to surpass the debit threshold via low-level libeufin-sandbox 
command..."
-libeufin-sandbox \
-  make-transaction \
-  --credit-account=admin \
-  --debit-account=www \
-  MANA:9999 "Go debit again."  &> /dev/null || true
-echo DONE
-
-echo -n Check the amount is still the initial zero...
-RESP=$(libeufin-cli sandbox --sandbox-url http://localhost:5000/ demobank info 
--bank-account www)
-BALANCE=$(echo $RESP | jq -r '.balance.amount')
-if [ "$BALANCE" != "MANA:0" ]; then
-  echo Debit threshold of MANA:0 not respected via low-level libeufin-sandbox 
command.
-  exit 1
-fi
-echo DONE
diff --git a/cli/tests/launch_services_with_ebics.sh 
b/cli/tests/launch_services_with_ebics.sh
deleted file mode 100755
index fdd5a74d..00000000
--- a/cli/tests/launch_services_with_ebics.sh
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/bash
-
-# Convenience script to setup and run a Sandbox + Nexus
-# EBICS pair, in order to try CLI commands.
-set -eu
-
-function exit_cleanup()
-{
-  echo "Running exit-cleanup"
-  for n in `jobs -p`
-    do
-      kill $n 2> /dev/null || true
-    done
-    wait || true
-    echo "DONE"
-}
-
-trap "exit_cleanup" EXIT
-echo RUNNING SANDBOX-NEXUS EBICS PAIR
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/libeufin-cli-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-
-echo -n Delete previous data...
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank with MANA...
-libeufin-sandbox config --with-signup-bonus --currency MANA default
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=foo
-libeufin-sandbox serve &> sandbox.log &
-SANDBOX_PID=$!
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-echo -n Make one superuser at Nexus...
-export LIBEUFIN_NEXUS_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-libeufin-nexus superuser test-user --password x
-echo DONE
-echo -n Launching Nexus...
-libeufin-nexus serve &> nexus.log &
-NEXUS_PID=$!
-echo DONE
-echo -n Waiting for Nexus...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5001/ &> /dev/null
-echo DONE
-
-echo -n "Register the 'www' Sandbox account..."
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  register
-echo DONE
-export LIBEUFIN_SANDBOX_USERNAME=admin
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-echo -n "Create EBICS host at Sandbox..."
-libeufin-cli sandbox \
-  --sandbox-url http://localhost:5000 \
-  ebicshost create --host-id wwwebics
-echo OK
-echo -n "Create 'www' EBICS subscriber at Sandbox..."
-libeufin-cli sandbox \
-  --sandbox-url http://localhost:5000 \
-  demobank new-ebicssubscriber --host-id wwwebics \
-  --user-id wwwebics --partner-id wwwpartner \
-  --bank-account www # that's a username _and_ a bank account name
-echo OK
-export LIBEUFIN_NEXUS_USERNAME=test-user
-export LIBEUFIN_NEXUS_PASSWORD=x
-export LIBEUFIN_NEXUS_URL=http://localhost:5001
-echo -n Creating the EBICS connection at Nexus...
-libeufin-cli connections new-ebics-connection \
-  --ebics-url "http://localhost:5000/ebicsweb"; \
-  --host-id wwwebics \
-  --partner-id wwwpartner \
-  --ebics-user-id wwwebics \
-  wwwconn
-echo DONE
-echo -n Setup EBICS keying...
-libeufin-cli connections connect wwwconn > /dev/null
-echo OK
-echo -n Download bank account name from Sandbox...
-libeufin-cli connections download-bank-accounts wwwconn
-echo OK
-echo -n Importing bank account info into Nexus...
-libeufin-cli connections import-bank-account \
-  --offered-account-id www \
-  --nexus-bank-account-id www-nexus \
-  wwwconn
-echo OK
-echo -n Create the Taler facade at Nexus...
-libeufin-cli facades \
-  new-taler-wire-gateway-facade \
-  --currency TESTKUDOS --facade-name test-facade \
-  wwwconn www-nexus
-echo OK
-echo -n "Ticking, to let statements be generated..."
-libeufin-sandbox camt053tick
-echo OK
-read -p "Press Enter to terminate..."
diff --git a/cli/tests/launch_services_with_xlibeufinbank.sh 
b/cli/tests/launch_services_with_xlibeufinbank.sh
deleted file mode 100755
index 228b372b..00000000
--- a/cli/tests/launch_services_with_xlibeufinbank.sh
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/bin/bash
-
-# Convenience script to setup and run a Sandbox & Nexus
-# connected through x-libeufin-bank.
-set -eu
-
-# WITH_TASKS=1
-WITH_TASKS=0
-function exit_cleanup()
-{
-  echo "Running exit-cleanup"
-  for n in `jobs -p`
-    do
-      kill $n 2> /dev/null || true
-    done
-    wait || true
-    echo "DONE"
-}
-
-trap "exit_cleanup" EXIT
-echo RUNNING SANDBOX-NEXUS EBICS PAIR
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_CONN="postgresql:///libeufincheck"
-export LIBEUFIN_SANDBOX_DB_CONNECTION=$DB_CONN
-export LIBEUFIN_NEXUS_DB_CONNECTION=$DB_CONN
-
-echo -n Delete previous data...
-libeufin-sandbox reset-tables
-libeufin-nexus reset-tables
-echo DONE
-echo -n Configure the default demobank with MANA...
-libeufin-sandbox config --with-signup-bonus --currency MANA default
-echo DONE
-echo -n Setting the default exchange at Sandbox...
-libeufin-sandbox \
-  default-exchange \
-  "https://exchange.example.com/"; \
-  "payto://iban/NOTUSED"
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=foo
-libeufin-sandbox serve > sandbox.log 2>&1 &
-SANDBOX_PID=$!
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 4 --retry-all-errors --retry-connrefused --retry-delay 1 
--retry 10 http://localhost:5000/ &> /dev/null
-echo DONE
-echo -n Make one superuser at Nexus...
-libeufin-nexus superuser test-user --password x
-echo DONE
-echo -n Launching Nexus...
-libeufin-nexus serve &> nexus.log &
-NEXUS_PID=$!
-echo DONE
-echo -n Waiting for Nexus...
-curl --max-time 4 --retry-all-errors --retry-connrefused --retry-delay 1 
--retry 10 http://localhost:5001/ &> /dev/null
-echo DONE
-
-echo -n "Register the Sandbox account..."
-export LIBEUFIN_SANDBOX_USERNAME=sandbox-user
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  register
-echo DONE
-echo -n Creating the x-libeufin-bank connection at Nexus...
-export LIBEUFIN_NEXUS_USERNAME=test-user
-export LIBEUFIN_NEXUS_PASSWORD=x
-export LIBEUFIN_NEXUS_URL=http://localhost:5001
-# echoing the password to STDIN, as that is a "prompt" option.
-libeufin-cli connections new-xlibeufinbank-connection \
-  --bank-url "http://localhost:5000/demobanks/default/access-api"; \
-  --username sandbox-user \
-  --password foo \
-  wwwconn
-echo DONE
-echo -n Connecting the x-libeufin-bank connection...
-libeufin-cli connections connect wwwconn
-echo DONE
-# Importing the bank account under a local name at Nexus.
-echo -n Importing the x-libeufin-bank account locally..
-libeufin-cli connections import-bank-account \
-  --offered-account-id sandbox-user \
-  --nexus-bank-account-id foo-at-nexus wwwconn
-echo DONE
-echo -n Create the Taler facade at Nexus...
-libeufin-cli facades \
-  new-taler-wire-gateway-facade \
-  --currency TESTKUDOS --facade-name test-facade \
-  wwwconn foo-at-nexus
-echo DONE
-if test 1 = $WITH_TASKS; then
-  echo -n Creating submit transactions task..
-  libeufin-cli accounts task-schedule \
-    --task-type submit \
-    --task-name www-payments \
-    --task-cronspec "* * *" \
-    foo-at-nexus || true
-  # Tries every second.  Ask C52
-  echo DONE
-  echo -n Creating fetch transactions task..
-  # Not idempotent, FIXME #7739
-  libeufin-cli accounts task-schedule \
-    --task-type fetch \
-    --task-name www-history \
-    --task-cronspec "* * *" \
-    --task-param-level statement \
-    --task-param-range-type since-last \
-    foo-at-nexus || true
-  echo DONE
-else
-  echo NOT creating background tasks!
-fi
-
-read -p "Press Enter to terminate..."
diff --git a/cli/tests/libeufin-cli b/cli/tests/libeufin-cli
deleted file mode 120000
index c69a3d87..00000000
--- a/cli/tests/libeufin-cli
+++ /dev/null
@@ -1 +0,0 @@
-../bin/libeufin-cli
\ No newline at end of file
diff --git a/cli/tests/registration_test.sh b/cli/tests/registration_test.sh
deleted file mode 100755
index 0e561cbc..00000000
--- a/cli/tests/registration_test.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-# Tests successful cases of the CLI acting
-# as the client of the Circuit API.
-
-set -eu
-
-echo TESTING ACCESS API REGISTRATION
-jq --version &> /dev/null || (echo "'jq' command not found"; exit 77)
-curl --version &> /dev/null || (echo "'curl' command not found"; exit 77)
-
-DB_PATH=/tmp/registration-test.sqlite3
-export LIBEUFIN_SANDBOX_DB_CONNECTION=jdbc:sqlite:$DB_PATH
-
-echo -n Delete previous data..
-rm -f $DB_PATH
-echo DONE
-echo -n Configure the default demobank, with users limit 0...
-libeufin-sandbox config default
-echo DONE
-echo -n Start the bank...
-export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=circuit
-libeufin-sandbox serve &> sandbox.log &
-SANDBOX_PID=$!
-trap "echo -n 'killing the bank (pid $SANDBOX_PID)...'; kill $SANDBOX_PID; 
wait; echo DONE" EXIT
-echo DONE
-echo -n Wait for the bank...
-curl --max-time 2 --retry-connrefused --retry-delay 1 --retry 10 
http://localhost:5000/ &> /dev/null
-echo DONE
-
-echo -n "Register new account..."
-export LIBEUFIN_SANDBOX_USERNAME=www
-export LIBEUFIN_SANDBOX_PASSWORD=foo
-
-./libeufin-cli \
-  sandbox --sandbox-url http://localhost:5000/ \
-  demobank \
-  register
-echo DONE
-
-echo -n Check the account is found...
-curl -u "www:foo" 
http://localhost:5000/demobanks/default/access-api/accounts/www
-echo DONE
diff --git a/cli/tests/twg-history-loop.sh b/cli/tests/twg-history-loop.sh
deleted file mode 100755
index eafff9e1..00000000
--- a/cli/tests/twg-history-loop.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-set -exu
-
-HOWMANY_SECONDS=30
-NO_LONG_POLL=0
-
-if test $NO_LONG_POLL = 1; then
-  echo "Requesting Taler history WITHOUT any long-poll in infinite loop..."
-  while true; do
-    curl -u test-user:x \
-      
"http://localhost:5001/facades/test-facade/taler-wire-gateway/history/incoming?delta=5";
-  done
-  exit
-fi
-
-echo "Requesting Taler history with $HOWMANY_SECONDS second(s) timeout in 
infinite loop..."
-while true; do
-  curl -v -u test-user:x \
-    
"http://localhost:5001/facades/test-facade/taler-wire-gateway/history/incoming?delta=5&long_poll_ms=${HOWMANY_SECONDS}000";
-done
diff --git a/cli/tests/wire-transfer.sh b/cli/tests/wire-transfer.sh
deleted file mode 100755
index ce0526c6..00000000
--- a/cli/tests/wire-transfer.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-
-set -eux
-
-# Pays the www Sandbox user, using one reserve pub
-# as the subject -- _in case_ Taler is being tested.
-RESERVE_PUB=$(gnunet-ecc -g1 /tmp/www &> /dev/null && gnunet-ecc -p /tmp/www)
-# Must match the one from launch_services.sh
-export 
LIBEUFIN_SANDBOX_DB_CONNECTION="jdbc:postgresql://localhost:5432/libeufincheck?user=$(whoami)"
-libeufin-sandbox \
-  make-transaction \
-    --credit-account=sandbox-user \
-    --debit-account=admin MANA:2 \
-   $RESERVE_PUB
diff --git a/cli/tests/wirewatch.conf b/cli/tests/wirewatch.conf
deleted file mode 100644
index c9587441..00000000
--- a/cli/tests/wirewatch.conf
+++ /dev/null
@@ -1,11 +0,0 @@
-[exchange-accountcredentials-1]
-WIRE_GATEWAY_URL = 
"http://localhost:5001/accounts/test-user/taler-wire-gateway/";
-WIRE_GATEWAY_AUTH_METHOD = basic
-USERNAME = test-user
-PASSWORD = x
-
-[exchange-account-1]
-# What is the account URL?
-PAYTO_URI = "payto://iban/NOTUSED"
-ENABLE_DEBIT = YES
-ENABLE_CREDIT = YES

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]