mirror of
https://github.com/openziti/desktop-edge-win.git
synced 2026-10-15 09:01:27 +00:00
Merge branch 'zde-manual-install' of https://github.com/openziti/desktop-edge-win into zde-manual-install
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# Code of Conduct
|
||||
|
||||
All open source projects managed by NetFoundry share a common [code of
|
||||
conduct](https://netfoundry.github.io/policies/CODE_OF_CONDUCT.html) which all contributors are expected to follow.
|
||||
Please be sure you read, understand and adhere to the thoughts expressed therein.
|
||||
|
||||
Individuals acting in any way that is considered in violation of the Code of Conduct will receive corrective actions
|
||||
appropriate for the violation. It is possible to act in ways which technically do not violate the Code of Conduct but
|
||||
are clearly against the spirit of the project. These situations will also be considered on a case by case basis and if
|
||||
necessary the Code of Conduct will be revised accordingly and approrpiate notifications will be made to the community
|
||||
and to the violator.
|
||||
|
||||
## Violations
|
||||
|
||||
Contributors violating the Code of Conduct will receive public notification of the violation. Continued violations or
|
||||
aggregious violations of the Code of Conduct will result in the contributor being removed from the contributors list as
|
||||
well as further contributions being declined.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Contributing
|
||||
|
||||
NetFoundry welcomes all and any contributions. All open source projects managed by NetFoundry share a common
|
||||
[guide for contributions](https://netfoundry.github.io/policies/CONTRIBUTING.html).
|
||||
|
||||
If you are eager to contribute to a NetFoundry-managed open source project please read and act accordingly.
|
||||
@@ -131,6 +131,8 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
} else if (mfa.Action == "enrollment_remove") {
|
||||
// ShowBlurb("removed mfa: " + mfa.Successful, "");
|
||||
} else if (mfa.Action == "mfa_auth_status") {
|
||||
// ShowBlurb("mfa authenticated: " + mfa.Successful, "");
|
||||
} else {
|
||||
await ShowBlurbAsync ("Unexpected error when processing MFA", "");
|
||||
logger.Error("unexpected action: " + mfa.Action);
|
||||
@@ -509,6 +511,7 @@ namespace ZitiDesktopEdge {
|
||||
serviceClient.OnMfaEvent += ServiceClient_OnMfaEvent;
|
||||
serviceClient.OnLogLevelEvent += ServiceClient_OnLogLevelEvent;
|
||||
serviceClient.OnBulkServiceEvent += ServiceClient_OnBulkServiceEvent;
|
||||
serviceClient.OnNotificationEvent += ServiceClient_OnNotificationEvent;
|
||||
Application.Current.Properties.Add("ServiceClient", serviceClient);
|
||||
|
||||
monitorClient = new MonitorClient();
|
||||
@@ -570,7 +573,39 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
}
|
||||
|
||||
string nextVersionStr = null;
|
||||
private void ServiceClient_OnNotificationEvent(object sender, NotificationEvent e) {
|
||||
var displayMFARequired = false;
|
||||
foreach (var notification in e.Notification) {
|
||||
var found = identities.Find(id => id.Fingerprint == notification.Fingerprint);
|
||||
if (found == null) {
|
||||
logger.Warn($"{e.Op} event for {notification.Fingerprint} but the provided identity fingerprint was not found!");
|
||||
continue;
|
||||
}
|
||||
if (notification.MfaMaximumTimeout == 0) {
|
||||
found.MFAInfo.IsAuthenticated = false;
|
||||
// display notification message - critical
|
||||
displayMFARequired = true;
|
||||
} else if (notification.MfaMinimumTimeout == 0) {
|
||||
// display notification message, only few services are timed out
|
||||
} else {
|
||||
// display notification message, only few services are about to timeout
|
||||
}
|
||||
}
|
||||
// we may need to display mfa icon, based on the timer in UI, remove found.MFAInfo.IsAuthenticated setting in this function.
|
||||
// the below function can show mfa icon even after user authenticates successfully, in race conditions
|
||||
if (displayMFARequired) {
|
||||
LoadIdentities(true);
|
||||
this.Dispatcher.Invoke(() => {
|
||||
IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
|
||||
if (deets.IsVisible) {
|
||||
deets.UpdateView();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string nextVersionStr = null;
|
||||
private void MonitorClient_OnReconnectFailure(object sender, object e) {
|
||||
if (nextVersionStr == null) {
|
||||
// check for the current version
|
||||
@@ -653,7 +688,7 @@ namespace ZitiDesktopEdge {
|
||||
IsUpdateAvailable = true;
|
||||
MainMenu.ShowUpdateAvailable(evt.TimeRemaining, evt.InstallTime);
|
||||
AlertCanvas.Visibility = Visibility.Visible;
|
||||
ShowToast("An Update is Available for Ziti Desktop Edge");
|
||||
ShowToast("An Update is Available for Ziti Desktop Edge, will initiate auto installation by " + evt.InstallTime);
|
||||
SetNotifyIcon("");
|
||||
// display a tag in UI and a button for the update software
|
||||
}
|
||||
@@ -800,12 +835,16 @@ namespace ZitiDesktopEdge {
|
||||
found.IsEnabled = zid.IsEnabled;
|
||||
found.MFAInfo.IsAuthenticated = !e.Id.MfaNeeded;
|
||||
LoadIdentities(true);
|
||||
return;
|
||||
}
|
||||
} else if (e.Action == "updated") {
|
||||
//this indicates that all updates have been sent to the UI... wait for 2 seconds then trigger any ui updates needed
|
||||
await Task.Delay(2000);
|
||||
|
||||
} else if (e.Action == "connected") {
|
||||
//this indicates that all updates have been sent to the UI... wait for 2 seconds then trigger any ui updates needed
|
||||
await Task.Delay(2000);
|
||||
} else if (e.Action == "disconnected") {
|
||||
//this indicates that all updates have been sent to the UI... wait for 2 seconds then trigger any ui updates needed
|
||||
await Task.Delay(2000);
|
||||
} else {
|
||||
IdentityForgotten(ZitiIdentity.FromClient(e.Id));
|
||||
}
|
||||
|
||||
@@ -50,6 +50,6 @@ using System.Windows;
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.9.9.0")]
|
||||
[assembly: AssemblyVersion("1.9.9.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.9.0")]
|
||||
// [assembly: AssemblyVersion("1.10.0.0")]
|
||||
[assembly: AssemblyVersion("1.10.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0.0")]
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
<CheckBox x:Name="AddDnsNew" Content="Add DNS" IsChecked="True" Margin="10"/>
|
||||
|
||||
<local:StyledButton x:Name="SaveConfigButton" OnClick="SaveConfig" Label="Save" Grid.Row="8"></local:StyledButton>
|
||||
|
||||
</StackPanel>
|
||||
<Image Source="/Assets/Images/closeBlack.png" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,40,40,0" Width="10" Height="10" Cursor="Hand" MouseUp="CloseEditConfig"></Image>
|
||||
</Grid>
|
||||
|
||||
@@ -509,6 +509,33 @@ namespace ZitiDesktopEdge {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save the frequency information to the properties and queue for update.
|
||||
/// </summary>
|
||||
async private void UpdateFrequency() {
|
||||
logger.Info("updating frequency...");
|
||||
DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
|
||||
try {
|
||||
var newFrequencyVar = 5; // Int32.Parse(FrequencyNew.Text);
|
||||
|
||||
var r = await client.NotificationFrequencyPayloadAsync(newFrequencyVar);
|
||||
if (r.Code != 0) {
|
||||
this.OnShowBlurb?.Invoke("Error: " + r.Error);
|
||||
logger.Debug("ERROR: {0} : {1}", r.Message, r.Error);
|
||||
} else {
|
||||
this.OnShowBlurb?.Invoke("Frequency Saved");
|
||||
this.CloseEdit();
|
||||
}
|
||||
logger.Info("Got response from update frequency task : {0}", r);
|
||||
} catch (DataStructures.ServiceException se) {
|
||||
this.OnShowBlurb?.Invoke("Error: " + se.Message);
|
||||
logger.Error(se, "service exception in update frequency check: {0}", se.Message);
|
||||
} catch (Exception ex) {
|
||||
this.OnShowBlurb?.Invoke("Error: " + ex.Message);
|
||||
logger.Error(ex, "unexpected error in update frequency check: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Show the Edit Modal and blur the background
|
||||
/// </summary>
|
||||
@@ -591,5 +618,9 @@ namespace ZitiDesktopEdge {
|
||||
private void SaveConfig() {
|
||||
this.UpdateConfig();
|
||||
}
|
||||
|
||||
private void SaveFrequency() {
|
||||
this.UpdateFrequency();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<DOCUMENT Type="Advanced Installer" CreateVersion="17.4.1" version="18.3" Modules="professional" RootPath="." Language="en" Id="{7315FE7B-0418-4F38-8B12-6C0594276D30}">
|
||||
<DOCUMENT Type="Advanced Installer" CreateVersion="17.4.1" version="18.4" Modules="professional" RootPath="." Language="en" Id="{7315FE7B-0418-4F38-8B12-6C0594276D30}">
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
|
||||
<ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
|
||||
<ROW Property="AI_BackgroundColor" Value="lightblue" MsiKey="AI_BackgroundColor"/>
|
||||
@@ -23,10 +23,10 @@
|
||||
<ROW Property="CTRLS" Value="2"/>
|
||||
<ROW Property="Manufacturer" Value="NetFoundry, Inc."/>
|
||||
<ROW Property="MsiLogging" MultiBuildValue="AnyCPU_Release:vp"/>
|
||||
<ROW Property="ProductCode" Value="1033:{7C6269AD-D8A5-4B9F-8C73-A8EECAD26919} " Type="16"/>
|
||||
<ROW Property="ProductCode" Value="1033:{3530A7C6-F816-430B-A8CC-3F98EBD35A07} " Type="16"/>
|
||||
<ROW Property="ProductLanguage" Value="1033"/>
|
||||
<ROW Property="ProductName" Value="Ziti Desktop Edge"/>
|
||||
<ROW Property="ProductVersion" Value="1.9.9" Type="32"/>
|
||||
<ROW Property="ProductVersion" Value="1.10.0" Type="32"/>
|
||||
<ROW Property="REBOOT" MultiBuildValue="AnyCPU_Release:Suppress"/>
|
||||
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
|
||||
<ROW Property="UpgradeCode" Value="{CB7E173A-663D-4A23-BB22-D1E8D885C2F3}"/>
|
||||
@@ -45,6 +45,7 @@
|
||||
<ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1"/>
|
||||
<ROW Directory="DesktopFolder" Directory_Parent="TARGETDIR" DefaultDir="DESKTO~1|DesktopFolder" IsPseudoRoot="1"/>
|
||||
<ROW Directory="SHORTCUTDIR" Directory_Parent="TARGETDIR" DefaultDir="SHORTC~1|SHORTCUTDIR" IsPseudoRoot="1"/>
|
||||
<ROW Directory="StartupFolder" Directory_Parent="TARGETDIR" DefaultDir="STARTU~1|StartupFolder" IsPseudoRoot="1"/>
|
||||
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
||||
@@ -52,6 +53,7 @@
|
||||
<ROW Component="APPDIR" ComponentId="{B3881A25-6890-4920-9F69-CACA0C9ABA63}" Directory_="APPDIR" Attributes="0"/>
|
||||
<ROW Component="App.config" ComponentId="{27FAD46C-8379-4680-8506-4BCBA5A012E8}" Directory_="APPDIR" Attributes="0" KeyPath="ZitiDesktopEdge.exe.config" Type="0"/>
|
||||
<ROW Component="DnsClient.dll" ComponentId="{8C789D0B-0EB7-4172-ADB8-11D52C22488C}" Directory_="APPDIR" Attributes="0" KeyPath="DnsClient.dll"/>
|
||||
<ROW Component="Microsoft.Toolkit.Uwp.Notifications.dll" ComponentId="{EA48696A-A312-46C2-B720-6E4AB15406CA}" Directory_="APPDIR" Attributes="0" KeyPath="Microsoft.Toolkit.Uwp.Notifications.dll"/>
|
||||
<ROW Component="NLog.dll" ComponentId="{384D38B5-A4A0-4BC6-886A-82153E2687ED}" Directory_="APPDIR" Attributes="0" KeyPath="NLog.dll"/>
|
||||
<ROW Component="Newtonsoft.Json.dll" ComponentId="{5D7B59CE-A1B5-4EE9-842E-0206408F8674}" Directory_="APPDIR" Attributes="0" KeyPath="Newtonsoft.Json.dll"/>
|
||||
<ROW Component="ProductInformation" ComponentId="{4FC3A7CB-D334-466A-A919-E6A237EF4443}" Directory_="APPDIR" Attributes="260" KeyPath="Version"/>
|
||||
@@ -94,6 +96,7 @@
|
||||
<ROW File="DnsClient.dll" Component_="DnsClient.dll" FileName="DNSCLI~1.DLL|DnsClient.dll" Attributes="0" SourcePath="..\ZitiUpdateService\bin\Release\DnsClient.dll" SelfReg="false"/>
|
||||
<ROW File="System.Buffers.dll" Component_="System.Buffers.dll" FileName="SYSTEM~1.DLL|System.Buffers.dll" Attributes="0" SourcePath="..\ZitiUpdateService\bin\Release\System.Buffers.dll" SelfReg="false"/>
|
||||
<ROW File="QRCoder.dll" Component_="QRCoder.dll" FileName="QRCoder.dll" Attributes="0" SourcePath="..\DesktopEdge\bin\Release\QRCoder.dll" SelfReg="false"/>
|
||||
<ROW File="Microsoft.Toolkit.Uwp.Notifications.dll" Component_="Microsoft.Toolkit.Uwp.Notifications.dll" FileName="MICROS~1.DLL|Microsoft.Toolkit.Uwp.Notifications.dll" Attributes="0" SourcePath="..\DesktopEdge\bin\Release\Microsoft.Toolkit.Uwp.Notifications.dll" SelfReg="false"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.AiPersistentDataComponent">
|
||||
<ROW PersistentRow="ZitiUpdateServicelog.config" Type="0" Condition="OLDPRODUCTS"/>
|
||||
@@ -260,6 +263,7 @@
|
||||
<ROW Feature_="MainFeature" Component_="DnsClient.dll"/>
|
||||
<ROW Feature_="MainFeature" Component_="System.Buffers.dll"/>
|
||||
<ROW Feature_="MainFeature" Component_="QRCoder.dll"/>
|
||||
<ROW Feature_="MainFeature" Component_="Microsoft.Toolkit.Uwp.Notifications.dll"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
|
||||
<ROW Name="ziti.exe" SourcePath="ziti.ico" Index="0"/>
|
||||
@@ -336,6 +340,7 @@
|
||||
<ROW ServiceInstall="zititunnel.exe" Name="ziti" DisplayName="Ziti Desktop Edge Service" ServiceType="16" StartType="2" ErrorControl="32769" Component_="zititunnel.exe" Description="Access your Networks Secured by Ziti"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
|
||||
<ROW Shortcut="ZitiDesktopEdge" Directory_="StartupFolder" Name="ZITIDE~2|Ziti Desktop Edge" Component_="ZitiDesktopEdge.exe" Target="[#ZitiDesktopEdge.exe]" Description="Ziti Desktop Edge configuration interface" Hotkey="0" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||
<ROW Shortcut="ZitiDesktopEdge.exe" Directory_="SHORTCUTDIR" Name="ZITIDE~1|Ziti Desktop Edge" Component_="ZitiDesktopEdge.exe" Target="[#ZitiDesktopEdge.exe]" Description="Ziti Desktop Edge configuration interface" Hotkey="0" Icon_="ziti.exe" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||
<ROW Shortcut="ZitiDesktopEdge.exe_1" Directory_="DesktopFolder" Name="ZITIDE~1|Ziti Desktop Edge" Component_="ZitiDesktopEdge.exe" Target="[#ZitiDesktopEdge.exe]" Description="Ziti Desktop Edge configuration interface" Hotkey="0" Icon_="ziti.exe" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
|
||||
</COMPONENT>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ msbuild ZitiDesktopEdge.sln /property:Configuration=Release
|
||||
|
||||
Pop-Location
|
||||
|
||||
$ADV_INST_HOME = "C:\Program Files (x86)\Caphyon\Advanced Installer 18.3"
|
||||
$ADV_INST_HOME = "C:\Program Files (x86)\Caphyon\Advanced Installer 18.4"
|
||||
$ADVINST = "${ADV_INST_HOME}\bin\x86\AdvancedInstaller.com"
|
||||
$ADVPROJECT = "${scriptPath}\ZitiDesktopEdge.aip"
|
||||
$installerVersion=(Get-Content -Path ${scriptPath}\..\version)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
"C:\Program Files (x86)\Caphyon\Advanced Installer 18.3\bin\x86\AdvancedInstaller.com" /register %1
|
||||
"C:\Program Files (x86)\Caphyon\Advanced Installer 18.4\bin\x86\AdvancedInstaller.com" /register %1
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -321,6 +321,17 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
}
|
||||
}
|
||||
|
||||
public class Notification {
|
||||
public string IdentityName { get; set; }
|
||||
public string Fingerprint { get; set; }
|
||||
public string Message { get; set; }
|
||||
public int MfaMinimumTimeout { get; set; }
|
||||
public int MfaMaximumTimeout { get; set; }
|
||||
public int TimeDuration { get; set; }
|
||||
public string Severity { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ZitiTunnelStatus : SvcResponse
|
||||
{
|
||||
public TunnelStatus Status { get; set; }
|
||||
@@ -415,6 +426,11 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
public List<Identity> Identities { get; set; }
|
||||
}
|
||||
|
||||
public class NotificationEvent : StatusEvent {
|
||||
public List<Notification> Notification { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ServiceEvent : ActionEvent {
|
||||
public string Fingerprint { get; set; }
|
||||
public Service Service { get; set; }
|
||||
@@ -494,4 +510,19 @@ namespace ZitiDesktopEdge.DataStructures {
|
||||
public ConfigPayload Payload { get; set; }
|
||||
}
|
||||
|
||||
public class NotificationFrequencyPayload {
|
||||
public int NotificationFrequency { get; set; }
|
||||
}
|
||||
|
||||
public class NotificationFrequencyFunction: ServiceFunction {
|
||||
public NotificationFrequencyFunction(int notificationFrequency) {
|
||||
this.Function = "UpdateFrequency";
|
||||
this.Payload = new NotificationFrequencyPayload() {
|
||||
NotificationFrequency = notificationFrequency
|
||||
};
|
||||
}
|
||||
|
||||
public NotificationFrequencyPayload Payload { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
public event EventHandler<LogLevelEvent> OnLogLevelEvent;
|
||||
public event EventHandler<MfaEvent> OnMfaEvent;
|
||||
public event EventHandler<BulkServiceEvent> OnBulkServiceEvent;
|
||||
public event EventHandler<NotificationEvent> OnNotificationEvent;
|
||||
|
||||
protected override void ShutdownEvent(StatusEvent e) {
|
||||
Logger.Debug("Clean shutdown detected from ziti");
|
||||
@@ -71,6 +72,10 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
OnMfaEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected virtual void NotificationEvent(NotificationEvent e) {
|
||||
OnNotificationEvent?.Invoke(this, e);
|
||||
}
|
||||
|
||||
protected override void ClientConnected(object e) {
|
||||
base.ClientConnected(e);
|
||||
}
|
||||
@@ -176,6 +181,7 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
Function = "RemoveIdentity",
|
||||
Payload = new FingerprintPayload() { Fingerprint = fingerPrint }
|
||||
};
|
||||
Logger.Info("Removing Identity with fingerprint {0}", fingerPrint);
|
||||
await sendAsync(removeFunction);
|
||||
var r = await readAsync<SvcResponse>(ipcReader);
|
||||
} catch (Exception ioe) {
|
||||
@@ -367,6 +373,11 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
MfaEvent mfa = serializer.Deserialize<MfaEvent>(jsonReader);
|
||||
MfaEvent(mfa);
|
||||
break;
|
||||
case "notification":
|
||||
Logger.Debug("Notification event received");
|
||||
NotificationEvent notificationEvent = serializer.Deserialize<NotificationEvent>(jsonReader);
|
||||
NotificationEvent(notificationEvent);
|
||||
break;
|
||||
default:
|
||||
Logger.Debug("unexpected operation! " + evt.Op);
|
||||
break;
|
||||
@@ -414,6 +425,30 @@ namespace ZitiDesktopEdge.ServiceClient {
|
||||
return resp;
|
||||
}
|
||||
|
||||
async public Task<SvcResponse> NotificationFrequencyPayloadAsync(int frequency) {
|
||||
SvcResponse resp = null;
|
||||
try {
|
||||
|
||||
NotificationFrequencyFunction frequencyPayload = new NotificationFrequencyFunction(frequency);
|
||||
|
||||
await sendAsync(frequencyPayload);
|
||||
resp = await readAsync<SvcResponse>(ipcReader);
|
||||
Logger.Debug("frequency update payload is sent to the ziti tunnel");
|
||||
} catch (Exception ex) {
|
||||
//almost certainly a problem with the pipe - recreate the pipe...
|
||||
//setupPipe();
|
||||
//throw;
|
||||
Logger.Error(ex, "Unexpected error");
|
||||
CommunicationError(ex);
|
||||
throw ex;
|
||||
}
|
||||
if (resp?.Code != 0) {
|
||||
Logger.Warn("failed to update the frequency. {0} {1}", resp.Message, resp.Error);
|
||||
throw new ServiceException("Failed to update the frequency", resp.Code, "Un expected error.");
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
async public Task<ZitiTunnelStatus> debugAsync() {
|
||||
try {
|
||||
await sendAsync(new ServiceFunction() { Function = "Debug" });
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
This operation is should probably remain high such as "1:0:0" (every hour) or "1:0:0:0" (every day)
|
||||
-->
|
||||
<add key="UpdateTimer" value="0:10:0" />
|
||||
<add key="InstallationReminder" value="4:0:0"/>
|
||||
<add key="InstallationReminder" value="2:0:0"/>
|
||||
<!--default to look for updates once every ten minutes-->
|
||||
<add key="Version" value="release" />
|
||||
<add key="ClientSettingsProvider.ServiceUri" value="" />
|
||||
|
||||
@@ -30,6 +30,6 @@ using System.Runtime.InteropServices;
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.9.9.0")]
|
||||
[assembly: AssemblyVersion("1.9.9.0")]
|
||||
[assembly: AssemblyFileVersion("1.9.9.0")]
|
||||
// [assembly: AssemblyVersion("1.10.0.0")]
|
||||
[assembly: AssemblyVersion("1.10.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.10.0.0")]
|
||||
|
||||
@@ -582,7 +582,7 @@ namespace ZitiUpdateService {
|
||||
|
||||
ConfigureCheck();
|
||||
|
||||
// for testing checkUpdateImmediately();
|
||||
checkUpdateImmediately();
|
||||
|
||||
try {
|
||||
dataClient.ConnectAsync().Wait();
|
||||
@@ -668,22 +668,13 @@ namespace ZitiUpdateService {
|
||||
}
|
||||
|
||||
if (sender == null && e == null) {
|
||||
Logger.Info("package is in {0} - moving to install phase", fileDestination);
|
||||
|
||||
if (!check.HashIsValid(updateFolder, filename)) {
|
||||
Logger.Warn("The file was downloaded but the hash is not valid. The file will be removed: {0}", fileDestination);
|
||||
File.Delete(fileDestination);
|
||||
semaphore.Release();
|
||||
return;
|
||||
}
|
||||
Logger.Debug("downloaded file hash was correct. update can continue.");
|
||||
new SignedFileValidator(fileDestination).Verify();
|
||||
|
||||
installZDE(fileDestination);
|
||||
installZDE(fileDestination, filename);
|
||||
} else {
|
||||
Checkers.ZDEInstallerInfo info = check.GetZDEInstallerInfo(fileDestination);
|
||||
|
||||
if (info.IsCritical && _installationReminder == null) {
|
||||
if (info.IsCritical) {
|
||||
installZDE(fileDestination, filename);
|
||||
} else if (!info.IsCritical && _installationReminder == null) {
|
||||
// Timer for installation reminder
|
||||
var installationReminderInterval = ConfigurationManager.AppSettings.Get("InstallationReminder");
|
||||
var instInt = TimeSpan.Zero;
|
||||
@@ -698,6 +689,10 @@ namespace ZitiUpdateService {
|
||||
_installationReminder = new CustomTimer(callback, state, instInt, instInt);
|
||||
state._timer = _installationReminder;
|
||||
Logger.Info("Installation reminder for ZDE version {0} is set to {1}", info.Version, instInt);
|
||||
|
||||
info.TimeRemaining = _installationReminder.DueTime.TotalMilliseconds / 1000; // converting to seconds
|
||||
info.InstallTime = DateTime.Now.AddMilliseconds(_installationReminder.DueTime.TotalMilliseconds);
|
||||
NotifyInstallationUpdates(info, 0, "");
|
||||
}
|
||||
|
||||
if (_installationReminder != null) {
|
||||
@@ -705,9 +700,6 @@ namespace ZitiUpdateService {
|
||||
info.InstallTime = DateTime.Now.AddMilliseconds(_installationReminder.DueTime.TotalMilliseconds);
|
||||
Logger.Info("Installation of ZDE version {0} will be initiated in {1} seconds, approximately at {2}", info.Version, info.TimeRemaining, info.InstallTime);
|
||||
}
|
||||
if (info.Version != null) {
|
||||
NotifyInstallationUpdates(info, 0, "");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
try {
|
||||
@@ -724,7 +716,18 @@ namespace ZitiUpdateService {
|
||||
semaphore.Release();
|
||||
}
|
||||
|
||||
private void installZDE(string fileDestination) {
|
||||
private void installZDE(string fileDestination, string filename) {
|
||||
Logger.Info("package is in {0} - moving to install phase", fileDestination);
|
||||
|
||||
if (!check.HashIsValid(updateFolder, filename)) {
|
||||
Logger.Warn("The file was downloaded but the hash is not valid. The file will be removed: {0}", fileDestination);
|
||||
File.Delete(fileDestination);
|
||||
semaphore.Release();
|
||||
return;
|
||||
}
|
||||
Logger.Debug("downloaded file hash was correct. update can continue.");
|
||||
new SignedFileValidator(fileDestination).Verify();
|
||||
|
||||
try {
|
||||
StopZiti();
|
||||
StopUI().Wait();
|
||||
|
||||
@@ -181,10 +181,7 @@ namespace ZitiUpdateService.Checkers {
|
||||
} else {
|
||||
Logger.Debug("Comparing Version {0}, with current {1}", info.Version.ToString(), assemblyVersion.ToString());
|
||||
|
||||
if (info.Version.Build - assemblyVersion.Build >= 5) {
|
||||
info.IsCritical = true;
|
||||
Logger.Info("ZDEInstaller is marked as critical because the client is behind 5 updates");
|
||||
} else if ((info.Version.Major - assemblyVersion.Major >= 1) || (info.Version.Minor - assemblyVersion.Minor >= 1)) {
|
||||
if ((info.Version.Major - assemblyVersion.Major >= 1) || (info.Version.Minor - assemblyVersion.Minor >= 1)) {
|
||||
info.IsCritical = true;
|
||||
Logger.Info("ZDEInstaller is marked as critical because the major/minor version has changed");
|
||||
} else {
|
||||
|
||||
+19
-1
@@ -4,14 +4,32 @@
|
||||
* none
|
||||
|
||||
## Other changes:
|
||||
* [#278](https://github.com/openziti/desktop-edge-win/issues/278) inform the user an update is available before automatically updating. So user can manually install the latest version anytime within 1 week after the release is published. If a major/minor version has changed or if the client is missing 5 updates, then the auto installation will start in 4 hours. If the user does not initiate manual installation within the given time, a warning will be displayed for 4 hours and ZDE will auto update.
|
||||
* [#278](https://github.com/openziti/desktop-edge-win/issues/278) inform the user an update is available before automatically updating. So user can manually install the latest version anytime within 1 week after the release is published. If a major/minor version has changed or if the client is missing 5 updates, then the auto installation will start immediately. If the user does not initiate manual installation within the given time, a warning will be displayed for 2 hours and ZDE will auto update.
|
||||
* mfa timeout process
|
||||
|
||||
## Other changes:
|
||||
* none
|
||||
|
||||
## Bugs fixed:
|
||||
* none
|
||||
|
||||
## Dependency Updates
|
||||
* updated c-sdk to v0.25.2, updated t-sdk to v0.15.9
|
||||
|
||||
# Release 1.9.10
|
||||
|
||||
## What's New
|
||||
* none
|
||||
|
||||
## Other changes:
|
||||
* none
|
||||
|
||||
## Bugs fixed:
|
||||
* none
|
||||
|
||||
## Dependency Updates
|
||||
* wintun updated to 0.12
|
||||
|
||||
# Release 1.9.9
|
||||
|
||||
## What's New
|
||||
|
||||
+2
-2
@@ -14,12 +14,12 @@ REM See the License for the specific language governing permissions and
|
||||
REM limitations under the License.
|
||||
REM
|
||||
SET REPO_URL=https://github.com/openziti/ziti-tunnel-sdk-c.git
|
||||
SET ZITI_TUNNEL_REPO_BRANCH=v0.15.8
|
||||
SET ZITI_TUNNEL_REPO_BRANCH=v0.15.10
|
||||
REM override the c sdk used in the build - leave blank for the same as specified in the tunneler sdk
|
||||
SET ZITI_SDK_C_BRANCH=
|
||||
REM the number of TCP connections the tunneler sdk can have at any one time
|
||||
SET TCP_MAX_CONNECTIONS=256
|
||||
SET WINTUN_DL_URL=https://www.wintun.net/builds/wintun-0.11.zip
|
||||
SET WINTUN_DL_URL=https://www.wintun.net/builds/wintun-0.12.zip
|
||||
|
||||
set SVC_ROOT_DIR=%~dp0
|
||||
set CURDIR=%CD%
|
||||
|
||||
+24
-7
@@ -45,6 +45,7 @@ void readIdle(uv_prepare_t *idler);
|
||||
|
||||
void call_on_packet(void *packet, ssize_t len, packet_cb cb, void *ctx);
|
||||
void remove_intercepts(uv_async_t *handle);
|
||||
void add_intercepts(uv_async_t *handle);
|
||||
void free_async(uv_handle_t* timer);
|
||||
|
||||
dns_manager* get_dns_mgr_from_c();
|
||||
@@ -242,26 +243,42 @@ func (t *tunnel) runWriteLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
type RemoveWG struct {
|
||||
type TunnelerActionWaitGroup struct {
|
||||
Wg *sync.WaitGroup
|
||||
Czsvc *ZService
|
||||
}
|
||||
|
||||
func RemoveIntercept(rwg *RemoveWG) {
|
||||
func RemoveIntercept(removeWaitGroup *TunnelerActionWaitGroup) {
|
||||
async := (*C.uv_async_t)(C.malloc(C.sizeof_uv_async_t))
|
||||
async.data = unsafe.Pointer(rwg)
|
||||
async.data = unsafe.Pointer(removeWaitGroup)
|
||||
C.uv_async_init(_impl.libuvCtx.l, async, C.uv_async_cb(C.remove_intercepts))
|
||||
C.uv_async_send((*C.uv_async_t)(unsafe.Pointer(async)))
|
||||
}
|
||||
|
||||
func AddIntercept(addWaitGroup *TunnelerActionWaitGroup) {
|
||||
async := (*C.uv_async_t)(C.malloc(C.sizeof_uv_async_t))
|
||||
async.data = unsafe.Pointer(addWaitGroup)
|
||||
C.uv_async_init(_impl.libuvCtx.l, async, C.uv_async_cb(C.add_intercepts))
|
||||
C.uv_async_send((*C.uv_async_t)(unsafe.Pointer(async)))
|
||||
}
|
||||
|
||||
//export remove_intercepts
|
||||
func remove_intercepts(async *C.uv_async_t) {
|
||||
rwg := (*RemoveWG)(async.data)
|
||||
cSvcName := C.CString(rwg.Czsvc.Name)
|
||||
removeWaitGroup := (*TunnelerActionWaitGroup)(async.data)
|
||||
cSvcName := C.CString(removeWaitGroup.Czsvc.Name)
|
||||
defer C.free(unsafe.Pointer(cSvcName))
|
||||
C.ziti_tunneler_stop_intercepting(theTun.tunCtx, unsafe.Pointer(rwg.Czsvc.Czctx), cSvcName)
|
||||
C.ziti_tunneler_stop_intercepting(theTun.tunCtx, unsafe.Pointer(removeWaitGroup.Czsvc.Czctx), cSvcName)
|
||||
C.uv_close((*C.uv_handle_t)(unsafe.Pointer(async)), C.uv_close_cb(C.free_async))
|
||||
rwg.Wg.Done()
|
||||
removeWaitGroup.Wg.Done()
|
||||
}
|
||||
|
||||
//export add_intercepts
|
||||
func add_intercepts(async *C.uv_async_t) {
|
||||
addWaitGroup := (*TunnelerActionWaitGroup)(async.data)
|
||||
|
||||
C.ziti_sdk_c_on_service(addWaitGroup.Czsvc.Czctx, addWaitGroup.Czsvc.Czsvc, C.ZITI_OK, unsafe.Pointer(theTun.tunCtx))
|
||||
C.uv_close((*C.uv_handle_t)(unsafe.Pointer(async)), C.uv_close_cb(C.free_async))
|
||||
addWaitGroup.Wg.Done()
|
||||
}
|
||||
|
||||
//export apply_dns_go
|
||||
|
||||
@@ -57,7 +57,7 @@ func processDNSquery(packet []byte, p *net.UDPAddr, s *net.UDPConn, ipVer int) {
|
||||
query = q.Question[0]
|
||||
log.Tracef("processing a dns query. type:%s, for:%s on %v. id:%v", dns.Type(query.Qtype), query.Name, p, q.Id)
|
||||
} else {
|
||||
log.Warnf("DNS MSG had no question! %v", msg.String())
|
||||
log.Warnf("discarding dns message as it contained no question! %v", msg.String())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -378,7 +378,11 @@ outer:
|
||||
for k, r := range reqs {
|
||||
if now.After(r.exp) {
|
||||
log.Debugf("a DNS request has expired - enable trace logging and reproduce this issue for more information")
|
||||
log.Tracef("expired DNS req: %s %s", dns.Type(r.req.Question[0].Qtype), r.req.Question[0].Name)
|
||||
if len(r.req.Question) > 1 {
|
||||
log.Tracef("expired DNS req: %s %s", dns.Type(r.req.Question[0].Qtype), r.req.Question[0].Name)
|
||||
} else {
|
||||
log.Tracef("expired DNS req - had no question???")
|
||||
}
|
||||
|
||||
delete(reqs, k)
|
||||
}
|
||||
@@ -399,7 +403,7 @@ outer:
|
||||
case rep := <-respChan:
|
||||
reply := dns.Msg{}
|
||||
if err := reply.Unpack(rep); err == nil {
|
||||
id := (uint32(reply.Id) << 16) | uint32(reply.Question[0].Qtype)
|
||||
id := calcDnsId(&reply)
|
||||
dnsReqMutex.Lock()
|
||||
req, found := reqs[id]
|
||||
if found {
|
||||
@@ -428,7 +432,7 @@ outer:
|
||||
log.Debug("Upstream DNS proxy loop begins")
|
||||
for {
|
||||
pr := <-proxiedRequests
|
||||
id := (uint32(pr.req.Id) << 16) | uint32(pr.req.Question[0].Qtype)
|
||||
id := calcDnsId(pr.req)
|
||||
dnsReqMutex.Lock()
|
||||
reqs[id] = pr
|
||||
dnsReqMutex.Unlock()
|
||||
@@ -450,6 +454,13 @@ outer:
|
||||
log.Tracef("Proxied request sent to %v from ipv%d listener", proxy.RemoteAddr(), pr.ipVer)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func calcDnsId(req *dns.Msg) uint32 {
|
||||
if len(req.Question) > 0 {
|
||||
return (uint32(req.Id) << 16) | uint32(req.Question[0].Qtype)
|
||||
} else {
|
||||
return 0 //this shouldn't be happening - yet a user hit this situation
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright NetFoundry, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sdk.h"
|
||||
#include <ziti/ziti_tunnel.h>
|
||||
#include <ziti/ziti_log.h>
|
||||
|
||||
void ziti_mfa_auth_request(ziti_ar_mfa_cb response_cb, ziti_context ztx, void *mfa_ctx, char *code, ziti_ar_mfa_status_cb auth_response, char *fingerprint) {
|
||||
response_cb(ztx, mfa_ctx, code, auth_response, fingerprint);
|
||||
}
|
||||
+53
-62
@@ -47,26 +47,6 @@ type mfaCodes struct {
|
||||
var emptyCodes []string
|
||||
var mfaAuthResults = make(chan string)
|
||||
|
||||
//export ziti_aq_mfa_cb_go
|
||||
func ziti_aq_mfa_cb_go(ztx C.ziti_context, mfa_ctx unsafe.Pointer, aq_mfa *C.ziti_auth_query_mfa, response_cb C.ziti_ar_mfa_cb) {
|
||||
appCtx := C.ziti_app_ctx(ztx)
|
||||
if appCtx != C.NULL {
|
||||
log.Debugf("mfa requested for ziti context %p.", ztx)
|
||||
zid := (*ZIdentity)(appCtx)
|
||||
mfa := &Mfa{
|
||||
mfaContext: mfa_ctx,
|
||||
authQuery: aq_mfa,
|
||||
responseCb: response_cb,
|
||||
}
|
||||
zid.mfa = mfa
|
||||
zid.MfaNeeded = true
|
||||
zid.MfaEnabled = true
|
||||
log.Debugf("mfa enabled/needed set to true for ziti context [%p]. Identity name:%s [fingerprint: %s]", zid, zid.Name, zid.Fingerprint)
|
||||
} else {
|
||||
log.Debugf("mfa requested for ziti context/mfa context [%p, %p] but the context was NOT found in the map. This is unexpected. Please report.", ztx, mfa_ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func EnableMFA(id *ZIdentity) {
|
||||
C.ziti_mfa_enroll(id.czctx, C.ziti_mfa_cb(C.ziti_mfa_enroll_cb_go), unsafe.Pointer(C.CString(id.Fingerprint)))
|
||||
}
|
||||
@@ -99,6 +79,7 @@ func ziti_mfa_enroll_cb_go(_ C.ziti_context, status C.int, enrollment *C.ziti_mf
|
||||
}
|
||||
}
|
||||
|
||||
// requires that the identity already be fully authenticated and used specifically for enrollment
|
||||
func VerifyMFA(id *ZIdentity, code string) {
|
||||
ccode := C.CString(code)
|
||||
defer C.free(unsafe.Pointer(ccode))
|
||||
@@ -157,6 +138,53 @@ func ReturnMfaCodes(id *ZIdentity, code string) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// used when an identity is partially authenticated and waiting on 2fa, i.e. for authentication and for timeouts
|
||||
func AuthMFA(id *ZIdentity, code string) error {
|
||||
ccode := C.CString(code)
|
||||
defer C.free(unsafe.Pointer(ccode))
|
||||
|
||||
log.Tracef("authenticating MFA for fingerprint: %s using code: %s", id.Fingerprint, code)
|
||||
C.ziti_mfa_auth(id.czctx, ccode, C.ziti_mfa_cb(C.ziti_auth_mfa_status_cb_go), unsafe.Pointer(C.CString(id.Fingerprint)))
|
||||
authResult := strings.TrimSpace(<-mfaAuthResults)
|
||||
|
||||
if authResult == "" {
|
||||
id.MfaEnabled = true
|
||||
id.MfaNeeded = false
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error in authMFA: %v", authResult)
|
||||
}
|
||||
|
||||
//export ziti_auth_mfa_status_cb_go
|
||||
func ziti_auth_mfa_status_cb_go(ztx C.ziti_context, status C.int, cFingerprint *C.char) {
|
||||
defer C.free(unsafe.Pointer(cFingerprint))
|
||||
fp := C.GoString(cFingerprint)
|
||||
|
||||
log.Debugf("ziti_auth_mfa_status_cb_go called for %s. status: %d for ", fp, int(status))
|
||||
var m = dto.MfaEvent{
|
||||
ActionEvent: dto.MFAAuthenticationEvent,
|
||||
Fingerprint: fp,
|
||||
Successful: false,
|
||||
RecoveryCodes: nil,
|
||||
}
|
||||
|
||||
if status != C.ZITI_OK {
|
||||
e := C.ziti_errorstr(status)
|
||||
ego := C.GoString(e)
|
||||
log.Errorf("Error encounted when authenticating 2f mfa: %v", ego)
|
||||
m.Error = ego
|
||||
mfaAuthResults <- ego
|
||||
} else {
|
||||
log.Infof("Identity with fingerprint %s has successfully authenticated MFA", fp)
|
||||
m.Successful = true
|
||||
goapi.UpdateMfa(fp, true, false)
|
||||
mfaAuthResults <- ""
|
||||
}
|
||||
|
||||
log.Debugf("sending ziti_mfa_auth response back to UI for %s. verified: %t. error: %s", fp, m.Successful, m.Error)
|
||||
goapi.BroadcastEvent(m)
|
||||
}
|
||||
|
||||
//export ziti_mfa_recovery_codes_cb_return
|
||||
func ziti_mfa_recovery_codes_cb_return(_ C.ziti_context, status C.int, recoveryCodes **C.char, cFingerprint *C.char) {
|
||||
fp := C.GoString(cFingerprint)
|
||||
@@ -237,48 +265,6 @@ func populateStringSlice(c_char_array **C.char) []string {
|
||||
return strs
|
||||
}
|
||||
|
||||
func AuthMFA(id *ZIdentity, code string) error {
|
||||
if id.mfa == nil {
|
||||
log.Warnf("AuthMFA called but mfa is nil. This usually is because AuthMFA is called from an unenrolled MFA endpoint or the endpoint has already been auth'ed")
|
||||
return fmt.Errorf("identity has not authenticated yet")
|
||||
}
|
||||
if id.mfa.responseCb == nil {
|
||||
log.Warnf("AuthMFA called but response cb is nil. This usually is because the session is already validiated. returning true from AuthMFA")
|
||||
return nil
|
||||
}
|
||||
|
||||
ccode := C.CString(code)
|
||||
defer C.free(unsafe.Pointer(ccode))
|
||||
|
||||
cfp := C.CString(id.Fingerprint)
|
||||
defer C.free(unsafe.Pointer(cfp))
|
||||
log.Debugf("beginning authentication for fingerprint %s with code %s", id.Fingerprint, code)
|
||||
C.ziti_mfa_auth_request(id.mfa.responseCb, id.czctx, id.mfa.mfaContext, ccode, C.ziti_ar_mfa_status_cb(C.ziti_ar_mfa_status_cb_go), cfp)
|
||||
authResult := strings.TrimSpace(<-mfaAuthResults)
|
||||
|
||||
if authResult == "" {
|
||||
id.mfa.responseCb = nil
|
||||
id.MfaNeeded = false
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("error in authMFA: %v", authResult)
|
||||
}
|
||||
|
||||
//export ziti_ar_mfa_status_cb_go
|
||||
func ziti_ar_mfa_status_cb_go(ztx C.ziti_context, mfa_ctx unsafe.Pointer, status C.int, cFingerprint *C.char) {
|
||||
fp := C.GoString(cFingerprint)
|
||||
log.Debugf("ziti_ar_mfa_status_cb_go called for fingerprint: %s with status %v", fp, status)
|
||||
if status == C.ZITI_OK {
|
||||
log.Infof("mfa authentication succeeded for fingerprint: %s", fp)
|
||||
mfaAuthResults <- ""
|
||||
} else {
|
||||
log.Warnf("mfa authentication failed for fingerprint: %s", fp)
|
||||
e := C.ziti_errorstr(status)
|
||||
ego := C.GoString(e)
|
||||
mfaAuthResults <- ego
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveMFA(id *ZIdentity, code string) {
|
||||
ccode := C.CString(code)
|
||||
defer C.free(unsafe.Pointer(ccode))
|
||||
@@ -314,3 +300,8 @@ func ziti_mfa_cb_remove_go(_ C.ziti_context, status C.int, cFingerprint *C.char)
|
||||
log.Debugf("sending ziti_mfa_verify response back to UI for %s. verified: %t. error: %s", fp, m.Successful, m.Error)
|
||||
goapi.BroadcastEvent(m)
|
||||
}
|
||||
|
||||
func EndpointStateChanged(id *ZIdentity, woken bool, unlocked bool) {
|
||||
C.ziti_endpoint_state_change(id.czctx, C.bool(woken), C.bool(unlocked))
|
||||
log.Debugf("Endpoint status changed for id %s - woken %t, unlocked %t", id.Fingerprint, woken, unlocked)
|
||||
}
|
||||
|
||||
+156
-34
@@ -47,12 +47,14 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/api"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/constants"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/dto"
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/util/logging"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -73,11 +75,29 @@ type ServiceChange struct {
|
||||
ZitiContext *ZIdentity
|
||||
}
|
||||
type BulkServiceChange struct {
|
||||
Fingerprint string
|
||||
HostnamesToAdd map[string]bool
|
||||
HostnamesToRemove map[string]bool
|
||||
ServicesToRemove []*dto.Service
|
||||
ServicesToAdd []*dto.Service
|
||||
Fingerprint string
|
||||
HostnamesToAdd map[string]bool
|
||||
HostnamesToRemove map[string]bool
|
||||
ServicesToRemove []*dto.Service
|
||||
ServicesToAdd []*dto.Service
|
||||
MfaMinTimeout int32
|
||||
MfaMaxTimeout int32
|
||||
MfaLastUpdatedTime time.Time
|
||||
}
|
||||
|
||||
type NotificationMessage struct {
|
||||
IdentityName string
|
||||
Fingerprint string
|
||||
Message string
|
||||
MfaMinimumTimeout int32
|
||||
MfaMaximumTimeout int32
|
||||
MfaTimeDuration int
|
||||
Severity string
|
||||
}
|
||||
|
||||
type TunnelNotificationEvent struct {
|
||||
Op string
|
||||
Notification []NotificationMessage
|
||||
}
|
||||
|
||||
var _impl sdk
|
||||
@@ -109,35 +129,34 @@ func (inst *sdk) run(loglevel int) {
|
||||
C.libuv_run(inst.libuvCtx)
|
||||
}
|
||||
|
||||
type RefreshRequiredCheck func(int32, int32) bool
|
||||
|
||||
type ZService struct {
|
||||
Name string
|
||||
Id string
|
||||
Service *dto.Service
|
||||
Czsvc *C.ziti_service
|
||||
Czctx C.ziti_context
|
||||
}
|
||||
|
||||
type ZIdentity struct {
|
||||
Options *C.ziti_options
|
||||
czctx C.ziti_context
|
||||
czid *C.ziti_identity
|
||||
status int
|
||||
statusErr error
|
||||
Loaded bool
|
||||
Name string
|
||||
Version string
|
||||
Services sync.Map
|
||||
Fingerprint string
|
||||
Active bool
|
||||
StatusChanges func(int)
|
||||
MfaNeeded bool
|
||||
MfaEnabled bool
|
||||
mfa *Mfa
|
||||
}
|
||||
|
||||
type Mfa struct {
|
||||
mfaContext unsafe.Pointer
|
||||
authQuery *C.ziti_auth_query_mfa
|
||||
responseCb C.ziti_ar_mfa_cb
|
||||
Options *C.ziti_options
|
||||
czctx C.ziti_context
|
||||
czid *C.ziti_identity
|
||||
status int
|
||||
statusErr error
|
||||
Loaded bool
|
||||
Name string
|
||||
Version string
|
||||
Services sync.Map
|
||||
Fingerprint string
|
||||
Active bool
|
||||
StatusChanges func(int)
|
||||
MfaNeeded bool
|
||||
MfaEnabled bool
|
||||
MfaMinTimeout int32
|
||||
MfaMaxTimeout int32
|
||||
MfaLastUpdatedTime time.Time
|
||||
}
|
||||
|
||||
func NewZid(statusChange func(int)) *ZIdentity {
|
||||
@@ -145,6 +164,9 @@ func NewZid(statusChange func(int)) *ZIdentity {
|
||||
zid.Services = sync.Map{}
|
||||
zid.Options = (*C.ziti_options)(C.calloc(1, C.sizeof_ziti_options))
|
||||
zid.StatusChanges = statusChange
|
||||
zid.MfaMinTimeout = -1
|
||||
zid.MfaMaxTimeout = -1
|
||||
zid.MfaLastUpdatedTime = time.Now()
|
||||
return zid
|
||||
}
|
||||
|
||||
@@ -224,6 +246,34 @@ func (zid *ZIdentity) Shutdown() {
|
||||
C.uv_async_send((*C.uv_async_t)(unsafe.Pointer(async)))
|
||||
}
|
||||
|
||||
func (zid *ZIdentity) MfaRefreshNeeded() bool {
|
||||
return !(zid.MfaMinTimeout == -1 && zid.MfaMaxTimeout == -1)
|
||||
}
|
||||
|
||||
func (zid *ZIdentity) GetRemainingTime(timeout int32) int32 {
|
||||
var remainingTimeout int32
|
||||
if (timeout - int32(time.Since(zid.MfaLastUpdatedTime).Seconds())) <= 0 {
|
||||
remainingTimeout = 0
|
||||
} else {
|
||||
remainingTimeout = timeout - int32(time.Since(zid.MfaLastUpdatedTime).Seconds())
|
||||
}
|
||||
return remainingTimeout
|
||||
}
|
||||
|
||||
func (zid *ZIdentity) GetMFAState(interval int32) int {
|
||||
var mfaState int
|
||||
if (zid.MfaMaxTimeout > -1) && (zid.MfaMaxTimeout-int32(time.Since(zid.MfaLastUpdatedTime).Seconds())) < 0 {
|
||||
mfaState = constants.MfaAllSvcTimeout
|
||||
} else if (zid.MfaMinTimeout - int32(time.Since(zid.MfaLastUpdatedTime).Seconds())) < 0 {
|
||||
mfaState = constants.MfaFewSvcTimeout
|
||||
} else if (zid.MfaMinTimeout - int32(time.Since(zid.MfaLastUpdatedTime).Seconds())) < interval {
|
||||
mfaState = constants.MfaNearingTimeout
|
||||
} else {
|
||||
mfaState = -1
|
||||
}
|
||||
return mfaState
|
||||
}
|
||||
|
||||
//export doZitiShutdown
|
||||
func doZitiShutdown(async *C.uv_async_t) {
|
||||
ctx := C.ziti_context(async.data)
|
||||
@@ -315,6 +365,7 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
|
||||
|
||||
//if any posture query sets pass - that will grant the user access to that service
|
||||
hasAccess := false
|
||||
timeout := -1
|
||||
|
||||
//find all posture checks sets...
|
||||
for setIdx := 0; true; setIdx++ {
|
||||
@@ -344,17 +395,28 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
|
||||
|
||||
var pcId string
|
||||
pcId = C.GoString(pq.id)
|
||||
log.Infof("Posture query %s, timeout %d", C.GoString(pq.id), int(pq.timeout))
|
||||
|
||||
_, found := pcIds[pcId]
|
||||
if found {
|
||||
log.Tracef("posture check with id %s already in failing posture check map", pcId)
|
||||
for _, pc := range postureChecks {
|
||||
if pc.Id == C.GoString(pq.id) {
|
||||
if timeout == -1 || timeout > int(pq.timeout) {
|
||||
timeout = int(pq.timeout)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pcIds[C.GoString(pq.id)] = false
|
||||
pc := dto.PostureCheck{
|
||||
IsPassing: bool(pq.is_passing),
|
||||
QueryType: C.GoString(pq.query_type),
|
||||
Id: pcId,
|
||||
Timeout: int(pq.timeout),
|
||||
}
|
||||
timeout = pc.Timeout
|
||||
|
||||
postureChecks = append(postureChecks, pc)
|
||||
}
|
||||
@@ -370,11 +432,13 @@ func serviceCB(ziti_ctx C.ziti_context, service *C.ziti_service, status C.int, z
|
||||
OwnsIntercept: true,
|
||||
PostureChecks: postureChecks,
|
||||
IsAccessable: hasAccess,
|
||||
Timeout: int32(timeout),
|
||||
}
|
||||
added := ZService{
|
||||
Name: name,
|
||||
Id: svcId,
|
||||
Service: svc,
|
||||
Czsvc: service,
|
||||
Czctx: ziti_ctx,
|
||||
}
|
||||
zid.Services.Store(svcId, &added)
|
||||
@@ -506,6 +570,7 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
if unsafe.Pointer(added) == C.NULL {
|
||||
break
|
||||
}
|
||||
|
||||
svcToAdd := serviceCB(ztx, added, C.ZITI_OK, zid)
|
||||
if svcToAdd != nil {
|
||||
addAddys := svcToAdd.Addresses
|
||||
@@ -517,13 +582,45 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
servicesToAdd = append(servicesToAdd, svcToAdd)
|
||||
}
|
||||
}
|
||||
var minimumTimeout int32 = -1
|
||||
var maximumTimeout int32 = -1
|
||||
noTimeoutSvc := false
|
||||
if len(servicesToAdd) > 0 {
|
||||
zid.Services.Range(func(key interface{}, value interface{}) bool {
|
||||
//string, ZService
|
||||
val := value.(*ZService)
|
||||
|
||||
if val.Service.Timeout >= 0 {
|
||||
if minimumTimeout == -1 || minimumTimeout > val.Service.Timeout {
|
||||
minimumTimeout = val.Service.Timeout
|
||||
}
|
||||
if maximumTimeout == -1 || maximumTimeout < val.Service.Timeout {
|
||||
maximumTimeout = val.Service.Timeout
|
||||
}
|
||||
} else {
|
||||
noTimeoutSvc = true
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
})
|
||||
if noTimeoutSvc {
|
||||
maximumTimeout = -1
|
||||
}
|
||||
}
|
||||
|
||||
zid.MfaMinTimeout = minimumTimeout
|
||||
zid.MfaMaxTimeout = maximumTimeout
|
||||
|
||||
svcChange := BulkServiceChange{
|
||||
Fingerprint: zid.Fingerprint,
|
||||
HostnamesToAdd: hostnamesToAdd,
|
||||
HostnamesToRemove: hostnamesToRemove,
|
||||
ServicesToAdd: servicesToAdd,
|
||||
ServicesToRemove: servicesToRemove,
|
||||
Fingerprint: zid.Fingerprint,
|
||||
HostnamesToAdd: hostnamesToAdd,
|
||||
HostnamesToRemove: hostnamesToRemove,
|
||||
ServicesToAdd: servicesToAdd,
|
||||
ServicesToRemove: servicesToRemove,
|
||||
MfaMinTimeout: minimumTimeout,
|
||||
MfaMaxTimeout: maximumTimeout,
|
||||
MfaLastUpdatedTime: time.Now(),
|
||||
}
|
||||
|
||||
if len(BulkServiceChanges) == cap(BulkServiceChanges) {
|
||||
@@ -531,6 +628,33 @@ func eventCB(ztx C.ziti_context, event *C.ziti_event_t) {
|
||||
} else {
|
||||
BulkServiceChanges <- svcChange
|
||||
}
|
||||
case C.ZitiMfaAuthEvent:
|
||||
zid := (*ZIdentity)(appCtx)
|
||||
log.Debugf("mfa auth event for finger print %s", zid.Fingerprint)
|
||||
zid.MfaNeeded = true
|
||||
zid.MfaEnabled = true
|
||||
|
||||
if zid.Fingerprint != "" {
|
||||
var id = dto.Identity{
|
||||
Name: zid.Name,
|
||||
FingerPrint: zid.Fingerprint,
|
||||
Active: zid.Active,
|
||||
ControllerVersion: zid.Version,
|
||||
Status: "",
|
||||
MfaNeeded: true,
|
||||
MfaEnabled: true,
|
||||
Tags: nil,
|
||||
}
|
||||
|
||||
var m = dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: id,
|
||||
}
|
||||
goapi.BroadcastEvent(m)
|
||||
log.Debugf("mfa auth event set enabled/needed to true for ziti context [%p]. Identity name:%s [fingerprint: %s]", zid, zid.Name, zid.Fingerprint)
|
||||
} else {
|
||||
log.Debugf("mfa auth event set received with empty finger print, ziti context [%p]", zid)
|
||||
}
|
||||
default:
|
||||
log.Infof("event %d not handled", event._type)
|
||||
}
|
||||
@@ -576,11 +700,9 @@ func LoadZiti(zid *ZIdentity, cfg string, refreshInterval int) {
|
||||
zid.Options.pq_os_cb = C.ziti_pq_os_cb(C.ziti_pq_os_go)
|
||||
zid.Options.pq_process_cb = C.ziti_pq_process_cb(C.ziti_pq_process_go)
|
||||
|
||||
zid.Options.events = C.ZitiContextEvent | C.ZitiServiceEvent | C.ZitiRouterEvent
|
||||
zid.Options.events = C.ZitiContextEvent | C.ZitiServiceEvent | C.ZitiRouterEvent | C.ZitiMfaAuthEvent
|
||||
zid.Options.event_cb = C.ziti_event_cb(C.eventCB)
|
||||
|
||||
zid.Options.aq_mfa_cb = C.ziti_aq_mfa_cb(C.ziti_aq_mfa_cb_go)
|
||||
|
||||
ptr := unsafe.Pointer(zid)
|
||||
zid.Options.app_ctx = ptr
|
||||
|
||||
|
||||
+1
-2
@@ -75,15 +75,14 @@ ziti_service* ziti_service_array_get(ziti_service_array arr, int idx);
|
||||
void ziti_dump_go(char *msg);
|
||||
|
||||
//declare all mfa callbacks
|
||||
void ziti_aq_mfa_cb_go(ziti_context ztx, void *mfa_ctx, ziti_auth_query_mfa *aq_mfa, ziti_ar_mfa_cb response_cb);
|
||||
void ziti_mfa_enroll_cb_go(ziti_context ztx, int status, ziti_mfa_enrollment *mfa_enrollment, char *fingerprint);
|
||||
void ziti_mfa_cb_verify_go(ziti_context ztx, int status, char *fingerprint);
|
||||
void ziti_mfa_cb_remove_go(ziti_context ztx, int status, char *fingerprint);
|
||||
void ziti_mfa_recovery_codes_cb_return(ziti_context ztx, int status, char **recovery_codes, char *fingerprint);
|
||||
void ziti_mfa_recovery_codes_cb_generate(ziti_context ztx, int status, char **recovery_codes, char *fingerprint);
|
||||
void ziti_mfa_auth_request(ziti_ar_mfa_cb response_cb, ziti_context ztx, void *mfa_ctx, char *code, ziti_ar_mfa_status_cb auth_response, char *fingerprint);
|
||||
void ziti_mfa_ar_cb(ziti_context ztx, void *mfa_ctx, int status);
|
||||
void ziti_ar_mfa_status_cb_go(ziti_context ztx, void *mfa_ctx, int status, char *fingerprint);
|
||||
void ziti_auth_mfa_status_cb_go(ziti_context ztx, int status, char *fingerprint);
|
||||
|
||||
ziti_posture_query_set* posture_query_set_get(ziti_posture_query_set_array arr, int idx);
|
||||
ziti_posture_query* posture_queries_get(ziti_posture_query_array arr, int idx);
|
||||
|
||||
@@ -307,4 +307,4 @@ Get-ItemProperty -Path $key | where {$_.ProfileName -match "Ziti.*"} | Remove-It
|
||||
log.Errorf("ERROR Cleaning up the Network Adapter profiles: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,14 @@
|
||||
package constants
|
||||
|
||||
const (
|
||||
Ipv4ip = "100.64.0.1"
|
||||
Ipv4MaxMask = 8
|
||||
Ipv4MinMask = 16
|
||||
Ipv4DefaultMask = 10
|
||||
Ipv4ip = "100.64.0.1"
|
||||
Ipv4MaxMask = 10
|
||||
Ipv4MinMask = 16
|
||||
Ipv4DefaultMask = 10
|
||||
MinimumFrequency = 5 // minimum notification window
|
||||
MaximumFrequency = 20 // maximum notification window
|
||||
|
||||
MfaAllSvcTimeout = 0
|
||||
MfaFewSvcTimeout = 1
|
||||
MfaNearingTimeout = 2
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ package dto
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/openziti/desktop-edge-win/service/ziti-tunnel/config"
|
||||
idcfg "github.com/openziti/sdk-golang/ziti/config"
|
||||
@@ -39,6 +40,7 @@ type Service struct {
|
||||
OwnsIntercept bool
|
||||
PostureChecks []PostureCheck
|
||||
IsAccessable bool
|
||||
Timeout int32
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
@@ -57,6 +59,7 @@ type PostureCheck struct {
|
||||
IsPassing bool
|
||||
QueryType string
|
||||
Id string
|
||||
Timeout int
|
||||
}
|
||||
|
||||
type ServiceOwner struct {
|
||||
@@ -68,17 +71,20 @@ type HostContext struct {
|
||||
}
|
||||
|
||||
type Identity struct {
|
||||
Name string
|
||||
FingerPrint string
|
||||
Active bool
|
||||
Config idcfg.Config
|
||||
ControllerVersion string
|
||||
Status string
|
||||
MfaEnabled bool
|
||||
MfaNeeded bool
|
||||
Services []*Service `json:",omitempty"`
|
||||
Metrics *Metrics `json:",omitempty"`
|
||||
Tags []string `json:",omitempty"`
|
||||
Name string
|
||||
FingerPrint string
|
||||
Active bool
|
||||
Config idcfg.Config
|
||||
ControllerVersion string
|
||||
Status string
|
||||
MfaEnabled bool
|
||||
MfaNeeded bool
|
||||
Services []*Service `json:",omitempty"`
|
||||
Metrics *Metrics `json:",omitempty"`
|
||||
Tags []string `json:",omitempty"`
|
||||
MfaMinTimeout int32
|
||||
MfaMaxTimeout int32
|
||||
MfaLastUpdatedTime time.Time
|
||||
}
|
||||
type Metrics struct {
|
||||
Up int64
|
||||
@@ -110,16 +116,17 @@ func (id *Identity) Path() string {
|
||||
}
|
||||
|
||||
type TunnelStatus struct {
|
||||
Active bool
|
||||
Duration int64
|
||||
Identities []*Identity
|
||||
IpInfo *TunIpInfo `json:"IpInfo,omitempty"`
|
||||
LogLevel string
|
||||
ServiceVersion ServiceVersion
|
||||
TunIpv4 string
|
||||
TunIpv4Mask int
|
||||
Status string
|
||||
AddDns bool
|
||||
Active bool
|
||||
Duration int64
|
||||
Identities []*Identity
|
||||
IpInfo *TunIpInfo `json:"IpInfo,omitempty"`
|
||||
LogLevel string
|
||||
ServiceVersion ServiceVersion
|
||||
TunIpv4 string
|
||||
TunIpv4Mask int
|
||||
Status string
|
||||
AddDns bool
|
||||
NotificationFrequency int
|
||||
}
|
||||
|
||||
type ServiceVersion struct {
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
package dto
|
||||
|
||||
const (
|
||||
ADDED = "added"
|
||||
BULK = "bulk"
|
||||
REMOVED = "removed"
|
||||
ERROR = "error"
|
||||
UPDATED = "updated"
|
||||
CHANGED = "changed"
|
||||
NORMAL = "Normal"
|
||||
ADDED = "added"
|
||||
BULK = "bulk"
|
||||
REMOVED = "removed"
|
||||
ERROR = "error"
|
||||
UPDATED = "updated"
|
||||
CHANGED = "changed"
|
||||
NORMAL = "Normal"
|
||||
CONNECTED = "connected"
|
||||
DISCONNECTED = "disconnected"
|
||||
|
||||
SERVICE_OP = "service"
|
||||
BULK_SERVICE_OP = "bulkservice"
|
||||
@@ -37,6 +39,7 @@ const (
|
||||
MFAEnrollmentRemovedAction = "enrollment_remove"
|
||||
|
||||
MFA_AUTH_CHALLENGE_ACTION = "auth_challenge"
|
||||
MFAAuthenticationAction = "mfa_auth_status"
|
||||
)
|
||||
|
||||
var SERVICE_ADDED = ActionEvent{
|
||||
@@ -60,6 +63,14 @@ var IDENTITY_REMOVED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: IDENTITY_OP},
|
||||
Action: REMOVED,
|
||||
}
|
||||
var IDENTITY_CONNECTED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: IDENTITY_OP},
|
||||
Action: CONNECTED,
|
||||
}
|
||||
var IDENTITY_DISCONNECTED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: IDENTITY_OP},
|
||||
Action: DISCONNECTED,
|
||||
}
|
||||
var LOGLEVEL_CHANGED = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: LOGLEVEL_OP},
|
||||
Action: CHANGED,
|
||||
@@ -96,3 +107,7 @@ var MFAAuthChallengeEvent = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: MFA_OP},
|
||||
Action: MFA_AUTH_CHALLENGE_ACTION,
|
||||
}
|
||||
var MFAAuthenticationEvent = ActionEvent{
|
||||
StatusEvent: StatusEvent{Op: MFA_OP},
|
||||
Action: MFAAuthenticationAction,
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package service
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
@@ -37,6 +38,7 @@ import (
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
@@ -45,6 +47,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -61,8 +64,9 @@ func (p *Pipes) Close() {
|
||||
}
|
||||
|
||||
var shutdown = make(chan bool, 8) //a channel informing go routines to exit
|
||||
var notificationFrequency *time.Ticker
|
||||
|
||||
func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
func SubMain(ops chan string, changes chan<- svc.Status, winEvents <-chan WindowsEvents) error {
|
||||
log.Info("============================== service begins ==============================")
|
||||
windns.RemoveAllNrptRules()
|
||||
// cleanup old ziti tun profiles
|
||||
@@ -82,6 +86,7 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
|
||||
// a channel to signal the handleEvents that initialization is complete
|
||||
initialized := make(chan struct{})
|
||||
shutdownDelay := make(chan bool)
|
||||
|
||||
// initialize the network interface
|
||||
err := initialize(cLogLevel)
|
||||
@@ -101,6 +106,32 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
//listen for services that show up
|
||||
go acceptServices()
|
||||
|
||||
// listen for windows power events and call mfa auth func
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case wEvents := <-winEvents:
|
||||
if wEvents.WinPowerEvent == PBT_APMRESUMESUSPEND || wEvents.WinPowerEvent == PBT_APMRESUMEAUTOMATIC {
|
||||
log.Debugf("Received Windows Power Event in tunnel %d", wEvents.WinPowerEvent)
|
||||
for _, id := range rts.ids {
|
||||
cziti.EndpointStateChanged(id.CId, true, false)
|
||||
}
|
||||
}
|
||||
if wEvents.WinSessionEvent == WTS_SESSION_UNLOCK {
|
||||
log.Debugf("Received Windows Session Event (device unlocked) in tunnel %d", wEvents.WinSessionEvent)
|
||||
for _, id := range rts.ids {
|
||||
if id.CId != nil && id.CId.Loaded {
|
||||
cziti.EndpointStateChanged(id.CId, false, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-shutdownDelay:
|
||||
log.Tracef("Exiting windows power events loop")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// open the pipe for business
|
||||
pipes, err := openPipes()
|
||||
if err != nil {
|
||||
@@ -136,10 +167,9 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
})
|
||||
|
||||
// wait 1 second for the shutdown to send to clients
|
||||
shutdownDelay := make(chan bool)
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
shutdownDelay <- true
|
||||
close(shutdownDelay)
|
||||
}()
|
||||
<-shutdownDelay
|
||||
|
||||
@@ -173,8 +203,7 @@ func SubMain(ops chan string, changes chan<- svc.Status) error {
|
||||
|
||||
func requestShutdown(requester string) {
|
||||
log.Infof("shutdown requested by %v", requester)
|
||||
shutdown <- true // stops the metrics ticker
|
||||
shutdown <- true // stops the service change listener
|
||||
close(shutdown) // stops the metrics ticker, service change listener and notification alert loop
|
||||
}
|
||||
|
||||
func waitForStopRequest(ops <-chan string) {
|
||||
@@ -551,6 +580,9 @@ func serveIpc(conn net.Conn) {
|
||||
fingerprint := cmd.Payload["Fingerprint"].(string)
|
||||
code := cmd.Payload["Code"].(string)
|
||||
removeMFA(enc, fingerprint, code)
|
||||
case "UpdateFrequency":
|
||||
notificationFreq := cmd.Payload["NotificationFrequency"].(float64)
|
||||
updateNotificationFrequency(enc, int(notificationFreq))
|
||||
case "Debug":
|
||||
dbg()
|
||||
respond(enc, dto.Response{
|
||||
@@ -931,16 +963,31 @@ func connectIdentity(id *Id) {
|
||||
|
||||
if id.CId == nil || !id.CId.Loaded {
|
||||
rts.LoadIdentity(id, DEFAULT_REFRESH_INTERVAL)
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
Id: id.Identity,
|
||||
})
|
||||
} else {
|
||||
log.Debugf("%s[%s] is already loaded", id.Name, id.FingerPrint)
|
||||
|
||||
id.CId.Services.Range(func(key interface{}, value interface{}) bool {
|
||||
id.Services = append(id.Services, nil)
|
||||
|
||||
val := value.(*cziti.ZService)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
rwg := &cziti.TunnelerActionWaitGroup{
|
||||
Wg: &wg,
|
||||
Czsvc: val,
|
||||
}
|
||||
cziti.AddIntercept(rwg)
|
||||
wg.Wait()
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_ADDED,
|
||||
ActionEvent: dto.IDENTITY_CONNECTED,
|
||||
Id: id.Identity,
|
||||
})
|
||||
log.Infof("connecting identity completed: %s[%s] %t/%t", id.Name, id.FingerPrint, id.MfaEnabled, id.MfaNeeded)
|
||||
@@ -960,7 +1007,7 @@ func disconnectIdentity(id *Id) error {
|
||||
val := value.(*cziti.ZService)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
rwg := &cziti.RemoveWG{
|
||||
rwg := &cziti.TunnelerActionWaitGroup{
|
||||
Wg: &wg,
|
||||
Czsvc: val,
|
||||
}
|
||||
@@ -968,6 +1015,10 @@ func disconnectIdentity(id *Id) error {
|
||||
wg.Wait()
|
||||
return true
|
||||
})
|
||||
rts.BroadcastEvent(dto.IdentityEvent{
|
||||
ActionEvent: dto.IDENTITY_DISCONNECTED,
|
||||
Id: id.Identity,
|
||||
})
|
||||
log.Infof("disconnecting identity complete: %s", id.Name)
|
||||
}
|
||||
} else {
|
||||
@@ -1085,10 +1136,38 @@ func handleBulkServiceChange(sc cziti.BulkServiceChange) {
|
||||
rts.BroadcastEvent(m)
|
||||
}
|
||||
|
||||
func addUnit(count int, unit string) (result string) {
|
||||
if (count == 1) || (count == 0) {
|
||||
result = strconv.Itoa(count) + " " + unit + " "
|
||||
} else {
|
||||
result = strconv.Itoa(count) + " " + unit + "s "
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func secondsToReadableFmt(input int32) (result string) {
|
||||
seconds := input % (60 * 60 * 24)
|
||||
hours := math.Floor(float64(seconds) / 60 / 60)
|
||||
seconds = input % (60 * 60)
|
||||
minutes := math.Floor(float64(seconds) / 60)
|
||||
seconds = input % 60
|
||||
|
||||
if hours > 0 {
|
||||
result = addUnit(int(hours), "hour") + addUnit(int(minutes), "minute") + addUnit(int(seconds), "second")
|
||||
} else if minutes > 0 {
|
||||
result = addUnit(int(minutes), "minute") + addUnit(int(seconds), "second")
|
||||
} else {
|
||||
result = addUnit(int(seconds), "second")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func handleEvents(isInitialized chan struct{}) {
|
||||
events.run()
|
||||
d := 5 * time.Second
|
||||
every5s := time.NewTicker(d)
|
||||
notificationFrequency = time.NewTicker(time.Duration(rts.state.NotificationFrequency) * time.Minute)
|
||||
|
||||
defer log.Debugf("exiting handleEvents. loops were set for %v", d)
|
||||
<-isInitialized
|
||||
@@ -1100,14 +1179,68 @@ func handleEvents(isInitialized chan struct{}) {
|
||||
case <-every5s.C:
|
||||
s := rts.ToMetrics()
|
||||
|
||||
// broadcast metrics
|
||||
rts.BroadcastEvent(dto.MetricsEvent{
|
||||
StatusEvent: dto.StatusEvent{Op: "metrics"},
|
||||
Identities: s.Identities,
|
||||
})
|
||||
|
||||
// notification message
|
||||
case <-notificationFrequency.C:
|
||||
cleanNotifications := make([]cziti.NotificationMessage, 0)
|
||||
for _, id := range rts.ids {
|
||||
if id.CId == nil || !id.CId.MfaRefreshNeeded() {
|
||||
continue
|
||||
}
|
||||
notificationMessage := ""
|
||||
|
||||
var notificationMinTimeout int32 = 0
|
||||
var notificationMaxTimeout int32 = -1
|
||||
switch mfaState := id.CId.GetMFAState(int32((constants.MaximumFrequency+rts.state.NotificationFrequency)*60)); mfaState {
|
||||
case constants.MfaAllSvcTimeout:
|
||||
notificationMessage = fmt.Sprintf("All of the services of identity %s are timed out", id.Name)
|
||||
case constants.MfaFewSvcTimeout:
|
||||
notificationMessage = fmt.Sprintf("Some of the services of identity %s are timed out", id.Name)
|
||||
case constants.MfaNearingTimeout:
|
||||
notificationMinTimeout = id.CId.GetRemainingTime(id.CId.MfaMinTimeout)
|
||||
notificationMessage = fmt.Sprintf("Some of the services of identity %s are timing out in %s", id.Name, secondsToReadableFmt(notificationMinTimeout))
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
if len(notificationMessage) > 0 {
|
||||
|
||||
if id.CId.MfaMaxTimeout > -1 {
|
||||
notificationMaxTimeout = id.CId.GetRemainingTime(id.CId.MfaMaxTimeout)
|
||||
}
|
||||
notificationMinTimeout = id.CId.GetRemainingTime(id.CId.MfaMinTimeout)
|
||||
|
||||
cleanNotifications = append(cleanNotifications, cziti.NotificationMessage{
|
||||
Fingerprint: id.FingerPrint,
|
||||
IdentityName: id.Name,
|
||||
Severity: "major",
|
||||
MfaMinimumTimeout: notificationMinTimeout,
|
||||
MfaMaximumTimeout: notificationMaxTimeout,
|
||||
Message: notificationMessage,
|
||||
MfaTimeDuration: int(time.Since(id.CId.MfaLastUpdatedTime).Seconds()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if len(cleanNotifications) > 0 {
|
||||
log.Debugf("Sending notification message to UI %v", cleanNotifications)
|
||||
rts.BroadcastEvent(cziti.TunnelNotificationEvent{
|
||||
Op: "notification",
|
||||
Notification: cleanNotifications,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ResetFrequency(newFrequency int) {
|
||||
notificationFrequency.Reset(time.Duration(newFrequency) * time.Minute)
|
||||
}
|
||||
|
||||
//Removes the Config from the provided identity and returns a 'cleaned' id
|
||||
func Clean(src *Id) dto.Identity {
|
||||
mfaNeeded := false
|
||||
@@ -1118,7 +1251,7 @@ func Clean(src *Id) dto.Identity {
|
||||
mfaEnabled = src.CId.MfaEnabled
|
||||
}
|
||||
|
||||
log.Tracef("cleaning identity: %s %t %t", src.Name, mfaNeeded, mfaEnabled)
|
||||
log.Tracef("cleaning identity: %s: mfaNeeded: %t mfaEnabled:%t", src.Name, mfaNeeded, mfaEnabled)
|
||||
AddMetrics(src)
|
||||
nid := dto.Identity{
|
||||
Name: src.Name,
|
||||
@@ -1138,9 +1271,35 @@ func Clean(src *Id) dto.Identity {
|
||||
src.CId.Services.Range(func(key interface{}, value interface{}) bool {
|
||||
//string, ZService
|
||||
val := value.(*cziti.ZService)
|
||||
|
||||
if src.CId.MfaRefreshNeeded() && val.Service.Timeout > 0 {
|
||||
var svcTimeout int32 = -1
|
||||
for _, pc := range val.Service.PostureChecks {
|
||||
if svcTimeout == -1 || svcTimeout > int32(pc.Timeout) {
|
||||
svcTimeout = int32(pc.Timeout)
|
||||
}
|
||||
break
|
||||
}
|
||||
if (svcTimeout - int32(time.Since(src.CId.MfaLastUpdatedTime).Seconds())) < 0 {
|
||||
atomic.StoreInt32(&val.Service.Timeout, 0)
|
||||
} else {
|
||||
atomic.StoreInt32(&val.Service.Timeout, svcTimeout-int32(time.Since(src.CId.MfaLastUpdatedTime).Seconds()))
|
||||
}
|
||||
}
|
||||
|
||||
nid.Services = append(nid.Services /*svcToDto(val)*/, val.Service)
|
||||
return true
|
||||
})
|
||||
nid.MfaMinTimeout = src.CId.MfaMinTimeout
|
||||
nid.MfaMaxTimeout = src.CId.MfaMaxTimeout
|
||||
if !src.CId.MfaRefreshNeeded() {
|
||||
nid.MfaLastUpdatedTime = time.Now()
|
||||
} else {
|
||||
nid.MfaLastUpdatedTime = src.CId.MfaLastUpdatedTime
|
||||
if (nid.MfaMaxTimeout-int32(time.Since(nid.MfaLastUpdatedTime).Seconds())) < 0 && nid.MfaEnabled {
|
||||
nid.MfaNeeded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nid.Config.ZtAPI = src.Config.ZtAPI
|
||||
@@ -1163,6 +1322,8 @@ func authMfa(out *json.Encoder, fingerprint string, code string) {
|
||||
id := rts.Find(fingerprint)
|
||||
result := cziti.AuthMFA(id.CId, code)
|
||||
if result == nil {
|
||||
id.CId.MfaNeeded = false
|
||||
id.CId.MfaLastUpdatedTime = time.Now()
|
||||
respond(out, dto.Response{Message: "AuthMFA complete", Code: SUCCESS, Error: "", Payload: fingerprint})
|
||||
} else {
|
||||
respondWithError(out, fmt.Sprintf("AuthMFA failed. the supplied code [%s] was not valid: %s", code, result), 1, result)
|
||||
@@ -1199,3 +1360,18 @@ func sendIdentityAndNotifyUI(enc *json.Encoder, fingerprint string) {
|
||||
resp := dto.Response{Message: "", Code: ERROR, Error: "Could not find id matching fingerprint " + fingerprint, Payload: ""}
|
||||
respond(enc, resp)
|
||||
}
|
||||
|
||||
func updateNotificationFrequency(out *json.Encoder, notificationFreq int) {
|
||||
|
||||
if notificationFreq != rts.state.NotificationFrequency {
|
||||
err := rts.UpdateNotificationFrequency(notificationFreq)
|
||||
if err != nil {
|
||||
respondWithError(out, "Could not set notification frequency", UNKNOWN_ERROR, err)
|
||||
return
|
||||
}
|
||||
|
||||
ResetFrequency(notificationFreq)
|
||||
}
|
||||
respond(out, dto.Response{Message: "Notification frequency is set", Code: SUCCESS, Error: "", Payload: ""})
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ const (
|
||||
|
||||
DEFAULT_REFRESH_INTERVAL = 10
|
||||
|
||||
cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue | svc.AcceptPowerEvent
|
||||
cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue | svc.AcceptPowerEvent | svc.AcceptSessionChange
|
||||
|
||||
InformationEvent = 0 //1
|
||||
ContinueEvent = 0 //2
|
||||
@@ -81,6 +81,10 @@ const (
|
||||
PBT_APMPOWERSTATUSCHANGE = 10 // Power Status Change
|
||||
PBT_APMRESUMEAUTOMATIC = 18 // Resume Automatic
|
||||
|
||||
// windows session changes microsoft docs https://docs.microsoft.com/en-us/windows/win32/termserv/wm-wtssession-change
|
||||
WTS_SESSION_LOCK = 7
|
||||
WTS_SESSION_UNLOCK = 8
|
||||
|
||||
// This is the name you will use for the NET START command
|
||||
SvcStartName = "ziti"
|
||||
|
||||
|
||||
@@ -41,8 +41,9 @@ func (m *zitiService) Execute(args []string, r <-chan svc.ChangeRequest, changes
|
||||
}
|
||||
control := make(chan string)
|
||||
mainLoop := make(chan struct{})
|
||||
winEvents := make(chan WindowsEvents)
|
||||
go func() {
|
||||
err := SubMain(control, changes)
|
||||
err := SubMain(control, changes, winEvents)
|
||||
if err != nil {
|
||||
log.Errorf("the main loop exited with an unexpected error: %v", err)
|
||||
}
|
||||
@@ -82,6 +83,7 @@ loop:
|
||||
if c.EventType == PBT_APMRESUMESUSPEND || c.EventType == PBT_APMPOWERSTATUSCHANGE || c.EventType == PBT_APMRESUMEAUTOMATIC {
|
||||
// more than one event may be generated
|
||||
powerEvent = fmt.Sprintf("Power event received - resumed, Event Type - %d", c.EventType)
|
||||
winEvents <- WindowsEvents{WinPowerEvent: c.EventType, WinSessionEvent: 0}
|
||||
} else if c.EventType == PBT_APMSUSPEND {
|
||||
powerEvent = fmt.Sprintf("Power event received - suspend, Event Type - %d", c.EventType)
|
||||
} else {
|
||||
@@ -89,6 +91,18 @@ loop:
|
||||
}
|
||||
_ = logging.Elog.Info(InformationEvent, powerEvent)
|
||||
log.Infof(powerEvent)
|
||||
case svc.SessionChange:
|
||||
var sessionChangedEvent string
|
||||
if c.EventType == WTS_SESSION_UNLOCK {
|
||||
sessionChangedEvent = fmt.Sprintf("Windows session changed event received - unlocked device, Event Type %d", c.EventType)
|
||||
winEvents <- WindowsEvents{WinPowerEvent: 0, WinSessionEvent: c.EventType}
|
||||
} else if c.EventType == WTS_SESSION_LOCK {
|
||||
sessionChangedEvent = fmt.Sprintf("Windows session changed event received - locked device, Event Type %d", c.EventType)
|
||||
} else {
|
||||
sessionChangedEvent = fmt.Sprintf("Windows session changed unknown event received - Event Type %d", c.EventType)
|
||||
}
|
||||
_ = logging.Elog.Info(InformationEvent, sessionChangedEvent)
|
||||
log.Infof(sessionChangedEvent)
|
||||
default:
|
||||
_ = logging.Elog.Error(1, fmt.Sprintf("unexpected control request #%d", c))
|
||||
}
|
||||
|
||||
@@ -117,15 +117,16 @@ func (t *RuntimeState) ToStatus(onlyInitialized bool) dto.TunnelStatus {
|
||||
uptime = tunStart.Milliseconds()
|
||||
|
||||
clean := dto.TunnelStatus{
|
||||
Active: t.state.Active,
|
||||
Duration: uptime,
|
||||
Identities: make([]*dto.Identity, 0),
|
||||
IpInfo: t.state.IpInfo,
|
||||
LogLevel: t.state.LogLevel,
|
||||
ServiceVersion: Version,
|
||||
TunIpv4: t.state.TunIpv4,
|
||||
TunIpv4Mask: t.state.TunIpv4Mask,
|
||||
AddDns: t.state.AddDns,
|
||||
Active: t.state.Active,
|
||||
Duration: uptime,
|
||||
Identities: make([]*dto.Identity, 0),
|
||||
IpInfo: t.state.IpInfo,
|
||||
LogLevel: t.state.LogLevel,
|
||||
ServiceVersion: Version,
|
||||
TunIpv4: t.state.TunIpv4,
|
||||
TunIpv4Mask: t.state.TunIpv4Mask,
|
||||
AddDns: t.state.AddDns,
|
||||
NotificationFrequency: t.state.NotificationFrequency,
|
||||
}
|
||||
|
||||
i := 0
|
||||
@@ -154,12 +155,15 @@ func (t *RuntimeState) ToMetrics() dto.TunnelStatus {
|
||||
for _, id := range t.ids {
|
||||
AddMetrics(id)
|
||||
clean.Identities[i] = &dto.Identity{
|
||||
Name: id.Name,
|
||||
FingerPrint: id.FingerPrint,
|
||||
Metrics: id.Metrics,
|
||||
Active: id.Active,
|
||||
MfaEnabled: id.MfaEnabled,
|
||||
MfaNeeded: id.MfaNeeded,
|
||||
Name: id.Name,
|
||||
FingerPrint: id.FingerPrint,
|
||||
Metrics: id.Metrics,
|
||||
Active: id.Active,
|
||||
MfaEnabled: id.MfaEnabled,
|
||||
MfaNeeded: id.MfaNeeded,
|
||||
MfaMinTimeout: id.MfaMinTimeout,
|
||||
MfaMaxTimeout: id.MfaMaxTimeout,
|
||||
MfaLastUpdatedTime: id.MfaLastUpdatedTime,
|
||||
}
|
||||
i++
|
||||
}
|
||||
@@ -321,6 +325,10 @@ func (t *RuntimeState) LoadConfig() {
|
||||
log.Warnf("provided mask: [%d] is smaller than the minimum permitted: [%d] and will be changed", rts.state.TunIpv4Mask, constants.Ipv4MinMask)
|
||||
rts.UpdateIpv4Mask(constants.Ipv4MinMask)
|
||||
}
|
||||
|
||||
if t.state.NotificationFrequency < constants.MinimumFrequency {
|
||||
rts.UpdateNotificationFrequency(constants.MinimumFrequency)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *RuntimeState) scanForOrphanedIdentities(folder string) {
|
||||
@@ -544,3 +552,18 @@ func (t *RuntimeState) UpdateMfa(fingerprint string, mfaEnabled bool, mfaNeeded
|
||||
id.MfaNeeded = mfaNeeded
|
||||
}
|
||||
}
|
||||
|
||||
func (t *RuntimeState) UpdateNotificationFrequency(notificationFreq int) error {
|
||||
|
||||
log.Infof("setting notification frequency : %d", notificationFreq)
|
||||
|
||||
if notificationFreq < constants.MinimumFrequency || notificationFreq > constants.MaximumFrequency {
|
||||
return errors.New(fmt.Sprintf("Notification frequency should be between %d and %d minutes", constants.MinimumFrequency, constants.MaximumFrequency))
|
||||
}
|
||||
|
||||
rts.state.NotificationFrequency = notificationFreq
|
||||
|
||||
rts.SaveState()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,3 +9,8 @@ type Id struct {
|
||||
dto.Identity
|
||||
CId *cziti.ZIdentity
|
||||
}
|
||||
|
||||
type WindowsEvents struct {
|
||||
WinPowerEvent uint32
|
||||
WinSessionEvent uint32
|
||||
}
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
package main
|
||||
|
||||
const (
|
||||
Version = "1.9.9"
|
||||
Revision = "b6a4ad327bd0"
|
||||
Branch = "main"
|
||||
Version = "1.10.0"
|
||||
Revision = "efac1fb0a5f2"
|
||||
Branch = "release-next"
|
||||
BuildUser = ""
|
||||
BuildDate = "2021-06-24 10:44:17"
|
||||
BuildDate = "2021-07-22 15:53:14"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user