Skip to content

Commit ddf27e2

Browse files
committed
Improve input handling and expiry display
1 parent ce9c491 commit ddf27e2

5 files changed

Lines changed: 195 additions & 78 deletions

File tree

x64/main.cpp

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
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
811
std::string tm_to_readable_time(tm ctx);
912
static std::time_t string_to_timet(std::string timestamp);
1013
static std::tm timet_to_tm(time_t timestamp);
14+
static std::string remaining_until(std::string timestamp); // human readable expiry countdown. -nigel
1115
const std::string compilation_date = (std::string)skCrypt(__DATE__);
1216
const std::string compilation_time = (std::string)skCrypt(__TIME__);
1317
void sessionStatus();
@@ -27,6 +31,7 @@ api KeyAuthApp(name, ownerid, version, url, path);
2731

2832
int 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

211254
static 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

217262
static 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+
}

x64/utils.hpp

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,35 @@
66
#include "json.hpp"
77
using json = nlohmann::json;
88

9-
std::string ReadFromJson(std::string path, std::string section)
10-
{
11-
if (!std::filesystem::exists(path))
12-
return skCrypt("File Not Found").decrypt();
13-
std::ifstream file(path);
14-
json data = json::parse(file);
15-
return data[section];
16-
}
17-
18-
bool CheckIfJsonKeyExists(std::string path, std::string section)
19-
{
20-
if (!std::filesystem::exists(path))
21-
return skCrypt("File Not Found").decrypt();
22-
std::ifstream file(path);
23-
json data = json::parse(file);
24-
return data.contains(section);
25-
}
26-
27-
bool WriteToJson(std::string path, std::string name, std::string value, bool userpass, std::string name2, std::string value2)
28-
{
29-
json file;
9+
std::string ReadFromJson(std::string path, std::string section)
10+
{
11+
if (!std::filesystem::exists(path))
12+
return ""; // missing file returns empty. -nigel
13+
std::ifstream file(path);
14+
if (!file.good())
15+
return ""; // failed open returns empty. -nigel
16+
json data = json::parse(file, nullptr, false);
17+
if (data.is_discarded() || !data.contains(section))
18+
return ""; // invalid or missing key returns empty. -nigel
19+
return data[section];
20+
}
21+
22+
bool CheckIfJsonKeyExists(std::string path, std::string section)
23+
{
24+
if (!std::filesystem::exists(path))
25+
return false; // missing file means no key. -nigel
26+
std::ifstream file(path);
27+
if (!file.good())
28+
return false; // failed open means no key. -nigel
29+
json data = json::parse(file, nullptr, false);
30+
if (data.is_discarded())
31+
return false; // invalid json means no key. -nigel
32+
return data.contains(section);
33+
}
34+
35+
bool WriteToJson(std::string path, std::string name, std::string value, bool userpass, std::string name2, std::string value2)
36+
{
37+
json file;
3038
if (!userpass)
3139
{
3240
file[name] = value;
@@ -37,14 +45,16 @@ bool WriteToJson(std::string path, std::string name, std::string value, bool use
3745
file[name2] = value2;
3846
}
3947

40-
std::ofstream jsonfile(path, std::ios::out);
41-
jsonfile << file;
42-
jsonfile.close();
43-
if (!std::filesystem::exists(path))
44-
return false;
45-
46-
return true;
47-
}
48+
std::ofstream jsonfile(path, std::ios::out | std::ios::trunc);
49+
if (!jsonfile.good())
50+
return false; // failed open means no write. -nigel
51+
jsonfile << file;
52+
jsonfile.flush();
53+
if (!jsonfile.good() || !std::filesystem::exists(path))
54+
return false;
55+
56+
return true;
57+
}
4858

4959
void checkAuthenticated(std::string ownerid) {
5060
while (true) {

x86/lib/utils.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ std::string utils::get_hwid() {
1212
}
1313

1414
std::time_t utils::string_to_timet(std::string timestamp) {
15-
auto cv = strtol(timestamp.c_str(), NULL, 10);
16-
17-
return (time_t)cv;
15+
char* end = nullptr;
16+
auto cv = strtol(timestamp.c_str(), &end, 10);
17+
if (end == timestamp.c_str())
18+
return 0; // invalid timestamp returns epoch. -nigel
19+
return static_cast<time_t>(cv);
1820
}
1921

2022
std::tm utils::timet_to_tm(time_t timestamp) {

x86/main.cpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
#include <auth.hpp>
44
#include "utils.hpp"
55
#include "skStr.h"
6+
#include <limits> // input validation helpers. -nigel
7+
#include <chrono> // date math for expiry display. -nigel
68
std::string tm_to_readable_time(tm ctx);
79
static std::time_t string_to_timet(std::string timestamp);
810
static std::tm timet_to_tm(time_t timestamp);
11+
static std::string remaining_until(std::string timestamp); // human readable expiry countdown. -nigel
912
const std::string compilation_date = (std::string)skCrypt(__DATE__);
1013
const std::string compilation_time = (std::string)skCrypt(__TIME__);
1114

@@ -44,6 +47,14 @@ int main()
4447
std::string key;
4548

4649
std::cin >> option;
50+
if (std::cin.fail())
51+
{
52+
std::cin.clear();
53+
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
54+
std::cout << skCrypt("\n\n Status: Failure: Invalid Selection"); // bad input path. -nigel
55+
Sleep(3000);
56+
exit(1);
57+
}
4758
switch (option)
4859
{
4960
case 1:
@@ -99,6 +110,7 @@ int main()
99110
auto sub = KeyAuthApp.user_data.subscriptions.at(i);
100111
std::cout << skCrypt("\n name: ") << sub.name;
101112
std::cout << skCrypt(" : expiry: ") << tm_to_readable_time(timet_to_tm(string_to_timet(sub.expiry)));
113+
std::cout << skCrypt(" (") << remaining_until(sub.expiry) << skCrypt(")"); // show time remaining. -nigel
102114
}
103115

104116
std::cout << skCrypt("\n\n Closing in five seconds...");
@@ -116,9 +128,11 @@ std::string tm_to_readable_time(tm ctx) {
116128
}
117129

118130
static std::time_t string_to_timet(std::string timestamp) {
119-
auto cv = strtol(timestamp.c_str(), NULL, 10); // long
120-
121-
return (time_t)cv;
131+
char* end = nullptr;
132+
auto cv = strtol(timestamp.c_str(), &end, 10);
133+
if (end == timestamp.c_str())
134+
return 0; // invalid timestamp returns epoch. -nigel
135+
return static_cast<time_t>(cv);
122136
}
123137

124138
static std::tm timet_to_tm(time_t timestamp) {
@@ -128,3 +142,21 @@ static std::tm timet_to_tm(time_t timestamp) {
128142

129143
return context;
130144
}
145+
146+
static std::string remaining_until(std::string timestamp) {
147+
const auto expiry = string_to_timet(timestamp);
148+
const auto now = std::time(nullptr);
149+
if (expiry <= now)
150+
return "expired"; // already expired. -nigel
151+
auto diff = std::chrono::seconds(expiry - now);
152+
auto days = std::chrono::duration_cast<std::chrono::hours>(diff).count() / 24;
153+
auto weeks = days / 7;
154+
auto months = days / 30;
155+
auto years = days / 365;
156+
std::string out;
157+
if (years > 0) out += std::to_string(years) + "y ";
158+
if (months > 0) out += std::to_string(months % 12) + "mo ";
159+
if (weeks > 0) out += std::to_string(weeks % 4) + "w ";
160+
out += std::to_string(days % 7) + "d";
161+
return out;
162+
}

0 commit comments

Comments
 (0)