open Parse_config let config_filename = "mte.conf" let secrets_dir = Fpath.v "secrets" let secmod_dir = Fpath.(secrets_dir / "secmod") (* TODO config *) let secmod_eddsa_dir = Fpath.(secrets_dir / "secmod_eddsa") let config_data = match Assets_crunch.read config_filename with | None -> fail "static file not found: `%s`" config_filename | Some data -> let v = Config_section.parse data in v module Exchange = struct let get_opt field = get_opt config_data ~section:"exchange" ~field let get field = get config_data ~section:"exchange" ~field (* - *) let currency = (* todo: constraint on currency string *) get "currency" let currency_round_unit = get "currency_round_unit" |> amount let db = get "db" |> const_value "postgres" let attribute_encryption_key = get "attribute_encryption_key" let port = get "port" |> int let bind_to = get "bind_to" let master_public_key = get "master_public_key" |> ed25519 (* TODO Defaults to 0.0 if not specified. *) let stefan_abs = get "stefan_abs" |> amount let stefan_log = get "stefan_log" |> amount let stefan_lin = get_opt "stefan_lin" |> Option.map float |> Option.value ~default:0.0 let aggregator_idle_sleep_interval = get "aggregator_idle_sleep_interval" |> duration let closer_idle_sleep_interval = get "closer_idle_sleep_interval" |> duration let transfer_idle_sleep_interval = get "transfer_idle_sleep_interval" |> duration let wirewatch_idle_sleep_interval = get "wirewatch_idle_sleep_interval" |> duration let signkey_legal_duration = get "signkey_legal_duration" |> duration let max_keys_caching = get "max_keys_caching" |> duration let enable_kyc = get "enable_kyc" |> yes_no let terms_etag = get "terms_etag" |> etag let privacy_etag = get "privacy_etag" |> etag let base_url = get "base_url" let shopping_url = get_opt "shopping_url" let open_banking_gateway_url = get_opt "open_banking_gateway_url" let bank_compliance_language = get_opt "bank_compliance_language" let aml_spa_dialect = get_opt "aml_spa_dialect" let toplevel_redirect_url = get_opt "toplevel_redirect_url" let tiny_amount = get_opt "tiny_amount" |> Option.map amount (* not implemented or not relevant to MTE: let max_requests = get "max_requests" |> int aggregator_shard_size serve unixpath unixpath_mode terms_dir privacy_dir *) end module Exchangedb = struct let get field = get config_data ~section:"exchangedb" ~field (* - *) let idle_reserve_expiration_time = get "idle_reserve_expiration_time" |> duration let legal_reserve_expiration_time = get "legal_reserve_expiration_time" |> duration let aggregator_shift = get "aggregator_shift" |> duration let max_aml_program_runtime = get "max_aml_program_runtime" |> duration let default_purse_limit = get "default_purse_limit" |> int end module Exchangedb_postgres = struct let config = get config_data ~section:"exchangedb-postgres" ~field:"config" |> uri end module Currency = struct type t = { enabled: [ `YES | `NO ]; code: string; name: string; fractional_input_digits: int; fractional_normal_digits: int; fractional_trailing_zero_digits: int; alt_unit_names: (int * string) list; } let currency_sections = List.filter (fun v -> String.starts_with ~prefix:"currency-" v.header) config_data let parse_currency section = let get field = get config_data ~section:section.header ~field in { enabled= get "enabled" |> yes_no; code= get "code"; name= get "name"; fractional_input_digits= get "fractional_input_digits" |> int; fractional_normal_digits= get "fractional_normal_digits" |> int; fractional_trailing_zero_digits= get "fractional_trailing_zero_digits" |> int; alt_unit_names= get "alt_unit_names" |> Alt_unit_names.decode |> Parse_config.unwrap; } let all_currencies = List.map parse_currency currency_sections (* I think the exchange only handle one currency *) let v = match List.find_opt (fun v -> v.code = Exchange.currency) all_currencies with | None -> fail "section `[currency-%s]` not found, currency `%s` is not defined" Exchange.currency Exchange.currency | Some v -> ( match v.enabled = `YES with | false -> fail "currency `%s` is not enabled" Exchange.currency | true -> v) end module Coin = struct type t = { section_name: string; value: Amount.t; duration_withdraw: Time.Relative.t; duration_spend: Time.Relative.t; duration_legal: Time.Relative.t; fee_withdraw: Amount.t; fee_deposit: Amount.t; fee_refresh: Amount.t; fee_refund: Amount.t; cipher: [ (* `CS |*) `RSA ]; rsa_keysize: int; (* : int option (only if `RSA) *) age_restricted: [ (*`YES|*) `NO ]; } let coin_sections = List.filter (fun v -> (* note: here its a '_' not '-' *) String.starts_with ~prefix:"coin_" v.header) config_data let parse_coin section = let get field = get config_data ~section:section.header ~field in let section_name = String.sub section.header 5 (String.length section.header - 5) in { section_name; value= get "value" |> amount; duration_withdraw= get "duration_withdraw" |> duration; duration_spend= get "duration_spend" |> duration; duration_legal= get "duration_legal" |> duration; fee_withdraw= get "fee_withdraw" |> amount; fee_deposit= get "fee_deposit" |> amount; fee_refresh= get "fee_refresh" |> amount; fee_refund= get "fee_refund" |> amount; cipher= (get "cipher" |> const_value "RSA" |> fun _s -> `RSA); rsa_keysize= get "rsa_keysize" |> int; age_restricted= ( get "age_restricted" |> yes_no |> function | `NO -> `NO | `YES -> fail "`age_restricted = YES` is not supported" ); } let all_coins = List.map parse_coin coin_sections end module Exchange_secmod_rsa = struct let get field = let section = "taler-exchange-secmod-" ^ "rsa" in get config_data ~section ~field let lookahead_sign = get "lookahead_sign" |> duration let overlap_duration = get "overlap_duration" |> duration (* not relevant: sm_priv_key key_dir unixpath *) end module Exchange_secmod_eddsa = struct let get field = let section = "taler-exchange-secmod-" ^ "eddsa" in get config_data ~section ~field let lookahead_sign = get "lookahead_sign" |> duration let overlap_duration = get "overlap_duration" |> duration let duration = get "duration" |> duration (* TODO config LOOKAHEAD_SIGN How long do we generate denomination and signing keys ahead of time? OVERLAP_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. DURATION For how long should EdDSA keys be valid for signing? SM_PRIV_KEY Where should the security module store its long-term private key? KEY_DIR Where should the security module store the private keys it manages? UNIXPATH On which path should the security module listen for signing requests? *) end (* -- *) include Exchange