diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 4ee173d..7769e44 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -980,6 +980,15 @@ namespace MeshCentralRouter.Properties { } } + /// + /// Looks up a localized string similar to Complete 2FA setup online first. + /// + internal static string TwoFactorSetupRequired { + get { + return ResourceManager.GetString("TwoFactorSetupRequired", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unable to bind to local port. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 6a98f0c..023b2b5 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -478,4 +478,7 @@ Send token to registered messaging application? + + Complete 2FA setup online first + \ No newline at end of file diff --git a/src/MainForm.Designer.cs b/src/MainForm.Designer.cs index 5058503..a0dc636 100644 --- a/src/MainForm.Designer.cs +++ b/src/MainForm.Designer.cs @@ -91,6 +91,9 @@ this.devicesTabPage = new System.Windows.Forms.TabPage(); this.devicesPanel = new System.Windows.Forms.Panel(); this.cancelAutoCloseButton1 = new System.Windows.Forms.Button(); + this.devicesListView = new MeshCentralRouter.ListViewExtended(); + this.nameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.stateColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.devicesContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components); this.addMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addRelayMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -106,6 +109,7 @@ this.sshToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.scpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.wolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.chatToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.devicesImageList = new System.Windows.Forms.ImageList(this.components); this.noSearchResultsLabel = new System.Windows.Forms.Label(); this.noDevicesLabel = new System.Windows.Forms.Label(); @@ -138,10 +142,6 @@ this.customAppsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.openMapFileDialog = new System.Windows.Forms.OpenFileDialog(); this.saveMapFileDialog = new System.Windows.Forms.SaveFileDialog(); - this.chatToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.devicesListView = new MeshCentralRouter.ListViewExtended(); - this.nameColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.stateColumnHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.panel5.SuspendLayout(); this.mainPanel.SuspendLayout(); this.mainTabControl.SuspendLayout(); @@ -635,6 +635,37 @@ this.cancelAutoCloseButton1.Click += new System.EventHandler(this.cancelAutoCloseButton_Click); this.cancelAutoCloseButton1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.MainForm_KeyPress); // + // devicesListView + // + this.devicesListView.BackColor = System.Drawing.SystemColors.Window; + this.devicesListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.nameColumnHeader, + this.stateColumnHeader}); + this.devicesListView.ContextMenuStrip = this.devicesContextMenuStrip; + this.devicesListView.FullRowSelect = true; + this.devicesListView.GridLines = true; + this.devicesListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.devicesListView.HideSelection = false; + this.devicesListView.LargeImageList = this.devicesImageList; + resources.ApplyResources(this.devicesListView, "devicesListView"); + this.devicesListView.MultiSelect = false; + this.devicesListView.Name = "devicesListView"; + this.devicesListView.SmallImageList = this.devicesImageList; + this.devicesListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.devicesListView.UseCompatibleStateImageBehavior = false; + this.devicesListView.View = System.Windows.Forms.View.Details; + this.devicesListView.Click += new System.EventHandler(this.devicesListView_Click); + this.devicesListView.DoubleClick += new System.EventHandler(this.devicesListView_DoubleClick); + this.devicesListView.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.MainForm_KeyPress); + // + // nameColumnHeader + // + resources.ApplyResources(this.nameColumnHeader, "nameColumnHeader"); + // + // stateColumnHeader + // + resources.ApplyResources(this.stateColumnHeader, "stateColumnHeader"); + // // devicesContextMenuStrip // this.devicesContextMenuStrip.ImageScalingSize = new System.Drawing.Size(24, 24); @@ -742,6 +773,12 @@ resources.ApplyResources(this.wolToolStripMenuItem, "wolToolStripMenuItem"); this.wolToolStripMenuItem.Click += new System.EventHandler(this.wolToolStripMenuItem_Click); // + // chatToolStripMenuItem + // + this.chatToolStripMenuItem.Name = "chatToolStripMenuItem"; + resources.ApplyResources(this.chatToolStripMenuItem, "chatToolStripMenuItem"); + this.chatToolStripMenuItem.Click += new System.EventHandler(this.chatToolStripMenuItem_Click); + // // devicesImageList // this.devicesImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("devicesImageList.ImageStream"))); @@ -978,43 +1015,6 @@ this.saveMapFileDialog.DefaultExt = "mcrouter"; resources.ApplyResources(this.saveMapFileDialog, "saveMapFileDialog"); // - // chatToolStripMenuItem - // - this.chatToolStripMenuItem.Name = "chatToolStripMenuItem"; - resources.ApplyResources(this.chatToolStripMenuItem, "chatToolStripMenuItem"); - this.chatToolStripMenuItem.Click += new System.EventHandler(this.chatToolStripMenuItem_Click); - // - // devicesListView - // - this.devicesListView.BackColor = System.Drawing.SystemColors.Window; - this.devicesListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.nameColumnHeader, - this.stateColumnHeader}); - this.devicesListView.ContextMenuStrip = this.devicesContextMenuStrip; - this.devicesListView.FullRowSelect = true; - this.devicesListView.GridLines = true; - this.devicesListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; - this.devicesListView.HideSelection = false; - this.devicesListView.LargeImageList = this.devicesImageList; - resources.ApplyResources(this.devicesListView, "devicesListView"); - this.devicesListView.MultiSelect = false; - this.devicesListView.Name = "devicesListView"; - this.devicesListView.SmallImageList = this.devicesImageList; - this.devicesListView.Sorting = System.Windows.Forms.SortOrder.Ascending; - this.devicesListView.UseCompatibleStateImageBehavior = false; - this.devicesListView.View = System.Windows.Forms.View.Details; - this.devicesListView.Click += new System.EventHandler(this.devicesListView_Click); - this.devicesListView.DoubleClick += new System.EventHandler(this.devicesListView_DoubleClick); - this.devicesListView.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.MainForm_KeyPress); - // - // nameColumnHeader - // - resources.ApplyResources(this.nameColumnHeader, "nameColumnHeader"); - // - // stateColumnHeader - // - resources.ApplyResources(this.stateColumnHeader, "stateColumnHeader"); - // // MainForm // resources.ApplyResources(this, "$this"); diff --git a/src/MainForm.cs b/src/MainForm.cs index cdca0ff..8b869ed 100644 --- a/src/MainForm.cs +++ b/src/MainForm.cs @@ -1077,6 +1077,13 @@ namespace MeshCentralRouter stateClearTimer.Enabled = true; serverNameComboBox.Focus(); } + else if ((meshcentral.disconnectMsg != null) && meshcentral.disconnectMsg.StartsWith("2fasetuprequired")) + { + stateLabel.Text = Translate.T(Properties.Resources.TwoFactorSetupRequired); + stateLabel.Visible = true; + stateClearTimer.Enabled = true; + serverNameComboBox.Focus(); + } else if (meshcentral.disconnectMsg == "cert") { lastBadConnectCert = meshcentral.disconnectCert; diff --git a/src/MainForm.resx b/src/MainForm.resx index 50e7e8f..5c1f7e1 100644 --- a/src/MainForm.resx +++ b/src/MainForm.resx @@ -204,6 +204,9 @@ 241, 225 + + 241, 0 + 88, 13 @@ -1474,7 +1477,7 @@ NoControl - 6, 176 + 6, 164 168, 35 @@ -1519,19 +1522,19 @@ Segoe UI, 9pt, style=Bold - 180, 22 + 170, 22 Add &Map... - 180, 22 + 170, 22 Add &Relay Map... - 177, 6 + 167, 6 171, 22 @@ -1552,61 +1555,61 @@ Privacy Bar - 180, 22 + 170, 22 Remote Desktop... - 180, 22 + 170, 22 Remote Files... - 180, 22 + 170, 22 HTTP - 180, 22 + 170, 22 HTTPS - 180, 22 + 170, 22 RDP - 180, 22 + 170, 22 SSH - 180, 22 + 170, 22 SCP - 180, 22 + 170, 22 Wake Up... - 180, 22 + 170, 22 Chat - 181, 274 + 171, 252 devicesContextMenuStrip @@ -1622,7 +1625,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADg - HQAAAk1TRnQBSQFMAgEBEAEAAUABAQFAAQEBEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA + HQAAAk1TRnQBSQFMAgEBEAEAAVgBAQFYAQEBEAEAARABAAT/ARkBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABUAMAAQEBAAEYBgABPP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AJYAA/0D+AP3A/sD/yEAA/0D+gP5 A/wD/xgAAfoB+wH6A/4qAAP9A/8tAAP7A88D1QPbA88D1AO+A9QYAAP8A90D4APjA90D4APUA+MSAAP8 AZEBjwF9AU4BaAEhAfQB9QH0JAAD/gPRA8YD+ioAAcYCxwHPAtAB2ALZA90DywPBA68DmgP3FQAD2APd @@ -1768,7 +1771,7 @@ devicesListView - MeshCentralRouter.ListViewExtended, MeshCentralRouter, Version=1.8.8984.19540, Culture=neutral, PublicKeyToken=null + MeshCentralRouter.ListViewExtended, MeshCentralRouter, Version=1.8.9322.36929, Culture=neutral, PublicKeyToken=null devicesPanel @@ -1789,7 +1792,7 @@ 2, 88 - 358, 52 + 346, 52 5 @@ -1828,7 +1831,7 @@ 2, 88 - 358, 52 + 346, 52 4 @@ -1951,7 +1954,7 @@ 6, 79 - 430, 52 + 418, 52 4 @@ -5940,9 +5943,6 @@ Click "Add" to get started. AADAPwAAwD8AAMA/AADAPwAA - - NoControl - MeshCentral Router @@ -5994,6 +5994,18 @@ Click "Add" to get started. System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + nameColumnHeader + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + stateColumnHeader + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + addMapToolStripMenuItem @@ -6078,6 +6090,12 @@ Click "Add" to get started. System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + chatToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + devicesImageList @@ -6168,24 +6186,6 @@ Click "Add" to get started. System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - chatToolStripMenuItem - - - System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - nameColumnHeader - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - stateColumnHeader - - - System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - MainForm diff --git a/src/MeshCentralServer.cs b/src/MeshCentralServer.cs index d5e99e1..887b3e4 100644 --- a/src/MeshCentralServer.cs +++ b/src/MeshCentralServer.cs @@ -68,6 +68,7 @@ namespace MeshCentralRouter public int features = 0; // Bit flags of server features public int features2 = 0; // Bit flags of server features public Dictionary serverinfo = null; + public Dictionary userinfo = null; public int connectionState { get { return constate; } } @@ -206,6 +207,23 @@ namespace MeshCentralRouter } } + // Return the number of 2nd factor for this account + public int CountTwoFactorAuths() + { + if (userinfo == null) return -1; + int authFactorCount = 0; + object val; + if (userinfo.TryGetValue("otpsecret", out val) && Convert.ToInt32(val) == 1) authFactorCount++; + if (userinfo.TryGetValue("otpduo", out val) && Convert.ToInt32(val) == 1) authFactorCount++; + if (userinfo.TryGetValue("otpdev", out val) && Convert.ToInt32(val) == 1) authFactorCount++; + if (userinfo.TryGetValue("otphkeys", out val) && Convert.ToInt32(val) > 0) authFactorCount += Convert.ToInt32(val); + if ((features & 0x00800000) != 0 && userinfo.TryGetValue("otpekey", out val) && Convert.ToInt32(val) == 1) authFactorCount++; + if ((features & 0x02000000) != 0 && (features & 0x04000000) != 0 && userinfo.TryGetValue("phone", out val) && val != null) authFactorCount++; + if ((features2 & 0x02000000) != 0 && (features2 & 0x04000000) != 0 && userinfo.TryGetValue("msghandle", out val) && val != null) authFactorCount++; + if (authFactorCount > 0 && userinfo.TryGetValue("otpkeys", out val) && Convert.ToInt32(val) > 0 && (features2 & 0x40000) == 0) authFactorCount++; + return authFactorCount; + } + public void processServerData(webSocketClient sender, string data, int orglen) { if (debug) { try { File.AppendAllText("debug.log", "ServerData-" + data + "\r\n"); } catch (Exception) { } } @@ -292,7 +310,7 @@ namespace MeshCentralRouter } case "userinfo": { - Dictionary userinfo = (Dictionary)jsonAction["userinfo"]; + userinfo = (Dictionary)jsonAction["userinfo"]; userid = (string)userinfo["_id"]; if (userinfo.ContainsKey("name")) { username = (string)userinfo["name"]; } userRights = new Dictionary(); @@ -308,6 +326,19 @@ namespace MeshCentralRouter } } } + + int twoFactorCount = -1; + try { twoFactorCount = CountTwoFactorAuths(); } catch (Exception) { } + if (debug) { + try { File.AppendAllText("debug.log", "CountTwoFactorAuths-" + twoFactorCount + "\r\n"); } catch (Exception) { } + } + // If no 2FA is setup and feature flag set, set message and change state + if (twoFactorCount == 0 && (features & 0x00040000) != 0) + { + disconnectMsg = "2fasetuprequired"; + changeState(0); + } + break; } case "usergroups": diff --git a/src/Translate.cs b/src/Translate.cs index b6a4da2..a07744c 100644 --- a/src/Translate.cs +++ b/src/Translate.cs @@ -4920,6 +4920,29 @@ namespace MeshCentralRouter {"it","Avanzamento del trasferimento"}, {"ru","Прогресс передачи"} } + }, + { + "Complete 2FA setup online first", + new Dictionary() { + {"de","Vervollständigen Sie zunächst die 2FA-Einrichtung online"}, + {"hi","पहले ऑनलाइन 2FA सेटअप पूरा करें"}, + {"fr","Terminez d'abord la configuration 2FA en ligne"}, + {"zh-chs","首先在线完成 2FA 设置"}, + {"fi","Suorita ensin 2FA-asennus verkossa"}, + {"tr","Önce çevrimiçi 2FA kurulumunu tamamlayın"}, + {"cs","Nejprve dokončete nastavení 2FA online"}, + {"ja","まずオンラインで2FAのセットアップを完了してください"}, + {"es","Complete primero la configuración de 2FA en línea"}, + {"pl","Najpierw zakończ konfigurację 2FA online"}, + {"pt","Primeiro, conclua a configuração do 2FA online"}, + {"nl","Voltooi eerst de online 2FA-instelling"}, + {"pt-br","Primeiro, conclua a configuração do 2FA online"}, + {"sv","Slutför först 2FA-inställningen online"}, + {"da","Færdiggør først 2FA-opsætningen online"}, + {"ko","먼저 온라인으로 2FA 설정을 완료하세요."}, + {"it","Completa prima la configurazione di 2FA online"}, + {"ru","Сначала завершите настройку 2FA онлайн"} + } } }; // *** TRANSLATION TABLE END ***