diff --git a/uppsrc/Core/Hash.h b/uppsrc/Core/Hash.h index d301fe4c8..2d0c1d69d 100644 --- a/uppsrc/Core/Hash.h +++ b/uppsrc/Core/Hash.h @@ -70,7 +70,7 @@ class Sha256Stream : public OutStream { void Cleanup(); public: - void Finish(byte *hash20); + void Finish(byte *hash32); String FinishString(); String FinishStringS(); @@ -81,8 +81,8 @@ public: ~Sha256Stream(); }; -void SHA256(byte *hash20, const void *data, dword size); -void SHA256(byte *hash20, const String& s); +void SHA256(byte *hash32, const void *data, dword size); +void SHA256(byte *hash32, const String& s); String SHA256String(const void *data, dword size); String SHA256String(const String& data); String SHA256StringS(const void *data, dword size); diff --git a/uppsrc/ide/Credentials.cpp b/uppsrc/ide/Credentials.cpp index a098b77ad..06c5c43da 100644 --- a/uppsrc/ide/Credentials.cpp +++ b/uppsrc/ide/Credentials.cpp @@ -11,6 +11,39 @@ String GetSvnDir(const String& p) return Null; } +byte passkey_sha256[32]; + +String CredentialsCrypt(const String& src) +{ + int ci = 0; + byte c[32]; + memcpy(c, passkey_sha256, 32); + String r; + for(char b : src) { + if(ci >= 32) { // poor mans acceptable encryption + SHA256(c, c, 32); + ci = 0; + } + r.Cat(b ^ c[ci++]); + } + return r; +} + +struct PasskeyDlg : WithPasskeyLayout { + PasskeyDlg(); + + void Sync() { passkey1.Password(!show_passkey); passkey2.Password(!show_passkey); } +}; + +PasskeyDlg::PasskeyDlg() +{ + CtrlLayoutOK(*this, "Passkey"); + + show_passkey << [=] { Sync(); }; + + Sync(); +} + struct Credential { String url; String username; @@ -22,10 +55,12 @@ String CredentialsFile() return ConfigFile("repo.credentials"); } -bool LoadCredentials(Array& r) +bool LoadCredentials0(Array& r) { r.Clear(); String s = LoadFile(CredentialsFile()); + if(String(passkey_sha256, 32) != String(0, 32)) + s = CredentialsCrypt(s); Value v = ParseJSON(s); if(IsError(v)) return false; @@ -44,6 +79,45 @@ bool LoadCredentials(Array& r) return true; } +struct GetPasskeyDlg : WithGetPasskeyLayout { + GetPasskeyDlg(); + + void Sync() { passkey.Password(!show_passkey);; } +}; + +GetPasskeyDlg::GetPasskeyDlg() +{ + CtrlLayoutOKCancel(*this, "Passkey"); + + show_passkey << [=] { Sync(); }; + + Sync(); +} + +bool LoadCredentials(Array& r) +{ + if(!FileExists(CredentialsFile())) + return false; + if(LoadCredentials0(r)) return true; + if(String(passkey_sha256, 32) == String(0, 32)) { + for(;;) { + GetPasskeyDlg dlg; + dlg.Run(); + SHA256(passkey_sha256, ~dlg.passkey); + if(LoadCredentials0(r)) return true; + WithFailedPasskeyLayout p; + CtrlLayoutOK(p, "Passkey"); + p.Breaker(p.clear, IDEXIT); + if(p.Run() == IDEXIT) { + memset(passkey_sha256, 0, 32); + FileDelete(CredentialsFile()); + break; + } + } + } + return false; +} + bool GetCredentials(const String& url, const String& dir, String& username, String& password) { Array cr; @@ -97,11 +171,52 @@ struct CredentialsDlg : WithCredentialsLayout { void Load(); void Save(); + + void Passkey(); typedef CredentialsDlg CLASSNAME; CredentialsDlg(const Vector& url_hints); }; +CredentialsDlg::CredentialsDlg(const Vector& url_hints) +: url_hints(url_hints) +{ + CtrlLayoutOKCancel(*this, "Credentials"); + list.AddColumn("Url (or directory)"); + list.AddColumn("Username"); + list.AddColumn("Password"); + list.ColumnWidths("500 200 200"); + list.EvenRowColor(); + list.SetLineCy(max(Draw::GetStdFontCy() + Zy(4), Zy(20))); + list.WhenSel = [=] { Sync(); }; + list.WhenLeftDouble = [=] { Edit(); }; + + show_passwords << [=] { Sync(); }; + add << [=] { Add(); }; + edit << [=] { Edit(); }; + remove << [=] { Remove(); }; + clear << [=] { + if(PromptYesNo("Remove all?")) + list.Clear(); + }; + passkey << [=] { Passkey(); }; +} + +void CredentialsDlg::Passkey() +{ + PasskeyDlg dlg; + String k; + for(;;) { + if(dlg.Run() == IDCANCEL) + return; + k = ~dlg.passkey1; + if(k == ~dlg.passkey2) + break; + Exclamation("Fields do not match!"); + } + SHA256(passkey_sha256, k); +} + void CredentialsDlg::Load() { list.Clear(); @@ -121,7 +236,7 @@ void CredentialsDlg::Save() va << ValueMap()("url", list.Get(i, 0)) ("username", list.Get(i, 1)) ("password", list.Get(i, 2)); - SaveFile(CredentialsFile(), AsJSON(va)); + SaveFile(CredentialsFile(), CredentialsCrypt(AsJSON(va))); } else FileDelete(CredentialsFile()); @@ -189,29 +304,6 @@ void CredentialsDlg::Sync() ); } -CredentialsDlg::CredentialsDlg(const Vector& url_hints) -: url_hints(url_hints) -{ - CtrlLayoutOKCancel(*this, "Credentials"); - list.AddColumn("Url (or directory)"); - list.AddColumn("Username"); - list.AddColumn("Password"); - list.ColumnWidths("500 200 200"); - list.EvenRowColor(); - list.SetLineCy(max(Draw::GetStdFontCy() + Zy(4), Zy(20))); - list.WhenSel = [=] { Sync(); }; - list.WhenLeftDouble = [=] { Edit(); }; - - show_passwords << [=] { Sync(); }; - add << [=] { Add(); }; - edit << [=] { Edit(); }; - remove << [=] { Remove(); }; - clear << [=] { - if(PromptYesNo("Remove all?")) - list.Clear(); - }; -} - void EditCredentials(const Vector& url_hints) { CredentialsDlg dlg(url_hints); diff --git a/uppsrc/ide/urepo.lay b/uppsrc/ide/urepo.lay index 8a4452f3b..f5d447490 100644 --- a/uppsrc/ide/urepo.lay +++ b/uppsrc/ide/urepo.lay @@ -7,13 +7,14 @@ END_LAYOUT LAYOUT(CredentialsLayout, 680, 400) ITEM(Upp::ArrayCtrl, list, AutoHideSb(true).HSizePosZ(4, 4).VSizePosZ(4, 36)) + ITEM(Upp::Option, show_passwords, SetLabel(t_("Show passwords")).LeftPosZ(4, 108).TopPosZ(372, 20)) + ITEM(Upp::Button, passkey, SetLabel(t_("Passkey..")).LeftPosZ(136, 76).TopPosZ(372, 24)) + ITEM(Upp::Button, add, SetLabel(t_("Add..")).LeftPosZ(240, 64).TopPosZ(372, 24)) + ITEM(Upp::Button, edit, SetLabel(t_("Edit..")).LeftPosZ(308, 64).TopPosZ(372, 24)) + ITEM(Upp::Button, remove, SetLabel(t_("Remove")).LeftPosZ(376, 64).TopPosZ(372, 24)) + ITEM(Upp::Button, clear, SetLabel(t_("Remove all")).LeftPosZ(456, 72).TopPosZ(372, 24)) ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(544, 64).BottomPosZ(4, 24)) ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(612, 64).BottomPosZ(4, 24)) - ITEM(Upp::Option, show_passwords, SetLabel(t_("Show passwords")).LeftPosZ(4, 108).TopPosZ(372, 20)) - ITEM(Upp::Button, clear, SetLabel(t_("Remove all")).LeftPosZ(448, 72).TopPosZ(372, 24)) - ITEM(Upp::Button, add, SetLabel(t_("Add..")).LeftPosZ(220, 64).TopPosZ(372, 24)) - ITEM(Upp::Button, edit, SetLabel(t_("Edit..")).LeftPosZ(288, 64).TopPosZ(372, 24)) - ITEM(Upp::Button, remove, SetLabel(t_("Remove")).LeftPosZ(356, 64).TopPosZ(372, 24)) END_LAYOUT LAYOUT(UrepoConsoleLayout, 680, 660) @@ -45,3 +46,26 @@ LAYOUT(CredentialLayout, 368, 116) ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(296, 64).BottomPosZ(8, 24)) END_LAYOUT +LAYOUT(PasskeyLayout, 368, 92) + ITEM(Upp::Label, dv___0, SetLabel(t_("Passkey")).LeftPosZ(8, 92).TopPosZ(8, 19)) + ITEM(Upp::EditString, passkey1, LeftPosZ(112, 248).TopPosZ(8, 19)) + ITEM(Upp::Label, dv___2, SetLabel(t_("Passkey (confirm)")).LeftPosZ(8, 92).TopPosZ(32, 19)) + ITEM(Upp::EditString, passkey2, LeftPosZ(112, 248).TopPosZ(32, 19)) + ITEM(Upp::Option, show_passkey, SetLabel(t_("Show passkey")).LeftPosZ(8, 108).TopPosZ(60, 20)) + ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(296, 64).BottomPosZ(8, 24)) +END_LAYOUT + +LAYOUT(GetPasskeyLayout, 368, 68) + ITEM(Upp::Label, dv___0, SetLabel(t_("Passkey")).LeftPosZ(8, 92).TopPosZ(8, 19)) + ITEM(Upp::EditString, passkey, LeftPosZ(112, 248).TopPosZ(8, 19)) + ITEM(Upp::Option, show_passkey, SetLabel(t_("Show passkey")).LeftPosZ(8, 108).TopPosZ(36, 20)) + ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).LeftPosZ(228, 64).BottomPosZ(8, 24)) + ITEM(Upp::Button, ok, SetLabel(t_("OK")).LeftPosZ(296, 64).BottomPosZ(8, 24)) +END_LAYOUT + +LAYOUT(FailedPasskeyLayout, 296, 64) + ITEM(Upp::Label, dv___0, SetLabel(t_("Invalid passkey.")).LeftPosZ(8, 296).TopPosZ(8, 19)) + ITEM(Upp::Button, clear, SetLabel(t_("Clear credentials and passkey")).LeftPosZ(8, 168).TopPosZ(32, 24)) + ITEM(Upp::Button, ok, SetLabel(t_("Try again")).LeftPosZ(212, 76).TopPosZ(32, 24)) +END_LAYOUT +