mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
326 lines
6.7 KiB
C++
326 lines
6.7 KiB
C++
#include "ide.h"
|
|
|
|
String GetSvnDir(const String& p)
|
|
{
|
|
String dir = p;
|
|
while(dir.GetCount() > 4) {
|
|
if(DirectoryExists(AppendFileName(dir, ".svn")) || DirectoryExists(AppendFileName(dir, "_svn")))
|
|
return dir;
|
|
dir = GetFileFolder(dir);
|
|
}
|
|
return Null;
|
|
}
|
|
|
|
byte passkey_sha256[32];
|
|
|
|
bool HasCredentialsPasskey()
|
|
{
|
|
for(int i = 0; i < 32; i++)
|
|
if(passkey_sha256[i])
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
String CredentialsCrypt(const String& src)
|
|
{
|
|
if(!HasCredentialsPasskey())
|
|
return 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<TopWindow> {
|
|
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;
|
|
String password;
|
|
};
|
|
|
|
String CredentialsFile()
|
|
{
|
|
return ConfigFile("repo.credentials");
|
|
}
|
|
|
|
bool LoadCredentials0(Array<Credential>& r)
|
|
{
|
|
r.Clear();
|
|
Value v = ParseJSON(CredentialsCrypt(LoadFile(CredentialsFile())));
|
|
if(IsError(v))
|
|
return false;
|
|
try {
|
|
for(Value e : v) {
|
|
Credential& c = r.Add();
|
|
c.url = e["url"];
|
|
c.username = e["username"];
|
|
c.password = e["password"];
|
|
}
|
|
}
|
|
catch(ValueTypeError) {
|
|
r.Clear();
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
struct GetPasskeyDlg : WithGetPasskeyLayout<TopWindow> {
|
|
GetPasskeyDlg();
|
|
|
|
void Sync() { passkey.Password(!show_passkey); }
|
|
};
|
|
|
|
GetPasskeyDlg::GetPasskeyDlg()
|
|
{
|
|
CtrlLayoutOK(*this, "Passkey");
|
|
|
|
show_passkey << [=] { Sync(); };
|
|
|
|
Sync();
|
|
}
|
|
|
|
bool LoadCredentials(Array<Credential>& r)
|
|
{
|
|
if(!FileExists(CredentialsFile()))
|
|
return false;
|
|
if(LoadCredentials0(r)) return true;
|
|
if(!HasCredentialsPasskey()) {
|
|
for(;;) {
|
|
GetPasskeyDlg dlg;
|
|
dlg.Run();
|
|
SHA256(passkey_sha256, ~dlg.passkey);
|
|
if(LoadCredentials0(r)) return true;
|
|
WithFailedPasskeyLayout<TopWindow> 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<Credential> cr;
|
|
int best = 0;
|
|
if(LoadCredentials(cr)) {
|
|
for(const Credential& c : cr) {
|
|
for(int pass = 0; pass < 2; pass++) {
|
|
const String& u = pass ? url : dir;
|
|
int n = min(u.GetCount(), c.url.GetCount());
|
|
int ml;
|
|
for(ml = 0; ml < n; ml++)
|
|
if(u[ml] != c.url[ml])
|
|
break;
|
|
if(ml > best) {
|
|
best = ml;
|
|
username = c.username;
|
|
password = c.password;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return best;
|
|
}
|
|
|
|
struct CredentialDlg : WithCredentialLayout<TopWindow> {
|
|
void Hints(const Vector<String>& url_hints);
|
|
void Sync() { password.Password(!show_password); }
|
|
CredentialDlg();
|
|
};
|
|
|
|
void CredentialDlg::Hints(const Vector<String>& url_hints)
|
|
{
|
|
for(String s : url_hints)
|
|
url.AddList(s);
|
|
}
|
|
|
|
CredentialDlg::CredentialDlg()
|
|
{
|
|
CtrlLayoutOKCancel(*this, "Credentials");
|
|
Sync();
|
|
show_password << [=] { Sync(); };
|
|
}
|
|
|
|
struct CredentialsDlg : WithCredentialsLayout<TopWindow> {
|
|
const Vector<String>& url_hints;
|
|
|
|
void Sync();
|
|
void Add();
|
|
void Edit();
|
|
void Remove();
|
|
|
|
void Load();
|
|
void Save();
|
|
|
|
void Passkey();
|
|
|
|
typedef CredentialsDlg CLASSNAME;
|
|
CredentialsDlg(const Vector<String>& url_hints);
|
|
};
|
|
|
|
CredentialsDlg::CredentialsDlg(const Vector<String>& 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) {
|
|
if(k.GetCount() || PromptYesNo("Store credentials as plain text?"))
|
|
break;
|
|
}
|
|
else
|
|
Exclamation("Fields do not match!");
|
|
}
|
|
if(k.GetCount())
|
|
SHA256(passkey_sha256, k);
|
|
else
|
|
memset(passkey_sha256, 0, 32);
|
|
}
|
|
|
|
void CredentialsDlg::Load()
|
|
{
|
|
list.Clear();
|
|
Array<Credential> cr;
|
|
if(LoadCredentials(cr)) {
|
|
for(const Credential& c : cr)
|
|
list.Add(c.url, c.username, c.password);
|
|
list.GoBegin();
|
|
}
|
|
}
|
|
|
|
void CredentialsDlg::Save()
|
|
{
|
|
if(list.GetCount()) {
|
|
ValueArray va;
|
|
for(int i = 0; i < list.GetCount(); i++)
|
|
va << ValueMap()("url", list.Get(i, 0))
|
|
("username", list.Get(i, 1))
|
|
("password", list.Get(i, 2));
|
|
SaveFile(CredentialsFile(), CredentialsCrypt(AsJSON(va)));
|
|
}
|
|
else
|
|
FileDelete(CredentialsFile());
|
|
}
|
|
|
|
void CredentialsDlg::Add()
|
|
{
|
|
CredentialDlg dlg;
|
|
dlg.Hints(url_hints);
|
|
again:
|
|
if(dlg.Run() == IDOK) {
|
|
String url = ~dlg.url;
|
|
if(list.FindSetCursor(url)) {
|
|
Exclamation("Duplicate entry!");
|
|
goto again;
|
|
}
|
|
list.Add(url, ~dlg.username, ~dlg.password);
|
|
list.Sort();
|
|
list.FindSetCursor(url);
|
|
}
|
|
}
|
|
|
|
void CredentialsDlg::Edit()
|
|
{
|
|
if(!list.IsCursor())
|
|
return;
|
|
CredentialDlg dlg;
|
|
dlg.Hints(url_hints);
|
|
dlg.url <<= list.Get(0);
|
|
dlg.username <<= list.Get(1);
|
|
dlg.password <<= list.Get(2);
|
|
again:
|
|
if(dlg.Run() == IDOK) {
|
|
String url = ~dlg.url;
|
|
int ii = list.Find(url);
|
|
if(ii >= 0 && ii != list.GetCursor()) {
|
|
Exclamation("Duplicate entry!");
|
|
list.SetCursor(ii);
|
|
goto again;
|
|
}
|
|
list.Set(0, url);
|
|
list.Set(1, ~dlg.username);
|
|
list.Set(2, ~dlg.password);
|
|
list.Sort();
|
|
list.FindSetCursor(url);
|
|
}
|
|
}
|
|
|
|
void CredentialsDlg::Remove()
|
|
{
|
|
list.DoRemove();
|
|
}
|
|
|
|
void CredentialsDlg::Sync()
|
|
{
|
|
clear.Enable(list.GetCount());
|
|
edit.Enable(list.IsCursor());
|
|
remove.Enable(list.IsCursor());
|
|
|
|
list.ColumnAt(2)
|
|
.SetConvert(show_passwords ? StdConvert()
|
|
: LambdaConvert([](const Value& v) {
|
|
return String('*', (~v).GetCount());
|
|
})
|
|
);
|
|
}
|
|
|
|
void EditCredentials(const Vector<String>& url_hints)
|
|
{
|
|
CredentialsDlg dlg(url_hints);
|
|
dlg.Load();
|
|
if(dlg.Execute() == IDOK)
|
|
dlg.Save();
|
|
}
|