55#include " utils.hpp"
66#include " skStr.h"
77#include < iostream>
8+ #include < filesystem> // file checks for saved creds. -nigel
9+ #include < limits> // input validation helpers. -nigel
10+ #include < chrono> // date math for expiry display. -nigel
811std::string tm_to_readable_time (tm ctx);
912static std::time_t string_to_timet (std::string timestamp);
1013static std::tm timet_to_tm (time_t timestamp);
14+ static std::string remaining_until (std::string timestamp); // human readable expiry countdown. -nigel
1115const std::string compilation_date = (std::string)skCrypt(__DATE__);
1216const std::string compilation_time = (std::string)skCrypt(__TIME__);
1317void sessionStatus ();
@@ -27,6 +31,7 @@ api KeyAuthApp(name, ownerid, version, url, path);
2731
2832int main ()
2933{
34+ // clear plaintext config copies after api init below. -nigel
3035 std::string consoleTitle = skCrypt (" Loader - Built at: " ).decrypt () + compilation_date + " " + compilation_time;
3136 SetConsoleTitleA (consoleTitle.c_str ());
3237 std::cout << skCrypt (" \n\n Connecting.." );
@@ -38,31 +43,50 @@ int main()
3843 Sleep (1500 );
3944 exit (1 );
4045 }
46+ name.clear (); ownerid.clear (); version.clear (); url.clear (); path.clear (); // reduce exposure of config strings. -nigel
4147
4248 std::string username, password, key, TfaCode; // keep this before the auto-login with saved file.
4349 // because if you don't and the user has 2FA on, then they won't be asked for 2FA code and can't login.
4450
45- if (std::filesystem::exists (" test.json" )) // change test.txt to the path of your file :smile:
51+ const std::string save_path = " test.json" ; // keep consistent with existing example file. -nigel
52+ bool used_saved_creds = false ; // track whether we auto-logged in. -nigel
53+ if (std::filesystem::exists (save_path))
4654 {
47- if (!CheckIfJsonKeyExists (" test.json" , " username" ))
55+ // only trust saved data if it parses cleanly and is non-empty. -nigel
56+ const auto saved_license = ReadFromJson (save_path, " license" );
57+ const auto saved_username = ReadFromJson (save_path, " username" );
58+ const auto saved_password = ReadFromJson (save_path, " password" );
59+
60+ if (!saved_license.empty ())
4861 {
49- key = ReadFromJson ( " test.json " , " license " ) ;
62+ key = saved_license ;
5063 KeyAuthApp.license (key);
64+ used_saved_creds = true ;
5165 }
52- else
66+ else if (!saved_username. empty () && !saved_password. empty ())
5367 {
54- username = ReadFromJson ( " test.json " , " username " ) ;
55- password = ReadFromJson ( " test.json " , " password " ) ;
68+ username = saved_username ;
69+ password = saved_password ;
5670 KeyAuthApp.login (username, password);
71+ used_saved_creds = true ;
5772 }
5873 }
59- else
74+
75+ if (!used_saved_creds)
6076 {
6177 std::cout << skCrypt (" \n\n [1] Login\n [2] Register\n [3] Upgrade\n [4] License key only\n\n Choose option: " );
6278
6379 int option;
6480
6581 std::cin >> option;
82+ if (std::cin.fail ())
83+ {
84+ std::cin.clear ();
85+ std::cin.ignore (std::numeric_limits<std::streamsize>::max (), ' \n ' );
86+ std::cout << skCrypt (" \n\n Status: Failure: Invalid Selection" ); // bad input path. -nigel
87+ Sleep (3000 );
88+ exit (1 );
89+ }
6690 switch (option)
6791 {
6892 case 1 :
@@ -131,15 +155,33 @@ int main()
131155 }
132156 }
133157
134- if (username.empty () || password.empty ())
158+ bool save_creds = false ; // opt-in to disk storage to reduce exposure. -nigel
159+ std::cout << skCrypt (" \n\n Save credentials to disk for auto-login? [y/N]: " );
160+ char save_choice = ' n' ;
161+ std::cin >> save_choice;
162+ if (std::cin.fail ())
163+ {
164+ std::cin.clear ();
165+ std::cin.ignore (std::numeric_limits<std::streamsize>::max (), ' \n ' );
166+ save_choice = ' n' ; // default to no on bad input. -nigel
167+ }
168+ save_creds = (save_choice == ' y' || save_choice == ' Y' );
169+
170+ if (save_creds)
135171 {
136- WriteToJson (" test.json" , " license" , key, false , " " , " " );
172+ if (username.empty () || password.empty ())
173+ {
174+ WriteToJson (save_path, " license" , key, false , " " , " " );
175+ }
176+ else
177+ {
178+ WriteToJson (save_path, " username" , username, true , " password" , password);
179+ }
137180 std::cout << skCrypt (" Successfully Created File For Auto Login" );
138181 }
139182 else
140183 {
141- WriteToJson (" test.json" , " username" , username, true , " password" , password);
142- std::cout << skCrypt (" Successfully Created File For Auto Login" );
184+ std::remove (save_path.c_str ()); // remove stale creds if user opts out. -nigel
143185 }
144186
145187 /*
@@ -171,6 +213,7 @@ int main()
171213 auto sub = KeyAuthApp.user_data .subscriptions .at (i);
172214 std::cout << skCrypt (" \n name: " ) << sub.name ;
173215 std::cout << skCrypt (" : expiry: " ) << tm_to_readable_time (timet_to_tm (string_to_timet (sub.expiry )));
216+ std::cout << skCrypt (" (" ) << remaining_until (sub.expiry ) << skCrypt (" )" ); // show time remaining. -nigel
174217 }
175218
176219
@@ -209,9 +252,11 @@ std::string tm_to_readable_time(tm ctx) {
209252}
210253
211254static std::time_t string_to_timet (std::string timestamp) {
212- auto cv = strtol (timestamp.c_str (), NULL , 10 ); // long
213-
214- return (time_t )cv;
255+ char * end = nullptr ;
256+ auto cv = strtol (timestamp.c_str (), &end, 10 );
257+ if (end == timestamp.c_str ())
258+ return 0 ; // invalid timestamp returns epoch. -nigel
259+ return static_cast <time_t >(cv);
215260}
216261
217262static std::tm timet_to_tm (time_t timestamp) {
@@ -221,3 +266,21 @@ static std::tm timet_to_tm(time_t timestamp) {
221266
222267 return context;
223268}
269+
270+ static std::string remaining_until (std::string timestamp) {
271+ const auto expiry = string_to_timet (timestamp);
272+ const auto now = std::time (nullptr );
273+ if (expiry <= now)
274+ return " expired" ; // already expired. -nigel
275+ auto diff = std::chrono::seconds (expiry - now);
276+ auto days = std::chrono::duration_cast<std::chrono::hours>(diff).count () / 24 ;
277+ auto weeks = days / 7 ;
278+ auto months = days / 30 ;
279+ auto years = days / 365 ;
280+ std::string out;
281+ if (years > 0 ) out += std::to_string (years) + " y " ;
282+ if (months > 0 ) out += std::to_string (months % 12 ) + " mo " ;
283+ if (weeks > 0 ) out += std::to_string (weeks % 4 ) + " w " ;
284+ out += std::to_string (days % 7 ) + " d" ;
285+ return out;
286+ }
0 commit comments