From 79defa233a9d10f7943745110b0d17274c426906 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?=
=?UTF-8?q?=D0=A2=D0=B0=D1=83=D0=B5=D0=BD=D0=B8=D1=81?=
Date: Mon, 15 Jul 2024 23:21:13 +0300
Subject: [PATCH 01/13] add `--rebuild-ca` command line argument support
---
Program.cs | 33 +++++++++++++++++++++++++++------
WebOne.csproj | 4 ++--
2 files changed, 29 insertions(+), 8 deletions(-)
diff --git a/Program.cs b/Program.cs
index f1a3a2b..3ef21c2 100644
--- a/Program.cs
+++ b/Program.cs
@@ -33,6 +33,7 @@ public static class Program
public static string Protocols = "HTTP 1.1";
public static bool DaemonMode = false;
static bool ShutdownInitiated = false;
+ static bool RebuildCA = false;
const string CmdLineArgUnnamed = "--wo-short";
static List> CmdLineOptions = new List>();
@@ -62,7 +63,7 @@ static void Main(string[] args)
Assembly.GetExecutingAssembly().GetName().Version.Major + "." +
Assembly.GetExecutingAssembly().GetName().Version.Minor + "." +
Assembly.GetExecutingAssembly().GetName().Version.Build
- //+ "-pre"
+ + "-pre"
);
Variables.Add("WOSystem", RuntimeInformation.OSDescription);
@@ -147,12 +148,19 @@ static void Main(string[] args)
if (HaveCrtKey) HaveCrtKey = (new FileInfo(ConfigFile.SslCertificate).Length > MinPemLentgh) && (new FileInfo(ConfigFile.SslPrivateKey).Length > MinPemLentgh);
if (HaveCrtKey)
{ Log.WriteLine(false, false, "Using as SSL Certificate Authority: {0}, {1}.", ConfigFile.SslCertificate, ConfigFile.SslPrivateKey); }
- else
+ else if(!RebuildCA)
{
- Log.WriteLine(true, false, "Creating root SSL Certificate & Private Key for CA...");
- CertificateUtil.MakeSelfSignedCert(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey, ConfigFile.SslRootSubject, ConfigFile.SslHashAlgorithm);
- Log.WriteLine(true, false, "CA Certificate: {0}; Key: {1}.", ConfigFile.SslCertificate, ConfigFile.SslPrivateKey);
+ CreateRootCertificate();
}
+ if (RebuildCA)
+ {
+ Console.WriteLine();
+ Log.WriteLine(true, false, "CA Certificate will be new, so import it to browser(s) after build succeeds.");
+ CreateRootCertificate();
+ Log.WriteLine(true, false, "WebOne will now exit.");
+ Environment.Exit(0);
+ }
+
RootCertificate = new X509Certificate2(X509Certificate2.CreateFromPemFile(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey).Export(X509ContentType.Pkcs12));
Protocols += ", HTTPS 1.1";
if (!DefaultPACoverriden) DefaultPAC += DefaultPAChttps;
@@ -196,7 +204,7 @@ static void Main(string[] args)
if (!DefaultPACoverriden) DefaultPAC += DefaultPACfooter;
if (!DefaultPACoverriden) ConfigFile.PAC = DefaultPAC;
- Log.WriteLine(false, false, "Configured to http://{1}:{2}/, {3}", ConfigFileName, ConfigFile.DefaultHostName, ConfigFile.Port, Protocols);
+ Log.WriteLine(false, false, "Configured to http://{1}:{2}/, {3}", ConfigFileName, ConfigFile.DefaultHostName, ConfigFile.Port, Protocols);
//initialize server
try
@@ -280,6 +288,16 @@ static void Main(string[] args)
Shutdown();
}
+ ///
+ /// Create certificate and private key files for WebOne Certificate Authority
+ ///
+ private static void CreateRootCertificate()
+ {
+ Log.WriteLine(true, false, "Creating root SSL Certificate & Private Key for CA...");
+ CertificateUtil.MakeSelfSignedCert(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey, ConfigFile.SslRootSubject, ConfigFile.SslHashAlgorithm);
+ Log.WriteLine(true, false, "CA Certificate: {0}; Key: {1}.", ConfigFile.SslCertificate, ConfigFile.SslPrivateKey);
+ }
+
///
/// Shut down server and terminate process
///
@@ -382,6 +400,9 @@ private static void ProcessCommandLine(string[] args)
case "--dump-requests":
//all will be processed in ProcessCommandLineOptions()
break;
+ case "--rebuild-ca":
+ RebuildCA = true;
+ break;
case "--daemon":
DaemonMode = true;
break;
diff --git a/WebOne.csproj b/WebOne.csproj
index d05238e..c71e57c 100644
--- a/WebOne.csproj
+++ b/WebOne.csproj
@@ -5,8 +5,8 @@
Exe
net6.0
Alexander Tauenis
- 0.17.1
-
+ 0.17.2
+ -pre
$(Version)$(VersionSuffix)
World
WebOne HTTP Proxy Server
From dcc1637213761f37bb2382510545222065ec4db0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?=
=?UTF-8?q?=D0=A2=D0=B0=D1=83=D0=B5=D0=BD=D0=B8=D1=81?=
Date: Tue, 16 Jul 2024 11:52:27 +0300
Subject: [PATCH 02/13] improve log messages about CA certificate
---
Program.cs | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
diff --git a/Program.cs b/Program.cs
index 3ef21c2..da668aa 100644
--- a/Program.cs
+++ b/Program.cs
@@ -148,7 +148,7 @@ static void Main(string[] args)
if (HaveCrtKey) HaveCrtKey = (new FileInfo(ConfigFile.SslCertificate).Length > MinPemLentgh) && (new FileInfo(ConfigFile.SslPrivateKey).Length > MinPemLentgh);
if (HaveCrtKey)
{ Log.WriteLine(false, false, "Using as SSL Certificate Authority: {0}, {1}.", ConfigFile.SslCertificate, ConfigFile.SslPrivateKey); }
- else if(!RebuildCA)
+ else if (!RebuildCA)
{
CreateRootCertificate();
}
@@ -157,34 +157,45 @@ static void Main(string[] args)
Console.WriteLine();
Log.WriteLine(true, false, "CA Certificate will be new, so import it to browser(s) after build succeeds.");
CreateRootCertificate();
+ RootCertificate = new X509Certificate2(X509Certificate2.CreateFromPemFile(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey).Export(X509ContentType.Pkcs12));
+ Log.WriteLine(true, false, "The new certificate is called \"" + RootCertificate.GetNameInfo(X509NameType.SimpleName, false) + "\".");
Log.WriteLine(true, false, "WebOne will now exit.");
Environment.Exit(0);
}
+ try
+ {
+ RootCertificate = new X509Certificate2(X509Certificate2.CreateFromPemFile(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey).Export(X509ContentType.Pkcs12));
+ Protocols += ", HTTPS 1.1";
+ if (!DefaultPACoverriden) DefaultPAC += DefaultPAChttps;
- RootCertificate = new X509Certificate2(X509Certificate2.CreateFromPemFile(ConfigFile.SslCertificate, ConfigFile.SslPrivateKey).Export(X509ContentType.Pkcs12));
- Protocols += ", HTTPS 1.1";
- if (!DefaultPACoverriden) DefaultPAC += DefaultPAChttps;
+ //check validness period
+ if (RootCertificate.NotAfter < DateTime.Now || RootCertificate.NotBefore > DateTime.Now)
+ {
+ Log.WriteLine(true, false, "Warning! CA Certificate is out of date: {0}-{1}, now {2}.", RootCertificate.NotBefore, RootCertificate.NotAfter, DateTime.Now);
+ }
- //check validness period
- if (RootCertificate.NotAfter < DateTime.Now || RootCertificate.NotBefore > DateTime.Now)
- {
- Log.WriteLine(true, false, "Warning! CA Certificate is out of date: {0}-{1}, now {2}.", RootCertificate.NotBefore, RootCertificate.NotAfter, DateTime.Now);
+ if (RootCertificate.NotAfter < DateTimeOffset.Now.AddDays(ConfigFile.SslCertVaildAfterNow) ||
+ RootCertificate.NotBefore > DateTimeOffset.Now.AddDays(ConfigFile.SslCertVaildBeforeNow))
+ {
+ Log.WriteLine(true, false, "Warning! CA Certificate is too fresh or expires too soon. Check configuration.");
+ }
}
-
- if (RootCertificate.NotAfter < DateTimeOffset.Now.AddDays(ConfigFile.SslCertVaildAfterNow) ||
- RootCertificate.NotBefore > DateTimeOffset.Now.AddDays(ConfigFile.SslCertVaildBeforeNow))
+ catch (Exception CertLoadEx)
{
- Log.WriteLine(true, false, "Warning! CA Certificate is too fresh or expires too soon. Check configuration.");
-
+ if (CertLoadEx.InnerException != null)
+ {
+ Log.WriteLine(true, false, "Unable to load CA Certificate: {0}.", CertLoadEx.InnerException.Message);
+ }
+ else
+ {
+ Log.WriteLine(true, false, "Unable to load CA Certificate: {0}.", CertLoadEx.Message);
+ }
+ ConfigFile.SslEnable = false;
}
}
catch (Exception CertCreateEx)
{
Log.WriteLine(true, false, "Unable to create CA Certificate: {0}.", CertCreateEx.Message);
- /*
- Log.WriteLine(true, false, CertCreateEx.StackTrace.Replace("\n", " ; ")); //only for debug purposes at this moment
- Log.WriteLine(true, false, "End of CA build error information. HTTPS won't be available!");
- */
ConfigFile.SslEnable = false;
}
From 4466b9c353de60d4eb703bd78404801e56b585a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?=
=?UTF-8?q?=D0=A2=D0=B0=D1=83=D0=B5=D0=BD=D0=B8=D1=81?=
Date: Tue, 16 Jul 2024 13:33:21 +0300
Subject: [PATCH 03/13] improve ROVP look
---
HttpTransit.cs | 5 +++
WebVideoPlayer.cs | 112 +++-------------------------------------------
html/norovp.htm | 17 +++++++
html/rovp.gif | Bin 0 -> 15060 bytes
html/rovp.htm | 10 +++++
5 files changed, 39 insertions(+), 105 deletions(-)
create mode 100644 html/norovp.htm
create mode 100644 html/rovp.gif
diff --git a/HttpTransit.cs b/HttpTransit.cs
index 4d074ca..50b9f06 100644
--- a/HttpTransit.cs
+++ b/HttpTransit.cs
@@ -1186,6 +1186,11 @@ private void SendInternalPage(string InternalPageId, string Arguments)
}
return;
default:
+ if (InternalPageId.ToLowerInvariant() == "/rovp.htm" && !Program.ToBoolean(ConfigFile.WebVideoOptions["Enable"] ?? "yes"))
+ {
+ SendRedirect("/norovp.htm", "ROVP is disabled on this server.");
+ return;
+ }
if (CheckInternalContentModification(InternalPageId, ClientRequest.Headers["If-Modified-Since"]))
{
// send 304 Not Modified code
diff --git a/WebVideoPlayer.cs b/WebVideoPlayer.cs
index 4efc576..9699739 100644
--- a/WebVideoPlayer.cs
+++ b/WebVideoPlayer.cs
@@ -31,7 +31,8 @@ public WebVideoPlayer(NameValueCollection Parameters)
if (!Program.ToBoolean(ConfigFile.WebVideoOptions["Enable"] ?? "yes"))
{
- Page.Content = "Sorry, proxy server administrator has disabled the online video download feature.";
+ Page.Content = "It's disabled.";
+ Page.HttpHeaders.Add("Refresh", "0;url=/norovp.htm");
return;
}
@@ -39,110 +40,11 @@ public WebVideoPlayer(NameValueCollection Parameters)
{
case "":
case null:
- string Frameset =
- "" +
- "" +
- ""; ;
- Page.Content = Frameset;
+ Page.Content = "";
+ Page.Content += "";
+ Page.Content += "
Retro Online Video Player
";
+ Page.Content += "
";
+ Page.HttpHeaders.Add("Refresh", "5;url=/rovp.htm");
break;
case "intro":
Page.Content = "Use the toolbar above to watch a video.
";
diff --git a/html/norovp.htm b/html/norovp.htm
new file mode 100644
index 0000000..447ed35
--- /dev/null
+++ b/html/norovp.htm
@@ -0,0 +1,17 @@
+
+
+
+
+
+Retro online video player
+
+
+
+
+
+Sorry, proxy server administrator has disabled the online video download feature.
+
+
diff --git a/html/rovp.gif b/html/rovp.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f9700d4cb483158ffc97441e8a5a736978ce4123
GIT binary patch
literal 15060
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
N=+`lw{saJc{uhnCC;$Ke
literal 0
HcmV?d00001
diff --git a/html/rovp.htm b/html/rovp.htm
index 5afb3bc..213732f 100644
--- a/html/rovp.htm
+++ b/html/rovp.htm
@@ -38,6 +38,7 @@
+
Codecs |
|