/* This file is part of GNU Taler (C) 2023 Taler Systems SA GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU 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_private-post-instances-ID-token.c * @brief implementing POST /instances/$ID/token request handling * @author Christian Grothoff */ #include "platform.h" #include "taler-merchant-httpd_private-post-instances-ID-token.h" #include "taler-merchant-httpd_helper.h" #include /** * Default duration for the validity of a login token. */ #define DEFAULT_DURATION GNUNET_TIME_UNIT_DAYS MHD_RESULT TMH_private_post_instances_ID_token (const struct TMH_RequestHandler *rh, struct MHD_Connection *connection, struct TMH_HandlerContext *hc) { struct TMH_MerchantInstance *mi = hc->instance; json_t *jtoken = hc->request_body; const char *scope; uint32_t iscope = TMH_AS_NONE; bool refreshable = false; struct TALER_MERCHANTDB_LoginTokenP btoken; struct GNUNET_TIME_Relative duration = DEFAULT_DURATION; struct GNUNET_TIME_Timestamp expiration_time; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("scope", &scope), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_relative_time ("duration", &duration), NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_bool ("refreshable", &refreshable), NULL), GNUNET_JSON_spec_end () }; enum GNUNET_DB_QueryStatus qs; { enum GNUNET_GenericReturnValue res; res = TALER_MHD_parse_json_data (connection, jtoken, spec); if (GNUNET_OK != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; } GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &btoken, sizeof (btoken)); expiration_time = GNUNET_TIME_relative_to_timestamp (duration); if (0 == strcasecmp (scope, "readonly")) iscope = TMH_AS_READ_ONLY; else if (0 == strcasecmp (scope, "write")) iscope = TMH_AS_ALL; else { GNUNET_break_op (0); return TALER_MHD_reply_with_ec (connection, TALER_EC_GENERIC_PARAMETER_MALFORMED, "scope"); } if (refreshable) iscope |= TMH_AS_REFRESHABLE; if (0 != (iscope & (~hc->auth_scope))) { /* more permissions requested for the new token, not allowed */ GNUNET_break_op (0); return TALER_MHD_reply_with_ec (connection, TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT, NULL); } qs = TMH_db->insert_login_token (TMH_db->cls, mi->settings.id, &btoken, GNUNET_TIME_timestamp_get (), expiration_time, iscope); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: case GNUNET_DB_STATUS_SOFT_ERROR: case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: GNUNET_break (0); return TALER_MHD_reply_with_ec (connection, TALER_EC_GENERIC_DB_STORE_FAILED, "insert_login_token"); case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: break; } { char *tok; MHD_RESULT ret; char *val; val = GNUNET_STRINGS_data_to_string_alloc (&btoken, sizeof (btoken)); GNUNET_asprintf (&tok, RFC_8959_PREFIX "%s", val); GNUNET_free (val); ret = TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, GNUNET_JSON_pack_string ("token", tok), GNUNET_JSON_pack_string ("scope", scope), GNUNET_JSON_pack_bool ("refreshable", refreshable), GNUNET_JSON_pack_timestamp ("expiration", expiration_time)); GNUNET_free (tok); return ret; } } /* end of taler-merchant-httpd_private-post-instances-ID-token.c */