ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
strings.h File Reference

Go to the source code of this file.

Macros

#define SESSION_STRING_MAX_LEN   38
 Maximum length of a session string (without null terminator)
 
#define SESSION_STRING_BUFFER_SIZE   (SESSION_STRING_MAX_LEN + 1)
 Buffer size needed for session string storage (with null terminator) Used for static character array declarations.
 
#define ACDS_MAX_UNIQUE_SESSIONS   (2500LL * 5000LL * 5000LL)
 Maximum number of unique session strings that can be generated.
 

Functions

asciichat_error_t acds_string_generate (char *output, size_t output_size)
 Generate random session string.
 
asciichat_error_t acds_string_init (void)
 Initialize session string system with cached word validation.
 
bool is_session_string (const char *str)
 Check if a string is a valid session string.
 
void acds_strings_destroy (void)
 Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup. Safe to call multiple times (idempotent).
 

Macro Definition Documentation

◆ ACDS_MAX_UNIQUE_SESSIONS

#define ACDS_MAX_UNIQUE_SESSIONS   (2500LL * 5000LL * 5000LL)

Maximum number of unique session strings that can be generated.

Calculated from wordlist entropy: 2500 adjectives × 5000 nouns × 5000 nouns = 62,500,000,000 combinations

Definition at line 46 of file discovery/strings.h.

◆ SESSION_STRING_BUFFER_SIZE

#define SESSION_STRING_BUFFER_SIZE   (SESSION_STRING_MAX_LEN + 1)

Buffer size needed for session string storage (with null terminator) Used for static character array declarations.

Definition at line 38 of file discovery/strings.h.

◆ SESSION_STRING_MAX_LEN

#define SESSION_STRING_MAX_LEN   38

Maximum length of a session string (without null terminator)

Calculated from longest words:

  • Longest adjective: 12 chars (e.g., "affectionate")
  • Longest noun: 12 chars (e.g., "acquaintance")
  • Format: adjective-noun-noun = 12 + 1 + 12 + 1 + 12 = 38 chars

Definition at line 32 of file discovery/strings.h.

Function Documentation

◆ acds_string_generate()

asciichat_error_t acds_string_generate ( char *  output,
size_t  output_size 
)

Generate random session string.

Parameters
outputOutput buffer for session string
output_sizeSize of output buffer (should be at least SESSION_STRING_BUFFER_SIZE bytes)
Returns
ASCIICHAT_OK on success, error code otherwise

Generates strings in format: adjective-noun-noun Example: "affectionate-acquaintance-acquaintance" (38 characters max)

Use acds_string_get_max_length() to get the maximum possible length. Entropy: 2500 adjectives * 5000 nouns * 5000 nouns = 62.5 billion combinations

Definition at line 222 of file discovery/strings.c.

222 {
223 if (!output || output_size < SESSION_STRING_BUFFER_SIZE) {
224 return SET_ERRNO(ERROR_INVALID_PARAM, "output buffer must be at least %zu bytes",
226 }
227
228 // libsodium is guaranteed to be initialized by acds_string_init() before this is called
229 // No need to call sodium_init() again (redundant initialization removed)
230
231 // Pick random adjective
232 uint32_t adj_idx = randombytes_uniform((uint32_t)adjectives_count);
233 const char *adj = adjectives[adj_idx];
234
235 // Pick two random nouns
236 uint32_t noun1_idx = randombytes_uniform((uint32_t)nouns_count);
237 uint32_t noun2_idx = randombytes_uniform((uint32_t)nouns_count);
238 const char *noun1 = nouns[noun1_idx];
239 const char *noun2 = nouns[noun2_idx];
240
241 // Format: adjective-noun-noun
242 int written = safe_snprintf(output, output_size, "%s-%s-%s", adj, noun1, noun2);
243 if (written < 0 || (size_t)written >= output_size) {
244 return SET_ERRNO(ERROR_BUFFER_OVERFLOW, "Session string too long for buffer");
245 }
246
247 log_dev("Generated session string: %s", output);
248 return ASCIICHAT_OK;
249}
const char * adjectives[]
Array of English adjectives for ACDS session naming.
Definition adjectives.c:51
const size_t adjectives_count
Count of adjectives in the adjectives array.
Definition adjectives.c:411
unsigned int uint32_t
Definition common.h:58
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ASCIICHAT_OK
Definition error_codes.h:51
@ ERROR_INVALID_PARAM
@ ERROR_BUFFER_OVERFLOW
#define log_dev(...)
Log a DEV message (most verbose, development only)
Definition log/log.h:534
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:148
const char * nouns[]
Array of English nouns for session and client naming.
Definition nouns.c:55
const size_t nouns_count
Count of nouns in the nouns array.
Definition nouns.c:772
#define SESSION_STRING_BUFFER_SIZE

References adjectives, adjectives_count, ASCIICHAT_OK, ERROR_BUFFER_OVERFLOW, ERROR_INVALID_PARAM, log_dev, nouns, nouns_count, safe_snprintf(), SESSION_STRING_BUFFER_SIZE, and SET_ERRNO.

Referenced by database_session_create(), and options_preset_unified().

◆ acds_string_init()

asciichat_error_t acds_string_init ( void  )

Initialize session string system with cached word validation.

Returns
ASCIICHAT_OK on success, error code otherwise

Initializes the random number generator and caches adjectives/nouns in a hashtable for fast validation. Must be called before acds_string_generate() and before any is_session_string() validation calls.

Uses libsodium's randombytes for cryptographically secure randomness. Cleans up cached data on program exit via atexit() handler.

Definition at line 218 of file discovery/strings.c.

218 {
219 return ASCIICHAT_OK;
220}

References ASCIICHAT_OK.

◆ acds_strings_destroy()

void acds_strings_destroy ( void  )

Cleanup function for session string cache Called by asciichat_shared_destroy() during library cleanup. Safe to call multiple times (idempotent).

Definition at line 53 of file discovery/strings.c.

53 {
54 // Shutdown if initialized
55 if (!lifecycle_shutdown(&g_cache_lc)) {
56 return; // Not initialized
57 }
58
59 // Cleanup adjectives cache
60 word_cache_entry_t *adj_entry, *adj_tmp;
61 HASH_ITER(hh, g_adjectives_cache, adj_entry, adj_tmp) {
62 HASH_DEL(g_adjectives_cache, adj_entry);
63 SAFE_FREE(adj_entry->word);
64 SAFE_FREE(adj_entry);
65 }
66 g_adjectives_cache = NULL;
67
68 // Cleanup nouns cache
69 word_cache_entry_t *noun_entry, *noun_tmp;
70 HASH_ITER(hh, g_nouns_cache, noun_entry, noun_tmp) {
71 HASH_DEL(g_nouns_cache, noun_entry);
72 SAFE_FREE(noun_entry->word);
73 SAFE_FREE(noun_entry);
74 }
75 g_nouns_cache = NULL;
76
77 log_dev("Session string word cache cleaned up");
78}
#define SAFE_FREE(ptr)
Definition common.h:376
bool lifecycle_shutdown(lifecycle_t *lc)
Definition lifecycle.c:108
Hashtable entry for cached word lookups.
char * word
The word string (key)

References lifecycle_shutdown(), log_dev, SAFE_FREE, and word_cache_entry_t::word.

Referenced by asciichat_shared_destroy().

◆ is_session_string()

bool is_session_string ( const char *  str)

Check if a string is a valid session string.

Parameters
strString to validate
Returns
true if valid session string (adjective-noun-noun format), false otherwise

A valid session string must:

  • Be in format: adjective-noun-noun
  • Contain exactly 3 words separated by exactly 2 hyphens
  • Have each word be a real adjective or noun from cached wordlists
  • Contain only lowercase ASCII letters and hyphens
  • Be 5-47 characters long
  • Not start or end with hyphen
  • Not contain consecutive hyphens

This function validates against the cached wordlists populated by acds_string_init(). Non-session inputs return false without setting an error. Internal failures set errno.

Definition at line 251 of file discovery/strings.c.

251 {
252 if (!str || str[0] == '\0') {
253 return false;
254 }
255
256 size_t len = strlen(str);
257
258 // Check length bounds (min 4, max defined by SESSION_STRING_MAX_LEN)
259 if (len < 4 || len > SESSION_STRING_MAX_LEN) {
260 return false;
261 }
262
263 // Session strings must be ASCII-only (homograph attack prevention)
264 if (!utf8_is_ascii_only(str)) {
265 return false;
266 }
267
268 // Get compiled regex (lazy initialization)
269 pcre2_code *regex = session_format_regex_get();
270 if (!regex) {
271 SET_ERRNO(ERROR_INTERNAL, "Session string PCRE2 regex failed to initialize");
272 return false;
273 }
274
275 // Validate format using PCRE2 regex
276 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
277 if (!match_data) {
278 log_error("Failed to allocate match data for session string regex");
279 SET_ERRNO(ERROR_MEMORY, "Failed to allocate match data");
280 return false;
281 }
282
283 int match_result = pcre2_jit_match(regex, (PCRE2_SPTR8)str, len, 0, 0, match_data, NULL);
284
285 pcre2_match_data_free(match_data);
286
287 if (match_result < 0) {
288 if (match_result != PCRE2_ERROR_NOMATCH) {
289 SET_ERRNO(ERROR_INTERNAL, "Session string PCRE2 matching failed: %d", match_result);
290 }
291 return false;
292 }
293
294 // Extract the three words by finding hyphens
295 // Format is guaranteed to be: word-word-word where each word is 2-12 lowercase letters
296 const char *hyphen1 = strchr(str, '-');
297 if (!hyphen1) {
298 return false;
299 }
300
301 const char *hyphen2 = strchr(hyphen1 + 1, '-');
302 if (!hyphen2) {
303 return false;
304 }
305
306 // Extract three words
307 size_t adj_len = hyphen1 - str;
308 size_t noun1_len = hyphen2 - hyphen1 - 1;
309 size_t noun2_len = len - (hyphen2 - str) - 1;
310
311 if (adj_len >= 32 || noun1_len >= 32 || noun2_len >= 32) {
312 return false;
313 }
314
315 char adj[32], noun1[32], noun2[32];
316 memcpy(adj, str, adj_len);
317 adj[adj_len] = '\0';
318 memcpy(noun1, hyphen1 + 1, noun1_len);
319 noun1[noun1_len] = '\0';
320 memcpy(noun2, hyphen2 + 1, noun2_len);
321 noun2[noun2_len] = '\0';
322
323 // Lazy initialization: build validation caches on first use
324 // call_once ensures thread-safe exactly-once execution
325 build_validation_caches();
326 // If initialization fails silently (logs warning), hashtables will be empty
327 // and validation will fail, which is safe behavior
328
329 // Validate first word is an adjective
330 word_cache_entry_t *adj_entry = NULL;
331 HASH_FIND_STR(g_adjectives_cache, adj, adj_entry);
332 if (!adj_entry) {
333 return false;
334 }
335
336 // Validate second and third words are nouns
337 word_cache_entry_t *noun_entry1 = NULL;
338 HASH_FIND_STR(g_nouns_cache, noun1, noun_entry1);
339 if (!noun_entry1) {
340 return false;
341 }
342
343 word_cache_entry_t *noun_entry2 = NULL;
344 HASH_FIND_STR(g_nouns_cache, noun2, noun_entry2);
345 if (!noun_entry2) {
346 return false;
347 }
348
349 log_dev("Valid session string: %s", str);
350 return true;
351}
#define SESSION_STRING_MAX_LEN
Maximum length of a session string (without null terminator)
@ ERROR_MEMORY
Definition error_codes.h:56
@ ERROR_INTERNAL
Definition error_codes.h:92
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
bool utf8_is_ascii_only(const char *str)
Check if a string contains only ASCII characters.
Definition utf8.c:165

References ERROR_INTERNAL, ERROR_MEMORY, log_dev, log_error, SESSION_STRING_MAX_LEN, SET_ERRNO, and utf8_is_ascii_only().

Referenced by database_session_create(), discover_session_parallel(), and parse_client_address().