#!/usr/bin/env python3 import click import sys from collections import OrderedDict import json import os import urllib.parse import stat sections = OrderedDict() def cfg_put(section_name, key, value): s = sections[section_name] = sections.get(section_name, OrderedDict()) s[key] = value def cfg_write(file): for section_name, section in sections.items(): file.write("[" + section_name + "]" + "\n") for key, value in section.items(): file.write(key + " = " + value + "\n") file.write("\n") def coin(currency, name, value, d_overlap="5 minutes", d_withdraw="3 years", d_spend="5 years", d_legal="10 years", f_withdraw="0.01", f_deposit="0.01", f_refresh="0.01", f_refund="0.01", rsa_keysize="2048"): sec = "coin_"+currency+"_"+name cfg_put(sec, "value", currency+":"+value) cfg_put(sec, "duration_overlap", d_overlap) cfg_put(sec, "duration_withdraw", d_withdraw) cfg_put(sec, "duration_spend", d_spend) cfg_put(sec, "duration_legal", d_legal) cfg_put(sec, "fee_withdraw", currency+":"+f_withdraw) cfg_put(sec, "fee_refresh", currency+":"+f_refresh) cfg_put(sec, "fee_refund", currency+":"+f_refund) cfg_put(sec, "fee_deposit", currency+":"+f_deposit) cfg_put(sec, "rsa_keysize", rsa_keysize) def config(currency, envname, exchange_pub, standalone): cfg_put("paths", "TALER_DEPLOYMENT_SHARED", "${HOME}/shared-data") cfg_put("taler", "CURRENCY", currency) cfg_put("bank", "uwsgi_serve", "unix") cfg_put("bank", "uwsgi_unixpath", "$HOME/sockets/bank.uwsgi") cfg_put("bank", "uwsgi_unixpath_mode", "660") cfg_put("bank", "database", "taler"+envname) cfg_put("bank", "max_debt", "%s:0.0" % currency) cfg_put("bank", "max_debt_bank", "%s:0.0" % currency) if standalone: cfg_put("bank", "database", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) else: cfg_put("bank", "database", "postgres:///taler{}".format(envname)) if standalone: cfg_put("bank", "suggested_exchange", "https://env.taler.net/{}/exchange/".format(os.getenv("HOME"))) else: cfg_put("bank", "suggested_exchange", "https://exchange.{}.taler.net/".format(envname)) cfg_put("bank-admin", "uwsgi_serve", "unix") cfg_put("bank-admin", "uwsgi_unixpath", "$HOME/sockets/bank-admin.uwsgi") cfg_put("bank-admin", "uwsgi_unixpath_mode", "660") cfg_put("donations", "uwsgi_serve", "unix") cfg_put("donations", "uwsgi_unixpath", "$HOME/sockets/donations.uwsgi") cfg_put("donations", "uwsgi_unixpath_mode", "660") cfg_put("survey", "uwsgi_serve", "unix") cfg_put("survey", "uwsgi_unixpath", "$HOME/sockets/survey.uwsgi") cfg_put("survey", "uwsgi_unixpath_mode", "660") cfg_put("blog", "uwsgi_serve", "unix") cfg_put("blog", "uwsgi_unixpath", "$HOME/sockets/shop.uwsgi") cfg_put("blog", "uwsgi_unixpath_mode", "660") cfg_put("blog", "instance", "FSF") cfg_put("playground", "uwsgi_serve", "unix") cfg_put("playground", "uwsgi_unixpath", "$HOME/sockets/playground.uwsgi") cfg_put("playground", "uwsgi_unixpath_mode", "660") if standalone: cfg_put("backoffice-blog", "backend", "https://env.taler.net/{}/merchant-backend/".format(envname)) cfg_put("backoffice-donations", "backend", "https://env.taler.net/{}/merchant-backend/".format(envname)) else: cfg_put("backoffice-blog", "backend", "https://backend.{}.taler.net/".format(envname)) cfg_put("backoffice-donations", "backend", "https://backend.{}.taler.net/".format(envname)) cfg_put("merchant", "wireformat", "test") cfg_put("merchant", "serve", "unix") cfg_put("merchant", "unixpath", "$HOME/sockets/merchant.http") cfg_put("merchant", "wire_transfer_delay", "1 m") cfg_put("merchant", "default_max_wire_fee", currency + ":" + "0.01") cfg_put("merchant", "default_max_deposit_fee", currency + ":" + "0.05") if standalone: cfg_put("merchantdb-postgres", "config", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) else: cfg_put("merchantdb-postgres", "config", "postgres:///taler{}".format(envname)) if standalone: cfg_put("merchant-exchange-test", "url", "https://env.taler.net/{}/exchange/".format(envname)) else: cfg_put("merchant-exchange-test", "url", "https://exchange.{}.taler.net/".format(envname)) cfg_put("merchant-exchange-test", "master_key", exchange_pub) cfg_put("frontends", "backend_apikey", "sandbox".format(envname)) if standalone: cfg_put("frontends", "backend", "https://env.taler.net/{}/merchant-backend/".format(os.getenv("USER"))) else: cfg_put("frontends", "backend", "https://backend.{}.taler.net/".format(envname)) cfg_put("exchange-{}".format(currency), "master_key", exchange_pub) cfg_put("exchange-{}".format(currency), "currency", currency) if standalone: cfg_put("exchange-{}".format(currency), "base_url", "https://env.taler.net/{}/exchange".format(os.getenv("USER"))) else: cfg_put("exchange-{}".format(currency), "base_url", "https://exchange.{}.taler.net/".format(envname)) cfg_put("auditor", "auditor_priv_file", "${TALER_DEPLOYMENT_SHARED}/auditor/offline-keys/auditor.priv") cfg_put("exchange", "base_url", "https://exchange.{}.taler.net/".format(envname)) cfg_put("exchange", "serve", "unix") cfg_put("exchange", "unixpath", "$HOME/sockets/exchange.http") cfg_put("exchange", "master_public_key", exchange_pub) cfg_put("exchange", "master_priv_file", "${TALER_DEPLOYMENT_SHARED}/exchange/offline-keys/master.priv") cfg_put("exchange", "keydir", "${TALER_DEPLOYMENT_SHARED}/exchange/live-keys/") cfg_put("exchangedb", "auditor_base_dir", "${TALER_DEPLOYMENT_SHARED}/exchange/auditors/") cfg_put("exchangedb", "wirefee_base_dir", "${TALER_DEPLOYMENT_SHARED}/exchange/wirefees/") if standalone: cfg_put("exchangedb-postgres", "db_conn_str", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) cfg_put("exchangedb-postgres", "config", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) cfg_put("auditordb-postgres", "db_conn_str", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) cfg_put("auditordb-postgres", "config", "postgres:///taler?host={}/sockets".format(os.getenv("HOME"))) else: cfg_put("exchangedb-postgres", "db_conn_str", "postgres:///taler{}".format(envname)) cfg_put("exchangedb-postgres", "config", "postgres:///taler{}".format(envname)) cfg_put("auditordb-postgres", "db_conn_str", "postgres:///taler{}".format(envname)) cfg_put("auditordb-postgres", "config", "postgres:///taler{}".format(envname)) if standalone: cfg_put("account-1", "url", "payto://x-taler-bank/env.taler.net/{}/bank/2".format(envname)) else: cfg_put("account-1", "url", "payto://x-taler-bank/bank.{}.taler.net/2".format(envname)) cfg_put("account-1", "wire_response", "${TALER_DEPLOYMENT_SHARED}/exchange/wire/test.json") cfg_put("account-1", "plugin", "taler_bank") cfg_put("account-1", "taler_bank_auth_method", "basic") cfg_put("account-1", "username", "user") cfg_put("account-1", "password", "pass") cfg_put("account-1", "enable_debit", "yes") cfg_put("account-1", "enable_credit", "yes") cfg_put("fees-x-taler-bank", "wire-fee-2018", currency + ":" + "0.02") cfg_put("fees-x-taler-bank", "wire-fee-2019", currency + ":" + "0.03") cfg_put("fees-x-taler-bank", "wire-fee-2020", currency + ":" + "0.04") cfg_put("fees-x-taler-bank", "wire-fee-2021", currency + ":" + "0.04") cfg_put("fees-x-taler-bank", "wire-fee-2022", currency + ":" + "0.05") cfg_put("fees-x-taler-bank", "wire-fee-2023", currency + ":" + "0.06") cfg_put("fees-x-taler-bank", "wire-fee-2024", currency + ":" + "0.07") cfg_put("fees-x-taler-bank", "wire-fee-2025", currency + ":" + "0.08") cfg_put("fees-x-taler-bank", "closing-fee-2018", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2019", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2020", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2021", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2022", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2023", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2024", currency + ":" + "0.01") cfg_put("fees-x-taler-bank", "closing-fee-2025", currency + ":" + "0.01") # how long is one signkey valid? cfg_put("exchange_keys", "signkey_duration", "18 weeks") # how long are the signatures with the signkey valid? cfg_put("exchange_keys", "legal_duration", "2 years") # how long do we generate denomination and signing keys # ahead of time? cfg_put("exchange_keys", "lookahead_sign", "32 weeks 1 day") cfg_put("exchange_keys", "lookahead_provide", "4 weeks 1 day") # instance FSF cfg_put("instance-FSF", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/fsf.priv") cfg_put("instance-FSF", "name", "Free Software Foundation") cfg_put("merchant-location-FSF-address", "street", "51 Franklin Street, Fifth Floor.") cfg_put("merchant-location-FSF-address", "city", "Boston") cfg_put("merchant-location-FSF-address", "country", "USA") # instance Tor cfg_put("instance-Tor", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/tor.priv") cfg_put("instance-Tor", "name", "The Tor Project") # instance GNUnet cfg_put("instance-GNUnet", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/gnunet.priv") cfg_put("instance-GNUnet", "name", "GNUnet Project") # instance Taler cfg_put("instance-Taler", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/taler.priv") cfg_put("instance-Taler", "name", "Taler") # instance default cfg_put("instance-default", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/default.priv") cfg_put("instance-default", "name", "Kudos Inc.") cfg_put("merchant-location-default-address", "country", "Kudosland") cfg_put("instance-default", "tip_reserve_priv_filename", "${TALER_DEPLOYMENT_SHARED}/merchant/default-tip.priv") cfg_put("instance-default", "tip_exchange", "https://exchange.{}.taler.net/".format(envname)) # instance tutorial cfg_put("instance-tutorial", "keyfile", "${TALER_DEPLOYMENT_SHARED}/merchant/tutorial.priv") cfg_put("instance-tutorial", "name", "Tutorial") if standalone: cfg_put("account-merchant", "url", "payto://x-taler-bank/env.taler.net/{}/bank/{}".format(os.getenv("HOME"), "3")) else: cfg_put("account-merchant", "url", "payto://x-taler-bank/bank.{}.taler.net/{}".format(envname, "3")) cfg_put("account-merchant", "plugin", "taler_bank") cfg_put("account-merchant", "taler_bank_auth_method", "basic") cfg_put("account-merchant", "username", "user") cfg_put("account-merchant", "password", "pass") cfg_put("account-merchant", "wire_response", "${TALER_DEPLOYMENT_SHARED}/merchant/wire/merchant.json") cfg_put("account-merchant", "HONOR_default", "YES") cfg_put("account-merchant", "HONOR_tor", "YES") cfg_put("account-merchant", "HONOR_gnunet", "YES") cfg_put("account-merchant", "HONOR_taler", "YES") cfg_put("account-merchant", "HONOR_fsf", "YES") coin(currency, "ct_10", "0.10") coin(currency, "1", "1") coin(currency, "2", "2") coin(currency, "5", "5") coin(currency, "10", "10") coin(currency, "1000", "1000") def merchant_wf(envname, acct_no, standalone): if standalone: payto_url = "payto://x-taler-bank/env.taler.net/{}/bank/{}".format(envname, acct_no) else: payto_url = "payto://x-taler-bank/bank.{}.taler.net/{}".format(envname, acct_no) data = OrderedDict( url=payto_url, salt="SALT" ) return json.dumps(data, indent=2) def exchange_wf(envname, wfname, acct_no, name, standalone): if standalone: bank_url = "https://env.taler.net/{}/bank/".format(envname) else: bank_url = "https://bank.{}.taler.net/".format(envname) bank_host = urllib.parse.urlparse(bank_url).netloc data = OrderedDict( name=name, type=wfname, bank_url=bank_url, account_number=acct_no, url="payto://x-taler-bank/{}/{}".format(bank_host, acct_no) ) return (wfname, json.dumps(data, indent=2)) @click.command() @click.option("--currency", default="KUDOS") @click.option("--envname", default="demo") @click.option("--outdir", default=None) @click.option("--shared-outdir", default=None) @click.option("--standalone", default=None, help="Enable a standalone/env deployment instead of test/demo") @click.option("--exchange-pub", required=True) def main(currency, envname, outdir, shared_outdir, exchange_pub, standalone): if not standalone: if envname not in ("demo", "test"): print("envname {} not supported unless in standalone mode".format(envname)) return # We have the --standalone option as 0/1 instead of as a flag, # since this way it's easier to read it from an environment variable # in shell scripts. if standalone == "1": standalone = True else: standalone = False config(currency, envname, exchange_pub, standalone) exchange_wireformats = [ exchange_wf(envname, "test", 2, "The exchange", standalone) ] merchant_wireformats = [ merchant_wf(envname, 3, standalone) ] if outdir: os.makedirs(outdir, exist_ok=True) tc = os.path.join(outdir, "taler.conf") cfg_write(open(tc, "w")) else: cfg_write(sys.stdout) if shared_outdir: d = os.path.join(shared_outdir, "merchant", "wire") os.makedirs(d, exist_ok=True) for data in merchant_wireformats: filename = os.path.join(d, "merchant.json") f = open(filename, "w") f.write(data) f.close() d = os.path.join(shared_outdir, "exchange", "wire") os.makedirs(d, exist_ok=True) for name, data in exchange_wireformats: # These files must be signed by the exchange in # a later step filename = os.path.join(d, name+".json") f = open(filename, "w") f.write(data) f.close() else: cfg_write(sys.stdout) if __name__ == "__main__": main()