18using System.Collections.Generic;
19using System.Diagnostics;
22using System.Threading;
26using Newtonsoft.Json.Linq;
28using static Org.BouncyCastle.Asn1.Cmp.Challenge;
32 internal class ChromeProfileManager
44 private static readonly Random random =
new Random();
46 internal static string CreateTempUserProfile(
47 string downloadDirectory,
48 bool promptForDownload,
49 bool openPDFExternally,
52 Dictionary<string, object> additionalPrefs =
null)
56 if (!Directory.Exists(downloadDirectory))
57 Directory.CreateDirectory(downloadDirectory);
60 string tempProfileDir =
61 Path.Combine(GPAL.TempProfileDirectory, $
"BrowserProfile_{Guid.NewGuid():N}");
63 string defaultDir = Path.Combine(tempProfileDir,
"Default");
65 Directory.CreateDirectory(defaultDir);
67 Base64Helper base64Helper =
new Base64Helper();
68 base64Helper.WithInput(GPAL.GPALSettings.Preferences).SaveTo(Path.Combine(defaultDir,
"Preferences"));
69 base64Helper.WithInput(GPAL.GPALSettings.SecurePreferences).SaveTo(Path.Combine(defaultDir,
"Secure Preferences"));
70 base64Helper.WithInput(GPAL.GPALSettings.LocalState).SaveTo(Path.Combine(tempProfileDir,
"Local State"));
72 return tempProfileDir;
76 GPAL.PublishSimpleEvent(
77 Enums.GPALEventType.EXCEPTION,
78 $
"Failed creating temp Chrome profile folder",
80 Enums.GPALObjectType.None,
99 private static readonly
string[] downloadPreferenceKeys =
101 "download.prompt_for_download",
102 "download.default_directory",
103 "plugins.always_open_pdf_externally",
104 "browser.show_hub_popup_on_download_start",
115 private static void SetByPath(JObject root,
string path, JToken value)
117 string[] parts = path.Split(
'.');
120 for (
int idx = 0; idx < parts.Length - 1; idx++)
122 if (
false == (node[parts[idx]] is JObject child))
124 child =
new JObject();
125 node[parts[idx]] = child;
131 node[parts[parts.Length - 1]] = value;
139 private static string PreferencesFileFor(
string profileDirectory)
141 string preferencesPath =
null;
143 if (
false ==
string.IsNullOrEmpty(profileDirectory))
145 string inDefault = Path.Combine(profileDirectory,
"Default",
"Preferences");
146 string inProfile = Path.Combine(profileDirectory,
"Preferences");
148 preferencesPath = File.Exists(inDefault) ? inDefault : File.Exists(inProfile) ? inProfile :
null;
151 return preferencesPath;
165 internal static Dictionary<string, JToken> ApplyDownloadPreferences(
string profileDirectory,
string downloadDirectory,
bool promptForDownload,
bool openPDFExternally)
167 Dictionary<string, JToken> previous =
null;
168 string preferencesPath = PreferencesFileFor(profileDirectory);
170 if (
null == preferencesPath)
171 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $
"No chrome Preferences file under [{profileDirectory}], so prompt for download and open pdf externally cannot be set for this profile.",
null, GPALObjectType.None);
175 JObject preferences = JObject.Parse(File.ReadAllText(preferencesPath));
177 previous =
new Dictionary<string, JToken>();
178 foreach (
string key
in downloadPreferenceKeys)
179 previous[key] = preferences.SelectToken(key);
181 SetByPath(preferences,
"download.prompt_for_download", promptForDownload);
182 SetByPath(preferences,
"plugins.always_open_pdf_externally", openPDFExternally);
186 SetByPath(preferences,
"browser.show_hub_popup_on_download_start",
false);
192 SetByPath(preferences,
"profile.exit_type",
"Normal");
194 if (
false ==
string.IsNullOrEmpty(downloadDirectory))
195 SetByPath(preferences,
"download.default_directory", downloadDirectory);
197 File.WriteAllText(preferencesPath, JsonConvert.SerializeObject(preferences));
202 GPAL.PublishSimpleEvent(GPALEventType.DEBUG, $
"Profile [{preferencesPath}] prompt for download [{previous["download.prompt_for_download
"]?.ToString() ?? "unset
"}] -> [{promptForDownload}], open pdf externally [{previous["plugins.always_open_pdf_externally
"]?.ToString() ?? "unset
"}] -> [{openPDFExternally}], download directory [{previous["download.default_directory
"]?.ToString() ?? "unset
"}] -> [{downloadDirectory ?? "left alone
"}]",
null, GPALObjectType.None);
207 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION, $
"Could not write download preferences into [{preferencesPath}]",
null, GPALObjectType.None, ex);
219 internal static void RestoreDownloadPreferences(
string profileDirectory, Dictionary<string, JToken> previous)
221 string preferencesPath =
null == previous ? null : PreferencesFileFor(profileDirectory);
223 if (
null == preferencesPath)
228 JObject preferences = JObject.Parse(File.ReadAllText(preferencesPath));
230 foreach (
string key
in downloadPreferenceKeys)
231 if (
null == previous[key])
232 preferences.SelectToken(key)?.Parent?.Remove();
234 SetByPath(preferences, key, previous[key]);
236 File.WriteAllText(preferencesPath, JsonConvert.SerializeObject(preferences));
240 GPAL.PublishSimpleEvent(GPALEventType.DEBUG, $
"Profile [{preferencesPath}] put back, prompt for download [{previous["download.prompt_for_download
"]?.ToString() ?? "unset
"}], download directory [{previous["download.default_directory
"]?.ToString() ?? "unset
"}]",
null, GPALObjectType.None);
244 GPAL.PublishSimpleEvent(GPALEventType.EXCEPTION, $
"Could not put the download preferences back in [{preferencesPath}]",
null, GPALObjectType.None, ex);
248 internal static void RemoveTempUserProfile(
string profileDirectory)
250 Exception innerEx =
null;
251 if (!Directory.Exists(profileDirectory))
254 for (
int i = 0; i < 10; i++)
258 Directory.Delete(profileDirectory,
true);
259 GPAL.PublishSimpleEvent(Enums.GPALEventType.INFO, $
"Deleted temporary user profile at [{profileDirectory}]");
265 System.Threading.Thread.Sleep(500);
266 GPAL.PublishSimpleEvent(Enums.GPALEventType.EXCEPTION, $
"Failed to delete temporary user profile at [{profileDirectory}][{innerEx.Message}]",
null, GPALObjectType.None, innerEx);
269 GPAL.PublishSimpleEvent(Enums.GPALEventType.ERROR, $
"GIVING UP: Failed to delete temporary user profile after 10 tries at [{profileDirectory}][{innerEx.Message}]",
null, GPALObjectType.None, innerEx);