/*
This file is part of TALER
(C) 2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
*/
/**
* @file taler-merchant-httpd_contract.h
* @brief shared logic for contract terms handling
* @author Christian Blättler
*/
#include "taler-merchant-httpd.h"
#include
#include
#include
/**
* Possible versions of the contract terms.
*/
enum TALER_MerchantContractVersion
{
/**
* Version 0
*/
TALER_MCV_V0 = 0,
/**
* Version 1
*/
TALER_MCV_V1 = 1
};
/**
* Possible token kinds.
*/
enum TALER_MerchantContractTokenKind
{
/**
* Subscription token kind
*/
TALER_MCTK_SUBSCRIPTION = 0,
/**
* Discount token kind
*/
TALER_MCTK_DISCOUNT = 1
};
/**
* Possible input types for the contract terms.
*/
enum TALER_MerchantContractInputType
{
/**
* Input type invalid
*/
TALER_MCIT_INVALID = 0,
/**
* Input type coin
*/
TALER_MCIT_COIN = 1,
/**
* Input type token
*/
TALER_MCIT_TOKEN = 2
};
/**
* Contract input (part of the v1 contract terms).
*/
struct TALER_MerchantContractInput
{
/**
* Type of the input.
*/
enum TALER_MerchantContractInputType type;
union
{
/**
* Coin-based input (ration). (Future work, only here for reference)
*/
// struct
// {
// /**
// * Price to be paid.
// */
// struct TALER_Amount price;
// /**
// * Base URL of the ration authority.
// */
// const char *ration_authority_url;
// } coin;
/**
* Token-based input.
*/
struct
{
/**
* Slug of the token family to be used.
*/
const char *token_family_slug;
/**
* Start time of the validity period of the token. Base on this timestamp
* the wallet can find the correct key for this token in token_authorities.
*/
struct GNUNET_TIME_Timestamp valid_after;
/**
* Number of tokens of this type required. Defaults to one if the
* field is not provided.
*/
unsigned int count;
} token;
} details;
};
/**
* Possible output types for the contract terms.
*/
enum TALER_MerchantContractOutputType
{
/**
* Invalid output type
*/
TALER_MCOT_INVALID = 0,
/**
* Output type coin
*/
TALER_MCOT_COIN = 1,
/**
* Output type token
*/
TALER_MCOT_TOKEN = 2,
/**
* Output type tax-receipt
*/
TALER_MCOT_TAX_RECEIPT = 3
};
/**
* Contract output (part of the v1 contract terms).
*/
struct TALER_MerchantContractOutput
{
/**
* Type of the output.
*/
enum TALER_MerchantContractOutputType type;
union
{
/**
* Coin-based output.
*/
struct {
/**
* Coins that will be yielded. This excludes any applicable withdraw fees.
*/
struct TALER_Amount brutto_yield;
/**
* Base URL of the exchange that will issue the coins.
*/
const char *exchange_url;
} coin;
/**
* Tax-receipt output.
*/
struct
{
/**
* Base URL of the donation authority that will issue the tax receipt.
*/
const char *donau_url;
} tax_receipt;
/**
* Token-based output.
*/
struct
{
/**
* Slug of the token family to be issued.
*/
const char *token_family_slug;
/**
* Start time of the validity period of the token. Base on this timestamp
* the wallet can find the correct key for this token in token_authorities.
*/
struct GNUNET_TIME_Timestamp valid_after;
/**
* Number of tokens of this type required. Defaults to one if the
* field is not provided.
*/
unsigned int count;
} token;
} details;
};
/**
* Contract choice (part of the v1 contract terms).
*/
struct TALER_MerchantContractChoice
{
/**
* List of inputs the wallet must provision (all of them) to satisfy the
* conditions for the contract.
*/
struct TALER_MerchantContractInput *inputs;
/**
* Length of the @e inputs array.
*/
unsigned int inputs_len;
/**
* List of outputs the merchant promises to yield (all of them) once
* the contract is paid.
*/
struct TALER_MerchantContractOutput *outputs;
/**
* Length of the @e outputs array.
*/
unsigned int outputs_len;
};
/**
* Public key and corresponding metadata for a token family.
*/
struct TALER_MerchantContractTokenFamilyKey
{
/**
* Public key.
*/
struct TALER_TokenIssuePublicKeyP pub;
/**
* Tokens signed by this key will be valid after this time.
*/
struct GNUNET_TIME_Timestamp valid_after;
/**
* Tokens signed by this key will be valid before this time.
*/
struct GNUNET_TIME_Timestamp valid_before;
};
struct TALER_MerchantContractTokenFamily
{
/**
* Slug of the token family.
*/
const char *slug;
/**
* Human-readable name of the token family.
*/
char *name;
/**
* Human-readable description of the semantics of the tokens issued by
* this token family.
*/
char *description;
/**
* Map from IETF BCP 47 language tags to localized description.
*/
json_t *description_i18n;
/**
* Relevant public keys of this token family for the given contract.
*/
struct TALER_MerchantContractTokenFamilyKey *keys;
/**
* Length of the @e keys array.
*/
unsigned int keys_len;
/**
* Must a wallet understand this token type to process contracts that
* consume or yield it?
*/
bool critical;
/**
* Kind of the token family.
*/
enum TALER_MerchantContractTokenKind kind;
/**
* Kind-specific information about the token.
*/
union
{
/**
* Subscription token.
*/
struct
{
/**
* Array of domain names where this subscription can be safely used
* (e.g. the issuer warrants that these sites will re-issue tokens of
* this type if the respective contract says so). May contain "*" for
* any domain or subdomain.
*/
const char **trusted_domains;
/**
* Length of the @e trusted_domains array.
*/
unsigned int trusted_domains_len;
} subscription;
/**
* Discount token.
*/
struct
{
/**
* Array of domain names where this discount token is intended to be
* used. May contain "*" for any domain or subdomain. Users should be
* warned about sites proposing to consume discount tokens of this
* type that are not in this list that the merchant is accepting a
* coupon from a competitor and thus may be attaching different
* semantics (like get 20% discount for my competitors 30% discount
* token).
*/
const char **expected_domains;
/**
* Length of the @e expected_domains array.
*/
unsigned int expected_domains_len;
} discount;
} details;
};
/**
* Struct to hold contract terms in v0 and v1 format. v0 contracts are modelled
* as a v1 contract with a single choice and no inputs and outputs. Use the
* version field to explicitly differentiate between v0 and v1 contracts.
*/
struct TALER_MerchantContract
{
/**
* URL where the same contract could be ordered again (if available).
*/
const char *public_reorder_url;
/**
* Our order ID.
*/
const char *order_id;
/**
* Merchant base URL.
*/
char *merchant_base_url;
/**
* Merchant information.
*/
struct
{
/**
* Legal name of the instance
*/
char *name;
/**
* Merchant's site url
*/
char *website;
/**
* Email contact for customers
*/
char *email;
/**
* merchant's logo data uri
*/
char *logo;
/**
* Merchant address
*/
json_t *address;
/**
* Jurisdiction of the business
*/
json_t *jurisdiction;
} merchant;
/**
* Price to be paid for the transaction. Could be 0. The price is in addition
* to other instruments, such as rations and tokens.
* The exchange will subtract deposit fees from that amount
* before transferring it to the merchant.
*/
struct TALER_Amount brutto;
/**
* Summary of the contract.
*/
const char *summary;
/**
* Internationalized summary.
*/
json_t *summary_i18n;
/**
* URL that will show that the contract was successful
* after it has been paid for.
*/
const char *fulfillment_url;
/**
* Message shown to the customer after paying for the contract.
* Either fulfillment_url or fulfillment_message must be specified.
*/
const char *fulfillment_message;
/**
* Map from IETF BCP 47 language tags to localized fulfillment messages.
*/
json_t *fulfillment_message_i18n;
/**
* Array of products that are part of the purchase.
*/
const json_t *products;
/**
* Timestamp of the contract.
*/
struct GNUNET_TIME_Timestamp timestamp;
/**
* Deadline for refunds.
*/
struct GNUNET_TIME_Timestamp refund_deadline;
/**
* Specifies for how long the wallet should try to get an
* automatic refund for the purchase.
*/
struct GNUNET_TIME_Relative auto_refund;
/**
* Payment deadline.
*/
struct GNUNET_TIME_Timestamp pay_deadline;
/**
* Wire transfer deadline.
*/
struct GNUNET_TIME_Timestamp wire_deadline;
/**
* Delivery date.
*/
struct GNUNET_TIME_Timestamp delivery_date;
/**
* Delivery location.
*/
json_t *delivery_location;
/**
* Nonce generated by the wallet and echoed by the merchant
* in this field when the proposal is generated.
*/
const char *nonce;
/**
* Extra data that is only interpreted by the merchant frontend.
*/
const json_t *extra;
/**
* Specified version of the contract.
*/
enum TALER_MerchantContractVersion version;
/**
* Array of possible specific contracts the wallet/customer may choose
* from by selecting the respective index when signing the deposit
* confirmation.
*/
struct TALER_MerchantContractChoice *choices;
/**
* Length of the @e choices array.
*/
unsigned int choices_len;
/**
* Array of token authorities.
*/
struct TALER_MerchantContractTokenFamily *token_authorities;
/**
* Length of the @e token_authorities array.
*/
unsigned int token_authorities_len;
/**
* Maximum fee as given by the client request.
*/
struct TALER_Amount max_fee;
// TODO: Add exchanges array
};
enum TALER_MerchantContractInputType
TMH_contract_input_type_from_string (const char *str);
enum TALER_MerchantContractOutputType
TMH_contract_output_type_from_string (const char *str);
const char *
TMH_string_from_contract_input_type (enum TALER_MerchantContractInputType t);
const char *
TMH_string_from_contract_output_type (enum TALER_MerchantContractOutputType t);
/**
* Serialize @a contract to a JSON object, ready to be stored in the database.
* The @a contract can be of v0 or v1.
*
* @param[in] contract contract struct to serialize
* @param[in] instance merchant instance for this contract
* @param[in] exchanges JSON array of exchanges
* @param[out] out serialized contract as JSON object
* @return #GNUNET_OK on success
* #GNUNET_NO if @a contract was not valid
* #GNUNET_SYSERR on failure
*/
enum GNUNET_GenericReturnValue
TMH_serialize_contract (const struct TALER_MerchantContract *contract,
const struct TMH_MerchantInstance *instance,
json_t *exchanges,
json_t **out);
enum GNUNET_GenericReturnValue
TMH_serialize_contract_v0 (const struct TALER_MerchantContract *contract,
const struct TMH_MerchantInstance *instance,
json_t *exchanges,
json_t **out);
enum GNUNET_GenericReturnValue
TMH_serialize_contract_v1 (const struct TALER_MerchantContract *contract,
const struct TMH_MerchantInstance *instance,
json_t *exchanges,
json_t **out);
/**
* Provide specification to parse given JSON array to an array
* of contract choices.
*
* @param name name of the choices field in the JSON
* @param[out] choices pointer to the first element of the array
* @param[out] choices_len pointer to the length of the array
* @return spec for parsing a choices array
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_choices (const char *name,
struct TALER_MerchantContractChoice **choices,
unsigned int *choices_len);
/**
* Provide specification to parse given JSON object to an array
* of token families.
*
* @param name name of the token families field in the JSON
* @param[out] families pointer to the first element of the array
* @param[out] families_len pointer to the length of the array
* @return spec for parsing a token families object
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_token_families (const char *name,
struct TALER_MerchantContractTokenFamily **families,
unsigned int *families_len);
/**
* Find matching token family in @a families based on @a slug. Then use
* @a valid_after to find the matching public key within it.
*
* @param slug slug of the token family
* @param valid_after start time of the validity period of the key
* @param families array of token families to search in
* @param families_len length of the @a families array
* @param[out] family found family, set to NULL to only check for existence
* @param[out] key found key, set to NULL to only check for existence
* @return #GNUNET_OK on success #GNUNET_NO if no key was found
*/
enum GNUNET_GenericReturnValue
TMH_find_token_family_key (const char *slug,
struct GNUNET_TIME_Timestamp valid_after,
struct TALER_MerchantContractTokenFamily *families,
unsigned int families_len,
struct TALER_MerchantContractTokenFamily *family,
struct TALER_MerchantContractTokenFamilyKey *key);