/// <summary> /// Load the authenticators into the display list /// </summary> /// <param name="added">authenticator we just added</param> private void loadAuthenticatorList(WinAuthAuthenticator added = null) { // set up list authenticatorList.Items.Clear(); int index = 0; foreach (var auth in Config) { var ali = new AuthenticatorListitem(auth, index); if (added != null && added == auth && auth.AutoRefresh == false && !(auth.AuthenticatorData is HOTPAuthenticator)) { ali.LastUpdate = DateTime.Now; ali.DisplayUntil = DateTime.Now.AddSeconds(10); } authenticatorList.Items.Add(ali); index++; } authenticatorList.Visible = (authenticatorList.Items.Count != 0); }
/// <summary> /// Unprotected an authenticator (if possible) /// </summary> /// <param name="item">item to unprotect</param> /// <param name="screen">screen to display dialog for multi-monitors</param> /// <returns></returns> private DialogResult UnprotectAuthenticator(AuthenticatorListitem item, Screen screen = null) { // keep a count so we can have multiples if (item.UnprotectCount > 0) { item.UnprotectCount++; return DialogResult.OK; } // if there is no protection return None WinAuthAuthenticator auth = item.Authenticator; if (auth.AuthenticatorData == null || auth.AuthenticatorData.RequiresPassword == false) { return DialogResult.None; } // request the password UnprotectPasswordForm getPassForm = new UnprotectPasswordForm(); getPassForm.Authenticator = auth; if (screen != null) { // center on the current windows screen (in case of multiple monitors) getPassForm.StartPosition = FormStartPosition.Manual; int left = (screen.Bounds.Width / 2) - (getPassForm.Width / 2) + screen.Bounds.Left; int top = (screen.Bounds.Height / 2) - (getPassForm.Height / 2) + screen.Bounds.Top; getPassForm.Location = new Point(left, top); } else { getPassForm.StartPosition = FormStartPosition.CenterScreen; } DialogResult result = getPassForm.ShowDialog(this.Parent as Form); if (result == DialogResult.OK) { item.UnprotectCount++; } return result; }
/// <summary> /// Reprotect the authenticator and each action or when the 30second window has expired /// </summary> /// <param name="item"></param> private void ProtectAuthenticator(AuthenticatorListitem item) { // if already protected just decrement counter item.UnprotectCount--; if (item.UnprotectCount > 0) { return; } // reprotect the authenticator WinAuthAuthenticator auth = item.Authenticator; if (auth.AuthenticatorData == null) { return; } auth.AuthenticatorData.Protect(); item.UnprotectCount = 0; }
/// <summary> /// When a dragdrop operation has completed /// </summary> /// <param name="e"></param> protected override void OnDragDrop(DragEventArgs e) { AuthenticatorListitem item = e.Data.GetData(typeof(AuthenticatorListitem)) as AuthenticatorListitem; if (item != null) { // stop paiting as we reorder to reduce flicker WinAPI.SendMessage(this.Handle, WinAPI.WM_SETREDRAW, 0, IntPtr.Zero); try { // get the new index Point point = this.PointToClient(new Point(e.X, e.Y)); int index = this.IndexFromPoint(point); if (index < 0) { index = this.Items.Count - 1; } // move the item this.Items.Remove(item); this.Items.Insert(index, item); // set the correct indexes of our items for (int i = 0; i < this.Items.Count; i++) { (this.Items[i] as AuthenticatorListitem).Index = i; } // fire the reordered event Reordered(this, new AuthenticatorListReorderedEventArgs()); // clear state item.Dragging = false; _draggedItem = null; if (_draggedBitmap != null) { _draggedBitmap.Dispose(); _draggedBitmap = null; } if (_lastDragTopIndex != null) { this.TopIndex = _lastDragTopIndex.Value; } } finally { // resume painting WinAPI.SendMessage(this.Handle, WinAPI.WM_SETREDRAW, 1, IntPtr.Zero); } this.Refresh(); } else { base.OnDragDrop(e); } }
/// <summary> /// Set the current item based on the mouse position /// </summary> /// <param name="mouseLocation">mouse position</param> private void SetCurrentItem(Point mouseLocation) { int index = this.IndexFromPoint(mouseLocation); if (index < 0) { index = 0; } else if (index >= this.Items.Count) { index = this.Items.Count - 1; } if (index >= this.Items.Count) { CurrentItem = null; } else { CurrentItem = this.Items[index] as AuthenticatorListitem; } }
/// <summary> /// Handle the mouse move event to capture cursor position /// </summary> /// <param name="e"></param> protected override void OnMouseMove(MouseEventArgs e) { _mouseMoveLocation = e.Location; // if we are moving with LeftMouse down and moved more than 2 pixles then we are dragging if (e.Button == System.Windows.Forms.MouseButtons.Left && _mouseDownLocation != Point.Empty && this.Items.Count > 1) { int dx = Math.Abs(_mouseDownLocation.X - e.Location.X); int dy = Math.Abs(_mouseDownLocation.Y - e.Location.Y); if (dx > 2 || dy > 2) { _draggedItem = this.CurrentItem; // get a snapshot of the current item for the drag bool hasvscroll = (this.Height < (this.Items.Count * this.ItemHeight)); _draggedBitmap = new Bitmap(this.Width - (hasvscroll ? SystemInformation.VerticalScrollBarWidth : 0), this.ItemHeight); _draggedBitmapRect = Rectangle.Empty; using (Graphics g = Graphics.FromImage(_draggedBitmap)) { int y = (this.ItemHeight * this.CurrentItem.Index) - (this.ItemHeight * this.TopIndex); Point screen = this.Parent.PointToScreen(new Point(this.Location.X, this.Location.Y + y)); g.CopyFromScreen(screen.X, screen.Y, 0, 0, new Size(this.Width - (hasvscroll ? SystemInformation.VerticalScrollBarWidth : 0), this.ItemHeight), CopyPixelOperation.SourceCopy); // save offset in Y from top of item _draggedBitmapOffsetY = e.Y - y; } // make the bitmap darker Lighten(_draggedBitmap, -10); _draggedItem.Dragging = true; this.RefreshItem(_draggedItem); // moved enough so start drag this.DoDragDrop(_draggedItem, DragDropEffects.Move); } } else if (e.Button == System.Windows.Forms.MouseButtons.None) { SetCursor(e.Location); } base.OnMouseMove(e); }
/// <summary> /// Check if we should continue dragging /// </summary> /// <param name="e"></param> protected override void OnQueryContinueDrag(QueryContinueDragEventArgs e) { Rectangle screen = this.Parent.RectangleToScreen(new Rectangle(this.Location.X, this.Location.Y, this.Width, this.Height)); Point mousePoint = Cursor.Position; // if ESC is pressed, always stop if (e.EscapePressed == true || ((e.KeyState & 1) == 0 && screen.Contains(mousePoint) == false)) { e.Action = DragAction.Cancel; if (_draggedItem != null) { _draggedItem.Dragging = false; this.RefreshItem(_draggedItem); _draggedItem = null; } if (_draggedBitmap != null) { _draggedBitmap.Dispose(); _draggedBitmap = null; this.Invalidate(_draggedBitmapRect); } _mouseDownLocation = Point.Empty; } else { DateTime now = DateTime.Now; // if we are at the top or bottom, scroll every 150ms if (mousePoint.Y >= screen.Bottom) { int visible = this.ClientSize.Height / this.ItemHeight; int maxtopindex = Math.Max(this.Items.Count - visible + 1, 0); if (this.TopIndex < maxtopindex && now.Subtract(_lastDragScroll).TotalMilliseconds >= 150) { this.TopIndex++; _lastDragScroll = now; this.Refresh(); } } else if (mousePoint.Y <= screen.Top) { int visible = this.ClientSize.Height / this.ItemHeight; if (this.TopIndex > 0 && now.Subtract(_lastDragScroll).TotalMilliseconds >= 150) { this.TopIndex--; _lastDragScroll = now; this.Refresh(); } } _lastDragTopIndex = this.TopIndex; base.OnQueryContinueDrag(e); } }
/// <summary> /// Handle the mouse up and check for click in the refresh icon /// </summary> /// <param name="e"></param> protected override void OnMouseUp(MouseEventArgs e) { base.OnMouseUp(e); if ((e.Button & System.Windows.Forms.MouseButtons.Left) != 0) { // if this was in a refresh icon, we do a refresh int index = this.IndexFromPoint(e.Location); if (index >= 0 && index < this.Items.Count) { var item = this.Items[index] as AuthenticatorListitem; int x = 0; int y = (this.ItemHeight * index) - (this.ItemHeight * this.TopIndex); bool hasvscroll = (this.Height < (this.Items.Count * this.ItemHeight)); if (item.Authenticator.AutoRefresh == false && item.DisplayUntil < DateTime.Now && new Rectangle(x + this.Width - (ICON_WIDTH + MARGIN_RIGHT) - (hasvscroll ? SystemInformation.VerticalScrollBarWidth : 0), y + MARGIN_TOP, ICON_WIDTH, ICON_HEIGHT).Contains(e.Location)) { if (UnprotectAuthenticator(item) == DialogResult.Cancel) { return; } item.LastCode = item.Authenticator.CurrentCode; item.LastUpdate = DateTime.Now; item.DisplayUntil = DateTime.Now.AddSeconds(10); if (item.Authenticator.CopyOnCode == true) { // copy to clipboard item.Authenticator.CopyCodeToClipboard(this.Parent as Form); } RefreshCurrentItem(); } } } // dispose and reset the dragging _mouseDownLocation = Point.Empty; if (_draggedBitmap != null) { _draggedBitmap.Dispose(); _draggedBitmap = null; this.Invalidate(_draggedBitmapRect); } if (_draggedItem != null) { _draggedItem = null; } }
/// <summary> /// Refresh the item by invalidating it /// </summary> private void RefreshItem(AuthenticatorListitem item) { bool hasvscroll = (this.Height < (this.Items.Count * this.ItemHeight)); int y = (this.ItemHeight * item.Index) - (this.ItemHeight * this.TopIndex); Rectangle rect = new Rectangle(0, y, this.Width, this.Height); this.Invalidate(rect, false); }
/// <summary> /// Get the current code for an item in the list, unprotecting and reprotecting the authenticator if necessary /// </summary> /// <param name="item">List item to get code</param> /// <returns>code or null if failed (i.e. bad password)</returns> public string GetItemCode(AuthenticatorListitem item, Screen screen = null) { WinAuthAuthenticator auth = item.Authenticator; // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item, screen); if (wasprotected == DialogResult.Cancel) { return null; } try { return auth.CurrentCode; } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } }
/// <summary> /// Process the context menu item /// </summary> /// <param name="menuitem"></param> private void ProcessMenu(ToolStripItem menuitem) { var item = this.CurrentItem; var auth = item.Authenticator; // check and perform each menu if (menuitem.Name == "setPasswordMenuItem") { // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { // show the new password form SetPasswordForm form = new SetPasswordForm(); if (form.ShowDialog(this.Parent as Form) != DialogResult.OK) { return; } // set the encrpytion string password = form.Password; if (string.IsNullOrEmpty(password) == false) { auth.AuthenticatorData.SetEncryption(Authenticator.PasswordTypes.Explicit, password); // can't have autorefresh on auth.AutoRefresh = false; item.UnprotectCount = 0; item.DisplayUntil = DateTime.MinValue; item.LastUpdate = DateTime.MinValue; item.LastCode = null; } else { auth.AuthenticatorData.SetEncryption(Authenticator.PasswordTypes.None); } // make sure authenticator is saved auth.MarkChanged(); RefreshCurrentItem(); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "showCodeMenuItem") { // check if the authentcated is still protected if (UnprotectAuthenticator(item) == DialogResult.Cancel) { return; } // reduce unprotect count if already displayed if (item.DisplayUntil != DateTime.MinValue) { ProtectAuthenticator(item); } item.LastCode = auth.CurrentCode; item.LastUpdate = DateTime.Now; item.DisplayUntil = DateTime.Now.AddSeconds(10); RefreshCurrentItem(); } else if (menuitem.Name == "copyCodeMenuItem") { // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { auth.CopyCodeToClipboard(this.Parent as Form, item.LastCode, true); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "autoRefreshMenuItem") { auth.AutoRefresh = !auth.AutoRefresh; item.LastUpdate = DateTime.Now; item.DisplayUntil = DateTime.MinValue; RefreshCurrentItem(); } else if (menuitem.Name == "shortcutKeyMenuItem") { DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { SetShortcutKeyForm form = new SetShortcutKeyForm(); form.Hotkey = auth.HotKey; if (form.ShowDialog(this.Parent as Form) != DialogResult.OK) { return; } auth.HotKey = form.Hotkey; } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "copyOnCodeMenuItem") { auth.CopyOnCode = !auth.CopyOnCode; } else if (menuitem.Name == "showRestoreCodeMenuItem") { // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { if (wasprotected != DialogResult.OK) { // confirm current main password var mainform = this.Parent as WinAuthForm; if ((mainform.Config.PasswordType & Authenticator.PasswordTypes.Explicit) != 0) { bool invalidPassword = false; while (true) { GetPasswordForm checkform = new GetPasswordForm(); checkform.InvalidPassword = invalidPassword; var result = checkform.ShowDialog(this); if (result == DialogResult.Cancel) { return; } if (mainform.Config.IsPassword(checkform.Password) == true) { break; } invalidPassword = true; } } } // show the serial and restore code for Battle.net authenticator ShowRestoreCodeForm form = new ShowRestoreCodeForm(); form.CurrentAuthenticator = auth; form.ShowDialog(this.Parent as Form); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "showGoogleSecretMenuItem") { // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { if (wasprotected != DialogResult.OK) { // confirm current main password var mainform = this.Parent as WinAuthForm; if ((mainform.Config.PasswordType & Authenticator.PasswordTypes.Explicit) != 0) { bool invalidPassword = false; while (true) { GetPasswordForm checkform = new GetPasswordForm(); checkform.InvalidPassword = invalidPassword; var result = checkform.ShowDialog(this); if (result == DialogResult.Cancel) { return; } if (mainform.Config.IsPassword(checkform.Password) == true) { break; } invalidPassword = true; } } } // show the secret key for Google authenticator ShowSecretKeyForm form = new ShowSecretKeyForm(); form.CurrentAuthenticator = auth; form.ShowDialog(this.Parent as Form); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "showTrionSecretMenuItem") { // check if the authenticator is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { // show the secret key for Trion authenticator ShowTrionSecretForm form = new ShowTrionSecretForm(); form.CurrentAuthenticator = auth; form.ShowDialog(this.Parent as Form); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "showSteamSecretMenuItem") { // check if the authenticator is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { if (wasprotected != DialogResult.OK) { // confirm current main password var mainform = this.Parent as WinAuthForm; if ((mainform.Config.PasswordType & Authenticator.PasswordTypes.Explicit) != 0) { bool invalidPassword = false; while (true) { GetPasswordForm checkform = new GetPasswordForm(); checkform.InvalidPassword = invalidPassword; var result = checkform.ShowDialog(this); if (result == DialogResult.Cancel) { return; } if (mainform.Config.IsPassword(checkform.Password) == true) { break; } invalidPassword = true; } } } // show the secret key for Google authenticator ShowSteamSecretForm form = new ShowSteamSecretForm(); form.CurrentAuthenticator = auth; form.ShowDialog(this.Parent as Form); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "showSteamTradesMenuItem") { // check if the authenticator is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } try { // show the Steam trades dialog ShowSteamTradesForm form = new ShowSteamTradesForm(); form.Authenticator = auth; form.ShowDialog(this.Parent as Form); } finally { if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name == "deleteMenuItem") { if (WinAuthForm.ConfirmDialog(this.Parent as Form, strings.DeleteAuthenticatorWarning, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2) == DialogResult.Yes) { int index = item.Index; this.Items.Remove(item); ItemRemoved(this, new AuthenticatorListItemRemovedEventArgs(item)); if (index >= this.Items.Count) { index = this.Items.Count - 1; } this.CurrentItem = (this.Items.Count != 0 ? this.Items[index] as AuthenticatorListitem : null); // reset the correct indexes of our items for (int i = 0; i < this.Items.Count; i++) { (this.Items[i] as AuthenticatorListitem).Index = i; } } } else if (menuitem.Name == "renameMenuItem") { int y = (this.ItemHeight * item.Index) - (this.TopIndex * this.ItemHeight) + 8; RenameTextbox.Location = new Point(64, y); RenameTextbox.Text = auth.Name; RenameTextbox.Tag = item; RenameTextbox.Visible = true; RenameTextbox.Focus(); } else if (menuitem.Name == "syncMenuItem") { // check if the authentcated is still protected DialogResult wasprotected = UnprotectAuthenticator(item); if (wasprotected == DialogResult.Cancel) { return; } Cursor cursor = Cursor.Current; try { Cursor.Current = Cursors.WaitCursor; auth.Sync(); RefreshItem(item); } finally { Cursor.Current = cursor; if (wasprotected == DialogResult.OK) { ProtectAuthenticator(item); } } } else if (menuitem.Name.StartsWith("iconMenuItem_") == true) { if (menuitem.Tag is string && string.Compare((string)menuitem.Tag, "OTHER") == 0) { do { // other..choose an image file OpenFileDialog ofd = new OpenFileDialog(); ofd.AddExtension = true; ofd.CheckFileExists = true; ofd.DefaultExt = "png"; ofd.InitialDirectory = Directory.GetCurrentDirectory(); ofd.FileName = string.Empty; ofd.Filter = "PNG Image Files (*.png)|*.png|GIF Image Files (*.gif)|*.gif|All Files (*.*)|*.*"; ofd.RestoreDirectory = true; ofd.ShowReadOnly = false; ofd.Title = strings.LoadIconImage + " (png or gif @ 48x48)"; DialogResult result = ofd.ShowDialog(this); if (result != System.Windows.Forms.DialogResult.OK) { return; } try { // get the image and create an icon if not already the right size using (Bitmap iconimage = (Bitmap)Image.FromFile(ofd.FileName)) { if (iconimage.Width != ICON_WIDTH || iconimage.Height != ICON_HEIGHT) { using (Bitmap scaled = new Bitmap(ICON_WIDTH, ICON_HEIGHT)) { using (Graphics g = Graphics.FromImage(scaled)) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality; g.DrawImage(iconimage, new Rectangle(0, 0, ICON_WIDTH, ICON_HEIGHT)); } auth.Icon = scaled; } } else { auth.Icon = iconimage; } RefreshCurrentItem(); } } catch (Exception ex) { if (MessageBox.Show(this.Parent as Form, string.Format(strings.ErrorLoadingIconFile, ex.Message), WinAuthMain.APPLICATION_NAME, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes) { continue; } } break; } while (true); } else { auth.Skin = (((string)menuitem.Tag).Length != 0 ? (string)menuitem.Tag : null); RefreshCurrentItem(); } } }
/// <summary> /// Default constructor /// </summary> public AuthenticatorListItemRemovedEventArgs(AuthenticatorListitem item) : base() { Item = item; }