GCC Code Coverage Report


src/
File: src/login/login.c
Date: 2026-03-31 17:48:22
Lines:
66/94
70.2%
Functions:
5/7
71.4%
Branches:
45/79
57.0%

Line Branch Exec Source
1 #include <glib.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <json-glib/json-glib.h>
6 #include "login/login.h"
7
8 #ifdef _WIN32
9 #include <conio.h>
10 #else
11 #include <errno.h>
12 #include <termios.h>
13 #include <sys/stat.h>
14 #endif
15
16 2 extern authentication_dto_t* parse_authentication_json(const char* json) {
17 2 JsonParser* parser = json_parser_new();
18
19 // Load JSON data into parser
20
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (!json_parser_load_from_data(parser, json, -1, NULL)) {
21 1 g_object_unref(parser);
22 1 return NULL;
23 }
24
25 // Get the root to make sure it's an object
26 1 JsonNode* root_node = json_parser_get_root(parser);
27
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if (!root_node || !JSON_NODE_HOLDS_OBJECT(root_node)) {
28 g_object_unref(parser);
29 return NULL;
30 }
31
32 // Parse JSON object into authentication_dto_t
33 1 JsonObject* root_obj = json_node_get_object(root_node);
34 1 authentication_dto_t* dto = g_malloc0(sizeof(authentication_dto_t));
35
36
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (json_object_has_member(root_obj, "accessToken"))
37 1 dto->access_token =
38 2 g_strdup(json_object_get_string_member(root_obj, "accessToken"));
39
40
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (json_object_has_member(root_obj, "tokenType"))
41 1 dto->token_type =
42 2 g_strdup(json_object_get_string_member(root_obj, "tokenType"));
43
44
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (json_object_has_member(root_obj, "expires"))
45 1 dto->expires =
46 2 g_strdup(json_object_get_string_member(root_obj, "expires"));
47
48 1 g_object_unref(parser);
49 1 return dto;
50 }
51
52 2 extern char* build_login_json(const login_dto_t* dto) {
53
1/1
✓ Branch 1 taken 2 times.
2 JsonBuilder* builder = json_builder_new();
54
1/1
✓ Branch 1 taken 2 times.
2 json_builder_begin_object(builder);
55
56
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (dto->email) {
57
1/1
✓ Branch 1 taken 1 times.
1 json_builder_set_member_name(builder, "email");
58
1/1
✓ Branch 1 taken 1 times.
1 json_builder_add_string_value(builder, dto->email);
59 }
60
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (dto->username) {
62 json_builder_set_member_name(builder, "username");
63 json_builder_add_string_value(builder, dto->username);
64 }
65
66
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (dto->password) {
67
1/1
✓ Branch 1 taken 1 times.
1 json_builder_set_member_name(builder, "password");
68
1/1
✓ Branch 1 taken 1 times.
1 json_builder_add_string_value(builder, dto->password);
69 }
70
71
1/1
✓ Branch 1 taken 2 times.
2 json_builder_end_object(builder);
72
73
1/1
✓ Branch 1 taken 2 times.
2 JsonGenerator* generator = json_generator_new();
74
1/1
✓ Branch 1 taken 2 times.
2 JsonNode* root = json_builder_get_root(builder);
75
1/1
✓ Branch 1 taken 2 times.
2 json_generator_set_root(generator, root);
76
1/1
✓ Branch 1 taken 2 times.
2 json_node_free(root);
77
78 2 gsize len = 0;
79
1/1
✓ Branch 1 taken 2 times.
2 char* json_str = json_generator_to_data(generator, &len);
80
81
1/1
✓ Branch 1 taken 2 times.
2 g_object_unref(generator);
82
1/1
✓ Branch 1 taken 2 times.
2 g_object_unref(builder);
83
84 2 return json_str;
85 }
86
87 1 extern void authentication_dto_free(authentication_dto_t* dto) {
88
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!dto)
89 return;
90
91 1 g_free(dto->access_token);
92 1 g_free(dto->token_type);
93 1 g_free(dto->expires);
94 1 g_free(dto);
95 }
96
97 extern void login_dto_free(login_dto_t* dto) {
98 if (dto->email)
99 g_free(dto->email);
100 if (dto->username)
101 g_free(dto->username);
102 if (dto->password)
103 g_free(dto->password);
104 }
105
106 2 extern int prompt_line(const char* prompt,
107 bool hide_input,
108 char* buffer,
109 size_t buffer_size) {
110
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
2 if (!prompt || !buffer || buffer_size == 0) {
111 2 return EINVAL;
112 }
113
114
1/1
✓ Branch 1 taken 2 times.
2 printf("%s: ", prompt);
115
1/1
✓ Branch 1 taken 2 times.
2 fflush(stdout);
116
117 #ifdef _WIN32 // Windows implementation using _getch()
118 if (hide_input) {
119 size_t pos = 0;
120 while (1) {
121 int ch = _getch();
122 if (ch == '\r' || ch == '\n') {
123 // End input on Enter
124 break;
125 } else if ((ch == '\b' || ch == 127) && pos > 0) {
126 // Handle backspace
127 pos--;
128 } else if (ch == 3) {
129 // Handle Ctrl+C
130 printf("\n");
131 return EINTR;
132 } else if (ch >= 32 && ch < 127 && pos < buffer_size - 1) {
133 // Handle regular character
134 buffer[pos++] = (char)ch;
135 }
136 }
137 buffer[pos] = '\0';
138 printf("\n");
139 } else {
140 if (!fgets(buffer, (int)buffer_size, stdin)) {
141 return EIO;
142 }
143 }
144 #else // Unix-like implementation using termios
145 struct termios oldt;
146 struct termios newt;
147 2 bool changed_term = false;
148
149
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
2 if (hide_input && tcgetattr(STDIN_FILENO, &oldt) == 0) {
150 newt = oldt;
151 newt.c_lflag &= (tcflag_t)~ECHO;
152 if (tcsetattr(STDIN_FILENO, TCSANOW, &newt) == 0) {
153 changed_term = true;
154 }
155 }
156
157
2/3
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
2 if (!fgets(buffer, (int)buffer_size, stdin)) {
158 if (changed_term) {
159 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
160 printf("\n");
161 }
162
163 return EIO;
164 }
165
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (changed_term) {
167 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
168 printf("\n");
169 }
170 #endif
171
172 // Remove trailing newline if present
173 2 size_t len = strlen(buffer);
174
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if (len > 0 && buffer[len - 1] == '\n') {
175 2 buffer[len - 1] = '\0';
176 }
177
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (strlen(buffer) == 0) {
179 return EINVAL;
180 }
181
182 2 return 0;
183 }
184
185 1 extern void secure_zero(void* ptr, size_t len) {
186
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (ptr && len > 0) {
187 1 volatile char* p = (volatile char*)ptr;
188
2/2
✓ Branch 0 taken 2048 times.
✓ Branch 1 taken 1 times.
2049 while (len--) {
189 2048 *p++ = 0;
190 }
191 }
192 1 }
193
194 extern int lock_file_permissions(__attribute__((__unused__)) const char* path) {
195 #ifdef _WIN32
196 #else
197 // Unix-like: Use chmod to set file permissions to 0600 (read/write for
198 // owner only)
199 if (chmod(path, S_IRUSR | S_IWUSR) != 0) {
200 return errno;
201 }
202 #endif
203 return 0;
204 }
205