/// <summary> /// Load the application configuration data for a 1.3 version /// </summary> /// <param name="form">parent winform</param> /// <param name="configFile">name of configuration file</param> /// <returns>new WinAuthConfig</returns> private static WinAuthConfig LoadConfig_1_3(MainForm form, string configFile) { WinAuthConfig config = new WinAuthConfig(); if (File.Exists(configFile) == false) { return config; } XmlDocument doc = new XmlDocument(); doc.Load(configFile); bool boolVal = false; // load the system config XmlNode node = doc.DocumentElement.SelectSingleNode("AlwaysOnTop"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AlwaysOnTop = boolVal; } node = doc.DocumentElement.SelectSingleNode("UseTrayIcon"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.UseTrayIcon = boolVal; } node = doc.DocumentElement.SelectSingleNode("StartWithWindows"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.StartWithWindows = boolVal; } // load the authenticator config node = doc.DocumentElement.SelectSingleNode("AutoRefresh"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AutoRefresh = boolVal; } node = doc.DocumentElement.SelectSingleNode("AllowCopy"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AllowCopy = boolVal; } node = doc.DocumentElement.SelectSingleNode("CopyOnCode"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.CopyOnCode = boolVal; } node = doc.DocumentElement.SelectSingleNode("HideSerial"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.HideSerial = boolVal; } node = doc.DocumentElement.SelectSingleNode("AutoLogin"); if (node != null && node.InnerText.Length != 0) { config.AutoLogin = new HoyKeySequence(node.InnerText); } node = doc.DocumentElement.SelectSingleNode("AuthenticatorFile"); if (node != null && node.InnerText.Length != 0) { // load the authenticaotr.xml file string filename = node.InnerText; if (File.Exists(filename) == true) { Authenticator auth = LoadAuthenticator(form, filename); if (auth != null) { config.Authenticator = auth; } } config.Filename = filename; } return config; }
/// <summary> /// Load the authenticator and configuration settings /// </summary> /// <param name="form">parent winform</param> /// <param name="configFile">name of configfile or null for auto</param> /// <param name="password">optional supplied password or null to prompt if necessatu</param> /// <returns>new WinAuthConfig settings</returns> public static WinAuthConfig LoadConfig(MainForm form, string configFile, string password) { WinAuthConfig config = new WinAuthConfig(); if (string.IsNullOrEmpty(configFile) == true) { configFile = GetLastFile(1); if (string.IsNullOrEmpty(configFile) == false && File.Exists(configFile) == false) { // ignore it if file does't exist configFile = null; } } if (string.IsNullOrEmpty(configFile) == true) { // do we have a file specific in the registry? string configDirectory = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), WinAuth.APPLICATION_NAME); Directory.CreateDirectory(configDirectory); // check the old 1.3 file name configFile = Path.Combine(configDirectory, CONFIG_FILE_NAME_1_3); if (File.Exists(configFile) == false) { // check for default authenticator configFile = Path.Combine(configDirectory, DEFAULT_AUTHENTICATOR_FILE_NAME); } // if no config file, just return a blank config if (File.Exists(configFile) == false) { return config; } } // if no config file when one was specified; report an error if (File.Exists(configFile) == false) { MessageBox.Show(form, "Unable to find your configuration file \"" + configFile + "\"", form.Text, MessageBoxButtons.OK, MessageBoxIcon.Error); return config; } DialogResult configloaded; do { configloaded = DialogResult.OK; try { XmlDocument doc = null; XmlNode node = null; try { doc = new XmlDocument(); doc.Load(configFile); // check and load older versions node = doc.SelectSingleNode("WinAuth"); } catch (XmlException ) { // cause by invalid format, so we try and load other type of authenticator } if (node == null) { // foreign file so we import (authenticator.xml from winauth_1.3, android BMA xml or Java rs) Authenticator auth = LoadAuthenticator(form, configFile); if (auth != null) { config.Authenticator = auth; } SetLastFile(configFile); // set this as the new last opened file return config; } // Show if BETA //if (new BetaForm().ShowDialog(form) != DialogResult.OK) //{ // return null; //} XmlAttribute versionAttr; decimal version = Authenticator.DEAFULT_CONFIG_VERSION; if ((versionAttr = node.Attributes["version"]) != null && (version = decimal.Parse(versionAttr.InnerText, System.Globalization.CultureInfo.InvariantCulture)) < (decimal)1.4) { // old version 1.3 file config = LoadConfig_1_3(form, configFile); if (string.IsNullOrEmpty(config.Filename) == true) { config.Filename = configFile; } else if (string.Compare(configFile, config.Filename, true) != 0) { // switch over from winauth.xml to authenticator.xml and remove old winauth.xml File.Delete(configFile); configFile = config.Filename; } SaveAuthenticator(form, configFile, config); SetLastFile(configFile); // set this as the new last opened file return config; } // set the filename as itself config.Filename = configFile; bool boolVal = false; node = doc.DocumentElement.SelectSingleNode("alwaysontop"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AlwaysOnTop = boolVal; } node = doc.DocumentElement.SelectSingleNode("usetrayicon"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.UseTrayIcon = boolVal; } node = doc.DocumentElement.SelectSingleNode("startwithwindows"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.StartWithWindows = boolVal; } node = doc.DocumentElement.SelectSingleNode("autorefresh"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AutoRefresh = boolVal; } node = doc.DocumentElement.SelectSingleNode("allowcopy"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.AllowCopy = boolVal; } node = doc.DocumentElement.SelectSingleNode("copyoncode"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.CopyOnCode = boolVal; } node = doc.DocumentElement.SelectSingleNode("hideserial"); if (node != null && bool.TryParse(node.InnerText, out boolVal) == true) { config.HideSerial = boolVal; } // load the authenticator(s) - may have multiple authenticators in future version XmlNodeList nodes = doc.DocumentElement.SelectNodes("authenticator"); if (nodes != null) { // get the local machine time diff long machineTimeDiff = GetMachineTimeDiff(); foreach (XmlNode authenticatorNode in nodes) { // load the data Authenticator auth = null; try { try { auth = new Authenticator(); auth.Load(authenticatorNode, password, version); config.Authenticator = auth; } catch (EncrpytedSecretDataException) { PasswordForm passwordForm = new PasswordForm(); int retries = 0; do { passwordForm.Password = string.Empty; DialogResult result = passwordForm.ShowDialog(form); if (result != System.Windows.Forms.DialogResult.OK) { break; } try { auth = new Authenticator(); auth.Load(authenticatorNode, passwordForm.Password, version); config.Authenticator = auth; break; } catch (BadPasswordException) { MessageBox.Show(form, "Invalid password", "Load Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); if (retries++ >= MAX_PASSWORD_RETRIES - 1) { break; } } } while (true); } // adjust the time diff from the local machine if (auth != null && machineTimeDiff != 0) { auth.ServerTimeDiff = machineTimeDiff; } } catch (InvalidUserDecryptionException) { MessageBox.Show(form, "The authenticator was encrypted using a different Windows User account.", "Load Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (InvalidMachineDecryptionException) { MessageBox.Show(form, "The authenticator was encrypted using a different Windows computer.", "Load Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (InvalidConfigDataException) { MessageBox.Show(form, "The authenticator data in " + configFile + " is not valid", "Load Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception ex) { MessageBox.Show(form, "Unable to load authenticator from " + configFile + ": " + ex.Message, "Load Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } // get the autologin node after we have gotten the pasword node = doc.DocumentElement.SelectSingleNode("autologin"); if (node != null && node.InnerText.Length != 0 && config.Authenticator != null) { config.AutoLogin = new HoyKeySequence(node, config.Authenticator.Password, version); } } catch (Exception ex) { configloaded = MessageBox.Show(form, "An error occured while loading your configuration file \"" + configFile + "\": " + ex.Message + "\n\nIt may be corrupted or in use by another application.", form.Text, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error); if (configloaded == DialogResult.Abort) { return null; } } } while (configloaded == DialogResult.Retry); SetLastFile(configFile); // set this as the new last opened file return config; }
/// <summary> /// Save the authenticator /// </summary> /// <param name="form">parent winform</param> /// <param name="configFile">filename to save to</param> /// <param name="config">current settings to save</param> public static void SaveAuthenticator(Form form, string configFile, WinAuthConfig config) { // create the xml XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; // Issue 41 (http://code.google.com/p/winauth/issues/detail?id=41): saving may crash leaving file corrupt, so write into memory stream first before an atomic file write using (MemoryStream ms = new MemoryStream()) { // save config into memory using (XmlWriter writer = XmlWriter.Create(ms, settings)) { config.WriteXmlString(writer); } // write memory stream to file byte[] data = ms.ToArray(); using (FileStream fs = new FileStream(configFile, FileMode.Create, FileAccess.Write, FileShare.None)) { fs.Write(data, 0, data.Length); } } // use this as the last fle SetLastFile(configFile); }
/// <summary> /// Show the form to import a key /// </summary> private bool ImportKey() { // already have one? if (Authenticator != null) { DialogResult warning = MessageBox.Show(this, "WARNING: You already have an authenticator registered.\n\n" + "You will NOT be able to access your Battle.net account if you continue and this authenticator is overwritten.\n\n" + "Do you still want to import an authenticator?", "Import Authenticator", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (warning != System.Windows.Forms.DialogResult.Yes) { return false; } } // get the import ImportForm import = new ImportForm(); if (import.ShowDialog(this) != System.Windows.Forms.DialogResult.OK) { return false; } // remember old WinAuthConfig oldconfig = Config; // set the new authenticator Config = Config.Clone() as WinAuthConfig; Config.Authenticator = import.Authenticator; Config.AutoLogin = null; // save config data if (SaveAuthenticator(null) == false) { // restore auth Config = oldconfig; return false; } // unhook and rehook hotkey HookHotkey(this.Config); // set filename and window title notifyIcon.Text = this.Text = WinAuth.APPLICATION_TITLE + " - " + Path.GetFileNameWithoutExtension(Config.Filename); // prompt to backup InitializedForm initForm = new InitializedForm(); initForm.Authenticator = Config.Authenticator; if (initForm.ShowDialog(this) == System.Windows.Forms.DialogResult.Yes) { BackupData(); } // show new code and serial ShowCode(); return true; }
/// <summary> /// Hook the hot key for the authenticator /// </summary> /// <param name="config">current config settings</param> private void HookHotkey(WinAuthConfig config) { // unhook any old hotkey UnhookHotkey(); // hook new hotkey if (config != null && config.AutoLogin != null) { Dictionary<Keys, WinAPI.KeyModifiers> keys = new Dictionary<Keys, WinAPI.KeyModifiers>(); keys.Add((Keys)config.AutoLogin.HotKey, config.AutoLogin.Modifiers); m_hook = new KeyboardHook(keys); m_hook.KeyDown += new KeyboardHook.KeyboardHookEventHandler(Hotkey_KeyDown); } }
/// <summary> /// Enroll a new Authenticator /// </summary> /// <returns></returns> private bool Enroll() { // already have one? if (Authenticator != null) { DialogResult warning = MessageBox.Show(this, "WARNING: You already have an authenticator registered.\n\n" + "You will NOT be able to access your Battle.net account if you continue and this authenticator is overwritten.\n\n" + "Do you still want to create a new authenticator?", "New Authenticator", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if (warning != System.Windows.Forms.DialogResult.Yes) { return false; } } // initialise the new authenticator Authenticator authenticator = null; try { // get the current country code string region = (RegionInfo.CurrentRegion != null ? RegionInfo.CurrentRegion.TwoLetterISORegionName : null); EnrollForm enrollform = new EnrollForm(); enrollform.CurrentRegion = region; if (enrollform.ShowDialog(this) != System.Windows.Forms.DialogResult.OK) { return false; } region = enrollform.CurrentRegion; // create and enroll a new authenticator authenticator = new Authenticator(); authenticator.Enroll(region); } catch (Exception ex) { MessageBox.Show(this, "There was an error registering your authenticator:\n\n" + ex.Message + "\n\nThis may be because the Battle.net servers are unavailable. Please try again later.", "New Authenticator", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } // prompt now done if (MessageBox.Show(this, "Your authenticator has been created and registered.\n\n" + "You will now be prompted to save it to a file on your computer before you can add it to your account.\n\n" + "1. Choose a file to save your new authenticator.\n" + "2. Select the encrpytion option.\n" + "3. Add your authenticator to your Battle.net account.\n\n" + "Click \"OK\" to save your authenticator.", "New Registered Authenticator", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) != DialogResult.OK) { return false; } // remember old config WinAuthConfig oldconfig = Config; // set the new authenticator Config = Config.Clone() as WinAuthConfig; Config.Authenticator = authenticator; Config.AutoLogin = null; // clear autologin // save config data if (SaveAuthenticator(null) == false) { // restore authenticator Config = oldconfig; return false; } // refresh this machine time diff based on this new authenticator WinAuthHelper.SetMachineTimeDiff(authenticator.ServerTimeDiff); // unhook and rehook hotkey HookHotkey(this.Config); // set filename and window title notifyIcon.Text = this.Text = WinAuth.APPLICATION_TITLE + " - " + Path.GetFileNameWithoutExtension(Config.Filename); // prompt to backup InitializedForm initForm = new InitializedForm(); initForm.Authenticator = Config.Authenticator; if (initForm.ShowDialog(this) == System.Windows.Forms.DialogResult.Yes) { BackupData(); } // show the new code ShowCode(); return true; }
/// <summary> /// Load the form and initialize the controls /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MainForm_Load(object sender, EventArgs e) { // get any command arguments string configFile = null; string password = null; string skin = null; // string[] args = Environment.GetCommandLineArgs(); for (int i = 1; i < args.Length; i++) { string arg = args[i]; if (arg[0] == '-') { switch (arg) { case "-min": case "--minimize": // set initial state as minimized this.WindowState = FormWindowState.Minimized; break; case "-p": case "--password": // set explicit password to use i++; password = args[i]; break; case "-s": case "--skin": // set skin name i++; skin = args[i]; break; default: break; } } else { configFile = arg; } } // load config data this.Config = WinAuthHelper.LoadConfig(this, configFile, password); if (this.Config == null) { System.Diagnostics.Process.GetCurrentProcess().Kill(); return; } // load the skin if (string.IsNullOrEmpty(skin) == true) { // load the current skin if we haven't specified one skin = this.Config.CurrentSkin; } if (string.IsNullOrEmpty(skin) == false) { LoadSkin(skin); } // set title notifyIcon.Text = this.Text = WinAuth.APPLICATION_TITLE + " - " + Path.GetFileNameWithoutExtension(Config.Filename); Authenticator authenticator = this.Authenticator; serialLabel.Visible = !Config.HideSerial; serialLabel.Text = (authenticator != null ? authenticator.Serial : string.Empty); CodeField.Text = (authenticator != null && Config.AutoRefresh == true ? authenticator.CurrentCode : string.Empty); if (CodeField is SecretTextBox) { ((SecretTextBox)CodeField).SecretMode = !AllowCopy; } progressBar.Value = 0; progressBar.Visible = (authenticator != null && AutoRefresh == true); // set the buttons to force tooltips to update this.CalcCodeButton = this.CalcCodeButton; this.CopyClipboardButton = this.CopyClipboardButton; this.SyncButton = this.SyncButton; // hook our hotkey to send code to target window (e.g . Ctrl-Alt-C) HookHotkey(this.Config); // finally enable the timer to show code changes refreshTimer.Enabled = true; }
/// <summary> /// Load a new authenticator by prompting for a file /// </summary> private void LoadAuthenticator(string configFile) { if (string.IsNullOrEmpty(configFile) == true) { // use default or the path of the current authenticator string configDirectory = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), WinAuth.APPLICATION_NAME); configFile = WinAuthHelper.DEFAULT_AUTHENTICATOR_FILE_NAME; if (string.IsNullOrEmpty(Config.Filename) == false) { configFile = Path.GetFileName(Config.Filename); configDirectory = Path.GetDirectoryName(Config.Filename); } OpenFileDialog ofd = new OpenFileDialog(); ofd.AddExtension = true; ofd.CheckFileExists = true; ofd.DefaultExt = "xml"; ofd.InitialDirectory = configDirectory; ofd.FileName = configFile; ofd.Filter = "WinAuth Authenticator (*.xml)|*.xml|Java BMA File (*.rs;*.rms)|*.rs;*.rms|All Files (*.*)|*.*"; ofd.RestoreDirectory = true; ofd.ShowReadOnly = false; ofd.Title = "Load Authenticator"; DialogResult result = ofd.ShowDialog(this); if (result != System.Windows.Forms.DialogResult.OK) { return; } configFile = ofd.FileName; } if (File.Exists(configFile) == false) { return; } // if the file is xml, could be our 1.4 config, 1.3 authenticator or android. Otherwise is an import WinAuthConfig config = WinAuthHelper.LoadConfig(this, configFile, null); Authenticator auth = (config != null && config.Authenticator != null ? config.Authenticator : null); if (config != null && auth != null) { // if there is no filename, we imported a different authenticator, so clone some of the current config if (string.IsNullOrEmpty(config.Filename) == true) { // set specific authenticator settings config.AllowCopy = Config.AllowCopy; config.AlwaysOnTop = Config.AlwaysOnTop; config.AutoRefresh = Config.AutoRefresh; config.CopyOnCode = Config.CopyOnCode; config.HideSerial = Config.HideSerial; config.UseTrayIcon = Config.UseTrayIcon; // set the filename config.Filename = configFile; } // if this was an import, i.e. an .rms file, then clear authFile so we are forced to save a new name if (auth.LoadedFormat != Authenticator.FileFormat.WinAuth) { config.Filename = null; } // set up the Authenticator Config = config; // unhook and rehook hotkey HookHotkey(this.Config); // show the new code ShowCode(); // re-save SaveAuthenticator(Config.Filename); // set title notifyIcon.Text = this.Text = WinAuth.APPLICATION_TITLE + " - " + Path.GetFileNameWithoutExtension(Config.Filename); } }