Skip to content
This repository was archived by the owner on Feb 27, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions AddNewTunnelWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Add New Tunnel" Height="190" Width="300" Icon="icons8-tunnel-256.png">
Title="Add New Tunnel" Height="210" Width="300" Icon="icons8-tunnel-256.png">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand All @@ -15,6 +15,7 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" Name="wdSubdomain" />
<RowDefinition Height="Auto" Name="wdCustomdomain" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>

Expand All @@ -32,7 +33,10 @@
<Label Grid.Row="3" Name="llsubdomain" >Subdomain:</Label>
<TextBox Name="tbSubdomain" Grid.Column="1" Grid.Row="3" />

<Button Name="btnAddNewTunnel" Content="Add new tunnel" Grid.Column="1" Grid.Row="4"
<Label Grid.Row="4" Name="llCustomDomain" >Custom Domain:</Label>
<TextBox Name="tbCustomDomain" Grid.Column="1" Grid.Row="4" />

<Button Name="btnAddNewTunnel" Content="Add new tunnel" Grid.Column="1" Grid.Row="5"
Click="BtnAddNewTunnel_OnClick" />
</Grid>
</Window>
6 changes: 6 additions & 0 deletions AddNewTunnelWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,14 @@ public AddNewTunnelWindow(List<TunnelDescription> currentTunnelDescriptions ,boo
if (!paidAccount)
{
tbSubdomain.Visibility = Visibility.Hidden;
tbCustomDomain.Visibility = Visibility.Hidden;

llsubdomain.Visibility = Visibility.Hidden;
llCustomDomain.Visibility = Visibility.Hidden;

wdSubdomain.MaxHeight = 0;
wdCustomdomain.MaxHeight = 0;

Height = 170;
}

Expand Down
1 change: 1 addition & 0 deletions DataTemplates/TunnelDescription.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public bool Active
}

public string SubDomain { get; set; }
public string CustomDomain { get; set; }

public event PropertyChangedEventHandler PropertyChanged;

Expand Down
29 changes: 15 additions & 14 deletions FirstTimeWizard.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using NgrokSharp;
Expand Down Expand Up @@ -35,19 +36,9 @@ public FirstTimeWizard(INgrokManager ngrokManager)
cmbTunnelExit.SelectedIndex = 0;

_ngrokManager = ngrokManager;
_ngrokManager.DownloadAndUnZipDone += _ngrokManager_DownloadAndUnZipDone;
}

private void _ngrokManager_DownloadAndUnZipDone(object sender, EventArgs e)
{
btnDownload.Content = "Next";
txtbkDownloadInstruction.Text = "Download completed successfully! Please click next.";
btnDownload.IsEnabled = true;
pbprogress.IsIndeterminate = false;
pbprogress.Value = 100;
}

private void BtnDownload_OnClick(object sender, RoutedEventArgs e)
private async void BtnDownload_OnClick(object sender, RoutedEventArgs e)
{
if ((string)btnDownload.Content == "Next")
{
Expand All @@ -58,15 +49,25 @@ private void BtnDownload_OnClick(object sender, RoutedEventArgs e)
txtbkDownloadInstruction.Text = "Please wait while ngrok is downloading";
pbprogress.IsIndeterminate = true;
btnDownload.IsEnabled = false;
_ngrokManager.DownloadNgrok();
await _ngrokManager.DownloadAndUnzipNgrokAsync();
DownloadAndUnZipDone();
}

private void DownloadAndUnZipDone()
{
btnDownload.Content = "Next";
txtbkDownloadInstruction.Text = "Download completed successfully! Please click next.";
btnDownload.IsEnabled = true;
pbprogress.IsIndeterminate = false;
pbprogress.Value = 100;
}

private void BtnSelectDataCenter_OnClick(object sender, RoutedEventArgs e)
{
tabcl.SelectedIndex = 2;
}

private void BtnAuth_OnClick(object sender, RoutedEventArgs e)
private async void BtnAuth_OnClick(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(txtbxAuthToken.Text))
{
Expand All @@ -88,7 +89,7 @@ private void BtnAuth_OnClick(object sender, RoutedEventArgs e)
}
}

_ngrokManager.RegisterAuthToken(txtbxAuthToken.Text);
await _ngrokManager.RegisterAuthTokenAsync(txtbxAuthToken.Text);

DialogResult = true;

Expand Down
41 changes: 23 additions & 18 deletions MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Windows;
using Newtonsoft.Json;
using NgrokSharp;
using NgrokSharp.DTO;

namespace ngrokGUI
{
Expand Down Expand Up @@ -40,7 +42,7 @@ public MainWindow()
try
{
//Load settings
settings = JsonConvert.DeserializeObject<Settings>(File.ReadAllText($"{_downloadFolder}Settings.json"));
settings = JsonSerializer.Deserialize<Settings>(File.ReadAllText($"{_downloadFolder}Settings.json"));

if (settings.FirstTimeSetupDone == false)
{
Expand All @@ -53,7 +55,7 @@ public MainWindow()
settings.DataCenterRegion = firstTimeWizard.cmbTunnelExit.SelectedIndex;
settings.PaidAccount = (bool) firstTimeWizard.cbxPaidAccount.IsChecked;

File.WriteAllText($"{_downloadFolder}Settings.json", JsonConvert.SerializeObject(settings));
File.WriteAllText($"{_downloadFolder}Settings.json", JsonSerializer.Serialize(settings));
}
}

Expand All @@ -63,7 +65,7 @@ public MainWindow()

if (File.Exists($"{_downloadFolder}SavedTunnels.json"))
{
JsonConvert.DeserializeObject<List<TunnelDescription>>(File.ReadAllText(
JsonSerializer.Deserialize<List<TunnelDescription>>(File.ReadAllText(
$"{_downloadFolder}SavedTunnels.json"))?.ForEach( x => _tunnelDescriptions.Add(x));
}

Expand Down Expand Up @@ -96,7 +98,8 @@ private async void btnMenuItemAddNew_OnClick(object sender, RoutedEventArgs e)
proto = addNewTunnelWindow.cobProtocol.SelectionBoxItem.ToString(),
addr = addNewTunnelWindow.tbLocalPort.Text,
bind_tls = "false",
subdomain = addNewTunnelWindow.tbSubdomain.Text
subdomain = addNewTunnelWindow.tbSubdomain.Text,
hostname = addNewTunnelWindow.tbCustomDomain.Text
};

// bind_tls http bind an HTTPS or HTTP endpoint or both true, false, or both
Expand All @@ -106,12 +109,12 @@ private async void btnMenuItemAddNew_OnClick(object sender, RoutedEventArgs e)
startTunnelDto.bind_tls = "true";
}

var httpResponseMessage = await _ngrokManager.StartTunnel(startTunnelDto);
var httpResponseMessage = await _ngrokManager.StartTunnelAsync(startTunnelDto);

if ((int) httpResponseMessage.StatusCode == 201)
{
var tunnelDetail =
JsonConvert.DeserializeObject<TunnelDetailDTO>(
JsonSerializer.Deserialize<TunnelDetailDTO>(
await httpResponseMessage.Content.ReadAsStringAsync());

var tunnel = new TunnelDescription
Expand All @@ -121,14 +124,15 @@ private async void btnMenuItemAddNew_OnClick(object sender, RoutedEventArgs e)
Port = Convert.ToInt32(addNewTunnelWindow.tbLocalPort.Text),
Url = tunnelDetail.PublicUrl,
Active = true,
SubDomain = addNewTunnelWindow.tbSubdomain.Text
SubDomain = addNewTunnelWindow.tbSubdomain.Text,
CustomDomain = addNewTunnelWindow.tbCustomDomain.Text
};
_tunnelDescriptions.Add(tunnel);
}
else
{
var tunnelError =
JsonConvert.DeserializeObject<TunnelErrorDTO>(
JsonSerializer.Deserialize<TunnelErrorDTO>(
await httpResponseMessage.Content.ReadAsStringAsync());
MessageBox.Show(tunnelError.Details.Err);
}
Expand All @@ -149,7 +153,7 @@ private void Window_Closed(object sender, EventArgs e)
}
}

File.WriteAllText($"{_downloadFolder}SavedTunnels.json", JsonConvert.SerializeObject(_tunnelDescriptions));
File.WriteAllText($"{_downloadFolder}SavedTunnels.json", JsonSerializer.Serialize(_tunnelDescriptions));

}

Expand All @@ -167,9 +171,9 @@ private async void btnMenuItemStopTunnel_OnClick(object sender, RoutedEventArgs
{
if (lwTunnels.SelectedIndex == -1) return;

var result = await _ngrokManager.StopTunnel(_tunnelDescriptions[lwTunnels.SelectedIndex].Name);
var result = await _ngrokManager.StopTunnelAsync(_tunnelDescriptions[lwTunnels.SelectedIndex].Name);

if (result == 204)
if (result.StatusCode == HttpStatusCode.NoContent)
{
_tunnelDescriptions[lwTunnels.SelectedIndex].Active = false;

Expand All @@ -187,7 +191,7 @@ private void BtnMenuItemRunFirstTimeWizard_OnClick(object sender, RoutedEventArg
if (result == MessageBoxResult.Yes)
{
Settings settings = new Settings {FirstTimeSetupDone = false};
File.WriteAllText($"{_downloadFolder}Settings.json", JsonConvert.SerializeObject(settings));
File.WriteAllText($"{_downloadFolder}Settings.json", JsonSerializer.Serialize(settings));
Close();
}
}
Expand All @@ -205,7 +209,8 @@ private async void btnMenuItemStartTunnel_OnClick(object sender, RoutedEventArgs
proto = _tunnelDescriptions[lwTunnels.SelectedIndex].Protocol,
addr = _tunnelDescriptions[lwTunnels.SelectedIndex].Port.ToString(),
bind_tls = "false",
subdomain = _tunnelDescriptions[lwTunnels.SelectedIndex].SubDomain
subdomain = _tunnelDescriptions[lwTunnels.SelectedIndex].SubDomain,
hostname = _tunnelDescriptions[lwTunnels.SelectedIndex].CustomDomain
};

// bind_tls http bind an HTTPS or HTTP endpoint or both true, false, or both
Expand All @@ -215,12 +220,12 @@ private async void btnMenuItemStartTunnel_OnClick(object sender, RoutedEventArgs
startTunnelDto.bind_tls = "true";
}

var httpResponseMessage = await _ngrokManager.StartTunnel(startTunnelDto);
var httpResponseMessage = await _ngrokManager.StartTunnelAsync(startTunnelDto);

if ((int)httpResponseMessage.StatusCode == 201)
{
var tunnelDetail =
JsonConvert.DeserializeObject<TunnelDetailDTO>(
JsonSerializer.Deserialize<TunnelDetailDTO>(
await httpResponseMessage.Content.ReadAsStringAsync());

_tunnelDescriptions[lwTunnels.SelectedIndex].Active = true;
Expand All @@ -229,7 +234,7 @@ private async void btnMenuItemStartTunnel_OnClick(object sender, RoutedEventArgs
else
{
var tunnelError =
JsonConvert.DeserializeObject<TunnelErrorDTO>(
JsonSerializer.Deserialize<TunnelErrorDTO>(
await httpResponseMessage.Content.ReadAsStringAsync());
MessageBox.Show(tunnelError.Details.Err);
}
Expand All @@ -242,7 +247,7 @@ private async void btnMenuItemDeleteTunnel_OnClick(object sender, RoutedEventArg

if (_tunnelDescriptions[lwTunnels.SelectedIndex].Active)
{
var result = await _ngrokManager.StopTunnel(_tunnelDescriptions[lwTunnels.SelectedIndex].Name);
var result = await _ngrokManager.StopTunnelAsync(_tunnelDescriptions[lwTunnels.SelectedIndex].Name);
}

var tunnel = _tunnelDescriptions.SingleOrDefault(x => x.Name == _tunnelDescriptions[lwTunnels.SelectedIndex].Name);
Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
<li>
<a href="#about-the-project">About The Project</a>
</li>
<li>
<a href="#Features">Features</a>
</li>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
Expand All @@ -53,10 +56,24 @@
NgrokGUI is a windows GUI for ngrok. It helps download ngrok, getting it ready for first time use and managing tunnels. The idea for the project arose due to friends wanting a gui to ngrok that was more user friendly.
I later found a Dungeons & Dragons community that uses [Foundryvtt](https://foundryvtt.com/) to run their games. NgrokGUI allows an easy way for the dungeon master to host the game without spending additional money on hosting or messing with port forwarding.

<!--

#### 🔨 New version underway! 🔨
I have gotten requests for this application to be ported to Linux and Mac as well. Therefore, I am in the process of rewriting the application in avaloniaui.
Look at the v2 branch if you wanna follow the progress

-->

## Features

* Create tunnels for http https and tcp protocols.
* Downloads Ngrok automatically.
* Start and stop tunnels.
* Remembers previous created tunnels.
* Support for paid Ngrok account features
* Create tunnel with subdomain
* Create tunnels on custom branded domains

### Built With

* [NgrokSharp](https://github.com/entvex/NgrokSharp)
Expand All @@ -69,7 +86,7 @@ To get a local copy up and running follow these simple steps.
### Prerequisites

* Windows 7 or Later
* [.NET 5.0 x64](https://dotnet.microsoft.com/download/dotnet/5.0/runtime/) or later
* [.NET 6.0 x64](https://dotnet.microsoft.com/download/dotnet/6.0/runtime) or later
* [Ngrok authtoken](https://dashboard.ngrok.com/get-started/setup)
### Installation

Expand Down
6 changes: 3 additions & 3 deletions ngrokGUI.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ApplicationIcon>icons8-tunnel-256.ico</ApplicationIcon>
<AssemblyName>ngrokGUI</AssemblyName>
Expand All @@ -21,7 +21,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="NgrokSharp" Version="1.0.7" />
<PackageReference Include="NgrokSharp" Version="1.0.12" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions ngrokGUI.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31019.35
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ngrokGUI", "ngrokGUI.csproj", "{F0DA3BFF-57BE-4E5E-8C67-2C4692E144E4}"
EndProject
Expand Down