1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.Diagnostics; 23 using System.IO; 24 using System.Text; 25 using System.Windows.Forms; 26 27 using KeePass.App; 28 using KeePass.Ecas; 29 using KeePass.Forms; 30 using KeePass.Native; 31 using KeePass.UI; 32 using KeePass.Util; 33 using KeePass.Util.Spr; 34 35 using KeePassLib; 36 using KeePassLib.Cryptography; 37 using KeePassLib.Security; 38 using KeePassLib.Utility; 39 40 using NativeLib = KeePassLib.Native.NativeLib; 41 42 namespace KeePass.Util 43 { 44 public static partial class ClipboardUtil 45 { 46 private static byte[] g_pbDataHash = null; 47 private static readonly CriticalSectionEx g_csClearing = new CriticalSectionEx(); 48 49 [Obsolete] Copy(string strToCopy, bool bIsEntryInfo, PwEntry peEntryInfo, PwDatabase pwReferenceSource)50 public static bool Copy(string strToCopy, bool bIsEntryInfo, 51 PwEntry peEntryInfo, PwDatabase pwReferenceSource) 52 { 53 return Copy(strToCopy, true, bIsEntryInfo, peEntryInfo, 54 pwReferenceSource, IntPtr.Zero); 55 } 56 57 [Obsolete] Copy(ProtectedString psToCopy, bool bIsEntryInfo, PwEntry peEntryInfo, PwDatabase pwReferenceSource)58 public static bool Copy(ProtectedString psToCopy, bool bIsEntryInfo, 59 PwEntry peEntryInfo, PwDatabase pwReferenceSource) 60 { 61 if(psToCopy == null) throw new ArgumentNullException("psToCopy"); 62 return Copy(psToCopy.ReadString(), true, bIsEntryInfo, peEntryInfo, 63 pwReferenceSource, IntPtr.Zero); 64 } 65 Copy(string strToCopy, bool bSprCompile, bool bIsEntryInfo, PwEntry peEntryInfo, PwDatabase pwReferenceSource, IntPtr hOwner)66 public static bool Copy(string strToCopy, bool bSprCompile, bool bIsEntryInfo, 67 PwEntry peEntryInfo, PwDatabase pwReferenceSource, IntPtr hOwner) 68 { 69 if(strToCopy == null) throw new ArgumentNullException("strToCopy"); 70 if(strToCopy.Length == 0) { Clear(); return true; } 71 72 if(bIsEntryInfo && !AppPolicy.Try(AppPolicyId.CopyToClipboard)) 73 return false; 74 75 string strData = strToCopy; 76 if(bSprCompile) 77 strData = SprEngine.Compile(strData, new SprContext( 78 peEntryInfo, pwReferenceSource, SprCompileFlags.All)); 79 80 try 81 { 82 // if(SetStringUwp(strData)) { } else 83 if(!NativeLib.IsUnix()) // Windows 84 { 85 if(!OpenW(hOwner, true)) 86 throw new InvalidOperationException(); 87 88 bool bFailed = false; 89 if(!AttachIgnoreFormatsW()) bFailed = true; 90 if(!SetDataW(null, strData, null)) bFailed = true; 91 CloseW(); 92 93 if(bFailed) return false; 94 } 95 else if(NativeLib.GetPlatformID() == PlatformID.MacOSX) 96 SetStringM(strData); 97 else if(NativeLib.IsUnix()) 98 SetStringU(strData); 99 else 100 { 101 Debug.Assert(false); 102 Clipboard.SetText(strData); 103 } 104 } 105 catch(Exception) { Debug.Assert(false); return false; } 106 107 g_pbDataHash = HashString(strData); 108 109 if(peEntryInfo != null) peEntryInfo.Touch(false); 110 111 if(bIsEntryInfo) 112 Program.TriggerSystem.RaiseEvent(EcasEventIDs.CopiedEntryInfo, 113 EcasProperty.Text, strData); 114 115 // SprEngine.Compile might have modified the database 116 MainForm mf = Program.MainForm; 117 if((mf != null) && bSprCompile) 118 { 119 mf.RefreshEntriesList(); 120 mf.UpdateUI(false, null, false, null, false, null, false); 121 } 122 123 return true; 124 } 125 126 [Obsolete] Copy(byte[] pbToCopy, string strFormat, bool bIsEntryInfo)127 public static bool Copy(byte[] pbToCopy, string strFormat, bool bIsEntryInfo) 128 { 129 return Copy(pbToCopy, strFormat, bIsEntryInfo, IntPtr.Zero); 130 } 131 132 [Obsolete] Copy(byte[] pbToCopy, string strFormat, bool bEncode, bool bIsEntryInfo, IntPtr hOwner)133 public static bool Copy(byte[] pbToCopy, string strFormat, bool bEncode, 134 bool bIsEntryInfo, IntPtr hOwner) 135 { 136 return Copy(pbToCopy, strFormat, bIsEntryInfo, hOwner); 137 } 138 Copy(byte[] pbToCopy, string strFormat, bool bIsEntryInfo, IntPtr hOwner)139 public static bool Copy(byte[] pbToCopy, string strFormat, bool bIsEntryInfo, 140 IntPtr hOwner) 141 { 142 if(pbToCopy == null) throw new ArgumentNullException("pbToCopy"); 143 if(pbToCopy.Length == 0) { Clear(); return true; } 144 145 string strMedia = StrUtil.GetCustomMediaType(strFormat); 146 string strData = StrUtil.DataToDataUri(pbToCopy, strMedia); 147 148 return Copy(strData, false, bIsEntryInfo, null, null, hOwner); 149 } 150 151 [Obsolete] GetEncodedData(string strFormat, IntPtr hOwner)152 public static byte[] GetEncodedData(string strFormat, IntPtr hOwner) 153 { 154 return GetData(strFormat); 155 } 156 CopyAndMinimize(string strToCopy, bool bIsEntryInfo, Form formContext, PwEntry peContext, PwDatabase pdContext)157 public static bool CopyAndMinimize(string strToCopy, bool bIsEntryInfo, 158 Form formContext, PwEntry peContext, PwDatabase pdContext) 159 { 160 if(strToCopy == null) { Debug.Assert(false); return false; } 161 162 IntPtr hOwner = ((formContext != null) ? formContext.Handle : IntPtr.Zero); 163 164 if(Copy(strToCopy, true, bIsEntryInfo, peContext, pdContext, hOwner)) 165 { 166 if(formContext != null) 167 { 168 if(Program.Config.MainWindow.DropToBackAfterClipboardCopy) 169 NativeMethods.LoseFocus(formContext, true); 170 171 if(Program.Config.MainWindow.MinimizeAfterClipboardCopy && 172 formContext.MinimizeBox && formContext.Enabled) 173 UIUtil.SetWindowState(formContext, FormWindowState.Minimized); 174 } 175 176 return true; 177 } 178 179 return false; 180 } 181 CopyAndMinimize(ProtectedString psToCopy, bool bIsEntryInfo, Form formContext, PwEntry peContext, PwDatabase pdContext)182 public static bool CopyAndMinimize(ProtectedString psToCopy, bool bIsEntryInfo, 183 Form formContext, PwEntry peContext, PwDatabase pdContext) 184 { 185 if(psToCopy == null) { Debug.Assert(false); return false; } 186 187 return CopyAndMinimize(psToCopy.ReadString(), bIsEntryInfo, 188 formContext, peContext, pdContext); 189 } 190 191 /// <summary> 192 /// Safely clear the clipboard. The clipboard clearing method 193 /// of the .NET Framework stores an empty <c>DataObject</c> 194 /// in the clipboard; this can cause incompatibilities with 195 /// other applications. Therefore, the <c>Clear</c> method of 196 /// <c>ClipboardUtil</c> first tries to clear the clipboard using 197 /// native Windows functions (which *really* clear the clipboard). 198 /// </summary> Clear()199 public static void Clear() 200 { 201 // Ensure that there's no infinite recursion 202 if(!g_csClearing.TryEnter()) { Debug.Assert(false); return; } 203 204 // In some situations (e.g. when running in a VM, when using 205 // a clipboard extension utility, ...) the clipboard cannot 206 // be cleared; for this case we first overwrite the clipboard 207 // with a non-sensitive text 208 try { Copy("--", false, false, null, null, IntPtr.Zero); } 209 catch(Exception) { Debug.Assert(false); } 210 211 bool bNativeSuccess = false; 212 try 213 { 214 if(!NativeLib.IsUnix()) // Windows 215 { 216 if(OpenW(IntPtr.Zero, true)) // Clears the clipboard 217 { 218 CloseW(); 219 bNativeSuccess = true; 220 } 221 } 222 else if(NativeLib.GetPlatformID() == PlatformID.MacOSX) 223 { 224 SetStringM(string.Empty); 225 bNativeSuccess = true; 226 } 227 else if(NativeLib.IsUnix()) 228 { 229 SetStringU(string.Empty); 230 bNativeSuccess = true; 231 } 232 } 233 catch(Exception) { Debug.Assert(false); } 234 235 g_pbDataHash = null; 236 g_csClearing.Exit(); 237 238 if(bNativeSuccess) return; 239 240 Debug.Assert(false); 241 try { Clipboard.Clear(); } // Fallback; empty data object 242 catch(Exception) { Debug.Assert(false); } 243 } 244 ClearIfOwner()245 public static void ClearIfOwner() 246 { 247 // Handle-based detection doesn't work well, because a control 248 // or dialog that stored the data may not exist anymore and 249 // thus GetClipboardOwner returns null 250 /* bool bOwnHandle = false; 251 try 252 { 253 if(!NativeLib.IsUnix()) 254 { 255 IntPtr h = NativeMethods.GetClipboardOwner(); 256 bOwnHandle = GlobalWindowManager.HasWindowMW(h); 257 } 258 } 259 catch(Exception) { Debug.Assert(false); } */ 260 261 if(g_pbDataHash == null) return; 262 263 byte[] pbCur = ComputeHash(); 264 if((pbCur == null) || !MemUtil.ArraysEqual(pbCur, g_pbDataHash)) 265 return; 266 267 Clear(); 268 } 269 HashString(string str)270 private static byte[] HashString(string str) 271 { 272 try 273 { 274 if(string.IsNullOrEmpty(str)) return null; 275 276 byte[] pb = StrUtil.Utf8.GetBytes(str); 277 return CryptoUtil.HashSha256(pb); 278 } 279 catch(Exception) { Debug.Assert(false); } 280 281 return null; 282 } 283 ComputeHash()284 public static byte[] ComputeHash() 285 { 286 try { return HashString(GetText()); } 287 catch(Exception) { Debug.Assert(false); } 288 289 return null; 290 } 291 ContainsText()292 public static bool ContainsText() 293 { 294 if(NativeLib.IsUnix()) return true; 295 return Clipboard.ContainsText(); 296 } 297 ContainsData(string strFormat)298 public static bool ContainsData(string strFormat) 299 { 300 if(string.IsNullOrEmpty(strFormat)) { Debug.Assert(false); return false; } 301 if(strFormat.Equals(DataFormats.UnicodeText, StrUtil.CaseIgnoreCmp) || 302 strFormat.Equals(DataFormats.Text, StrUtil.CaseIgnoreCmp) || 303 strFormat.Equals(DataFormats.OemText, StrUtil.CaseIgnoreCmp)) 304 return ContainsText(); 305 306 string strData = GetText(); 307 if(string.IsNullOrEmpty(strData)) return false; 308 309 return StrUtil.IsDataUri(strData, StrUtil.GetCustomMediaType(strFormat)); 310 } 311 GetText()312 public static string GetText() 313 { 314 if(!NativeLib.IsUnix()) // Windows 315 return Clipboard.GetText(); 316 if(NativeLib.GetPlatformID() == PlatformID.MacOSX) 317 return GetStringM(); 318 if(NativeLib.IsUnix()) 319 return GetStringU(); 320 321 Debug.Assert(false); 322 return Clipboard.GetText(); 323 } 324 GetData(string strFormat)325 public static byte[] GetData(string strFormat) 326 { 327 try 328 { 329 string str = GetText(); 330 if(string.IsNullOrEmpty(str)) return null; 331 332 string strMedia = StrUtil.GetCustomMediaType(strFormat); 333 if(!StrUtil.IsDataUri(str, strMedia)) return null; 334 335 return StrUtil.DataUriToData(str); 336 } 337 catch(Exception) { Debug.Assert(false); } 338 339 return null; 340 } 341 } 342 } 343