diff --git a/Tomboy.sln b/Tomboy.sln index d9a1be53..6a32dbf0 100644 --- a/Tomboy.sln +++ b/Tomboy.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tomboy", "Tomboy.csproj", "{315DBB30-1461-4A41-A23F-A888D84E1EA0}" EndProject @@ -25,7 +25,9 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "Setup\Setup.wixpro EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrintNotes", "Tomboy\Addins\PrintNotes\PrintNotes.csproj", "{A13FBE2F-C5FF-4E8D-B687-4A309D3FE08F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Underline", "Tomboy\Addins\Underline\Underline.csproj", "{15A0F2C4-9BAD-11DE-B022-C19356D89593}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Underline", "Tomboy\Addins\Underline\Underline.csproj", "{15A0F2C4-C5FF-11CF-B022-C19356D89593}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PassEncrypt", "Tomboy\Addins\PassEncrypt\PassEncrypt.csproj", "{15AC9F12-9BAD-11DE-B022-C97A56D78593}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebSyncService", "Tomboy\Addins\WebSyncService\WebSyncService.csproj", "{A207AD10-9C5E-495F-9DEF-E7321A6FCB8F}" EndProject @@ -104,12 +106,18 @@ Global {A13FBE2F-C5FF-4E8D-B687-4A309D3FE08F}.Mac|Any CPU.Build.0 = Mac|Any CPU {A13FBE2F-C5FF-4E8D-B687-4A309D3FE08F}.Release|Any CPU.ActiveCfg = Release|Any CPU {A13FBE2F-C5FF-4E8D-B687-4A309D3FE08F}.Release|Any CPU.Build.0 = Release|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Debug|Any CPU.Build.0 = Debug|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Mac|Any CPU.ActiveCfg = Mac|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Mac|Any CPU.Build.0 = Mac|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Release|Any CPU.ActiveCfg = Release|Any CPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593}.Release|Any CPU.Build.0 = Release|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Mac|Any CPU.ActiveCfg = Mac|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Mac|Any CPU.Build.0 = Mac|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15A0F2C4-C5FF-11CF-B022-C19356D89593}.Release|Any CPU.Build.0 = Release|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Mac|Any CPU.ActiveCfg = Mac|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Mac|Any CPU.Build.0 = Mac|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593}.Release|Any CPU.Build.0 = Release|Any CPU {A207AD10-9C5E-495F-9DEF-E7321A6FCB8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A207AD10-9C5E-495F-9DEF-E7321A6FCB8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {A207AD10-9C5E-495F-9DEF-E7321A6FCB8F}.Mac|Any CPU.ActiveCfg = Mac|Any CPU diff --git a/Tomboy/Addins/PassEncrypt/Encrypter.cs b/Tomboy/Addins/PassEncrypt/Encrypter.cs new file mode 100644 index 00000000..08d4e4f2 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/Encrypter.cs @@ -0,0 +1,112 @@ +//According to https://stackoverflow.com/questions/10168240/encrypting-decrypting-a-string-in-c-sharp CraigTP answer. +using System; +using System.Text; +using System.Security.Cryptography; +using System.IO; +using System.Linq; + +namespace Tomboy.PassEncrypt +{ + public static class Encrypter + { + // This constant is used to determine the keysize of the encryption algorithm in bits. + // We divide this by 8 within the code below to get the equivalent number of bytes. + private const int Keysize = 256; + + // This constant determines the number of iterations for the password bytes generation function. + private const int DerivationIterations = 1000; + + public static string Encrypt(string plainText, string passPhrase) + { + // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text + // so that the same Salt and IV values can be used when decrypting. + var saltStringBytes = Generate256BitsOfRandomEntropy(); + var ivStringBytes = Generate256BitsOfRandomEntropy(); + var plainTextBytes = Encoding.Unicode.GetBytes(plainText); + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream()) + { + using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) + { + cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); + cryptoStream.FlushFinalBlock(); + // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes. + var cipherTextBytes = saltStringBytes; + cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray(); + cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray(); + memoryStream.Close(); + cryptoStream.Close(); + return Convert.ToBase64String(cipherTextBytes); + } + } + } + } + } + } + + public static string Decrypt(string cipherText, string passPhrase) + { + try + { + // Get the complete stream of bytes that represent: + // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText] + var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); + // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes. + var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); + // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes. + var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); + // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string. + var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray(); + + using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) + { + var keyBytes = password.GetBytes(Keysize / 8); + using (var symmetricKey = new RijndaelManaged()) + { + symmetricKey.BlockSize = 256; + symmetricKey.Mode = CipherMode.CBC; + symmetricKey.Padding = PaddingMode.PKCS7; + using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes)) + { + using (var memoryStream = new MemoryStream(cipherTextBytes)) + { + using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) + { + var plainTextBytes = new byte[cipherTextBytes.Length]; + var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); + memoryStream.Close(); + cryptoStream.Close(); + return Encoding.Unicode.GetString(plainTextBytes, 0, decryptedByteCount); + } + } + } + } + } + } + catch (CryptographicException) + { + return Encrypt(cipherText, passPhrase); + } + } + + private static byte[] Generate256BitsOfRandomEntropy() + { + var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits. + using (var rngCsp = new RNGCryptoServiceProvider()) + { + // Fill the array with cryptographically secure random bytes. + rngCsp.GetBytes(randomBytes); + } + return randomBytes; + } + } +} \ No newline at end of file diff --git a/Tomboy/Addins/PassEncrypt/Makefile.am b/Tomboy/Addins/PassEncrypt/Makefile.am new file mode 100644 index 00000000..801979d5 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/Makefile.am @@ -0,0 +1,41 @@ +include $(top_srcdir)/Makefile.include + +CSFLAGS = \ + -debug \ + -define:DEBUG \ + -target:library + +ASSEMBLIES = \ + $(LINK_TOMBOY_EXE) \ + $(GTKSHARP_LIBS) \ + $(LINK_MONO_ADDINS) \ + -r:Mono.Posix + +ADDIN_NAME = PassEncrypt +TARGET = $(top_builddir)/bin/addins/$(ADDIN_NAME).dll +CSFILES = \ + $(srcdir)/PassEncryptMenuItem.cs \ + $(srcdir)/PassEncryptNoteAddin.cs \ + $(srcdir)/PassEncryptTag.cs +RESOURCES = \ + -resource:$(srcdir)/$(ADDIN_NAME).addin.xml + +$(TARGET).mdb: $(TARGET) + +$(TARGET): $(CSFILES) $(TOMBOY_EXE_PATH) + mkdir -p `dirname $(TARGET)` && $(CSC) -out:$@ $(CSFLAGS) $(ASSEMBLIES) $(CSFILES) $(RESOURCES) + + +addinsdir = $(pkglibdir)/addins +addins_DATA = \ + $(TARGET) \ + $(TARGET).mdb + +EXTRA_DIST = \ + $(CSFILES) \ + $(srcdir)/$(ADDIN_NAME).addin.xml + +CLEANFILES = \ + $(TARGET).mdb \ + $(TARGET) + diff --git a/Tomboy/Addins/PassEncrypt/PassEncrypt-mac.csproj b/Tomboy/Addins/PassEncrypt/PassEncrypt-mac.csproj new file mode 100644 index 00000000..24640ef4 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncrypt-mac.csproj @@ -0,0 +1,95 @@ + + + + Debug + AnyCPU + {15A0F2C4-9BAD-11DE-B022-C19356D89593} + 9.0.21022 + 2.0 + Library + false + PassEncrypt + v3.5 + 512 + PassEncrypt + OnBuildSuccess + False + False + false + + + true + full + false + ..\..\..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + False + + + False + Auto + 4194304 + AnyCPU + + + + False + ..\..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\Current\lib\mono\gac\gtk-sharp\2.12.0.0__35e10195dab3c99f\gtk-sharp.dll + False + + + False + ..\..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\Current\lib\mono\gac\glib-sharp\2.12.0.0__35e10195dab3c99f\glib-sharp.dll + False + + + False + ..\..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\Current\lib\mono\gac\gdk-sharp\2.12.0.0__35e10195dab3c99f\gdk-sharp.dll + False + + + False + ..\..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\Current\lib\mono\gac\atk-sharp\2.12.0.0__35e10195dab3c99f\atk-sharp.dll + False + + + False + ..\..\..\..\..\..\..\Library\Frameworks\Mono.framework\Versions\Current\lib\mono\gac\pango-sharp\2.12.0.0__35e10195dab3c99f\pango-sharp.dll + False + + + + + + + + + + + + + + + + + {315DBB30-1461-4A41-A23F-A888D84E1EA0} + Tomboy-mac + + + + + + + \ No newline at end of file diff --git a/Tomboy/Addins/PassEncrypt/PassEncrypt.addin.xml b/Tomboy/Addins/PassEncrypt/PassEncrypt.addin.xml new file mode 100644 index 00000000..11ff03ae --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncrypt.addin.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + diff --git a/Tomboy/Addins/PassEncrypt/PassEncrypt.csproj b/Tomboy/Addins/PassEncrypt/PassEncrypt.csproj new file mode 100644 index 00000000..71ef6815 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncrypt.csproj @@ -0,0 +1,138 @@ + + + + Debug + AnyCPU + {15AC9F12-9BAD-11DE-B022-C97A56D78593} + 9.0.21022 + 2.0 + Library + false + PassEncrypt + 512 + PassEncrypt + OnBuildSuccess + False + False + false + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + v4.5 + + + + true + full + false + ..\..\..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + False + Auto + 4194304 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + False + Auto + 4194304 + AnyCPU + false + + + False + + + False + Auto + 4194304 + AnyCPU + + + true + bin\Mac\ + DEBUG;TRACE + full + prompt + 4 + false + false + + + + + + + + + + ..\..\..\winbin\Mono.Posix.dll + + + + + + + + + + + + + + + + + + + {315DBB30-1461-4A41-A23F-A888D84E1EA0} + Tomboy + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + \ No newline at end of file diff --git a/Tomboy/Addins/PassEncrypt/PassEncryptMenuItem.cs b/Tomboy/Addins/PassEncrypt/PassEncryptMenuItem.cs new file mode 100644 index 00000000..1a38aed6 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncryptMenuItem.cs @@ -0,0 +1,82 @@ + +// (C) 2018 Piotr Wiœniowski , LGPL 2.1 or later. +using System; +using Gtk; +using Mono.Unix; + +namespace Tomboy.PassEncrypt +{ + class PassEncryptMenuItem : CheckMenuItem + { + NoteAddin Addin; + bool event_freeze; + + public PassEncryptMenuItem (NoteAddin addin) : base ( Catalog.GetString ("_PassEncrypt")) + { + ((Label) Child).UseMarkup = true; + + Addin = addin; + Addin.Window.TextMenu.Shown += MenuShown; + AddAccelerator ("activate", Addin.Window.AccelGroup, + (uint) Gdk.Key.e, Gdk.ModifierType.ControlMask, + Gtk.AccelFlags.Visible); + + ShowAll(); + } + + protected void MenuShown (object sender, EventArgs e) + { + event_freeze = true; + Active = Addin.Buffer.IsActiveTag ("encpass"); + event_freeze = false; + } + + protected async override void OnActivated () + { + + string tagName = PassEncryptTag.TagName; + if (!event_freeze && Addin.Buffer.HasSelection && !Addin.Buffer.IsActiveTag(tagName)) + { + string selection = Addin.Buffer.Selection.Trim(); + TextIter start, end; + Addin.Note.Buffer.GetSelectionBounds(out start, out end); + if (string.IsNullOrWhiteSpace(selection)) + return; + + PasswordWindow passwordWindow = new PasswordWindow(true); + passwordWindow.ShowAll(); + string passPhrase = await passwordWindow.GetPassword(); + if (string.IsNullOrWhiteSpace(passPhrase)) + return; + string encPassword = Encrypter.Encrypt(selection, passPhrase); + PassEncryptTag encPassTag = (PassEncryptTag) Addin.Note.TagTable.CreateDynamicTag(PassEncryptTag.TagName); + encPassTag.SetPassword(encPassword); + Gtk.TextTag[] tags = { encPassTag }; + Addin.Note.Buffer.DeleteInteractive(ref start, ref end, true); + Addin.Note.Buffer.InsertWithTags(ref start, Catalog.GetString(" -Encoded Password- "), tags); + //PassEncryptTag encPassTag = new PassEncryptTag(encPassword); + //encPassTag.Initialize(PassEncryptTag.TagName); + //if (Addin.Note.TagTable.Lookup(encPassTag.ElementName) != null) + //{ + // // error same passwort hashcode + // PasswordWindow showException= new PasswordWindow(false); + // showException.ShowAll(); + // showException.ShowNonEditableText(Catalog.GetString(" Error - same password Id detected: " + encPassTag.Name)); + // return; + //} + //Addin.Note.TagTable.Add(encPassTag); + //Addin.Note.Buffer.DeleteInteractive(ref start, ref end, true); + //Addin.Note.Buffer.InsertInteractive(ref start, Catalog.GetString(" -Encoded Password- "), true); + //Addin.Note.Buffer.InsertWithTagsByName(ref start, Catalog.GetString(" -Encoded Password- "), encPassTag.ElementName); + } + } + + protected override void OnDestroyed () + { + if (Addin.HasWindow) + Addin.Window.TextMenu.Shown -= MenuShown; + + base.OnDestroyed(); + } + } +} diff --git a/Tomboy/Addins/PassEncrypt/PassEncryptNoteAddin.cs b/Tomboy/Addins/PassEncrypt/PassEncryptNoteAddin.cs new file mode 100644 index 00000000..482a146b --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncryptNoteAddin.cs @@ -0,0 +1,37 @@ +// Add an PassEncrypt item to the font styles menu. Just select text and press ctrl+e. +// (C) 2018 Piotr Wiœniowski , LGPL 2.1 or later. + +using Mono.Unix; +using System; +using Gtk; +using Tomboy; + +namespace Tomboy.PassEncrypt +{ + public class PassEncryptNoteAddin : NoteAddin + { + + public override void Initialize () + { + if (!Note.TagTable.IsDynamicTagRegistered(PassEncryptTag.TagName)) + { + Note.TagTable.RegisterDynamicTag(PassEncryptTag.TagName, typeof(PassEncryptTag)); + } + //Note.TagTable.RegisterDynamicTag(PassEncryptTag.TagName, typeof(PassEncryptTag)); + } + + public override void Shutdown () + { + } + + public override void OnNoteOpened () + { + // Add here instead of in Initialize to avoid creating unopened + // notes' windows/buffers. + AddTextMenuItem (new PassEncryptMenuItem (this)); + // get all note xml and search for passencrypt tags + string xml = Note.TextContent; + + } + } +} diff --git a/Tomboy/Addins/PassEncrypt/PassEncryptTag.cs b/Tomboy/Addins/PassEncrypt/PassEncryptTag.cs new file mode 100644 index 00000000..51c76c75 --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PassEncryptTag.cs @@ -0,0 +1,92 @@ + +// (C) 2018 Piotr Wiœniowski , LGPL 2.1 or later. +using Gtk; +using System; +using System.Xml; +using Tomboy; + +namespace Tomboy.PassEncrypt +{ + class PassEncryptTag : DynamicNoteTag + { + public static string TagName = "encpass"; + protected static string AtrName = "password"; + + public PassEncryptTag () //(TagName + encryptedPass.GetHashCode().ToString()) + { + //Initialize(encryptedPass); + //this.Attributes.Add(AtrName, EncryptedPass); + } + + public override void Initialize(string element_name) + { + base.Initialize(element_name); + this.Editable = false; + this.CanSplit = false; + this.CanSpellCheck = false; + this.CanGrow = false; + this.CanActivate = true; + this.Activated += PassEncryptTag_Activated; + this.SaveType = TagSaveType.Content; + } + public void SetPassword(string encryptedPass) + { + //EncryptedPass = encryptedPass; + this.Attributes.Add(AtrName, encryptedPass); + } + + //public string EncryptedPass { get; private set; } + + protected bool PassEncryptTag_Activated(NoteTag tag, NoteEditor editor, Gtk.TextIter start, Gtk.TextIter end) + { + string encPass = (tag as PassEncryptTag).Attributes[AtrName]; + // .Ens editor.Buffer.GetText(start, end, false); + if (string.IsNullOrWhiteSpace(encPass)) + return false; + DecryptPassAsync(encPass); + return true; + } + protected async void DecryptPassAsync(string encPass) + { + PasswordWindow passwordWindow = new PasswordWindow(false); + passwordWindow.ShowAll(); + string passPhrase = await passwordWindow.GetPassword(); + if (string.IsNullOrEmpty(passPhrase)) + return; + + string decrypted = Encrypter.Decrypt(encPass, passPhrase); + passwordWindow.ShowNonEditableText(decrypted); + } + + //// XmlTextWriter is required, because an XmlWriter created with + //// XmlWriter.Create considers ":" to be an invalid character + //// for an element name. + //// http://bugzilla.gnome.org/show_bug.cgi?id=559094 + //public override void Write(XmlTextWriter xml, bool start) + //{ + // if (CanSerialize && !string.IsNullOrWhiteSpace(EncryptedPass)) + // { + // if (start) + // { + // xml.WriteStartElement(null, ElementName, null); + // xml.WriteAttributeString(AtrName, EncryptedPass); + // } + // else + // { + // xml.WriteEndElement(); + // } + // } + //} + //public override void Read(XmlTextReader xml, bool start) + //{ + // if (CanSerialize) + // { + // if (start) + // { + // EncryptedPass = xml.GetAttribute(TagName); + // } + // } + // base.Read(xml, start); + //} + } +} diff --git a/Tomboy/Addins/PassEncrypt/PasswordWindow.cs b/Tomboy/Addins/PassEncrypt/PasswordWindow.cs new file mode 100644 index 00000000..d21ca8ab --- /dev/null +++ b/Tomboy/Addins/PassEncrypt/PasswordWindow.cs @@ -0,0 +1,109 @@ + +// (C) 2018 Piotr WiÅ›niowski , LGPL 2.1 or later. +using Gtk; +using Mono.Unix; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Tomboy.PassEncrypt +{ + class PasswordWindow : Window + { + public Entry firstEntry = new Entry(); + public Entry secondEntry = new Entry(); + VBox vbox = new VBox(); + public TaskCompletionSource EnteredPass = new TaskCompletionSource(); + private bool WithConfirmation = true; + + public PasswordWindow(bool withConfirmation) : base(WindowType.Toplevel) + { + WithConfirmation = withConfirmation; + firstEntry.GrabFocus(); + firstEntry.Text = Catalog.GetString("Please enter password"); + firstEntry.Changed += Entry_Changed; + firstEntry.Activated += Entry_Activated; + vbox.PackStart(firstEntry, false, true, 2); + + if (withConfirmation) + { + secondEntry.Text = Catalog.GetString("Reenter password"); + secondEntry.Changed += Entry_Changed; + secondEntry.Activated += Entry_Activated; + } + else + { + secondEntry.Text = Catalog.GetString("Decoded text"); + secondEntry.Visibility = true; + secondEntry.IsEditable = false; + } + vbox.PackStart(secondEntry, false, true, 2); + + this.Add(vbox); + this.Title = Catalog.GetString("Enter Password"); + this.SetPosition(WindowPosition.Mouse); + this.FocusOutEvent += PasswordWindow_FocusOutEvent; + } + + private void PasswordWindow_FocusOutEvent(object o, FocusOutEventArgs args) + { + EnteredPass.TrySetResult(string.Empty); + this.Destroy(); + } + + private void Entry_Changed(object sender, EventArgs e) + { + firstEntry.Changed -= Entry_Changed; + firstEntry.Text = string.Empty; + firstEntry.Visibility = false; + + secondEntry.Changed -= Entry_Changed; + secondEntry.Text = string.Empty; + secondEntry.Visibility = false; + } + + private void Entry_Activated(object sender, EventArgs e) + { + if (string.IsNullOrWhiteSpace(firstEntry.Text)) + { + firstEntry.GrabFocus(); + return; + } + if (WithConfirmation && (string.IsNullOrWhiteSpace(secondEntry.Text) || secondEntry.Text.Trim() != firstEntry.Text.Trim())) + { + secondEntry.GrabFocus(); + return; + } + else + { + firstEntry.IsEditable = false; + secondEntry.IsEditable = false; + + firstEntry.Activated -= Entry_Activated; + secondEntry.Activated -= Entry_Activated; + + EnteredPass.SetResult(firstEntry.Text.Trim()); + + if (WithConfirmation) + this.Destroy(); + return; + } + } + + public void ShowNonEditableText(string text) + { + secondEntry.Text = text; + secondEntry.Visibility = true; + secondEntry.IsEditable = false; + secondEntry.GetClipboard(Gdk.Selection.Clipboard).Text = text; + } + + public async Task GetPassword() + { + return await this.EnteredPass.Task; + } + } +} diff --git a/Tomboy/Addins/Underline/Underline.csproj b/Tomboy/Addins/Underline/Underline.csproj index d7a22da6..3cde3baa 100644 --- a/Tomboy/Addins/Underline/Underline.csproj +++ b/Tomboy/Addins/Underline/Underline.csproj @@ -3,7 +3,7 @@ Debug AnyCPU - {15A0F2C4-9BAD-11DE-B022-C19356D89593} + {15A0F2C4-C5FF-11CF-B022-C19356D89593} 9.0.21022 2.0 Library diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 00000000..33eaa06f Binary files /dev/null and b/UpgradeLog.htm differ diff --git a/UpgradeLog2.htm b/UpgradeLog2.htm new file mode 100644 index 00000000..33eaa06f Binary files /dev/null and b/UpgradeLog2.htm differ