Showing posts with label Advanced. Show all posts
Showing posts with label Advanced. Show all posts

8.1.12

Get Web Browser History in C# - Google Chrome

This post is a sort-of sequel to my previous blog post on getting web browser history in C#. Google Chrome is the browser I had missed in the last blog post and I must say, it was quite interesting to code this up. Just like Firefox, Chrome also uses an SQLite Database, but uses a structure quite different than that of Firefox. More details about it here. As for Firefox, a very nice article is here. Before you see the code, below are a few interesting points to note about Chrome:
  1. The History file for Chrome is an SQLite database, but without the .sqlite extension. In fact, it does not have any extension. Its name is just History.
  2. Google Chrome stores last visited times in UTC format. UTC time is basically the time elapsed since Jan 1, 1601. Unlike the UTC format for Windows file times which is in nanoseconds, Chrome stores the times in microseconds.
  3. Also, the times are as per the GMT time zone. So, to get local times, TimeZoneInfo class provided by the .NET framework must be used.
Below is a tiny code snippet for getting Chrome history in C#:



  1. public class HistoryItem
  2. {
  3. public string URL { get; set; }
  4. public string Title { get; set; }
  5. public DateTime VisitedTime { get; set; }
  6. }
  7. static class Program
  8. {
  9. static void Main()
  10. {
  11. string chromeHistoryFile = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData))
  12. + @"\Google\Chrome\User Data\Default\History";
  13. if (File.Exists(chromeHistoryFile))
  14. {
  15. SQLiteConnection connection = new SQLiteConnection
  16. ("Data Source=" + chromeHistoryFile + ";Version=3;New=False;Compress=True;");
  17. connection.Open();
  18. DataSet dataset = new DataSet();
  19. SQLiteDataAdapter adapter = new SQLiteDataAdapter
  20. ("select * from urls order by last_visit_time desc", connection);
  21. adapter.Fill(dataset);
  22. if (dataset != null && dataset.Tables.Count > 0 & dataset.Tables[0] != null)
  23. {
  24. DataTable dt = dataset.Tables[0];
  25. allHistoryItems = new List<HistoryItem>();
  26. foreach (DataRow historyRow in dt.Rows)
  27. {
  28. HistoryItem historyItem = new HistoryItem();
  29. {
  30. URL = Convert.ToString(historyRow["url"]),
  31. Title = Convert.ToString(historyRow["title"])
  32. };
  33. // Chrome stores time elapsed since Jan 1, 1601 (UTC format) in microseconds
  34. long utcMicroSeconds = Convert.ToInt64(historyRow["last_visit_time"]);
  35. // Windows file time UTC is in nanoseconds, so multiplying by 10
  36. DateTime gmtTime = DateTime.FromFileTimeUtc(10 * utcMicroSeconds);
  37. // Converting to local time
  38. DateTime localTime = TimeZoneInfo.ConvertTimeFromUtc(gmtTime, TimeZoneInfo.Local);
  39. historyItem.VisitedTime = localTime;
  40. allHistoryItems.Add(historyItem);
  41. }
  42. }
  43. }
  44. }
  45. }

27.12.09

Visual inheritance in WPF

My final year .NET project was a medium-weight WPF application which had some 8 windows in all. Creating the windows and customizing the interface in XAML was a breeze with Visual Studio 2008 and Expression Blend 2. Even coding up the window logic was not that tough, but halfway into the logic part, I realized that all my windows had some properties and methods in common. So the code could be shortened a great deal using inheritance.

Basically, the approach is simple. Create a class in a separate code file (say Blindow in Blindow.cs) which inherits from System.Windows.Window, add all the properties and method implementations and virtual methods you need to it, and make all your windows inherit from Blindow. So, our Blindow looks like this:


  1. namespace BlindApp.Windows
  2. {
  3. public class Blindow : Window
  4. {
  5. // all your properties and methods here
  6. }
  7. }


So, the class declarations for all the windows in the application now change from

public partial class Window1 : Window
to

public partial class Window1 : Blindow

All is fine and well, the code should compile correctly, but shockingly, it doesn't and throws up an error. Reason: Forgot the XAML. If you know WPF well, you must realize that the class declaration for Window1 in the codebehind is only partial. The remaining partial declaration lies in the XAML. So, this means one has to come up with a way to let XAML know that Window1 inherits from Blindow now.
The source of the error now lies here

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


So what we need to do to rectify the error is first add an XML namespace (with any name you like) for the CLR namespace. The CLR namespace for Window1 is BlindApp.Windows, so add a line as follows

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:blinder="clr-namespace:BlindApp.Windows">


You don't need to type out the clr-namespace: statement - Visual Studio 2008 provides IntelliSense for that. But, we are not done yet, an error will again pop up because we need to replace the first line itself. Now that the XML namespace has been created, this is how it's done:

<blinder:Blindow x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:blinder="clr-namespace:BlindApp.Windows">


Just like you could set Resources and Triggers with Window.Resources and Window.Triggers, you can do the same now with <blinder:blindow.resources> and <blinder:blindow.triggers>

20.12.09

MD5 and TripleDES encryption in .NET

The .NET Framework provides classes for MD5 hashing and TripleDES encryption, both of which, when used together with a good enough key, form a good cryptographic system for your application. There are a lot of scenarios one can think of where encryption can be put to good use in both Desktop and Web applications. The following code snippet provides functions for encryption and decryption using MD5 and TripleDES.

What you need to include in the usings list is System.Security.Cryptography and System.Text and you are good to go. Making the functions static is just one of the best practices.








  1. public class Utils
  2. {
  3. public static string Encrypt(string toEncrypt, string key, bool useHashing)
  4. {
  5. // Convert both strings to byte arrays - you can use encoding other than UTF8
  6. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  7. byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
  8. if (useHashing)
  9. {
  10. // Hash the key
  11. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  12. keyArray = hashmd5.ComputeHash(keyArray);
  13. hashmd5.Clear();
  14. }
  15. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  16. {
  17. Key = keyArray,
  18. // The following line is controversial - follow the link below the snippet
  19. Mode = CipherMode.ECB,
  20. Padding = PaddingMode.PKCS7
  21. };
  22. ICryptoTransform cTransform = tdes.CreateEncryptor();
  23. // Transform and store in resultArray
  24. byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
  25. tdes.Clear();
  26. return Convert.ToBase64String(resultArray, 0, resultArray.Length);
  27. }
  28. public static string Decrypt(string toDecrypt, string key, bool useHashing)
  29. {
  30. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  31. byte[] toDecryptArray = Convert.FromBase64String(toDecrypt);

  32. if (useHashing)
  33. {
  34. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  35. keyArray = hashmd5.ComputeHash(keyArray);
  36. hashmd5.Clear();
  37. }
  38. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  39. {
  40. Key = keyArray,
  41. Mode = CipherMode.ECB,
  42. Padding = PaddingMode.PKCS7
  43. };

  44. ICryptoTransform cTransform = tdes.CreateDecryptor();
  45. byte[] resultArray = cTransform.TransformFinalBlock(toDecryptArray, 0, toDecryptArray.Length);
  46. tdes.Clear();
  47. return UTF8Encoding.UTF8.GetString(resultArray);
  48. }
  49. }



FYI, here is the controversy.
As you can see, both functions are quite similar except for precisely 2 lines. The Clear() function on both occasions are required because MD5CryptoServiceProvider and TripleDESCryptoServiceProvider classes are "managed wrappers around unmanaged resources". Putting the Encrypt and Decrypt functions to use in your application would look like this:

  1. string encrypted = Utils.Encrypt("Password", "Key", true);
  2. string original = Utils.Decrypt(encrypted, "Key", true);


Just make sure that you use the same key in both the lines, wherever the lines may be (they may be in two different applications referencing a common dll containing these functions) and the same hashing parameter as well. Happy encryption!

22.10.09

(Ab)using Registry classes in .NET

The .NET Framework provides wonderful classes in the Microsoft.Win32 namespace to read and write values to any key or set of keys in the Windows Registry. These classes are not only wonderful but also dangerous because they have the potential to cause nasty and possibly irreversible changes to Windows. The following piece of code is DANGEROUS for your PC. So, do not run this code in your primary Windows Administrator account. Instead, create a dummy Windows Administrator account and run this code there. It's fun! And in fact there's so much else to do with the Registry!
Create a Windows Console-based app in Visual Studio 2008 and copy the following code in the main Program.cs.



  1. using System;
  2. using Microsoft.Win32;

  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Console.WriteLine("WELCOME TO NASTY APPLICATION");
  8. Console.WriteLine("\nThis application will do the following:");
  9. Console.WriteLine("1. Empty Start Menu");
  10. Console.WriteLine("2. Hide all drives");
  11. Console.WriteLine("3. Clean Windows Explorer");
  12. Console.WriteLine("4. Enforce restrictions in Internet Explorer");
  13. Console.WriteLine("5. Disable Task Manager");
  14. Console.WriteLine("\nPress any key to start");
  15. Console.ReadKey();

  16. using (RegistryKey r1 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\Explorer"
    ))
  17. {
  18. Console.WriteLine("Emptying Start Menu...");
  19. r1.SetValue("NoSMMyDocs", 1);
  20. r1.SetValue("NoSMMyPictures", 1);
  21. r1.SetValue("NoStartMenuMyMusic", 1);
  22. r1.SetValue("NoStartMenuNetworkPlaces", 1);
  23. r1.SetValue("NoStartMenuPinnedList", 1);
  24. r1.SetValue("NoStartMenuMFUprogramsList", 1);
  25. r1.SetValue("NoFind", 1);
  26. r1.SetValue("NoControlPanel", 1);
  27. r1.SetValue("NoStartMenuMorePrograms", 1);
  28. r1.SetValue("NoClose", 1);
  29. r1.SetValue("StartMenuLogOff", 1);
  30. r1.SetValue("NoRun", 1);
  31. Console.WriteLine("Done");

  32. Console.WriteLine("Hiding all drives...");
  33. r1.SetValue("NoViewOnDrive", 255);
  34. r1.SetValue("NoDrives", 255);
  35. Console.WriteLine("Done");

  36. Console.WriteLine("Cleaning Windows Explorer...");
  37. r1.SetValue("NoTrayItemsDisplay", 1);
  38. r1.SetValue("NoDesktop", 1);
  39. r1.SetValue("NoSetTaskbar", 1);
  40. r1.SetValue("HideClock", 1);
  41. Console.WriteLine("Done");
  42. }
  43. Console.WriteLine("Disabling Task Manager...");
  44. using (RegistryKey r2 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\System"
    ))
  45. {
  46. r2.SetValue("DisableTaskMgr", 1);
  47. }
  48. Console.WriteLine("Done");
  49. Console.WriteLine("Enforcing restrictions on IE...");
  50. using (RegistryKey ie = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Policies\Microsoft\
    Internet Explorer"
    ))
  51. {
  52. ie.CreateSubKey("Control Panel").SetValue("DisableDeleteBrowsingHistory", 1);
  53. ie.CreateSubKey("Control Panel").SetValue("FormSuggest Passwords", 1);
  54. ie.CreateSubKey("Control Panel").SetValue("FormSuggest", 1);
  55. ie.CreateSubKey("Control Panel").SetValue("History", 1);
  56. ie.CreateSubKey("LinksBar").SetValue("Enabled", 0);
  57. ie.CreateSubKey("Privacy").SetValue("EnableInPrivateBrowsing", 0);
  58. ie.CreateSubKey("Privacy").SetValue("CleanHistory", 0);
  59. ie.CreateSubKey("Restrictions").SetValue("NoBrowserOptions", 1);
  60. ie.CreateSubKey("Restrictions").SetValue("NoFavorites", 1);
  61. ie.CreateSubKey("Main").SetValue("Use FormSuggest", "no");
  62. }
  63. Console.WriteLine("Done!");

  64. Console.WriteLine("THANK YOU FOR YOUR PATIENCE");

  65. Console.WriteLine("A restart is necessary for the changes to take effect");
  66. Console.WriteLine("\nPress any key to restart");

  67. Console.ReadKey();
  68. Process.Start("shutdown.exe", "-r -t 00");
  69. }
  70. }


Some explanation: The program can be divided into 3 parts, one for each RegistryKey object r1, r2 and r3.

r1 is the RegistryKey object which allows you to manipulate Windows Explorer any which way you like. r1 provides access to a Registry key whose values affect Start Menu, Taskbar, Control Panel and My Computer. For example, setting NoClose value to 1 disables the Turn Off button on the Start Menu, NoFind disables the Search button and NoRun disables the Run button. The NoDrives and NoViewOnDrive keys deserve a bit more explanation. NoViewOnDrive makes drives disappear from My Computer, but the drives will be accessible elsewhere. NoDrives blocks access to the drives completely. The value passed to these keys determines the number and letters of drives affecte. Understand from this:
00000001 => 1 means only A: drive is affected.
00000011 => 3 means both A: and B: drives are affected.
00010100 => 20 means C: and E: drives are affected.
11111111 => 255 means all drives are affected.

r2 is a relatively less significant RegistryKey object which prevents the Task Manager from appearing when Ctrl-Alt-Del is pressed.

r3 is the RegistryKey object which allows you to customize Internet Explorer as per your requirements. The subkeys and their values set in the code are fairly self-explanatory. Some of them like InPrivate Browsing work only for IE 8.
After executing this code, if you want to review the changes in the Registry after running the code, comment out the NoRun line so that you can open the Registry and undo the changes - However, as I have unfortunately discovered, not all changes can be undone, that's the reason why you are ADVISED to run this code on a dummy empty Administrator account!

3.10.09

Get Web browser history in C#

In my final year .NET project, I had to code up a module to obtain the visited URL history of at least one web browser and delete some or all of the URLs from the history. A seemingly impossible job at first, I eventually managed to write (or rather get) some neat C# code for the purpose. Here is the outcome of some very good research.

  1. Internet Explorer

  2. This was the easiest browser whose URL history can be obtained and deleted at will. My research started off with a Registry discovery - URLs typed in the address box of IE are captured in the Registry key HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs. But that was way short of the purpose. Then, I came across the COM interface IUrlHistory on MSDN. But it was COM and writing a C# class wrapper or something was something I was not proficient in at all. So, I reluctantly began searching for ready code. And voila!

    An article on CodeProject was all it took to serve my purpose. It provides a UrlHistoryLibrary.dll file which provides type-safe classes to access and manipulate IE's browsing history. Details on how to use the classes are given in the article itself. However, this is how I used it.




    1. public class InternetExplorer
    2. {
    3. // List of URL objects
    4. public List<URL> URLs { get; set; }
    5. public IEnumerable<URL> GetHistory()
    6. {
    7. // Initiate main object
    8. UrlHistoryWrapperClass urlhistory = new UrlHistoryWrapperClass();

    9. // Enumerate URLs in History
    10. UrlHistoryWrapperClass.STATURLEnumerator enumerator =
    11. urlhistory.GetEnumerator();

    12. // Iterate through the enumeration
    13. while (enumerator.MoveNext())
    14. {
    15. // Obtain URL and Title
    16. string url = enumerator.Current.URL.Replace('\'', ' ');
    17. // In the title, eliminate single quotes to avoid confusion
    18. string title = string.IsNullOrEmpty(enumerator.Current.Title)
    19. ? enumerator.Current.Title.Replace('\'', ' ') : "";

    20. // Create new entry
    21. URL U = new URL(url, title, "Internet Explorer");

    22. // Add entry to list
    23. URLs.Add(U);
    24. }

    25. // Optional
    26. enumerator.Reset();

    27. // Clear URL History
    28. urlhistory.ClearHistory();

    29. return URLs;
    30. }
    31. }




    Notes:
    The code is fairly self-explanatory except for a few clarifications. The URL class used above is a simple class which has three string fields - URL, Title and BrowserName - and URLs is a List<URL>. Those little string.Replace functions are to eliminate single quotes in the URLs so that there are no problems inserting them into an SQL database.

  3. Mozilla Firefox

  4. The same thing for Mozilla Firefox was way tougher. First of all, it was difficult to locate where Firefox stores the browsing history. The answer came in the form of an SQLite database which is stored in the Application Data of the Windows user. So, I had a SQLite database at hand. First, I tried FileStream to the .sqlite file. I had opened the file in Notepad++ and seen that URLs were interspersed with quirky characters, so using the FileStream, I could manage to obtain the URLs, but obtaining the Titles was impossible. Moreover, I was never sure that a URL I come across was ever visited or was it a bookmark or what. So, again some code-googling later, I came across the ADO.NET Data Provider for SQLite.The download page is here.

    What is wonderful about this Provider is that not only it provided a .NET-native namespace (System.Data.SQLite), but also it provides full Visual Studio 2008 design-time support. So, without wasting more time, let me provide you the code.




    1. public class Firefox
    2. {
    3. public List<URL> URLs { get; set; }
    4. public IEnumerable<URL> GetHistory()
    5. {
    6. // Get Current Users App Data
    7. string documentsFolder = Environment.GetFolderPath
    8. (Environment.SpecialFolder.ApplicationData);

    9. // Move to Firefox Data
    10. documentsFolder += "\\Mozilla\\Firefox\\Profiles\\";

    11. // Check if directory exists
    12. if (Directory.Exists(documentsFolder))
    13. {
    14. // Loop each Firefox Profile
    15. foreach (string folder in Directory.GetDirectories
    16. (documentsFolder))
    17. {
    18. // Fetch Profile History
    19. return ExtractUserHistory(folder);
    20. }
    21. }
    22. return null;
    23. }

    24. IEnumerable<URL> ExtractUserHistory(string folder)
    25. {
    26. // Get User history info
    27. DataTable historyDT = ExtractFromTable("moz_places", folder);

    28. // Get visit Time/Data info
    29. DataTable visitsDT = ExtractFromTable("moz_historyvisits",
    30. folder);

    31. // Loop each history entry
    32. foreach (DataRow row in historyDT.Rows)
    33. {
    34. // Select entry Date from visits
    35. var entryDate = (from dates in visitsDT.AsEnumerable()
    36. where dates["place_id"].ToString() == row["id"].ToString()
    37. select dates).LastOrDefault();
    38. // If history entry has date
    39. if (entryDate != null)
    40. {
    41. // Obtain URL and Title strings
    42. string url = row["Url"].ToString();
    43. string title = row["title"].ToString();

    44. // Create new Entry
    45. URL u = new URL(url.Replace('\'', ' '),
    46. title.Replace('\'', ' '),
    47. "Mozilla Firefox");

    48. // Add entry to list
    49. URLs.Add(u);
    50. }
    51. }
    52. // Clear URL History
    53. DeleteFromTable("moz_places", folder);
    54. DeleteFromTable("moz_historyvisits", folder);

    55. return URLs;
    56. }
    57. void DeleteFromTable(string table, string folder)
    58. {
    59. SQLiteConnection sql_con;
    60. SQLiteCommand sql_cmd;

    61. // FireFox database file
    62. string dbPath = folder + "\\places.sqlite";

    63. // If file exists
    64. if (File.Exists(dbPath))
    65. {
    66. // Data connection
    67. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    68. ";Version=3;New=False;Compress=True;");

    69. // Open the Conn
    70. sql_con.Open();

    71. // Delete Query
    72. string CommandText = "delete from " + table;

    73. // Create command
    74. sql_cmd = new SQLiteCommand(CommandText, sql_con);

    75. sql_cmd.ExecuteNonQuery();

    76. // Clean up
    77. sql_con.Close();
    78. }
    79. }

    80. DataTable ExtractFromTable(string table, string folder)
    81. {
    82. SQLiteConnection sql_con;
    83. SQLiteCommand sql_cmd;
    84. SQLiteDataAdapter DB;
    85. DataTable DT = new DataTable();

    86. // FireFox database file
    87. string dbPath = folder + "\\places.sqlite";

    88. // If file exists
    89. if (File.Exists(dbPath))
    90. {
    91. // Data connection
    92. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    93. ";Version=3;New=False;Compress=True;");

    94. // Open the Connection
    95. sql_con.Open();
    96. sql_cmd = sql_con.CreateCommand();

    97. // Select Query
    98. string CommandText = "select * from " + table;

    99. // Populate Data Table
    100. DB = new SQLiteDataAdapter(CommandText, sql_con);
    101. DB.Fill(DT);

    102. // Clean up
    103. sql_con.Close();
    104. }
    105. return DT;
    106. }
    107. }



    So, while some of this code was taken from the mozillazine forums, some was written on my own and the combination worked perfectly well for me in my final year project. Hope it works for you, too!