Line data Source code
1 : /**
2 : * Copyright (c) Libmonero
3 : *
4 : * Permission is hereby granted, free of charge, to any person obtaining a copy
5 : * of this software and associated documentation files (the "Software"), to deal
6 : * in the Software without restriction, including without limitation the rights
7 : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : * copies of the Software, and to permit persons to whom the Software is
9 : * furnished to do so, subject to the following conditions:
10 : *
11 : * The above copyright notice and this permission notice shall be included in all
12 : * copies or substantial portions of the Software.
13 : *
14 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 : * SOFTWARE.
21 : *
22 : * Parts of this file are originally copyright (c) woodser
23 : *
24 : * Parts of this file are originally copyright (c) 2014-2019, The Monero Project
25 : *
26 : * Redistribution and use in source and binary forms, with or without modification, are
27 : * permitted provided that the following conditions are met:
28 : *
29 : * All rights reserved.
30 : *
31 : * 1. Redistributions of source code must retain the above copyright notice, this list of
32 : * conditions and the following disclaimer.
33 : *
34 : * 2. Redistributions in binary form must reproduce the above copyright notice, this list
35 : * of conditions and the following disclaimer in the documentation and/or other
36 : * materials provided with the distribution.
37 : *
38 : * 3. Neither the name of the copyright holder nor the names of its contributors may be
39 : * used to endorse or promote products derived from this software without specific
40 : * prior written permission.
41 : *
42 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
43 : * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
44 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
45 : * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
47 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
48 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
50 : * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 : *
52 : * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
53 : */
54 :
55 : #include "monero_c_utils.h"
56 : #include "common/monero_c_common.h"
57 : #include "utils/monero_utils.h"
58 : #include "crypto/hash.h"
59 : #include <cstdlib>
60 : #include <cstring>
61 : #include <memory>
62 : #include <mutex>
63 : #include <new>
64 : #include <stdexcept>
65 : #include <string>
66 :
67 : namespace {
68 :
69 : using monero_c::check_json_depth;
70 : using monero_c::check_mnemonic_length;
71 : using monero_c::MAX_MNEMONIC_LENGTH;
72 : using monero_c::dup_buffer;
73 : using monero_c::dup_string;
74 : using monero_c::guard;
75 : using monero_c::network_of;
76 : using monero_c::require;
77 : using monero_c::reset_out;
78 : using monero_c::safe_str;
79 : using monero_c::to_network_type;
80 :
81 : // the logging of monero-project is one global state, and two threads that change it together crash
82 1212 : std::mutex& logging_mutex() {
83 : static std::mutex mutex;
84 1212 : return mutex;
85 : }
86 :
87 1517 : std::string safe_bin(const uint8_t* data, size_t len) {
88 1517 : return data ? std::string(reinterpret_cast<const char*>(data), len) : std::string();
89 : }
90 :
91 : using binary_to_json_fn = void (*)(const std::string&, std::string&);
92 :
93 : // shared by the monero_utils_binary*_to_json wrappers below, which differ
94 : // only in which monero_utils converter they call
95 1523 : monero_result binary_to_json_impl(binary_to_json_fn fn, const uint8_t* data, size_t len, char** out_json) {
96 1523 : reset_out(out_json);
97 1523 : if (!require(out_json, "out_json")) return MONERO_ERROR;
98 3034 : return guard([&] {
99 1517 : std::string json;
100 1768 : fn(safe_bin(data, len), json);
101 1266 : *out_json = dup_string(json);
102 3034 : });
103 : }
104 :
105 : } // namespace
106 :
107 : extern "C" {
108 :
109 : // ---------------------------- ERROR / MEMORY --------------------------------
110 :
111 38319 : const char* monero_last_error(void) {
112 38319 : return monero_c::last_error().c_str();
113 : }
114 :
115 7129 : void monero_utils_free(void* ptr) {
116 7129 : std::free(ptr);
117 7129 : }
118 :
119 : // ---------------------------------- VERSION ---------------------------------
120 :
121 12 : monero_result monero_utils_get_abi_version(uint32_t* out_major, uint32_t* out_minor, uint32_t* out_patch) {
122 12 : if (!require(out_major, "out_major") || !require(out_minor, "out_minor") || !require(out_patch, "out_patch")) return MONERO_ERROR;
123 4 : *out_major = MONERO_C_ABI_VERSION_MAJOR;
124 4 : *out_minor = MONERO_C_ABI_VERSION_MINOR;
125 4 : *out_patch = MONERO_C_ABI_VERSION_PATCH;
126 4 : return MONERO_OK;
127 : }
128 :
129 : // --------------------------------- LOGGING ----------------------------------
130 :
131 403 : void monero_utils_set_log_level(int32_t level) {
132 403 : std::lock_guard<std::mutex> lock(logging_mutex());
133 403 : monero_utils::set_log_level(static_cast<int>(level));
134 403 : }
135 :
136 404 : void monero_utils_set_log_categories(const char* categories) {
137 404 : std::lock_guard<std::mutex> lock(logging_mutex());
138 404 : monero_utils::set_log_categories(safe_str(categories));
139 404 : }
140 :
141 405 : void monero_utils_configure_logging(const char* path, bool console) {
142 405 : std::lock_guard<std::mutex> lock(logging_mutex());
143 405 : monero_utils::configure_logging(safe_str(path), console);
144 405 : }
145 :
146 : // -------------------------------- VALIDATION --------------------------------
147 :
148 2268 : bool monero_utils_is_valid_address(const char* address, int32_t network_type) {
149 : monero_network_type nt;
150 2268 : if (!to_network_type(network_type, nt)) return false;
151 2267 : return monero_utils::is_valid_address(safe_str(address), nt);
152 : }
153 :
154 1360 : bool monero_utils_is_valid_private_view_key(const char* private_view_key) {
155 1360 : return monero_utils::is_valid_private_view_key(safe_str(private_view_key));
156 : }
157 :
158 457 : bool monero_utils_is_valid_private_spend_key(const char* private_spend_key) {
159 457 : return monero_utils::is_valid_private_spend_key(safe_str(private_spend_key));
160 : }
161 :
162 457 : bool monero_utils_is_valid_public_view_key(const char* public_view_key) {
163 457 : return monero_utils::is_valid_public_view_key(safe_str(public_view_key));
164 : }
165 :
166 457 : bool monero_utils_is_valid_public_spend_key(const char* public_spend_key) {
167 457 : return monero_utils::is_valid_public_spend_key(safe_str(public_spend_key));
168 : }
169 :
170 469 : bool monero_utils_is_valid_payment_id(const char* payment_id) {
171 469 : return monero_utils::is_valid_payment_id(safe_str(payment_id));
172 : }
173 :
174 2715 : bool monero_utils_is_valid_mnemonic(const char* mnemonic, const char* language) {
175 2715 : std::string text = safe_str(mnemonic);
176 5430 : return text.size() <= MAX_MNEMONIC_LENGTH && monero_utils::is_valid_mnemonic(text, safe_str(language));
177 2715 : }
178 :
179 461 : bool monero_utils_is_valid_language(const char* language) {
180 461 : return monero_utils::is_valid_language(safe_str(language));
181 : }
182 :
183 459 : monero_result monero_utils_validate_address(const char* address, int32_t network_type) {
184 918 : return guard([&] { monero_utils::validate_address(safe_str(address), network_of<monero_network_type>(network_type)); });
185 : }
186 :
187 456 : monero_result monero_utils_validate_private_view_key(const char* private_view_key) {
188 912 : return guard([&] { monero_utils::validate_private_view_key(safe_str(private_view_key)); });
189 : }
190 :
191 457 : monero_result monero_utils_validate_private_spend_key(const char* private_spend_key) {
192 914 : return guard([&] { monero_utils::validate_private_spend_key(safe_str(private_spend_key)); });
193 : }
194 :
195 456 : monero_result monero_utils_validate_public_view_key(const char* public_view_key) {
196 912 : return guard([&] { monero_utils::validate_public_view_key(safe_str(public_view_key)); });
197 : }
198 :
199 456 : monero_result monero_utils_validate_public_spend_key(const char* public_spend_key) {
200 912 : return guard([&] { monero_utils::validate_public_spend_key(safe_str(public_spend_key)); });
201 : }
202 :
203 468 : monero_result monero_utils_validate_payment_id(const char* payment_id) {
204 936 : return guard([&] { monero_utils::validate_payment_id(safe_str(payment_id)); });
205 : }
206 :
207 460 : monero_result monero_utils_validate_mnemonic(const char* mnemonic, const char* language) {
208 920 : return guard([&] {
209 460 : std::string text = safe_str(mnemonic);
210 460 : check_mnemonic_length(text);
211 783 : monero_utils::validate_mnemonic(text, safe_str(language));
212 1380 : });
213 : }
214 :
215 : // --------------------------- INTEGRATED ADDRESS / URIS ----------------------
216 :
217 2112 : monero_result monero_utils_get_integrated_address(int32_t network_type, const char* standard_address, const char* payment_id, char** out_json) {
218 2112 : reset_out(out_json);
219 2112 : if (!require(out_json, "out_json")) return MONERO_ERROR;
220 3320 : return guard([&] {
221 1660 : monero_network_type nt = network_of<monero_network_type>(network_type);
222 1754 : monero_integrated_address addr = monero_utils::get_integrated_address(nt, safe_str(standard_address), safe_str(payment_id));
223 935 : *out_json = dup_string(addr.serialize());
224 2595 : });
225 : }
226 :
227 160 : monero_result monero_utils_get_payment_uri(const char* tx_config_json, int32_t network_type, char** out_uri) {
228 160 : reset_out(out_uri);
229 160 : if (!require(out_uri, "out_uri")) return MONERO_ERROR;
230 316 : return guard([&] {
231 158 : monero_network_type nt = network_of<monero_network_type>(network_type);
232 156 : std::string json = safe_str(tx_config_json);
233 156 : check_json_depth(json);
234 154 : std::shared_ptr<monero_tx_config> config = monero_tx_config::deserialize(json);
235 48 : *out_uri = dup_string(monero_utils::get_payment_uri(*config, nt));
236 360 : });
237 : }
238 :
239 159 : monero_result monero_utils_parse_payment_uri(const char* uri, int32_t network_type, char** out_tx_config_json) {
240 159 : reset_out(out_tx_config_json);
241 159 : if (!require(out_tx_config_json, "out_tx_config_json")) return MONERO_ERROR;
242 314 : return guard([&] {
243 157 : monero_network_type nt = network_of<monero_network_type>(network_type);
244 282 : std::shared_ptr<monero_tx_config> config = monero_utils::parse_payment_uri(safe_str(uri), nt);
245 28 : *out_tx_config_json = dup_string(config->serialize());
246 185 : });
247 : }
248 :
249 : // ----------------------------- JSON / BINARY RPC ----------------------------
250 :
251 1514 : monero_result monero_utils_json_to_binary(const char* json, uint8_t** out_data, size_t* out_len) {
252 1514 : reset_out(out_data);
253 1514 : reset_out(out_len);
254 1514 : if (!require(out_data, "out_data") || !require(out_len, "out_len")) return MONERO_ERROR;
255 3018 : return guard([&] {
256 1509 : std::string text = safe_str(json);
257 1509 : check_json_depth(text);
258 1501 : std::string bin;
259 1501 : monero_utils::json_to_binary(text, bin);
260 1501 : *out_data = dup_buffer(bin, out_len);
261 3018 : });
262 : }
263 :
264 1203 : monero_result monero_utils_binary_to_json(const uint8_t* data, size_t len, char** out_json) {
265 1203 : return binary_to_json_impl(monero_utils::binary_to_json, data, len, out_json);
266 : }
267 :
268 160 : monero_result monero_utils_binary_blocks_to_json(const uint8_t* data, size_t len, char** out_json) {
269 160 : return binary_to_json_impl(monero_utils::binary_blocks_to_json, data, len, out_json);
270 : }
271 :
272 160 : monero_result monero_utils_binary_blocks_fast_to_json(const uint8_t* data, size_t len, char** out_json) {
273 160 : return binary_to_json_impl(monero_utils::binary_blocks_fast_to_json, data, len, out_json);
274 : }
275 :
276 : // -------------------------------- AMOUNTS / IDS -----------------------------
277 :
278 19 : monero_result monero_utils_xmr_to_atomic_units(double amount_xmr, uint64_t* out_atomic_units) {
279 19 : if (!require(out_atomic_units, "out_atomic_units")) return MONERO_ERROR;
280 34 : return guard([&] { *out_atomic_units = monero_utils::xmr_to_atomic_units(amount_xmr); });
281 : }
282 :
283 6 : double monero_utils_atomic_units_to_xmr(uint64_t amount_atomic_units) {
284 6 : return monero_utils::atomic_units_to_xmr(amount_atomic_units);
285 : }
286 :
287 458 : bool monero_utils_parse_payment_id_long(const char* payment_id_str, uint8_t out_payment_id[32]) {
288 : static_assert(sizeof(crypto::hash) == 32, "crypto::hash is expected to be 32 bytes");
289 : crypto::hash h;
290 458 : if (!monero_utils::parse_payment_id_long(safe_str(payment_id_str), h)) return false;
291 10 : if (out_payment_id != nullptr) std::memcpy(out_payment_id, &h, sizeof(h));
292 10 : return true;
293 : }
294 :
295 458 : bool monero_utils_parse_payment_id_short(const char* payment_id_str, uint8_t out_payment_id[8]) {
296 : static_assert(sizeof(crypto::hash8) == 8, "crypto::hash8 is expected to be 8 bytes");
297 : crypto::hash8 h;
298 458 : if (!monero_utils::parse_payment_id_short(safe_str(payment_id_str), h)) return false;
299 4 : if (out_payment_id != nullptr) std::memcpy(out_payment_id, &h, sizeof(h));
300 4 : return true;
301 : }
302 :
303 : // monero-cpp only exposes parse_payment_id_long/short, which return a bool and an out-ref.
304 : // the is_valid_ and validate_ wrappers match the checks of downstream bindings such as
305 : // monero-python's PyMoneroUtils, including the "Invalid {long,short} payment id" messages
306 :
307 459 : bool monero_utils_is_valid_payment_id_long(const char* payment_id_str) {
308 : crypto::hash h;
309 459 : return monero_utils::parse_payment_id_long(safe_str(payment_id_str), h);
310 : }
311 :
312 458 : bool monero_utils_is_valid_payment_id_short(const char* payment_id_str) {
313 : crypto::hash8 h;
314 458 : return monero_utils::parse_payment_id_short(safe_str(payment_id_str), h);
315 : }
316 :
317 458 : monero_result monero_utils_validate_payment_id_long(const char* payment_id_str) {
318 916 : return guard([&] {
319 : crypto::hash h;
320 458 : if (!monero_utils::parse_payment_id_long(safe_str(payment_id_str), h)) throw std::runtime_error("Invalid long payment id");
321 926 : });
322 : }
323 :
324 457 : monero_result monero_utils_validate_payment_id_short(const char* payment_id_str) {
325 914 : return guard([&] {
326 : crypto::hash8 h;
327 457 : if (!monero_utils::parse_payment_id_short(safe_str(payment_id_str), h)) throw std::runtime_error("Invalid short payment id");
328 917 : });
329 : }
330 :
331 5 : int32_t monero_utils_get_ring_size(void) {
332 5 : return monero_utils::RING_SIZE;
333 : }
334 :
335 : } // extern "C"
|