diff options
| author | Walker Thompson <walker.thompson@urz.uni-heidelberg.de> | 2025-12-18 23:13:27 +0000 |
|---|---|---|
| committer | Walker Thompson <walker.thompson@urz.uni-heidelberg.de> | 2025-12-18 23:13:27 +0000 |
| commit | fdda56c95ae249c90b47c1a060d081db66a730da (patch) | |
| tree | 5320deba531b864f64d08883f97515b9d84850f0 /wxgui.cpp | |
Initial commit
Diffstat (limited to 'wxgui.cpp')
| -rw-r--r-- | wxgui.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/wxgui.cpp b/wxgui.cpp new file mode 100644 index 0000000..6a6873a --- /dev/null +++ b/wxgui.cpp @@ -0,0 +1,216 @@ +#include "totpgen.h" + +#ifdef _WIN32 +static const std::string path_separator = "\\"; +static const std::string config_dir_name = "TOTPGen"; +#else +static const std::string path_separator = "/"; +static const std::string config_dir_name = ".totpgen"; +#endif + +IMPLEMENT_APP(TOTPGenGUI) + +bool TOTPGenGUI::OnInit() +{ + TOTPGen *MainAppFrame = new TOTPGen(); + MainAppFrame->Show(true); + return true; +} + +TOTPGen::TOTPGen() : wxFrame(nullptr, wxID_ANY, wxT("TOTP Generator"), + wxDefaultPosition, wxSize(320,240), + wxDEFAULT_FRAME_STYLE | wxRESIZE_BORDER) +{ + MainWindow = new wxPanel(this, wxID_ANY); + MainSizer = new wxBoxSizer(wxVERTICAL); + + Locked = true; + + wxString UserConfigDir = wxStandardPaths::Get().GetUserConfigDir(); + + wxString AppConfigDir = UserConfigDir + path_separator + config_dir_name; + if (!wxDirExists(AppConfigDir)) { + wxMkdir(AppConfigDir); + } + + SecretFile = AppConfigDir + path_separator + "secret.dat"; + + TOTPField = new wxStaticText(MainWindow, wxID_ANY, + wxEmptyString, wxDefaultPosition, + wxDefaultSize, wxTE_CENTER); + wxFont LabelFont(48, wxFONTFAMILY_TELETYPE, + wxFONTSTYLE_NORMAL, + wxFONTWEIGHT_NORMAL); + TOTPField->SetFont(LabelFont); + TOTPField->SetLabel(" "); + + TextSizer = new wxBoxSizer(wxHORIZONTAL); + TextSizer->Add(TOTPField, 2, wxCENTER); + + CountdownGauge = new wxGauge(MainWindow, wxID_ANY, 30, wxPoint(50, 50)); + CountdownTimer = new wxTimer(MainWindow, wxID_ANY); + CountdownTimer->Start(1000); + + UpdateSecretButton = new wxButton(MainWindow, wxID_OK, wxT("Set Key")); + UpdateSecretButton->Bind(wxEVT_BUTTON, &TOTPGen::UpdateSecret, this); + + UnlockButton = new wxButton(MainWindow, wxID_CLEAR, wxT("Unlock")); + UnlockButton->Bind(wxEVT_BUTTON, &TOTPGen::Unlock, this); + if (!wxFileExists(SecretFile)) { + UnlockButton->Enable(false); + } + + ButtonSizer_Upper = new wxBoxSizer(wxHORIZONTAL); + ButtonSizer_Upper->Add(UpdateSecretButton, 2, wxEXPAND | wxALL); + ButtonSizer_Upper->Add(UnlockButton, 2, wxEXPAND | wxALL); + + CopyButton = new wxButton(MainWindow, wxID_COPY, wxT("Copy")); + CopyButton->Bind(wxEVT_BUTTON, &TOTPGen::CopyText, this); + if (Locked) { + CopyButton->Enable(false); + } + + QuitButton = new wxButton(MainWindow, wxID_EXIT, wxT("Exit")); + QuitButton->Bind(wxEVT_BUTTON, &TOTPGen::OnExit, this); + + ButtonSizer_Lower = new wxBoxSizer(wxHORIZONTAL); + ButtonSizer_Lower->Add(CopyButton, 2, wxEXPAND | wxALL); + ButtonSizer_Lower->Add(QuitButton, 2, wxEXPAND | wxALL); + + MainSizer->Add(TextSizer, 2, wxCENTER | wxALIGN_CENTER); + MainSizer->Add(CountdownGauge, 2, wxEXPAND | wxALL); + MainSizer->Add(ButtonSizer_Upper, 2, wxEXPAND | wxALL); + MainSizer->Add(ButtonSizer_Lower, 2, wxEXPAND | wxALL); + + MainWindow->SetSizer(MainSizer); +} + +void TOTPGen::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(true); +} + +bool TOTPGen::IsBase32(std::string& str) +{ + std::unordered_set<char> Base32Chars(base32.begin(), base32.end()); + + for (char c: str) { + if (Base32Chars.find(c) == Base32Chars.end()) { + return false; + } + } + + return true; +} + +void TOTPGen::UpdateSecret(wxCommandEvent& WXUNUSED(event)) +{ + wxTextEntryDialog SecretPrompt(this, wxT("Please enter the base 32 token."), + wxT("Secret Entry"), wxEmptyString); + + std::string Secret_New; + if (SecretPrompt.ShowModal() == wxID_OK) { + Secret_New = SecretPrompt.GetValue().MakeUpper().ToStdString(); + if (!IsBase32(Secret_New)) { + wxMessageBox(wxT("Base 32 token contains invalid characters.\n" + "Only the following are permissible: \n" + base32), + wxT("Error"), wxOK | wxICON_ERROR); + return; + } + } + + wxPasswordEntryDialog PasswordPrompt(this, wxT("Please enter a new passphrase\n" + "to encrypt the secret token."), + wxT("Passphrase Entry"), wxEmptyString); + + wxPasswordEntryDialog ConfirmPrompt(this, wxT("Please confirm the passphrase."), + wxT("Passphrase Entry"), wxEmptyString); + + + if ((PasswordPrompt.ShowModal() == wxID_OK) + && (ConfirmPrompt.ShowModal() == wxID_OK)) { + if (PasswordPrompt.GetValue() == ConfirmPrompt.GetValue()) { + Passphrase = PasswordPrompt.GetValue(); + } + else { + wxMessageBox(wxT("Passphrases did not match - try again"), + wxT("Error"), wxOK | wxICON_ERROR); + return; + } + } + else { + return; + } + + + if (!GenTOTP(Secret_New)) { + wxMessageBox(wxT("Could not generate TOTP - bad token?"), + wxT("Error"), wxOK | wxICON_ERROR); + return; + } + + Secret = Secret_New; + EncryptSecret(Secret); + + if (Locked) { + Locked = false; + + MainWindow->Connect(CountdownTimer->GetId(), wxEVT_TIMER, + wxTimerEventHandler(TOTPGen::UpdateStatus), + NULL, this); + + CopyButton->Enable(true); + UnlockButton->Enable(false); + } + + return; +} + +void TOTPGen::Unlock(wxCommandEvent& WXUNUSED(event)) +{ + wxPasswordEntryDialog PasswordPrompt(this, wxT("Please enter your passphrase."), + wxT("Passphrase Entry"), wxEmptyString); + + if (PasswordPrompt.ShowModal() == wxID_OK) { + Passphrase = PasswordPrompt.GetValue(); + } + + if (!DecryptSecret()) { + wxMessageBox(wxT("Could not unlock base 32 token,\n" + "bad passphrase or corrupt file?"), + wxT("Error"), wxOK | wxICON_ERROR); + return; + } + + MainWindow->Connect(CountdownTimer->GetId(), wxEVT_TIMER, + wxTimerEventHandler(TOTPGen::UpdateStatus), + NULL, this); + + Locked = false; + + CopyButton->Enable(true); + UnlockButton->Enable(false); + + GenTOTP(Secret); +} + +void TOTPGen::UpdateStatus(wxTimerEvent& WXUNUSED(event)) +{ + unsigned char CounterValue = 29 - ((time(NULL) - 1) % 30); + + CountdownGauge->SetValue(CounterValue); + + if (CounterValue == 0) { + GenTOTP(Secret); + } +} + +void TOTPGen::CopyText(wxCommandEvent& WXUNUSED(event)) +{ + wxString ToCopy = TOTPField->GetLabel(); + + if (wxTheClipboard->Open() && !Locked) { + wxTheClipboard->SetData(new wxTextDataObject(ToCopy)); + wxTheClipboard->Close(); + } +}
\ No newline at end of file |
