merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 96c0fe1e71b2649c44f759d429579d2c830a6969
parent 0f77f90b48116c6509d1137b034724fc5f922c79
Author: Martin Schanzenbach <schanzen@gnunet.org>
Date:   Thu, 19 Jun 2025 10:22:26 +0200

cleanup and documentation

Diffstat:
Msrc/backend/taler-merchant-httpd.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/backend/taler-merchant-httpd.h | 11++++++++++-
Msrc/backend/taler-merchant-httpd_private-post-instances-ID-token.c | 21++-------------------
3 files changed, 100 insertions(+), 32 deletions(-)

diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c @@ -211,49 +211,105 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; */ char *TMH_default_pass; -#define THM_MAX_SCOPE_PERMISSIONS_LEN 4096 +/** + * Maximum length of a permissions string of a scope + */ +#define TMH_MAX_SCOPE_PERMISSIONS_LEN 4096 +/** + * Maximum length of a name of a scope + */ +#define TMH_MAX_NAME_LEN 255 + +/** + * Represents a hard-coded set of default scopes with their + * permissions and names + */ struct ScopePermissionMap { + /** + * The scope enum value + */ enum TMH_AuthScope as; - char permissions[THM_MAX_SCOPE_PERMISSIONS_LEN]; + + /** + * The scope name + */ + char name[TMH_MAX_NAME_LEN]; + + /** + * The scope permissions string. + * Comma-separated. + */ + char permissions[TMH_MAX_SCOPE_PERMISSIONS_LEN]; }; +/** + * The default scopes array for merchant + */ struct ScopePermissionMap scope_permissions[] = { + /* Deprecated since v42 */ + { + .as = TMH_AS_ADMIN, + .name = "write", + .permissions = "*" + }, + /* Full access */ { - .as = TMH_AS_ALL, + .as = TMH_AS_ADMIN, + .name = "admin", .permissions = "*" }, + /* Read-only access */ { .as = TMH_AS_READ_ONLY, + .name = "readonly", .permissions = "*-read" }, + /* Simple order management */ { .as = TMH_AS_ORDER_SIMPLE, + .name = "order-simple", .permissions = "orders-read,orders-write" }, + /* Simple order management for PoS, also allows inventory locking */ { .as = TMH_AS_ORDER_POS, + .name = "order-pos", .permissions = "orders-read,orders-write,inventory-lock" }, + /* Simple order management, also allows refunding */ { .as = TMH_AS_ORDER_MGMT, + .name = "order-mgmt", .permissions = "orders-read,orders-write,orders-refund" }, + /* Full order management, allows inventory locking and refunds */ { .as = TMH_AS_ORDER_FULL, + .name = "order-full", .permissions = "orders-read,orders-write,inventory-lock,orders-refund" }, + /* No permissions, dummy scope */ { .as = TMH_AS_NONE, } }; +/** + * Get permissions string for scope. + * Also extracts the leftmost bit into the @a refreshable + * output parameter. + * + * @param as the scope to get the permissions string from + * @param[out] refreshable true if the token associated with this scope is refreshable. + * @return the permissions string, or NULL if no such scope found + */ static const char* get_scope_permissions (enum TMH_AuthScope as, bool *refreshable) { *refreshable = as & TMH_AS_REFRESHABLE; - if (as != TMH_AS_ALL) + if (as != TMH_AS_ADMIN) as &= ~TMH_AS_REFRESHABLE; for (int i = 0; TMH_AS_NONE != scope_permissions[i].as; i++) { @@ -264,9 +320,17 @@ get_scope_permissions (enum TMH_AuthScope as, bool *refreshable) } +/** + * Checks if @a permission_required is in permissions of + * @a scope. + * + * @param permission_required the permission to check. + * @param scope the scope to check. + * @return true if @a permission_required is in the permissions set of @a scope. + */ static bool -capabilities_in_scope (const char*permission_required, - enum TMH_AuthScope scope) +permission_in_scope (const char *permission_required, + enum TMH_AuthScope scope) { char *permissions; const char*perms_tmp; @@ -360,7 +424,7 @@ TMH_scope_is_subset (enum TMH_AuthScope as, enum TMH_AuthScope candidate) } while (NULL != perm) { - if (! capabilities_in_scope (perm, as)) + if (! permission_in_scope (perm, as)) { GNUNET_free (permissions); return false; @@ -373,6 +437,18 @@ TMH_scope_is_subset (enum TMH_AuthScope as, enum TMH_AuthScope candidate) } +enum TMH_AuthScope +TMH_get_scope_by_name (const char *name) +{ + for (int i = 0; TMH_AS_NONE != scope_permissions[i].as; i++) + { + if (0 == strcasecmp (scope_permissions[i].name, name)) + return scope_permissions[i].as; + } + return TMH_AS_NONE; +} + + enum GNUNET_GenericReturnValue TMH_check_auth (const char *token, struct TALER_MerchantAuthenticationSaltP *salt, @@ -2161,7 +2237,7 @@ url_handler (void *cls, if ( (0 == GNUNET_CONTAINER_multihashmap_size (TMH_by_id_map)) && (NULL == TMH_default_pass) ) { - hc->auth_scope = TMH_AS_ALL; + hc->auth_scope = TMH_AS_ADMIN; } else if (is_basic_auth) { @@ -2188,7 +2264,7 @@ url_handler (void *cls, if (GNUNET_OK == TMH_check_auth_instance (auth, hc->instance)) - hc->auth_scope = TMH_AS_ALL; + hc->auth_scope = TMH_AS_ADMIN; else hc->auth_scope = TMH_AS_NONE; } @@ -2200,7 +2276,7 @@ url_handler (void *cls, if (GNUNET_is_zero (&hc->instance->auth.auth_hash)) { /* hash zero means no authentication for instance */ - hc->auth_scope = TMH_AS_ALL; + hc->auth_scope = TMH_AS_ADMIN; } else { @@ -2229,7 +2305,7 @@ url_handler (void *cls, } else { - hc->auth_scope = TMH_AS_ALL; + hc->auth_scope = TMH_AS_ADMIN; } } else @@ -2249,7 +2325,7 @@ url_handler (void *cls, - rh has an explicit non-NONE scope that matches - scope is 'read only' and we have a GET request */ if ((NULL != hc->rh->permission) && - (! capabilities_in_scope (hc->rh->permission, hc->auth_scope))) + (! permission_in_scope (hc->rh->permission, hc->auth_scope))) { if (auth_malformed && (TMH_AS_NONE == hc->auth_scope) ) diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h @@ -452,7 +452,7 @@ enum TMH_AuthScope /** * Full access is granted to everything. */ - TMH_AS_ALL = 7 | 1 << 31, + TMH_AS_ADMIN = 7 | 1 << 31, /** * /login access to renew the token is OK. @@ -859,4 +859,13 @@ TMH_compute_auth (const char *token, bool TMH_scope_is_subset (enum TMH_AuthScope as, enum TMH_AuthScope candidate); +/** + * Return the TMH_AuthScope corresponding to @a name. + * + * @param name the name to look for + * @return the scope corresponding to the name, or TMH_AS_NONE. + */ +enum TMH_AuthScope +TMH_get_scope_by_name (const char *name); + #endif diff --git a/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c b/src/backend/taler-merchant-httpd_private-post-instances-ID-token.c @@ -87,25 +87,8 @@ TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, if ((NULL != scope_suffix) && (0 == strcasecmp (scope_suffix, "refreshable"))) refreshable = true; - if (0 == strcasecmp (scope_prefix, - "readonly")) - iscope = TMH_AS_READ_ONLY; - else if (0 == strcasecmp (scope_prefix, - "write")) - iscope = TMH_AS_ALL; - else if (0 == strcasecmp (scope_prefix, - "order-simple")) - iscope = TMH_AS_ORDER_SIMPLE; - else if (0 == strcasecmp (scope_prefix, - "order-pos")) - iscope = TMH_AS_ORDER_POS; - else if (0 == strcasecmp (scope_prefix, - "order-mgmt")) - iscope = TMH_AS_ORDER_MGMT; - else if (0 == strcasecmp (scope_prefix, - "order-full")) - iscope = TMH_AS_ORDER_FULL; - else + iscope = TMH_get_scope_by_name (scope_prefix); + if (TMH_AS_NONE == iscope) { GNUNET_break_op (0); GNUNET_free (tmp_scope);