From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- src/detection/publicip/publicip.c | 95 +++++++++++++++++++++++++++++++++++++++ src/detection/publicip/publicip.h | 12 +++++ 2 files changed, 107 insertions(+) create mode 100644 src/detection/publicip/publicip.c create mode 100644 src/detection/publicip/publicip.h (limited to 'src/detection/publicip') diff --git a/src/detection/publicip/publicip.c b/src/detection/publicip/publicip.c new file mode 100644 index 0000000..abca57c --- /dev/null +++ b/src/detection/publicip/publicip.c @@ -0,0 +1,95 @@ +#include "publicip.h" +#include "common/networking.h" + +#define FF_UNINITIALIZED ((const char*) (uintptr_t) -1) +static FFNetworkingState states[2]; +static const char* statuses[2] = { FF_UNINITIALIZED, FF_UNINITIALIZED }; + +void ffPreparePublicIp(FFPublicIPOptions* options) { + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status != FF_UNINITIALIZED) { + fputs("Error: PublicIp module can only be used once due to internal limitations\n", stderr); + exit(1); + } + + state->timeout = options->timeout; + state->ipv6 = options->ipv6; + + if (options->url.length == 0) { + state->compression = true; + state->tfo = true; + *status = ffNetworkingSendHttpRequest(state, options->ipv6 ? "v6.ipinfo.io" : "ipinfo.io", "/json", NULL); + } else { + FF_STRBUF_AUTO_DESTROY host = ffStrbufCreateCopy(&options->url); + uint32_t hostStartIndex = ffStrbufFirstIndexS(&host, "://"); + if (hostStartIndex < host.length) { + if (hostStartIndex != 4 || !ffStrbufStartsWithIgnCaseS(&host, "http")) { + fputs("Error: only http: protocol is supported. Use `Command` module with `curl` if needed\n", stderr); + exit(1); + } + ffStrbufSubstrAfter(&host, hostStartIndex + (uint32_t) (strlen("://") - 1)); + } + uint32_t pathStartIndex = ffStrbufFirstIndexC(&host, '/'); + + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); + if (pathStartIndex != host.length) { + ffStrbufAppendNS(&path, pathStartIndex, host.chars + (host.length - pathStartIndex)); + host.length = pathStartIndex; + host.chars[pathStartIndex] = '\0'; + } + + *status = ffNetworkingSendHttpRequest(state, host.chars, path.length == 0 ? "/" : path.chars, NULL); + } +} + +static inline void wrapYyjsonFree(yyjson_doc** doc) { + assert(doc); + if (*doc) { + yyjson_doc_free(*doc); + } +} + +const char* ffDetectPublicIp(FFPublicIPOptions* options, FFPublicIpResult* result) { + FFNetworkingState* state = &states[options->ipv6]; + const char** status = &statuses[options->ipv6]; + if (*status == FF_UNINITIALIZED) { + ffPreparePublicIp(options); + } + + if (*status != NULL) { + return *status; + } + + FF_STRBUF_AUTO_DESTROY response = ffStrbufCreateA(4096); + const char* error = ffNetworkingRecvHttpResponse(state, &response); + + *state = (FFNetworkingState) {}; + *status = FF_UNINITIALIZED; + + if (error == NULL) { + ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n"); + } else { + return error; + } + + if (response.length == 0) { + return "Empty server response received"; + } + + if (options->url.length == 0) { + yyjson_doc* FF_A_CLEANUP(wrapYyjsonFree) doc = yyjson_read_opts(response.chars, response.length, 0, NULL, NULL); + if (doc) { + yyjson_val* root = yyjson_doc_get_root(doc); + ffStrbufAppendJsonVal(&result->ip, yyjson_obj_get(root, "ip")); + ffStrbufDestroy(&result->location); + ffStrbufInitF(&result->location, "%s, %s", yyjson_get_str(yyjson_obj_get(root, "city")), yyjson_get_str(yyjson_obj_get(root, "country"))); + return NULL; + } + } + + ffStrbufDestroy(&result->ip); + ffStrbufInitMove(&result->ip, &response); + ffStrbufTrimRightSpace(&result->ip); + return NULL; +} diff --git a/src/detection/publicip/publicip.h b/src/detection/publicip/publicip.h new file mode 100644 index 0000000..e8f9702 --- /dev/null +++ b/src/detection/publicip/publicip.h @@ -0,0 +1,12 @@ +#pragma once + +#include "fastfetch.h" +#include "modules/publicip/option.h" + +typedef struct FFPublicIpResult { + FFstrbuf ip; + FFstrbuf location; +} FFPublicIpResult; + +void ffPreparePublicIp(FFPublicIPOptions* options); +const char* ffDetectPublicIp(FFPublicIPOptions* options, FFPublicIpResult* result); -- cgit v1.2.3