JJ: Description from the destination commit:
~~ config JJ: Description from source commit: rename
This commit is contained in:
parent
f51d8ee374
commit
963393c626
7 changed files with 206 additions and 629 deletions
|
|
@ -13,16 +13,16 @@ type t =
|
||||||
| Privacy
|
| Privacy
|
||||||
|
|
||||||
let etag = function
|
let etag = function
|
||||||
| Terms -> Config_mte.terms_etag
|
| Terms -> Config.terms_etag
|
||||||
| Privacy -> Config_mte.privacy_etag
|
| Privacy -> Config.privacy_etag
|
||||||
|
|
||||||
let legal_version = function
|
let legal_version = function
|
||||||
| Terms -> Config_mte.terms_legal_version
|
| Terms -> Config.terms_legal_version
|
||||||
| Privacy -> Config_mte.privacy_legal_version
|
| Privacy -> Config.privacy_legal_version
|
||||||
|
|
||||||
let base_dir = function
|
let base_dir = function
|
||||||
| Terms -> Config_mte.terms_dir
|
| Terms -> Config.terms_dir
|
||||||
| Privacy -> Config_mte.privacy_dir
|
| Privacy -> Config.privacy_dir
|
||||||
|
|
||||||
(* TODO
|
(* TODO
|
||||||
better use of Fmt to have error prefix or smthing
|
better use of Fmt to have error prefix or smthing
|
||||||
|
|
@ -55,9 +55,8 @@ let supported_lang_arr, supported_ext_arr =
|
||||||
let () =
|
let () =
|
||||||
if List.is_empty lang_l then Fmt.failwith "no language supported";
|
if List.is_empty lang_l then Fmt.failwith "no language supported";
|
||||||
if List.is_empty ext_l then Fmt.failwith "no mimetype supported";
|
if List.is_empty ext_l then Fmt.failwith "no mimetype supported";
|
||||||
if not @@ List.mem Config_mte.default_lang lang_l then
|
if not @@ List.mem Config.default_lang lang_l then
|
||||||
Fmt.failwith "default language `%s` files not found"
|
Fmt.failwith "default language `%s` files not found" Config.default_lang;
|
||||||
Config_mte.default_lang;
|
|
||||||
if not @@ List.mem ".txt" ext_l then
|
if not @@ List.mem ".txt" ext_l then
|
||||||
Fmt.failwith "plain text file not found";
|
Fmt.failwith "plain text file not found";
|
||||||
if not @@ List.mem ".md" ext_l then Fmt.failwith "markdown file not found";
|
if not @@ List.mem ".md" ext_l then Fmt.failwith "markdown file not found";
|
||||||
|
|
|
||||||
615
src/config.ml
615
src/config.ml
|
|
@ -1,596 +1,19 @@
|
||||||
(* https://docs.taler.net/manpages/taler-exchange.conf.5.html
|
(* config_mte.ml
|
||||||
taler-docs/manpages/taler-exchange.conf.5.rst *)
|
config value that are not in official config options *)
|
||||||
(* TODO
|
|
||||||
- generate `config.ml` from config file (virtual module)?
|
let default_lang = "en"
|
||||||
- parse config file format
|
let default_encoding : [< `Identity | `DEFLATE | `Gzip ] = `Identity
|
||||||
- no relative path
|
|
||||||
- default config: use relevant duration, all set to 1 year for now
|
(* TODO Taler documentation markdown mimetype should be the prefered one, and be
|
||||||
*)
|
supported, according to DD we take text/plain as default instead for now *)
|
||||||
|
let default_mimetype = ("text", "plain")
|
||||||
(* TODO unikernel *)
|
let default_extension = ".txt"
|
||||||
type dir_path
|
let terms_dir = Fpath.(v "terms")
|
||||||
type file_path
|
let privacy_dir = Fpath.(v "privacy")
|
||||||
|
|
||||||
(* TODO *)
|
(* ETAG is used as base filename it should be encoded in Crockford base-32 we do
|
||||||
(* Values that represent a time duration are represented as a series of one or more NUMBER UNIT pairs, e.g. 60 s, 4 weeks 1 day, 5 years 2 minutes. *)
|
not generate it and we do not verify it *)
|
||||||
type duration
|
let terms_etag = "0" |> Headers_lib.Etag.of_crockford32 |> Result.get_ok
|
||||||
|
let privacy_etag = "0" |> Headers_lib.Etag.of_crockford32 |> Result.get_ok
|
||||||
(* TODO
|
let terms_legal_version = "1"
|
||||||
make it Amount.t *)
|
let privacy_legal_version = "1"
|
||||||
type amount = string
|
|
||||||
type payto_uri = string
|
|
||||||
|
|
||||||
(* TODO
|
|
||||||
still need to parse them and tell that its not supported
|
|
||||||
some maybe are relevant
|
|
||||||
idk *)
|
|
||||||
type not_relevant
|
|
||||||
type not_implemented
|
|
||||||
type url = string
|
|
||||||
type seconds = int
|
|
||||||
|
|
||||||
(* not relevant for mirage *)
|
|
||||||
module type Global = sig
|
|
||||||
(*
|
|
||||||
The “[PATHS]” section is special in that it contains paths that can be
|
|
||||||
referenced using “$” in other configuration values that specify
|
|
||||||
filenames. For Taler exchange, it commonly contains the following paths:
|
|
||||||
*)
|
|
||||||
|
|
||||||
val taler_home : dir_path
|
|
||||||
val taler_data_home : dir_path
|
|
||||||
val taler_config_home : dir_path
|
|
||||||
val taler_cache_home : dir_path
|
|
||||||
val taler_runtime_dir : dir_path
|
|
||||||
end
|
|
||||||
|
|
||||||
(*
|
|
||||||
Sections with a name of the form “[currency-$NAME]” (where "$NAME" could
|
|
||||||
be any unique string) are used to specify details about how currencies
|
|
||||||
should be handled (and in particularly rendered) by the user interface.
|
|
||||||
A detailed motivation for this section can be found in DD51.
|
|
||||||
Different components can have different rules for the same currency. For
|
|
||||||
example, a bank or merchant may decide to render Euros or Dollars with
|
|
||||||
always exactly two fractional decimals, while an Exchange for the same
|
|
||||||
currency may support additional decimals. The required options in each
|
|
||||||
currency specification section are: *)
|
|
||||||
module type Currency = sig
|
|
||||||
(*
|
|
||||||
Set to YES or NO. If set to NO, the currency specification
|
|
||||||
section is ignored. Can be used to disable currencies or
|
|
||||||
select alternative sections for the same CODE with different
|
|
||||||
choices. *)
|
|
||||||
val enabled : [ `YES | `NO ]
|
|
||||||
|
|
||||||
(*
|
|
||||||
Code name for the currency. Can be at most 11 characters,
|
|
||||||
only the letters A-Z are allowed. Primary way to identify
|
|
||||||
the currency in the protocol. *)
|
|
||||||
val code : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Long human-readable name for the currency. No restrictions,
|
|
||||||
but should match the official name in English. *)
|
|
||||||
val name : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Number of fractional digits that users are allowed to enter
|
|
||||||
manually in the user interface. *)
|
|
||||||
val fractional_input_digits : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
Number of fractional digits that will be rendered normally
|
|
||||||
(in terms of size and placement). Digits shown beyond this
|
|
||||||
number will typically be rendered smaller and raised (if
|
|
||||||
possible). *)
|
|
||||||
val fractional_normal_digits : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
Number of fractional digits to pad rendered amounts with
|
|
||||||
even if these digits are all zero. For example, use 2 to
|
|
||||||
render 1 USD as $1.00. *)
|
|
||||||
val fractional_trailing_zero_digits : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
JSON map determining how to encode very large or very tiny
|
|
||||||
amounts in this currency. Maps a base10 logarithm to the
|
|
||||||
respective currency symbol. Must include at least an
|
|
||||||
entry for 0 (currency unit). For example, use
|
|
||||||
{"0":"€"} for Euros or {"0":"$"} for Dollars. You could
|
|
||||||
additionally use {"0":"€","3":"k€"} to render 3000 EUR
|
|
||||||
as 3k€. For BTC a typical map would be
|
|
||||||
{"0":"BTC","-3":"mBTC"}, informing the UI to render small
|
|
||||||
amounts in milli-Bitcoin (mBTC). *)
|
|
||||||
val alt_unit_names : (int * string) list
|
|
||||||
end
|
|
||||||
|
|
||||||
(* The following options are from the “[exchange]” section and used by most
|
|
||||||
exchange tools. *)
|
|
||||||
module type Exchange = sig
|
|
||||||
(*
|
|
||||||
Name of the currency, e.g. “EUR” for Euro. *)
|
|
||||||
val currency : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Smallest amount in this currency that can be transferred using the
|
|
||||||
underlying RTGS. For example: "EUR:0.01" or "JPY:1". *)
|
|
||||||
val currency_round_unit : amount
|
|
||||||
|
|
||||||
(*
|
|
||||||
Plugin to use for the database, e.g. “postgres”. *)
|
|
||||||
val db : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Attribute encryption key for storing attributes encrypted
|
|
||||||
in the database. Should be a high-entropy nonce. *)
|
|
||||||
val attribute_encryption_key : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Should the HTTP server listen on a UNIX domain socket (set option to "unix"), or on a TCP socket (set option to "tcp"), or be activated via systemd (set option to "systemd"). *)
|
|
||||||
val serve : not_relevant
|
|
||||||
|
|
||||||
(*
|
|
||||||
Path to listen on if we "SERVE" is set to "unix". *)
|
|
||||||
val unixpath : not_relevant
|
|
||||||
|
|
||||||
(*
|
|
||||||
Access permission mask to use for the "UNIXPATH". *)
|
|
||||||
val unixpath_mode : not_relevant
|
|
||||||
|
|
||||||
(*
|
|
||||||
Port on which the HTTP server listens, e.g. 8080. *)
|
|
||||||
val port : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
Hostname to which the exchange HTTP server should be bound to, e.g. "localhost". *)
|
|
||||||
val bind_to : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Crockford Base32-encoded master public key, public version of the
|
|
||||||
exchange's long-time offline signing key. This configuration option
|
|
||||||
is also used by the **auditor** to determine the public key of the
|
|
||||||
exchange which it is auditing. *)
|
|
||||||
val master_public_key : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Small amount that can be transferred to the exchange for the
|
|
||||||
KYC authentication wire transfers. Should be given as a hint
|
|
||||||
for merchants what amount they need to transfer to begin the
|
|
||||||
KYC transfer. Note that the amount is not enforced by the
|
|
||||||
exchange *and* that this option is optional. However, if it is
|
|
||||||
not given, merchants will have to guess what amount to transfer,
|
|
||||||
so it really should be configured. *)
|
|
||||||
val tiny_amount : amount option
|
|
||||||
|
|
||||||
(*
|
|
||||||
Web URL where users can discover shops that accept digital cash
|
|
||||||
offered by this exchange. Optional, but highly recommended. *)
|
|
||||||
val shopping_url : url option
|
|
||||||
|
|
||||||
(*
|
|
||||||
URL where wallets can find an open banking gateway to
|
|
||||||
initiate wire transfers when withdrawing digital cash
|
|
||||||
from this exchange. Optional (as obviously not every
|
|
||||||
exchange will have an open banking gateway attached). *)
|
|
||||||
val open_banking_gateway_url : url option
|
|
||||||
|
|
||||||
(*
|
|
||||||
Determines the variant of the AML SPA that should be shown. This
|
|
||||||
will determine the set of forms shown to AML staff, statistics to
|
|
||||||
be displayed on the main page, and influence the default set of
|
|
||||||
properties/events the AML forms show when AML staff makes decisions.
|
|
||||||
Possible values for now include "gls", "tops" and "magnet".
|
|
||||||
Optional. The AML SPA will only show certain default forms and
|
|
||||||
generic decisions if this option is not set. *)
|
|
||||||
val aml_spa_dialect : string option
|
|
||||||
|
|
||||||
(*
|
|
||||||
Determines the legal language (and possibly other UI/UX aspects)
|
|
||||||
wallets should use when providing the user interface for this bank.
|
|
||||||
Allows banks to communicate the desired compliance language they
|
|
||||||
want to see used to the wallet. Wallets SHOULD follow the guidance
|
|
||||||
provided by the bank, but some wallets MAY not understand all compliance
|
|
||||||
languages. Optional, if not set wallets will use their default UI/UX. *)
|
|
||||||
val bank_compliance_language : string option
|
|
||||||
|
|
||||||
(*
|
|
||||||
Absolute amount to add as an offset in the STEFAN fee approximation
|
|
||||||
curve (see DD47). Defaults to CURRENCY:0 if not specified. *)
|
|
||||||
val stefan_abs : amount
|
|
||||||
|
|
||||||
(*
|
|
||||||
Amount to multiply by the base-2 logarithm of the total amount
|
|
||||||
divided by the amount of the smallest denomination
|
|
||||||
in the STEFAN fee approximation curve (see DD47).
|
|
||||||
Defaults to CURRENCY:0 if not specified. *)
|
|
||||||
val stefan_log : amount
|
|
||||||
|
|
||||||
(*
|
|
||||||
Linear floating point factor to be multiplied by the total amount
|
|
||||||
to use in the STEFAN fee approximation curve (see DD47).
|
|
||||||
Defaults to 0.0 if not specified. *)
|
|
||||||
val stefan_lin : float
|
|
||||||
|
|
||||||
(*
|
|
||||||
The base URL under which the exchange can be reached.
|
|
||||||
Added to wire transfers to enable tracking by merchants.
|
|
||||||
Used by the KYC logic when interacting with OAuth 2.0. *)
|
|
||||||
val base_url : url
|
|
||||||
|
|
||||||
(*
|
|
||||||
Where to redirect visitors that access the top-level
|
|
||||||
"/" endpoint of the exchange. Should point users to
|
|
||||||
information about the exchange operator.
|
|
||||||
Optional setting, defaults to "/terms". *)
|
|
||||||
val toplevel_redirect_url : string option
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long should the taler-exchange-aggregator sleep when it is idle
|
|
||||||
before trying to look for more work? Default is 60 seconds. *)
|
|
||||||
val aggregator_idle_sleep_interval : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long should the taler-exchange-closer sleep when it is idle
|
|
||||||
before trying to look for more work? Default is 60 seconds. *)
|
|
||||||
val closer_idle_sleep_interval : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long should the taler-exchange-transfer sleep when it is idle
|
|
||||||
before trying to look for more work? Default is 60 seconds. *)
|
|
||||||
val transfer_idle_sleep_interval : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long should the taler-exchange-wirewatch sleep when it is idle
|
|
||||||
before trying to look for more work? Default is 60 seconds. *)
|
|
||||||
val wirewatch_idle_sleep_interval : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
Which share of the range from [0,..2147483648] should be processed by one of the shards of the aggregator. Useful only for Taler exchanges with ultra high-performance needs. When changing this value, you must stop all aggregators and run "taler-exchange-dbinit -s" before resuming. Default is 2147483648 (no sharding). *)
|
|
||||||
val aggregator_shard_size : int option
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long are signatures with signing keys legally valid? *)
|
|
||||||
val signkey_legal_duration : duration
|
|
||||||
|
|
||||||
(*
|
|
||||||
For how long should clients cache ``/keys`` responses at most? *)
|
|
||||||
val max_keys_caching : duration
|
|
||||||
|
|
||||||
(*
|
|
||||||
How many requests should the HTTP server process at most before committing suicide? *)
|
|
||||||
val max_requests : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
Directory where the terms of service of the exchange operator can be fund.
|
|
||||||
The directory must contain sub-directories for every supported language,
|
|
||||||
using the two-character language code in lower case, e.g. "en/" or "fr/".
|
|
||||||
Each subdirectory must then contain files with the terms of service in
|
|
||||||
various formats. The basename of the file of the current policy must be
|
|
||||||
specified under ``TERMS_ETAG``. The extension defines the mime type.
|
|
||||||
Supported extensions include "html", "htm", "txt", "pdf", "jpg", "jpeg",
|
|
||||||
"png" and "gif". For example, using a ``TERMS_ETAG`` of "0", the structure
|
|
||||||
could be the following:
|
|
||||||
|
|
||||||
- $TERMS_DIR/en/0.pdf
|
|
||||||
- $TERMS_DIR/en/0.html
|
|
||||||
- $TERMS_DIR/en/0.txt
|
|
||||||
- $TERMS_DIR/fr/0.pdf
|
|
||||||
- $TERMS_DIR/fr/0.html
|
|
||||||
- $TERMS_DIR/de/0.txt *)
|
|
||||||
val terms_dir : dir_path
|
|
||||||
|
|
||||||
(*
|
|
||||||
Basename of the file(s) in the ``TERMS_DIR`` with the current terms of service.
|
|
||||||
The value is also used for the "Etag" in the HTTP request to control
|
|
||||||
caching. Whenever the terms of service change, the ``TERMS_ETAG`` MUST also
|
|
||||||
change, and old values MUST NOT be repeated. For example, the date or
|
|
||||||
version number of the terms of service SHOULD be used for the Etag. If
|
|
||||||
there are minor (e.g. spelling) fixes to the terms of service, the
|
|
||||||
``TERMS_ETAG`` probably SHOULD NOT be changed. However, whenever users must
|
|
||||||
approve the new terms, the ``TERMS_ETAG`` MUST change. *)
|
|
||||||
val terms_etag : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Works the same as ``TERMS_DIR``, just for the privacy policy. *)
|
|
||||||
val privacy_dir : dir_path
|
|
||||||
|
|
||||||
(*
|
|
||||||
Works the same as ``TERMS_ETAG``, just for the privacy policy. *)
|
|
||||||
val privacy_etag : string
|
|
||||||
|
|
||||||
(*
|
|
||||||
Must be set to ``YES`` to enable AML/KYC rule enforcement. Note that the administrative endpoints will always work, even if the flag is set to ``NO``. *)
|
|
||||||
val enable_kyc : [ `YES | `NO ]
|
|
||||||
end
|
|
||||||
|
|
||||||
(* todo: KYC and AML options *)
|
|
||||||
|
|
||||||
(* The following options must be in the section "[taler-exchange-secmod-{rsa|cs|eddsa}]". *)
|
|
||||||
module type Secmod = sig
|
|
||||||
(*
|
|
||||||
How long do we generate denomination and signing keys ahead of time?
|
|
||||||
*)
|
|
||||||
val lookahead_sign : duration
|
|
||||||
|
|
||||||
(*
|
|
||||||
How much should validity periods for coins overlap?
|
|
||||||
Should be long enough to avoid problems with
|
|
||||||
wallets picking one key and then due to network latency
|
|
||||||
another key being valid. The ``DURATION_WITHDRAW`` period
|
|
||||||
must be longer than this value.
|
|
||||||
*)
|
|
||||||
val overlap_duration : duration
|
|
||||||
|
|
||||||
(*
|
|
||||||
Where should the security module store its long-term private key?
|
|
||||||
*)
|
|
||||||
val sm_priv_key : file_path
|
|
||||||
|
|
||||||
(*
|
|
||||||
Where should the security module store the private keys it manages?
|
|
||||||
*)
|
|
||||||
val key_dir : dir_path
|
|
||||||
|
|
||||||
(*
|
|
||||||
On which path should the security module listen for signing requests?
|
|
||||||
*)
|
|
||||||
val unixpath : not_relevant
|
|
||||||
end
|
|
||||||
|
|
||||||
module type Secmod_rsa = Secmod
|
|
||||||
module type Secmod_cs = Secmod
|
|
||||||
module type Secmod_eddsa = Secmod
|
|
||||||
|
|
||||||
(* The following options must be in the section "[exchangedb]". *)
|
|
||||||
module type Database = sig
|
|
||||||
(* TODO not sure about what unit of time/duration is used here *)
|
|
||||||
|
|
||||||
(*
|
|
||||||
After which time period should reserves be closed if they are idle? *)
|
|
||||||
val idle_reserve_expiration_time : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
After what time do we forget about (drained) reserves during garbage collection? *)
|
|
||||||
val legal_reserve_expiration_time : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
Delay between a deposit being eligible for aggregation and
|
|
||||||
the aggregator actually triggering. *)
|
|
||||||
val aggregator_shift : seconds
|
|
||||||
|
|
||||||
(*
|
|
||||||
Number of concurrent purses that a reserve may have active
|
|
||||||
if it is paid to be opened for a year. *)
|
|
||||||
val default_purse_limit : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
Maximum time an AML program is allowed to run.
|
|
||||||
(Optional for taler-auditor.) *)
|
|
||||||
val max_aml_program_runtime : int option
|
|
||||||
|
|
||||||
(*
|
|
||||||
The following options must be in section “[exchangedb-postgres]” if the
|
|
||||||
“postgres” plugin was selected for the database. *)
|
|
||||||
module type Postgres_backend = sig
|
|
||||||
(*
|
|
||||||
How to access the database, e.g. “postgres:///taler-exchange” to use the
|
|
||||||
“taler-exchange” database. Testcases use “talercheck”. *)
|
|
||||||
val config : string
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
(*
|
|
||||||
An exchange (or merchant) can have multiple bank accounts. The following
|
|
||||||
options are for sections named “[exchange-account-SOMETHING]”. The ``SOMETHING`` is
|
|
||||||
arbitrary and should be chosen to uniquely identify the bank account for
|
|
||||||
the operator. These options are used by the **taler-exchange-aggregator**, **taler-exchange-closer**, **taler-exchange-transfer** and **taler-exchange-wirewatch** tools. *)
|
|
||||||
module type Account = sig
|
|
||||||
val payto_uri : payto_uri
|
|
||||||
val enable_debit : [ `YES | `NO ]
|
|
||||||
val enable_credit : [ `YES | `NO ]
|
|
||||||
end
|
|
||||||
|
|
||||||
(*
|
|
||||||
Additionally, for each enabled account there MUST be another matching section named “[exchange-accountcredentials-SOMETHING]”. This section SHOULD be in a ``secret/`` configuration file that is only readable for the **taler-exchange-wirewatch** and **taler-exchange-transfer** processes. It contains the credentials to access the bank account: *)
|
|
||||||
module type Account_secret = sig
|
|
||||||
val wire_gateway_url : url
|
|
||||||
val wire_gateway_auth_method : string
|
|
||||||
val username : string
|
|
||||||
val password : string
|
|
||||||
val token : string
|
|
||||||
end
|
|
||||||
|
|
||||||
(*
|
|
||||||
The following options must be in sections starting with ``"[coin_]"`` and are
|
|
||||||
largely used by **taler-exchange-httpd** to determine the meta data for the
|
|
||||||
denomination keys. Some of the options are used by the
|
|
||||||
**taler-exchange-secmod-rsa** to determine which RSA keys to create (and of
|
|
||||||
what key length). Note that the section names must match, so this part of the
|
|
||||||
configuration MUST be shared between the RSA helper and the exchange.
|
|
||||||
Configuration values MUST NOT be changed in a running setup. Instead, if
|
|
||||||
parameters for a denomination type are to change, a fresh *section name* should
|
|
||||||
be introduced (and the existing section should be deleted).
|
|
||||||
*)
|
|
||||||
module type Coin = sig
|
|
||||||
val value : amount
|
|
||||||
val duration_withdraw : duration
|
|
||||||
val duration_spend : duration
|
|
||||||
val duration_legal : duration
|
|
||||||
val fee_withdraw : amount
|
|
||||||
val fee_deposit : amount
|
|
||||||
val fee_refresh : amount
|
|
||||||
val fee_refund : amount
|
|
||||||
|
|
||||||
(*
|
|
||||||
What cryptosystem should be used? Must be set to either "CS" or "RSA".
|
|
||||||
The respective crypto-helper will then generate the keys for this
|
|
||||||
denomination. *)
|
|
||||||
val cipher : [ `CS | `RSA ]
|
|
||||||
|
|
||||||
(*What is the RSA keysize modulos (in bits)? Only used if "CIPHER=RSA".*)
|
|
||||||
val rsa_keysize : int
|
|
||||||
|
|
||||||
(*
|
|
||||||
For this option to be accepted the extension for age
|
|
||||||
restriction MUST be enabled. *)
|
|
||||||
val age_restricted : [ (*`YES|*) `NO ]
|
|
||||||
end
|
|
||||||
|
|
||||||
(*
|
|
||||||
The functionality of the exchange can be extended by extensions. Those are
|
|
||||||
shared libraries which implement the extension-API of the exchange and are
|
|
||||||
located under ``$LIBDIR``, starting with prefix ``libtaler_extension_``. Each
|
|
||||||
extension can be enabled by adding a dedicated section
|
|
||||||
"[exchange-extension-<extensionname>]" and the following option:
|
|
||||||
*)
|
|
||||||
module type Extensions = sig
|
|
||||||
(*
|
|
||||||
If set to ``YES`` the extension ``<extensionsname>`` is enabled. Extension-specific
|
|
||||||
options might be set in the same section. *)
|
|
||||||
val enabled : [ (*`YES|*) `NO ]
|
|
||||||
end
|
|
||||||
|
|
||||||
(* The following options must be in the section "[exchange-offline]". *)
|
|
||||||
module type Offline_signing = sig
|
|
||||||
(*
|
|
||||||
Location of the master private key on disk. Only used by tools that
|
|
||||||
can be run offline (as the master key is for offline signing).
|
|
||||||
Mandatory. *)
|
|
||||||
val master_priv_file : file_path
|
|
||||||
|
|
||||||
(* TODO
|
|
||||||
- we need two different file
|
|
||||||
- there is three, not two, crypto helper modules
|
|
||||||
is it only two, because the eddsa one is not comptabilized as a "crypto helper" here? *)
|
|
||||||
(*
|
|
||||||
Where to store the public keys of both crypto helper modules.
|
|
||||||
Used to persist the keys after the first invocation of the tool,
|
|
||||||
so that if they ever change in the future, this is detected and
|
|
||||||
the tool can abort.
|
|
||||||
Mandatory. *)
|
|
||||||
val secm_tofu_file : file_path
|
|
||||||
|
|
||||||
(*
|
|
||||||
Public key of the (RSA) crypto helper module. Optional. If not given,
|
|
||||||
we will rely on TOFU. Note that once TOFU has been established,
|
|
||||||
this option will also be ignored. *)
|
|
||||||
val secm_denom_pubkey : string option
|
|
||||||
|
|
||||||
(*
|
|
||||||
Public key of the (EdDSA) crypto helper module. Optional. If not given,
|
|
||||||
we will rely on TOFU. Note that once TOFU has been established,
|
|
||||||
this option will also be ignored. *)
|
|
||||||
val secm_esign_pubkey : string option
|
|
||||||
end
|
|
||||||
|
|
||||||
module type Sanctions_check = sig
|
|
||||||
(* not implemented *)
|
|
||||||
end
|
|
||||||
|
|
||||||
(* -- ********************************** -- *)
|
|
||||||
let currency = `Eur
|
|
||||||
let currency_to_string = function `Eur -> "EUR"
|
|
||||||
|
|
||||||
(* Values that represent an amount are in the usual amount syntax: CURRENCY:VALUE.FRACTION,
|
|
||||||
e.g. EUR:1.50. The FRACTION portion may extend up to 8 places. *)
|
|
||||||
type value = {
|
|
||||||
currency: [ `Eur ];
|
|
||||||
value: int;
|
|
||||||
fraction: int;
|
|
||||||
}
|
|
||||||
|
|
||||||
let currency_round_unit = { currency= `Eur; value= 0; fraction= 1 }
|
|
||||||
|
|
||||||
let value_to_string v =
|
|
||||||
Fmt.str "%s:%d.%d" (currency_to_string v.currency) v.value v.fraction
|
|
||||||
|
|
||||||
(* https://docs.taler.net/manpages/taler-exchange.conf.5.html#exchange-coin-options *)
|
|
||||||
module Coin = struct
|
|
||||||
(* How much is the coin worth, the format is CURRENCY:VALUE.FRACTION. For
|
|
||||||
example, a 10 cent piece is “EUR:0.10”. *)
|
|
||||||
let value = { currency= `Eur; value= 0; fraction= 1 }
|
|
||||||
|
|
||||||
(*How long can a coin of this type be withdrawn? This limits the losses
|
|
||||||
incurred by the exchange when a denomination key is compromised.*)
|
|
||||||
let duration_withdraw = Duration.of_year 1
|
|
||||||
|
|
||||||
(*How long is a coin of the given type valid? Smaller values result in lower
|
|
||||||
storage costs for the exchange.*)
|
|
||||||
let duration_spend = Duration.of_year 1
|
|
||||||
|
|
||||||
(*How long is the coin of the given type legal?*)
|
|
||||||
let duration_legal = Duration.of_year 1
|
|
||||||
|
|
||||||
(*What does it cost to withdraw this coin? Specified using the same format as
|
|
||||||
value.*)
|
|
||||||
let fee_withdraw = { currency= `Eur; value= 0; fraction= 0 }
|
|
||||||
|
|
||||||
(*What does it cost to deposit this coin? Specified using the same format as
|
|
||||||
value.*)
|
|
||||||
let fee_deposit = { currency= `Eur; value= 0; fraction= 0 }
|
|
||||||
|
|
||||||
(*What does it cost to refresh this coin? Specified using the same format as
|
|
||||||
value.*)
|
|
||||||
let fee_refresh = { currency= `Eur; value= 0; fraction= 0 }
|
|
||||||
|
|
||||||
(*What does it cost to refund this coin? Specified using the same format as
|
|
||||||
value.*)
|
|
||||||
let fee_refund = { currency= `Eur; value= 0; fraction= 0 }
|
|
||||||
|
|
||||||
(*Which cipher to use for this coin? Must be either RSA or CS.*)
|
|
||||||
let cipher : [ `RSA | `CS ] = `RSA
|
|
||||||
|
|
||||||
(*How many bits should the RSA modulus (product of the two primes) have for
|
|
||||||
this type of coin.*)
|
|
||||||
let rsa_keysize = -1
|
|
||||||
|
|
||||||
(*Set to YES to make this a denomination with support*)
|
|
||||||
let age_restricted : [ `YES | `NO ] = `NO
|
|
||||||
end
|
|
||||||
|
|
||||||
(* Crockford Base32-encoded master public key, public version of the exchange’s long-time offline signing key. *)
|
|
||||||
let master_public_key = "uhuh"
|
|
||||||
|
|
||||||
(* module type for CS/EDDSA/RSA config *)
|
|
||||||
module Secmod = struct
|
|
||||||
(* Note that the taler-exchange-secmod-rsa also evaluates the [coin_*] configuration sections described below. *)
|
|
||||||
|
|
||||||
(*How long do we generate denomination and signing keys ahead of time?*)
|
|
||||||
let lookahead_sign = Duration.of_year 1
|
|
||||||
|
|
||||||
(*How much should validity periods for coins overlap? Should be long enough to avoid problems with wallets picking one key and then due to network latency another key being valid. The DURATION_WITHDRAW period must be longer than this value.*)
|
|
||||||
let overlap_duration = Duration.of_year 1
|
|
||||||
|
|
||||||
(*
|
|
||||||
Where should the security module store its long-term private key?
|
|
||||||
SM_PRIV_KEY
|
|
||||||
|
|
||||||
Where should the security module store the private keys it manages?
|
|
||||||
KEY_DIR
|
|
||||||
|
|
||||||
On which path should the security module listen for signing requests?
|
|
||||||
UNIXPATH
|
|
||||||
*)
|
|
||||||
end
|
|
||||||
|
|
||||||
module Database = struct
|
|
||||||
(*After which time period should reserves be closed if they are idle?*)
|
|
||||||
let idle_reserve_expiration_time = -1
|
|
||||||
|
|
||||||
(*After what time do we forget about (drained) reserves during garbage collection?*)
|
|
||||||
let legal_reserve_expiration_time = -1
|
|
||||||
|
|
||||||
(*Delay between a deposit being eligible for aggregation and the aggregator actually triggering.*)
|
|
||||||
let aggregator_shift = -1
|
|
||||||
|
|
||||||
(*Number of concurrent purses that a reserve may have active if it is paid to be opened for a year.*)
|
|
||||||
let default_purse_limit = -1
|
|
||||||
|
|
||||||
(*Maximum time an AML program is allowed to run. (Optional for taler-auditor.)*)
|
|
||||||
let max_aml_program_runtime = -1
|
|
||||||
|
|
||||||
module Postgres = struct
|
|
||||||
(*How to access the database, e.g. “postgres:///taler-exchange” to use the “taler-exchange” database. Testcases use “talercheck”.*)
|
|
||||||
let config = "uhuh"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
(* config_mte.ml
|
|
||||||
config value that are not in official config options *)
|
|
||||||
|
|
||||||
let default_lang = "en"
|
|
||||||
let default_encoding : [< `Identity | `DEFLATE | `Gzip ] = `Identity
|
|
||||||
|
|
||||||
(* TODO Taler documentation markdown mimetype should be the prefered one, and be
|
|
||||||
supported, according to DD we take text/plain as default instead for now *)
|
|
||||||
let default_mimetype = ("text", "plain")
|
|
||||||
let default_extension = ".txt"
|
|
||||||
let terms_dir = Fpath.(v "terms")
|
|
||||||
let privacy_dir = Fpath.(v "privacy")
|
|
||||||
|
|
||||||
(* ETAG is used as base filename it should be encoded in Crockford base-32 we do
|
|
||||||
not generate it and we do not verify it *)
|
|
||||||
let terms_etag = "0" |> Headers_lib.Etag.of_crockford32 |> Result.get_ok
|
|
||||||
let privacy_etag = "0" |> Headers_lib.Etag.of_crockford32 |> Result.get_ok
|
|
||||||
let terms_legal_version = "1"
|
|
||||||
let privacy_legal_version = "1"
|
|
||||||
|
|
@ -19,14 +19,14 @@ let select_language headers =
|
||||||
|> Cohttp.Accept.qsort
|
|> Cohttp.Accept.qsort
|
||||||
|> List.map (fun (_q, lang) -> lang)
|
|> List.map (fun (_q, lang) -> lang)
|
||||||
|> List.map (function
|
|> List.map (function
|
||||||
| Cohttp.Accept.AnyLanguage -> Config_mte.default_lang
|
| Cohttp.Accept.AnyLanguage -> Config.default_lang
|
||||||
| Language language_range -> (
|
| Language language_range -> (
|
||||||
(* ignore language subtags (e.g. "en-US" -> "en") *)
|
(* ignore language subtags (e.g. "en-US" -> "en") *)
|
||||||
match language_range with
|
match language_range with
|
||||||
| [] -> assert false
|
| [] -> assert false
|
||||||
| primary_tag :: _ -> primary_tag))
|
| primary_tag :: _ -> primary_tag))
|
||||||
|> List.find_opt Assets.is_supported_lang
|
|> List.find_opt Assets.is_supported_lang
|
||||||
|> Option.value ~default:Config_mte.default_lang
|
|> Option.value ~default:Config.default_lang
|
||||||
|
|
||||||
let select_encoding headers =
|
let select_encoding headers =
|
||||||
Vif.Headers.get headers "accept-encoding"
|
Vif.Headers.get headers "accept-encoding"
|
||||||
|
|
@ -37,7 +37,7 @@ let select_encoding headers =
|
||||||
| Cohttp.Accept.Identity -> Some `Identity
|
| Cohttp.Accept.Identity -> Some `Identity
|
||||||
| Deflate -> Some `DEFLATE
|
| Deflate -> Some `DEFLATE
|
||||||
| Gzip -> Some `Gzip
|
| Gzip -> Some `Gzip
|
||||||
| AnyEncoding -> Some Config_mte.default_encoding
|
| AnyEncoding -> Some Config.default_encoding
|
||||||
| Encoding _ | Compress -> (* unsupported *) None)
|
| Encoding _ | Compress -> (* unsupported *) None)
|
||||||
|> function
|
|> function
|
||||||
| [] -> assert false
|
| [] -> assert false
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ module Static = struct
|
||||||
in
|
in
|
||||||
let* () =
|
let* () =
|
||||||
(* todo: is it "taler-privacy-version" for /policy ? *)
|
(* todo: is it "taler-privacy-version" for /policy ? *)
|
||||||
add ~field:"taler-terms-version" Config_mte.terms_legal_version
|
add ~field:"taler-terms-version" Config.terms_legal_version
|
||||||
in
|
in
|
||||||
let* () =
|
let* () =
|
||||||
add ~field:"avail-languages" Headers.avail_languages_header_value
|
add ~field:"avail-languages" Headers.avail_languages_header_value
|
||||||
|
|
|
||||||
174
src/taler_config.ml
Normal file
174
src/taler_config.ml
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
(* https://docs.taler.net/manpages/taler-exchange.conf.5.html
|
||||||
|
taler-docs/manpages/taler-exchange.conf.5.rst *)
|
||||||
|
(* TODO
|
||||||
|
- generate `config.ml` from config file (virtual module)?
|
||||||
|
- parse config file format
|
||||||
|
- no relative path
|
||||||
|
- default config
|
||||||
|
- better types
|
||||||
|
- impl duration
|
||||||
|
*)
|
||||||
|
|
||||||
|
(* TODO unikernel *)
|
||||||
|
type dir_path
|
||||||
|
type file_path
|
||||||
|
|
||||||
|
(* TODO *)
|
||||||
|
(* Values that represent a time duration are represented as a series of one or more NUMBER UNIT pairs, e.g. 60 s, 4 weeks 1 day, 5 years 2 minutes. *)
|
||||||
|
type duration
|
||||||
|
|
||||||
|
(* TODO
|
||||||
|
make it Amount.t *)
|
||||||
|
type amount = string
|
||||||
|
type payto_uri = string
|
||||||
|
|
||||||
|
(* TODO
|
||||||
|
still need to parse them and tell that its not supported
|
||||||
|
some maybe are relevant
|
||||||
|
idk *)
|
||||||
|
type not_relevant
|
||||||
|
type url = string
|
||||||
|
type seconds = int
|
||||||
|
|
||||||
|
(* not relevant for mirage *)
|
||||||
|
(* this contains path that can be referenced in other with $PATH
|
||||||
|
(unsupported) *)
|
||||||
|
module type Global = sig
|
||||||
|
val taler_home : dir_path
|
||||||
|
val taler_data_home : dir_path
|
||||||
|
val taler_config_home : dir_path
|
||||||
|
val taler_cache_home : dir_path
|
||||||
|
val taler_runtime_dir : dir_path
|
||||||
|
end
|
||||||
|
|
||||||
|
(* sections "[currency-$NAME]"
|
||||||
|
see DD51 *)
|
||||||
|
module type Currency = sig
|
||||||
|
val enabled : [ `YES | `NO ]
|
||||||
|
val code : string
|
||||||
|
val name : string
|
||||||
|
val fractional_input_digits : int
|
||||||
|
val fractional_normal_digits : int
|
||||||
|
val fractional_trailing_zero_digits : int
|
||||||
|
val alt_unit_names : (int * string) list
|
||||||
|
end
|
||||||
|
|
||||||
|
(* section "[exchange]" *)
|
||||||
|
module type Exchange = sig
|
||||||
|
val currency : string
|
||||||
|
val currency_round_unit : amount
|
||||||
|
val db : string
|
||||||
|
val attribute_encryption_key : string
|
||||||
|
val serve : [ `Unix | `Tcp | `Systemd ]
|
||||||
|
val unixpath : file_path
|
||||||
|
val unixpath_mode : int
|
||||||
|
val port : int
|
||||||
|
val bind_to : string
|
||||||
|
val master_public_key : string
|
||||||
|
val tiny_amount : amount option
|
||||||
|
val shopping_url : url option
|
||||||
|
val open_banking_gateway_url : url option
|
||||||
|
val aml_spa_dialect : string option
|
||||||
|
val bank_compliance_language : string option
|
||||||
|
val stefan_abs : amount
|
||||||
|
val stefan_log : amount
|
||||||
|
val stefan_lin : float
|
||||||
|
val base_url : url
|
||||||
|
val toplevel_redirect_url : string option
|
||||||
|
val aggregator_idle_sleep_interval : seconds
|
||||||
|
val closer_idle_sleep_interval : seconds
|
||||||
|
val transfer_idle_sleep_interval : seconds
|
||||||
|
val wirewatch_idle_sleep_interval : seconds
|
||||||
|
val aggregator_shard_size : int option
|
||||||
|
val signkey_legal_duration : duration
|
||||||
|
val max_keys_caching : duration
|
||||||
|
val max_requests : int
|
||||||
|
val terms_dir : dir_path
|
||||||
|
val terms_etag : string
|
||||||
|
val privacy_dir : dir_path
|
||||||
|
val privacy_etag : string
|
||||||
|
val enable_kyc : [ `YES | `NO ]
|
||||||
|
end
|
||||||
|
|
||||||
|
(* section "[taler-exchange-secmod-{rsa|cs|eddsa}]". *)
|
||||||
|
module type Secmod = sig
|
||||||
|
val lookahead_sign : duration
|
||||||
|
val overlap_duration : duration
|
||||||
|
val sm_priv_key : file_path
|
||||||
|
val key_dir : dir_path
|
||||||
|
val unixpath : not_relevant
|
||||||
|
end
|
||||||
|
|
||||||
|
module type Secmod_rsa = Secmod
|
||||||
|
module type Secmod_cs = Secmod
|
||||||
|
module type Secmod_eddsa = Secmod
|
||||||
|
|
||||||
|
(* TODO config
|
||||||
|
what is the time/duration unit used here? *)
|
||||||
|
(* section "[exchangedb]". *)
|
||||||
|
module type Database = sig
|
||||||
|
val idle_reserve_expiration_time : seconds
|
||||||
|
val legal_reserve_expiration_time : seconds
|
||||||
|
val aggregator_shift : seconds
|
||||||
|
val default_purse_limit : int
|
||||||
|
val max_aml_program_runtime : int option
|
||||||
|
|
||||||
|
module type Postgres_backend = sig
|
||||||
|
val config : string
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
(* sections "[coin_XXX]"
|
||||||
|
used by secmods *)
|
||||||
|
module type Coin = sig
|
||||||
|
val value : amount
|
||||||
|
val duration_withdraw : duration
|
||||||
|
val duration_spend : duration
|
||||||
|
val duration_legal : duration
|
||||||
|
val fee_withdraw : amount
|
||||||
|
val fee_deposit : amount
|
||||||
|
val fee_refresh : amount
|
||||||
|
val fee_refund : amount
|
||||||
|
val cipher : [ `CS | `RSA ]
|
||||||
|
val rsa_keysize : int option (*only if `RSA *)
|
||||||
|
val age_restricted : [ (*`YES|*) `NO ]
|
||||||
|
end
|
||||||
|
|
||||||
|
(* sections "[exchange-account-XXX]" *)
|
||||||
|
module type Account = sig
|
||||||
|
val payto_uri : payto_uri
|
||||||
|
val enable_debit : [ `YES | `NO ]
|
||||||
|
val enable_credit : [ `YES | `NO ]
|
||||||
|
end
|
||||||
|
|
||||||
|
(* sections "[exchange-accountcredentials-XXX]"
|
||||||
|
must exists for each "[exchange-account-XXX]" section
|
||||||
|
|
||||||
|
! credentials to access the bank account
|
||||||
|
should be in a secret configuration file
|
||||||
|
only redable for `taler-exchange-wirewatch` `taler-exchange-transfer` processes *)
|
||||||
|
module type Account_secret = sig
|
||||||
|
val wire_gateway_url : url
|
||||||
|
val wire_gateway_auth_method : string
|
||||||
|
val username : string
|
||||||
|
val password : string
|
||||||
|
val token : string
|
||||||
|
end
|
||||||
|
|
||||||
|
(* section "[exchange-extension-<extensionname>]" *)
|
||||||
|
module type Extensions = sig
|
||||||
|
val enabled : [ (*`YES|*) `NO ]
|
||||||
|
end
|
||||||
|
|
||||||
|
(* section "[exchange-offline]". *)
|
||||||
|
module type Offline_signing = sig
|
||||||
|
val master_priv_file : file_path
|
||||||
|
|
||||||
|
(* TODO
|
||||||
|
- we need two different file here
|
||||||
|
- there is three, not two, crypto helper modules
|
||||||
|
is it only two, because the eddsa one is not comptabilized as a "crypto helper" here? *)
|
||||||
|
val secm_tofu_file : file_path
|
||||||
|
val secm_denom_pubkey : string option
|
||||||
|
val secm_esign_pubkey : string option
|
||||||
|
end
|
||||||
|
|
@ -24,7 +24,7 @@ module Mimetype = struct
|
||||||
List.find_opt (( = ) (m, m_sub)) mimetype_l
|
List.find_opt (( = ) (m, m_sub)) mimetype_l
|
||||||
| AnyMediaSubtype m ->
|
| AnyMediaSubtype m ->
|
||||||
List.find_opt (fun (m', _) -> String.equal m m') mimetype_l
|
List.find_opt (fun (m', _) -> String.equal m m') mimetype_l
|
||||||
| AnyMedia -> Some Config_mte.default_mimetype
|
| AnyMedia -> Some Config.default_mimetype
|
||||||
|
|
||||||
let to_extension (m, m_sub) =
|
let to_extension (m, m_sub) =
|
||||||
assert (m <> "*");
|
assert (m <> "*");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue