From 14666fb836e80a41f305171bfa8c7bc53b75a7e2 Mon Sep 17 00:00:00 2001 From: Swrup Date: Wed, 1 Oct 2025 19:34:42 +0200 Subject: [PATCH] wip management todo --- src/assets.ml | 14 +++-- src/config.ml | 127 ++++++++++++++++++++++++++++++++++++++++----- src/dune | 3 +- src/headers_lib.ml | 21 ++++---- src/management.ml | 24 +++++++++ src/types.ml | 2 +- 6 files changed, 158 insertions(+), 33 deletions(-) create mode 100644 src/management.ml diff --git a/src/assets.ml b/src/assets.ml index dbc408d2..5116e366 100644 --- a/src/assets.ml +++ b/src/assets.ml @@ -1,13 +1,11 @@ -(* module to handle assets. - for now, assets are defined to all be in `src/assets/` folder. - crunched into the [Assets_crunch] module. +(* module to handle assets. for now, assets are defined to all be in + `src/assets/` folder. crunched into the [Assets_crunch] module. - to keep it simple, we require that /terms and /privacy support the same - set of languages X mimetypes *) + to keep it simple, we require that /terms and /privacy support the same set + of languages X mimetypes *) -(* docs: - https://docs.taler.net/manpages/taler-exchange.conf.5.html - https://docs.taler.net/design-documents/003-tos-rendering.html *) +(* docs: https://docs.taler.net/manpages/taler-exchange.conf.5.html + https://docs.taler.net/design-documents/003-tos-rendering.html *) (* todo: maybe move this type to config.ml *) type t = Terms | Privacy diff --git a/src/config.ml b/src/config.ml index 7960b13c..f5b0b0a8 100644 --- a/src/config.ml +++ b/src/config.ml @@ -1,23 +1,126 @@ -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" - +(* https://docs.taler.net/manpages/taler-exchange.conf.5.html#exchange-options *) (* TODO - generate `config.ml` from config file (virtual module)? - no relative path *) +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 *) +(* 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" + +(* ---- *) +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 + +(* todo: use relevant duration, all set to 1 year for now *) + +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 diff --git a/src/dune b/src/dune index bd0df5e4..fc4f47b2 100644 --- a/src/dune +++ b/src/dune @@ -1,11 +1,12 @@ (executable (public_name mte) (name mte) - (modules assets assets_crunch headers mte config util types) + (modules assets assets_crunch headers mte config util types management) (libraries headers_lib syntax ; + duration vif fmt jsont diff --git a/src/headers_lib.ml b/src/headers_lib.ml index 289e8018..c54081b4 100644 --- a/src/headers_lib.ml +++ b/src/headers_lib.ml @@ -1,11 +1,10 @@ (* independent library for headers fields value *) -(* TODO - - test - - can still bypass this module and directly set Etag header, but its fine *) +(* TODO - test - can still bypass this module and directly set Etag header, but + its fine *) module Etag : sig - (* module to parse etags header fields - used by If-Match and If-None-Match headers + (* module to parse etags header fields used by If-Match and If-None-Match + headers https://httpwg.org/specs/rfc9110.html#field.etag *) type t @@ -70,12 +69,12 @@ end = struct else invalid_etag)) |> Result.map (fun l -> Etag_list l) - (* To evaluate a received If-None-Match header field: - - If the field value is "*", the condition is false - if the origin server has a current representation for the target resource. - - If the field value is a list of entity tags, the condition is false - if one of the listed tags matches the entity tag of the selected representation. - - Otherwise, the condition is true. *) + (* To evaluate a received If-None-Match header field: - If the field value is + "*", the condition is false if the origin server has a current + representation for the target resource. - If the field value is a list of + entity tags, the condition is false if one of the listed tags matches the + entity tag of the selected representation. - Otherwise, the condition is + true. *) let evaluate t header_value = match header_value with | Any_etag -> false diff --git a/src/management.ml b/src/management.ml new file mode 100644 index 00000000..25d6825c --- /dev/null +++ b/src/management.ml @@ -0,0 +1,24 @@ +(* TODO + + https://docs.taler.net/taler-exchange-manual.html#offline-signing-setup-key-maintenance-and-tear-down + + + The exchange HTTP service must be running before you can complete the following offline signing procedure. Note that when an exchange is running without offline keys its not fully operational. To make the exchange HTTP service fully operational, the following steps involving the offline signing machine must be completed: + + 1) The public keys of various online keys used by the exchange service are exported via a management HTTP API. + + 2) The offline signing system validates this request and signs it. + Additionally, the offline signing system signs policy messages to configure the exchange’s bank + accounts and associated fees. + + 3) The messages generated by the offline signing system are uploaded via the management API + of the exchange HTTP service. +*) + +(* + - generate (pub&priv) key for online signing key + - generate (pub&priv) key for denomination(s) + - implement `GET /management/keys` + - implement `POST /management/keys` + - offline tool do: GET -> sign -> POST + - now we should have a server with valid keys signed by the master offline key *) diff --git a/src/types.ml b/src/types.ml index 7ba4d474..97699500 100644 --- a/src/types.ml +++ b/src/types.ml @@ -1,7 +1,7 @@ (* https://docs.taler.net/core/api-common.html#tsref-type-ErrorDetail *) module ErrorDetail = struct (* TODO GANA error codes - https://git.gnunet.org/gana.git/tree/gnu-taler-error-codes/registry.rec *) + https://git.gnunet.org/gana.git/tree/gnu-taler-error-codes/registry.rec *) type t = { code: int; hint: string option } let make code hint = { code; hint }