From 06581ffa2695c047abdc412ed6a7442ee9a81457 Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 6 Dec 2018 00:02:17 +0800 Subject: [PATCH] Update - Bug fix pressing faq multiple times - Add tx stats - Make C# lib (more changes to follow) --- index.html | 16 +- src/css/style.scss | 1 + src/js/App.js | 102 ++++- src/js/Util.js | 6 + src/php/api.php | 21 + src/php/stats.php | 27 +- src/php/tracking.php | 2 +- src/php/upload.php | 3 + .../{void_util => void_lib}/ChunkStream.cs | 2 +- tools/void_util/void_lib/Download.cs | 152 +++++++ .../void_util/{void_util => void_lib}/Ext.cs | 16 +- tools/void_util/void_lib/FileHeader.cs | 15 + tools/void_util/void_lib/Progress.cs | 55 +++ tools/void_util/void_lib/Upload.cs | 221 ++++++++++ .../{void_util => void_lib}/VoidApi.cs | 21 +- tools/void_util/void_lib/void_lib.csproj | 12 + tools/void_util/void_util.sln | 12 + tools/void_util/void_util/Program.cs | 387 ++---------------- tools/void_util/void_util/void_util.csproj | 4 +- tools/void_util/void_util_form/App.config | 6 + .../void_util_form/MainForm.Designer.cs | 197 +++++++++ tools/void_util/void_util_form/MainForm.cs | 63 +++ tools/void_util/void_util_form/MainForm.resx | 120 ++++++ tools/void_util/void_util_form/Program.cs | 22 + .../void_util_form/Properties/AssemblyInfo.cs | 36 ++ .../Properties/Resources.Designer.cs | 71 ++++ .../void_util_form/Properties/Resources.resx | 117 ++++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 7 + .../void_util_form/void_util_form.csproj | 89 ++++ utils/ga-page-view/ga-page-view/Program.cs | 13 +- .../PublishProfiles/FolderProfile.pubxml | 6 +- utils/ga_pageview/.gitignore | 3 - utils/ga_pageview/Cargo.toml | 7 - utils/ga_pageview/src/main.rs | 37 -- utils/logparser/.gitignore | 2 - utils/logparser/Cargo.toml | 13 - utils/logparser/block.html | 97 ----- utils/logparser/src/main.rs | 168 -------- 39 files changed, 1451 insertions(+), 728 deletions(-) rename tools/void_util/{void_util => void_lib}/ChunkStream.cs (99%) create mode 100644 tools/void_util/void_lib/Download.cs rename tools/void_util/{void_util => void_lib}/Ext.cs (74%) create mode 100644 tools/void_util/void_lib/FileHeader.cs create mode 100644 tools/void_util/void_lib/Progress.cs create mode 100644 tools/void_util/void_lib/Upload.cs rename tools/void_util/{void_util => void_lib}/VoidApi.cs (77%) create mode 100644 tools/void_util/void_lib/void_lib.csproj create mode 100644 tools/void_util/void_util_form/App.config create mode 100644 tools/void_util/void_util_form/MainForm.Designer.cs create mode 100644 tools/void_util/void_util_form/MainForm.cs create mode 100644 tools/void_util/void_util_form/MainForm.resx create mode 100644 tools/void_util/void_util_form/Program.cs create mode 100644 tools/void_util/void_util_form/Properties/AssemblyInfo.cs create mode 100644 tools/void_util/void_util_form/Properties/Resources.Designer.cs create mode 100644 tools/void_util/void_util_form/Properties/Resources.resx create mode 100644 tools/void_util/void_util_form/Properties/Settings.Designer.cs create mode 100644 tools/void_util/void_util_form/Properties/Settings.settings create mode 100644 tools/void_util/void_util_form/void_util_form.csproj delete mode 100644 utils/ga_pageview/.gitignore delete mode 100644 utils/ga_pageview/Cargo.toml delete mode 100644 utils/ga_pageview/src/main.rs delete mode 100644 utils/logparser/.gitignore delete mode 100644 utils/logparser/Cargo.toml delete mode 100644 utils/logparser/block.html delete mode 100644 utils/logparser/src/main.rs diff --git a/index.html b/index.html index a3b3b21..e562407 100644 --- a/index.html +++ b/index.html @@ -115,6 +115,8 @@
+

7 days tx graph

+
@@ -139,7 +141,7 @@ I have more questions
- Feel free to join Discord or send a mail to admin@void.cat + Feel free to join Discord and ask there.
@@ -149,7 +151,9 @@
24Hr Transfer:0 B
@@ -159,14 +163,6 @@ (adsbygoogle = window.adsbygoogle || []).push({}); - diff --git a/src/css/style.scss b/src/css/style.scss index 8fc7ecc..d2048ab 100644 --- a/src/css/style.scss +++ b/src/css/style.scss @@ -173,6 +173,7 @@ a:hover { text-decoration: underline; } #page-stats { display: none; + margin: 10px; } #page-faq { diff --git a/src/js/App.js b/src/js/App.js index e0523f3..110b356 100644 --- a/src/js/App.js +++ b/src/js/App.js @@ -2,12 +2,16 @@ * @constant {Object} */ const App = { + Loaded: false, + CharJsLoaded: false, + Elements: { get Dropzone() { return $('#dropzone') }, get Uploads() { return $('#uploads') }, get PageView() { return $('#page-view') }, get PageUpload() { return $('#page-upload') }, - get PageFaq() { return $('#page-faq') } + get PageFaq() { return $('#page-faq') }, + get PageStats() { return $('#page-stats') } }, Templates: { @@ -43,6 +47,61 @@ const App = { await Promise.all(proc_files); }, + ResetView: function () { + App.Elements.PageView.style.display = "none"; + App.Elements.PageUpload.style.display = "none"; + App.Elements.PageFaq.style.display = "none"; + App.Elements.PageStats.style.display = "none"; + }, + + ShowStats: async function () { + location.hash = "#stats"; + App.ResetView(); + + if (!App.CharJsLoaded) { + await App.InsertScript("//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js", () => { + return typeof moment !== "undefined"; + }); + await App.InsertScript("//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js", () => { + return typeof Chart !== "undefined"; + }); + } + + let api_rsp = await Api.GetTxChart(); + if (api_rsp.ok) { + let ctx = $('#weektxgraph').getContext('2d'); + new Chart(ctx, { + type: 'line', + data: api_rsp.data, + options: { + scales: { + xAxes: [{ + type: 'time', + time: { + source: 'data' + } + }], + yAxes: [{ + ticks: { + beginAtZero: true, + callback: function(label, index, labels) { + return Utils.FormatBytes(label); + } + } + }] + } + } + }); + } + App.Elements.PageStats.style.display = "block"; + }, + + ShowFAQ: function () { + location.hash = "#faq"; + App.ResetView(); + App.Elements.PageFaq.style.display = "block"; + }, + /** * Sets up the page */ @@ -50,26 +109,20 @@ const App = { App.CheckBrowserSupport(); App.MakePolyfills(); - window.site_info = await Api.GetSiteInfo(); - - App.Elements.PageView.style.display = "none"; - App.Elements.PageUpload.style.display = "none"; - App.Elements.PageFaq.style.display = "none"; + App.ResetView(); if (location.hash !== "") { if (location.hash == "#faq") { - let faq_headers = document.querySelectorAll('#page-faq .faq-header'); - for (let x = 0; x < faq_headers.length; x++) { - faq_headers[x].addEventListener('click', function () { - this.nextElementSibling.classList.toggle("show"); - }.bind(faq_headers[x])); - } - App.Elements.PageFaq.style.display = "block"; + App.ShowFAQ(); + } else if (location.hash == "#stats") { + App.ShowStats(); } else { App.Elements.PageView.style.display = "block"; new ViewManager(); } + window.site_info = await Api.GetSiteInfo(); } else { + window.site_info = await Api.GetSiteInfo(); App.Elements.PageUpload.style.display = "block"; $('#dropzone').innerHTML = `Click me!
(${Utils.FormatBytes(window.site_info.data.max_upload_size)} max)`; new DropzoneManager(App.Elements.Dropzone); @@ -81,6 +134,15 @@ const App = { elms[1].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Size, 2); elms[2].textContent = Utils.FormatBytes(window.site_info.data.basic_stats.Transfer_24h, 2); } + + let faq_headers = document.querySelectorAll('#page-faq .faq-header'); + for (let x = 0; x < faq_headers.length; x++) { + faq_headers[x].addEventListener('click', function () { + this.nextElementSibling.classList.toggle("show"); + }.bind(faq_headers[x])); + } + + App.Loaded = true; }, /** @@ -96,12 +158,24 @@ const App = { /** * Adds a script tag at the top of the header * @param {string} src - The script src url + * @param {function} fnWait - Function to use in promise to test if the script is loaded */ - InsertScript: function (src) { + InsertScript: async function (src, fnWait) { var before = document.head.getElementsByTagName('script')[0]; var newlink = document.createElement('script'); newlink.src = src; document.head.insertBefore(newlink, before); + + if (typeof fnWait === "function") { + await new Promise((resolve, reject) => { + let timer = setInterval(() => { + if (fnWait()) { + clearInterval(timer); + resolve(); + } + }, 100); + }); + } }, /** diff --git a/src/js/Util.js b/src/js/Util.js index 0cfbf22..cd3749d 100644 --- a/src/js/Util.js +++ b/src/js/Util.js @@ -81,6 +81,12 @@ const Api = { return JSON.parse((await JsonXHR('POST', '/api', req)).response); }, + GetTxChart: async function (id) { + return await Api.DoRequest({ + cmd: '7_day_tx_graph' + }); + }, + GetSiteInfo: async function (id) { return await Api.DoRequest({ cmd: 'site_info' diff --git a/src/php/api.php b/src/php/api.php index 2c0fc81..0193631 100644 --- a/src/php/api.php +++ b/src/php/api.php @@ -57,6 +57,27 @@ } break; } + case "7_day_tx_graph": { + $stats = Stats::GetTxStats(24 * 7); + $data = array(); + foreach($stats as $time => $bytes){ + $data[] = array( + "t" => date_timestamp_get(date_create_from_format("YmdH", $time)) * 1000, + "y" => $bytes + ); + } + + $rsp->data = array( + "datasets" => array( + array( + "label" => "bytes", + "data" => $data + ) + ) + ); + $rsp->ok = true; + break; + } } header('Content-Type: application/json'); diff --git a/src/php/stats.php b/src/php/stats.php index 8c50f37..0f94c42 100644 --- a/src/php/stats.php +++ b/src/php/stats.php @@ -7,18 +7,31 @@ private static $AllTransferStatsKey = REDIS_PREFIX . "stats-transfer-all:"; private static $GeneralStatsKey = REDIS_PREFIX . "stats-general"; + public static function GetTxStats($nHours) : array { + $redis = StaticRedis::ReadOp(); + $ret = array(); + + $now = time(); + for($x = 0; $x < $nHours; $x += 1) { + $stat_key = date("YmdH", $now - (60 * 60 * $x)); + $val = $redis->get(self::$AllTransferStatsKey . $stat_key); + if($val != False){ + $ret[$stat_key] = intval($val); + } else { + $ret[$stat_key] = 0; + } + } + + return $ret; + } + public static function Get() : Stats { $redis = StaticRedis::ReadOp(); //calculate 24hr transfer stats $tx_24h = 0; - $now = time(); - for($x = 0; $x < 24; $x += 1) { - $stat_key = date("YmdH", $now - (60 * 60 * $x)); - $val = $redis->get(self::$AllTransferStatsKey . $stat_key); - if($val != False){ - $tx_24h += intval($val); - } + foreach(self::GetTxStats(24) as $time => $bytes) { + $tx_24h += $bytes; } //get general stats diff --git a/src/php/tracking.php b/src/php/tracking.php index b63ba1e..4b340d8 100644 --- a/src/php/tracking.php +++ b/src/php/tracking.php @@ -56,7 +56,7 @@ )); //this should be sent to the slave node if we are connected on a slave - StaticRedis::ReadOp()->publish('ga-page-view-matomo', $msg); + StaticRedis::ReadOp()->publish(StaticRedis::$IsConnectedToSlave ? 'v3-matomo' : 'v3-matomo-master', $msg); } } ?> \ No newline at end of file diff --git a/src/php/upload.php b/src/php/upload.php index fc807aa..84989af 100644 --- a/src/php/upload.php +++ b/src/php/upload.php @@ -26,6 +26,9 @@ } public function HandleRequest() : void { + header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]); + header("Access-Control-Allow-Method: POST"); + $rsp = new UploadResponse(); $file_size = $_SERVER["CONTENT_LENGTH"]; diff --git a/tools/void_util/void_util/ChunkStream.cs b/tools/void_util/void_lib/ChunkStream.cs similarity index 99% rename from tools/void_util/void_util/ChunkStream.cs rename to tools/void_util/void_lib/ChunkStream.cs index 303c9ef..6bc5012 100644 --- a/tools/void_util/void_util/ChunkStream.cs +++ b/tools/void_util/void_lib/ChunkStream.cs @@ -4,7 +4,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -namespace void_util +namespace void_lib { public class ChunkStream : Stream, IDisposable { diff --git a/tools/void_util/void_lib/Download.cs b/tools/void_util/void_lib/Download.cs new file mode 100644 index 0000000..72953a4 --- /dev/null +++ b/tools/void_util/void_lib/Download.cs @@ -0,0 +1,152 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace void_lib +{ + public class DownloadResult + { + public string Filepath { get; set; } + public FileHeader Header { get; set; } + } + + public class Download : Progress + { + private Guid Id { get; set; } = Guid.NewGuid(); + private string UserAgent { get; set; } + + public Download(string ua = "VoidUtil/1.0") + { + UserAgent = ua; + } + + /// + /// Downloads a file and returns the temp file name and the FileHeader associated with the file + /// + /// Full url including key and iv + /// + public async Task DownloadFileAsync(string url) + { + var url_base = new Uri(url); + var hash_frag = url_base.Fragment.Substring(1).Split(':'); + var key = hash_frag[1].FromHex(); + var iv = hash_frag[2].FromHex(); + + base.OnReport(VoidProgress.Create(Id, label: $"Starting...")); + base.OnReport(VoidProgress.Create(Id, log: $"Starting download for: {hash_frag[0]}")); + + var req = (HttpWebRequest)WebRequest.Create($"{url_base.Scheme}://{url_base.Host}/{hash_frag[0]}"); + req.UserAgent = UserAgent; + + var rsp = await req.GetResponseAsync(); + var file_length = rsp.ContentLength; + using (var rsp_stream = rsp.GetResponseStream()) + { + var version = rsp_stream.ReadByte(); + var hmac_data = new byte[32]; + var ts = new byte[4]; + await rsp_stream.ReadAsync(hmac_data, 0, hmac_data.Length); + await rsp_stream.ReadAsync(ts, 0, ts.Length); + + base.OnReport(VoidProgress.Create(Id, log: $"Blob version is {version}, HMAC is {hmac_data.ToHex()}")); + + var tmp_name = Path.GetTempFileName(); + FileHeader header_obj = null; + using (var tmp_file = new FileStream(tmp_name, FileMode.Open, FileAccess.ReadWrite)) + { + using (var aes = new AesManaged()) + { + aes.Padding = PaddingMode.PKCS7; + aes.Mode = CipherMode.CBC; + + using (var ds = aes.CreateDecryptor(key, iv)) + { + var buf = new byte[ds.InputBlockSize * 1024]; + var out_buf = new byte[ds.OutputBlockSize * 1024]; + + bool first_block = true; + int read_offset = 0; + long t_len = 0; + while (true) + { + var rlen = await rsp_stream.ReadAsync(buf, read_offset, buf.Length - read_offset); + + //end do final block + if (rlen == 0) + { + var last_buf = ds.TransformFinalBlock(buf, 0, read_offset); + await tmp_file.WriteAsync(last_buf, 0, last_buf.Length); + break; + } + else + { + if ((read_offset + rlen) % ds.InputBlockSize != 0) + { + read_offset += rlen; + continue; + } + else + { + rlen += read_offset; + read_offset = 0; + } + } + + var clen = ds.TransformBlock(buf, 0, rlen, out_buf, 0); + if (first_block) + { + first_block = false; + var hlen = BitConverter.ToUInt16(out_buf, 0); + var header = Encoding.UTF8.GetString(out_buf, 2, hlen); + base.OnReport(VoidProgress.Create(Id, log: $"Header is: {header}")); + + header_obj = JsonConvert.DeserializeObject(header); + + var file_start = 2 + hlen; + await tmp_file.WriteAsync(out_buf, file_start, clen - file_start); + } + else + { + await tmp_file.WriteAsync(out_buf, 0, clen); + } + + t_len += rlen; + + base.OnReport(VoidProgress.Create(Id, percentage: t_len / (decimal)file_length)); + } + } + } + + tmp_file.Seek(0, SeekOrigin.Begin); + + using (var hmac = HMAC.Create("HMACSHA256")) + { + hmac.Key = key; + + var hmac_test = hmac.ComputeHash(tmp_file); + + if (hmac_test.ToHex() == hmac_data.ToHex()) + { + base.OnReport(VoidProgress.Create(Id, log: "HMAC verified!")); + } + else + { + throw new Exception($"HMAC verify failed.. {hmac_test.ToHex()} != {hmac_data.ToHex()}"); + } + } + } + + //file is downloaded to temp path, move it now + return new DownloadResult() + { + Filepath = tmp_name, + Header = header_obj + }; + } + } + } +} diff --git a/tools/void_util/void_util/Ext.cs b/tools/void_util/void_lib/Ext.cs similarity index 74% rename from tools/void_util/void_util/Ext.cs rename to tools/void_util/void_lib/Ext.cs index 63a17f2..d31c676 100644 --- a/tools/void_util/void_util/Ext.cs +++ b/tools/void_util/void_lib/Ext.cs @@ -1,13 +1,27 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using System.Threading.Tasks; -namespace void_util +namespace void_lib { public static class Ext { + public static byte[] FromHex(this string hex) + { + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); + } + + public static string ToHex(this byte[] data) + { + return BitConverter.ToString(data).Replace("-", string.Empty).ToLower(); + } + public static async Task CopyToAsync(this Stream in_stream, Stream out_stream, Action progress) { long total = 0; diff --git a/tools/void_util/void_lib/FileHeader.cs b/tools/void_util/void_lib/FileHeader.cs new file mode 100644 index 0000000..9b29205 --- /dev/null +++ b/tools/void_util/void_lib/FileHeader.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace void_lib +{ + + + public class FileHeader + { + public string name { get; set; } + public string mime { get; set; } + public ulong len { get; set; } + } +} diff --git a/tools/void_util/void_lib/Progress.cs b/tools/void_util/void_lib/Progress.cs new file mode 100644 index 0000000..d16af57 --- /dev/null +++ b/tools/void_util/void_lib/Progress.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace void_lib +{ + public abstract class VoidProgress + { + public Guid Id { get; set; } + + public static VoidProgress Create(Guid id, string label = null, string log = null, decimal? percentage = null) + { + if (label != null) + { + return new LabelVoidProgress() + { + Id = id, + Label = label + }; + } + else if (log != null) + { + return new LogVoidProgress() + { + Id = id, + Log = log + }; + } + else if (percentage != null) + { + return new PercentageVoidProgress() + { + Id = id, + Percentage = percentage.Value + }; + } + return null; + } + } + + public class LabelVoidProgress : VoidProgress + { + public string Label { get; set; } + } + + public class LogVoidProgress : VoidProgress + { + public string Log { get; set; } + } + + public class PercentageVoidProgress : VoidProgress + { + public decimal Percentage { get; set; } + } +} diff --git a/tools/void_util/void_lib/Upload.cs b/tools/void_util/void_lib/Upload.cs new file mode 100644 index 0000000..9d48ae4 --- /dev/null +++ b/tools/void_util/void_lib/Upload.cs @@ -0,0 +1,221 @@ +using Newtonsoft.Json; +using System; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace void_lib +{ + public class UploadResponse + { + public int status { get; set; } + public string msg { get; set; } + public string id { get; set; } + public int[] sync { get; set; } + } + + public class Upload : Progress + { + private Guid Id { get; set; } = Guid.NewGuid(); + private string UserAgent { get; set; } + private string BaseHostname { get; set; } + + public Upload(string host = "v3.void.cat", string ua = "VoidLib/1.0") + { + BaseHostname = host; + UserAgent = ua; + } + + public Task UploadFileAsync(string file, byte[] key, byte[] iv) + { + var fi = new FileInfo(file); + return UploadFileAsync(fi.OpenRead(), fi.Name, key, iv); + } + + public async Task UploadFileAsync(Stream in_stream, string filename, byte[] key, byte[] iv) + { + base.OnReport(VoidProgress.Create(Id, label: "Starting..")); + + var site_info = await new VoidApi(BaseHostname).GetUploadHostAsync(); + base.OnReport(VoidProgress.Create(Id, log: $"Starting upload for: {filename} => {site_info.upload_host}\nUsing key: {key.ToHex()} and IV: {iv.ToHex()}")); + + var file_length = in_stream.Length; + var header = JsonConvert.SerializeObject(new FileHeader() + { + name = filename, + mime = "", // idk what to do with this haha, its not really important anyway since we dont preview in browser + len = (ulong)file_length + }); + + base.OnReport(VoidProgress.Create(Id, log: $"Using header: {header}")); + + //unforutnatly we need to use a raw socket here because HttpWebRequest just bufferes forever + //sad.. no good for large uploads + var hosts = await Dns.GetHostAddressesAsync(site_info.upload_host); + if (hosts.Length > 0) + { + var sock = new Socket(SocketType.Stream, ProtocolType.Tcp); + var tcs = new TaskCompletionSource(); + var sae = new SocketAsyncEventArgs() + { + RemoteEndPoint = new IPEndPoint(hosts[0], 443) + }; + sae.Completed += (s, e) => + { + tcs.SetResult(true); + }; + + if (sock.ConnectAsync(sae)) + { + await tcs.Task; + } + + using (var ssl_stream = new SslStream(new NetworkStream(sock))) + { + await ssl_stream.AuthenticateAsClientAsync(site_info.upload_host); + + var http_header = $"POST /upload HTTP/1.1\r\nHost: {site_info.upload_host}\r\nConnection: close\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\nUser-Agent: {UserAgent}\r\nTrailer: \r\nAccept-Encoding: 0\r\n\r\n"; + var http_header_bytes = Encoding.UTF8.GetBytes(http_header); + + await ssl_stream.WriteAsync(http_header_bytes, 0, http_header_bytes.Length); + await ssl_stream.FlushAsync(); + + using (var cs = new ChunkStream(ssl_stream, 16384, true)) + { + //send the file data + byte[] hash; + + //create hmac + base.OnReport(VoidProgress.Create(Id, label: "Hashing...")); + using (var hmac = HMAC.Create("HMACSHA256")) + { + hmac.Key = key; + hash = hmac.ComputeHash(in_stream); + } + + base.OnReport(VoidProgress.Create(Id, log: $"HMAC is: {hash.ToHex()}")); + in_stream.Seek(0, SeekOrigin.Begin); + + //write header to request stream + var vbf_buf = new byte[37]; + vbf_buf[0] = 1; + Array.Copy(hash, 0, vbf_buf, 1, hash.Length); + var ts_buf = BitConverter.GetBytes((UInt32)DateTimeOffset.Now.ToUnixTimeSeconds()); + Array.Copy(ts_buf, 0, vbf_buf, 33, ts_buf.Length); + + await cs.WriteAsync(vbf_buf, 0, vbf_buf.Length); + + base.OnReport(VoidProgress.Create(Id, label: "Uploading...")); + using (var aes = new AesManaged()) + { + aes.Padding = PaddingMode.PKCS7; + aes.Mode = CipherMode.CBC; + + using (var ds = aes.CreateEncryptor(key, iv)) + { + var buf = new byte[ds.InputBlockSize * 1000]; + var out_buf = new byte[ds.OutputBlockSize * 1000]; + + var header_bytes = Encoding.UTF8.GetBytes(header); + var hlb = BitConverter.GetBytes((UInt16)header_bytes.Length); + Array.Copy(hlb, buf, hlb.Length); + Array.Copy(header_bytes, 0, buf, 2, header_bytes.Length); + + var init_offset = hlb.Length + header_bytes.Length; + long frlen = 0; + long tlen = 0; + while ((frlen = await in_stream.ReadAsync(buf, init_offset, buf.Length - init_offset)) > 0) + { + var actual_rlen = (int)(init_offset + frlen); + + if (actual_rlen % ds.InputBlockSize != 0) + { + var last_block = ds.TransformFinalBlock(buf, 0, actual_rlen); + await cs.WriteAsync(last_block, 0, last_block.Length); + } + else + { + var clen = ds.TransformBlock(buf, 0, actual_rlen, out_buf, 0); + await cs.WriteAsync(out_buf, 0, clen); + } + + //offset should always be 0 from after the first block + if (init_offset != 0) + { + init_offset = 0; + } + tlen += frlen; + base.OnReport(VoidProgress.Create(Id, percentage: tlen / (decimal)file_length)); + } + } + } + + //write end chunk + await cs.WriteAsync(new byte[0], 0, 0); + await cs.FlushAsync(); + } + + //fuck my life why am i doing this to mysefl.. + var crlf = new byte[] { 13, 10, 13, 10 }; + var sb_headers = new StringBuilder(); + var rlen = 0; + var header_buff = new byte[256]; + var header_end = 0; + while ((rlen = await ssl_stream.ReadAsync(header_buff, 0, header_buff.Length)) != 0) + { + if ((header_end = header_buff.IndexOf(crlf)) != -1) + { + sb_headers.Append(Encoding.UTF8.GetString(header_buff, 0, header_end + 4)); + break; + } + else + { + sb_headers.Append(Encoding.UTF8.GetString(header_buff, 0, rlen)); + } + } + + var header_dict = sb_headers.ToString().Split('\n').Select(a => + { + var i = a.IndexOf(":"); + return i == -1 ? null : new string[] { a.Substring(0, i), a.Substring(i + 2) }; + }).Where(a => a != null).ToDictionary(a => a[0].Trim(), b => b.Length > 1 ? b[1].Trim() : null); + + if (header_dict.ContainsKey("Content-Length")) + { + using (var msb = new MemoryStream()) + { + msb.Write(header_buff, header_end + 4, rlen - header_end - 4); + await ssl_stream.CopyToAsync(msb); + + return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(msb.ToArray())); + } + } + else + { + if (header_dict.ContainsKey("Transfer-Encoding") && header_dict["Transfer-Encoding"] == "chunked") + { + using (var msb = new MemoryStream()) + { + using (var cr = new ChunkStream(ssl_stream)) + { + cr.PreLoadBuffer(header_buff, header_end + 4, rlen - header_end - 4); + + await cr.CopyToAsync(msb); + } + + return JsonConvert.DeserializeObject(Encoding.UTF8.GetString(msb.ToArray())); + } + } + } + } + } + + return null; + } + } +} diff --git a/tools/void_util/void_util/VoidApi.cs b/tools/void_util/void_lib/VoidApi.cs similarity index 77% rename from tools/void_util/void_util/VoidApi.cs rename to tools/void_util/void_lib/VoidApi.cs index 9d8152c..fee415a 100644 --- a/tools/void_util/void_util/VoidApi.cs +++ b/tools/void_util/void_lib/VoidApi.cs @@ -1,12 +1,10 @@ using Newtonsoft.Json; -using System; -using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; -namespace void_util +namespace void_lib { public class BasicStats { @@ -38,12 +36,21 @@ namespace void_util public class VoidApi { - public static async Task CallApiAsync(string cmd) + public static string BaseHostname { get; set; } + public static string UserAgent { get; set; } + + public VoidApi(string hostname, string ua = "VoidApi/1.0") { - var req = (HttpWebRequest)WebRequest.Create($"https://{Program.BaseHostname}/api"); + BaseHostname = hostname; + UserAgent = ua; + } + + public async Task CallApiAsync(string cmd) + { + var req = (HttpWebRequest)WebRequest.Create($"https://{BaseHostname}/api"); req.Method = "POST"; req.ContentType = "application/json"; - req.UserAgent = Program.UserAgent; + req.UserAgent = UserAgent; var cmd_data = Encoding.UTF8.GetBytes(cmd); await (await req.GetRequestStreamAsync()).WriteAsync(cmd_data, 0, cmd_data.Length); @@ -55,7 +62,7 @@ namespace void_util } } - public static async Task GetUploadHostAsync() + public async Task GetUploadHostAsync() { return JsonConvert.DeserializeObject>(await CallApiAsync(JsonConvert.SerializeObject(new Cmd() { diff --git a/tools/void_util/void_lib/void_lib.csproj b/tools/void_util/void_lib/void_lib.csproj new file mode 100644 index 0000000..576acfd --- /dev/null +++ b/tools/void_util/void_lib/void_lib.csproj @@ -0,0 +1,12 @@ + + + + netcoreapp2.1;net472 + latest + + + + + + + diff --git a/tools/void_util/void_util.sln b/tools/void_util/void_util.sln index 2dc7c7b..c3951f7 100644 --- a/tools/void_util/void_util.sln +++ b/tools/void_util/void_util.sln @@ -5,6 +5,10 @@ VisualStudioVersion = 15.0.27703.2042 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "void_util", "void_util\void_util.csproj", "{6AE35BCD-015B-4316-8783-7AF6D75DE7E9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "void_util_form", "void_util_form\void_util_form.csproj", "{35F4300A-A50E-4D66-96D4-F9D380B21728}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "void_lib", "void_lib\void_lib.csproj", "{AF65F8E1-D7A7-4EE1-B6C2-31FC6047B8B0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +19,14 @@ Global {6AE35BCD-015B-4316-8783-7AF6D75DE7E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {6AE35BCD-015B-4316-8783-7AF6D75DE7E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {6AE35BCD-015B-4316-8783-7AF6D75DE7E9}.Release|Any CPU.Build.0 = Release|Any CPU + {35F4300A-A50E-4D66-96D4-F9D380B21728}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35F4300A-A50E-4D66-96D4-F9D380B21728}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35F4300A-A50E-4D66-96D4-F9D380B21728}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35F4300A-A50E-4D66-96D4-F9D380B21728}.Release|Any CPU.Build.0 = Release|Any CPU + {AF65F8E1-D7A7-4EE1-B6C2-31FC6047B8B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF65F8E1-D7A7-4EE1-B6C2-31FC6047B8B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF65F8E1-D7A7-4EE1-B6C2-31FC6047B8B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF65F8E1-D7A7-4EE1-B6C2-31FC6047B8B0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tools/void_util/void_util/Program.cs b/tools/void_util/void_util/Program.cs index 433130c..f72fb5a 100644 --- a/tools/void_util/void_util/Program.cs +++ b/tools/void_util/void_util/Program.cs @@ -1,13 +1,8 @@ -using Newtonsoft.Json; -using System; +using System; using System.IO; -using System.Linq; -using System.Net; -using System.Net.Security; -using System.Net.Sockets; using System.Security.Cryptography; -using System.Text; using System.Threading.Tasks; +using void_lib; namespace void_util { @@ -75,361 +70,61 @@ Modes: } } - public static byte[] FromHex(string hex) + private static void VoidProgress(object sender, VoidProgress vp) { - return Enumerable.Range(0, hex.Length) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) - .ToArray(); - } - - private static string ToHex(byte[] data) - { - return BitConverter.ToString(data).Replace("-", string.Empty).ToLower(); - } - - private static async Task UploadFileAsync(string filename, byte[] key, byte[] iv) - { - if (File.Exists(filename)) + switch (vp) { - var file_info = new FileInfo(filename); - - var site_info = await VoidApi.GetUploadHostAsync(); - Console.WriteLine($"Starting upload for: {file_info.Name} => {site_info.upload_host}\nUsing key: {ToHex(key)} and IV: {ToHex(iv)}"); - - var file_length = file_info.Length; - var header = JsonConvert.SerializeObject(new FileHeader() - { - name = file_info.Name, - mime = "", // idk what to do with this haha, its not really important anyway since we dont preview in browser - len = (ulong)file_length - }); - - Console.WriteLine($"Using header: {header}"); - - // unforutnatly we need to use a raw socket here because HttpWebRequest just bufferes forever - //sad.. no good for large uploads - var hosts = await Dns.GetHostAddressesAsync(site_info.upload_host); - if (hosts.Length > 0) - { - var sock = new Socket(SocketType.Stream, ProtocolType.Tcp); - var tcs = new TaskCompletionSource(); - var sae = new SocketAsyncEventArgs() + case LogVoidProgress l: { - RemoteEndPoint = new IPEndPoint(hosts[0], 443) - }; - sae.Completed += (s, e) => - { - tcs.SetResult(true); - }; - - if (sock.ConnectAsync(sae)) - { - await tcs.Task; + Console.WriteLine(l.Log); + break; } - - using (var ssl_stream = new SslStream(new NetworkStream(sock))) + case LabelVoidProgress l: { - await ssl_stream.AuthenticateAsClientAsync(site_info.upload_host); - - var http_header = $"POST /upload HTTP/1.1\r\nHost: {site_info.upload_host}\r\nConnection: close\r\nContent-Type: application/octet-stream\r\nTransfer-Encoding: chunked\r\nUser-Agent: {UserAgent}\r\nTrailer: \r\nAccept-Encoding: 0\r\n\r\n"; - var http_header_bytes = Encoding.UTF8.GetBytes(http_header); - - await ssl_stream.WriteAsync(http_header_bytes, 0, http_header_bytes.Length); - await ssl_stream.FlushAsync(); - - using (var cs = new ChunkStream(ssl_stream, 16384, true)) - { - //send the file data - using (var fs = file_info.OpenRead()) - { - byte[] hash; - - //create hmac - Console.WriteLine("Hashing..."); - using (var hmac = HMAC.Create("HMACSHA256")) - { - hmac.Key = key; - hash = hmac.ComputeHash(fs); - } - - Console.WriteLine($"Hash is {ToHex(hash)}"); - fs.Seek(0, SeekOrigin.Begin); - - //write header to request stream - var vbf_buf = new byte[37]; - vbf_buf[0] = 1; - Array.Copy(hash, 0, vbf_buf, 1, hash.Length); - var ts_buf = BitConverter.GetBytes((UInt32)DateTimeOffset.Now.ToUnixTimeSeconds()); - Array.Copy(ts_buf, 0, vbf_buf, 33, ts_buf.Length); - - await cs.WriteAsync(vbf_buf, 0, vbf_buf.Length); - - Console.WriteLine("Encrypting and Uploading..."); - using (var aes = new AesManaged()) - { - aes.Padding = PaddingMode.PKCS7; - aes.Mode = CipherMode.CBC; - - using (var ds = aes.CreateEncryptor(key, iv)) - { - var buf = new byte[ds.InputBlockSize * 1000]; - var out_buf = new byte[ds.OutputBlockSize * 1000]; - - var header_bytes = Encoding.UTF8.GetBytes(header); - var hlb = BitConverter.GetBytes((UInt16)header_bytes.Length); - Array.Copy(hlb, buf, hlb.Length); - Array.Copy(header_bytes, 0, buf, 2, header_bytes.Length); - - var init_offset = hlb.Length + header_bytes.Length; - long frlen = 0; - long tlen = 0; - while ((frlen = await fs.ReadAsync(buf, init_offset, buf.Length - init_offset)) > 0) - { - var actual_rlen = (int)(init_offset + frlen); - - if (actual_rlen % ds.InputBlockSize != 0) - { - var last_block = ds.TransformFinalBlock(buf, 0, actual_rlen); - await cs.WriteAsync(last_block, 0, last_block.Length); - } - else - { - var clen = ds.TransformBlock(buf, 0, actual_rlen, out_buf, 0); - await cs.WriteAsync(out_buf, 0, clen); - } - - //offset should always be 0 from after the first block - if (init_offset != 0) - { - init_offset = 0; - } - tlen += frlen; - Console.Write($"\r{(100 * (tlen / (decimal)file_length)).ToString("000.0")}%"); - } - } - } - } - - //write end chunk - await cs.WriteAsync(new byte[0], 0, 0); - await cs.FlushAsync(); - } - - //fuck my life why am i doing this to mysefl.. - var crlf = new byte[] { 13, 10, 13, 10 }; - var sb_headers = new StringBuilder(); - var rlen = 0; - var header_buff = new byte[256]; - var header_end = 0; - while ((rlen = await ssl_stream.ReadAsync(header_buff, 0, header_buff.Length)) != 0) - { - if ((header_end = header_buff.IndexOf(crlf)) != -1) - { - sb_headers.Append(Encoding.UTF8.GetString(header_buff, 0, header_end + 4)); - break; - } - else - { - sb_headers.Append(Encoding.UTF8.GetString(header_buff, 0, rlen)); - } - } - - var header_dict = sb_headers.ToString().Split('\n').Select(a => - { - var i = a.IndexOf(":"); - return i == -1 ? null : new string[] { a.Substring(0, i), a.Substring(i + 2) }; - }).Where(a => a != null).ToDictionary(a => a[0].Trim(), b => b.Length > 1 ? b[1].Trim() : null); - - if (header_dict.ContainsKey("Content-Length")) - { - using (var msb = new MemoryStream()) - { - msb.Write(header_buff, header_end + 4, rlen - header_end - 4); - await ssl_stream.CopyToAsync(msb); - - PrintUploadResult(msb.ToArray(), key, iv); - } - } - else - { - if (header_dict.ContainsKey("Transfer-Encoding") && header_dict["Transfer-Encoding"] == "chunked") - { - using (var msb = new MemoryStream()) - { - using (var cr = new ChunkStream(ssl_stream)) - { - cr.PreLoadBuffer(header_buff, header_end + 4, rlen - header_end - 4); - - await cr.CopyToAsync(msb); - } - - PrintUploadResult(msb.ToArray(), key, iv); - } - } - } + Console.WriteLine(l.Label); + break; } - } - } - else - { - Console.WriteLine("\nError: file not found!"); - } - } - - - private static void PrintUploadResult(byte[] data, byte[] key, byte[] iv) - { - var json_data = Encoding.UTF8.GetString(data); - try - { - var rsp = JsonConvert.DeserializeObject(json_data); - if (rsp != null) - { - if (rsp.status == 200) + case PercentageVoidProgress p: { - Console.WriteLine($"\nUpload complete!\nUrl: https://{BaseHostname}/#{rsp.id}:{ToHex(key)}:{ToHex(iv)}"); + Console.Write($"\r{(100 * p.Percentage).ToString("000.00")}%"); + break; } - else - { - Console.WriteLine($"\nUpload error: {rsp.msg}"); - } - } - else - { - Console.WriteLine($"\nGot invalid response: {json_data}"); - } - } - catch (Exception ex) - { - Console.WriteLine($"Got unknown response: \n{json_data}"); } } private static async Task DownloadFileAsync(string url) { - var url_base = new Uri(url); - var hash_frag = url_base.Fragment.Substring(1).Split(':'); + var dl = new Download(ua: UserAgent); + dl.ProgressChanged += VoidProgress; - Console.WriteLine($"Starting download for: {hash_frag[0]}"); + var res = await dl.DownloadFileAsync(url); - var req = (HttpWebRequest)WebRequest.Create($"{url_base.Scheme}://{url_base.Host}/{hash_frag[0]}"); - req.UserAgent = UserAgent; - - var rsp = await req.GetResponseAsync(); - var file_length = rsp.ContentLength; - using (var rsp_stream = rsp.GetResponseStream()) + if(res != null) { - var version = rsp_stream.ReadByte(); - var hmac_data = new byte[32]; - var ts = new byte[4]; - await rsp_stream.ReadAsync(hmac_data, 0, hmac_data.Length); - await rsp_stream.ReadAsync(ts, 0, ts.Length); - - Console.WriteLine($"Blob version is {version}, HMAC is {ToHex(hmac_data)}"); - - var tmp_name = Path.GetTempFileName(); - string real_name = null; - using (var tmp_file = new FileStream(tmp_name, FileMode.Open, FileAccess.ReadWrite)) - { - using (var aes = new AesManaged()) - { - aes.Padding = PaddingMode.PKCS7; - aes.Mode = CipherMode.CBC; - - using (var ds = aes.CreateDecryptor(FromHex(hash_frag[1]), FromHex(hash_frag[2]))) - { - var buf = new byte[ds.InputBlockSize * 1024]; - var out_buf = new byte[ds.OutputBlockSize * 1024]; - - bool first_block = true; - int read_offset = 0; - int last_rlen = 0; - long t_len = 0; - while (true) - { - var rlen = await rsp_stream.ReadAsync(buf, read_offset, buf.Length - read_offset); - - //end do final block - if (rlen == 0) - { - var last_buf = ds.TransformFinalBlock(buf, 0, last_rlen); - await tmp_file.WriteAsync(last_buf, 0, last_buf.Length); - break; - } - else - { - if ((read_offset + rlen) % ds.InputBlockSize != 0) - { - read_offset += rlen; - continue; - } - else - { - rlen += read_offset; - last_rlen = rlen; - read_offset = 0; - } - } - - var clen = ds.TransformBlock(buf, 0, rlen, out_buf, 0); - if (first_block) - { - first_block = false; - var hlen = BitConverter.ToUInt16(out_buf, 0); - var header = Encoding.UTF8.GetString(out_buf, 2, hlen); - Console.WriteLine($"Header is: {header}"); - - var header_obj = JsonConvert.DeserializeObject(header); - real_name = header_obj.name; - - var file_start = 2 + hlen; - await tmp_file.WriteAsync(out_buf, file_start, clen - file_start); - } - else - { - await tmp_file.WriteAsync(out_buf, 0, clen); - } - - t_len += rlen; - - Console.Write($"\r{(100 * (t_len / (decimal)file_length)).ToString("000.0")}%"); - } - } - } - - tmp_file.Seek(0, SeekOrigin.Begin); - - using (var hmac = HMAC.Create("HMACSHA256")) - { - var hmac_test = hmac.ComputeHash(tmp_file); - - if (ToHex(hmac_test) == ToHex(hmac_data)) - { - Console.WriteLine("HMAC verified!"); - } - else - { - throw new Exception($"HMAC verify failed.. {ToHex(hmac_test)} != {ToHex(hmac_data)}"); - } - } - } - - //file is downloaded to temp path, move it now - var out_file = Path.Combine(Directory.GetCurrentDirectory(), real_name); + var out_file = Path.Combine(Directory.GetCurrentDirectory(), res.Header.name); Console.WriteLine($"\nMoving file to {out_file}"); - File.Move(tmp_name, out_file); + File.Move(res.Filepath, out_file); } - - Console.WriteLine("\nDone!"); } - } - internal class FileHeader - { - public string name { get; set; } - public string mime { get; set; } - public ulong len { get; set; } + private static async Task UploadFileAsync(string filename, byte[] key, byte[] iv) + { + var up = new Upload(host: BaseHostname, ua: UserAgent); + up.ProgressChanged += VoidProgress; + + var rsp = await up.UploadFileAsync(filename, key, iv); + if (rsp != null) + { + if (rsp.status == 200) + { + Console.WriteLine($"\nUpload complete!\nUrl: https://{BaseHostname}/#{rsp.id}:{key.ToHex()}:{iv.ToHex()}"); + } + else + { + Console.WriteLine($"\nUpload error: {rsp.msg}"); + } + } + } } internal class FileData @@ -440,12 +135,4 @@ Modes: public DateTime Uploaded { get; set; } public byte[] EncryptedPayload { get; set; } } - - internal class UploadResponse - { - public int status { get; set; } - public string msg { get; set; } - public string id { get; set; } - public int[] sync { get; set; } - } } diff --git a/tools/void_util/void_util/void_util.csproj b/tools/void_util/void_util/void_util.csproj index 4cfecee..644d6a9 100644 --- a/tools/void_util/void_util/void_util.csproj +++ b/tools/void_util/void_util/void_util.csproj @@ -2,12 +2,12 @@ Exe - netcoreapp2.1;net471 + netcoreapp2.1;net472 latest - + diff --git a/tools/void_util/void_util_form/App.config b/tools/void_util/void_util_form/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/tools/void_util/void_util_form/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/tools/void_util/void_util_form/MainForm.Designer.cs b/tools/void_util/void_util_form/MainForm.Designer.cs new file mode 100644 index 0000000..321eeb8 --- /dev/null +++ b/tools/void_util/void_util_form/MainForm.Designer.cs @@ -0,0 +1,197 @@ +namespace void_util_form +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.listView1 = new System.Windows.Forms.ListView(); + this.button1 = new System.Windows.Forms.Button(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.listView2 = new System.Windows.Forms.ListView(); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.button2 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.button1); + this.groupBox1.Controls.Add(this.listView1); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(504, 246); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Upload"; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3}); + this.listView1.Location = new System.Drawing.Point(6, 19); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(409, 221); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + // + // button1 + // + this.button1.Location = new System.Drawing.Point(421, 19); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(83, 23); + this.button1.TabIndex = 1; + this.button1.Text = "Upload Files"; + this.button1.UseVisualStyleBackColor = true; + // + // columnHeader1 + // + this.columnHeader1.Text = "ID"; + this.columnHeader1.Width = 146; + // + // columnHeader2 + // + this.columnHeader2.Text = "Name"; + this.columnHeader2.Width = 187; + // + // columnHeader3 + // + this.columnHeader3.Text = "Progress"; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.textBox1); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Controls.Add(this.button2); + this.groupBox2.Controls.Add(this.listView2); + this.groupBox2.Location = new System.Drawing.Point(12, 264); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(504, 251); + this.groupBox2.TabIndex = 1; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Download"; + // + // listView2 + // + this.listView2.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader4, + this.columnHeader5, + this.columnHeader6}); + this.listView2.Location = new System.Drawing.Point(6, 39); + this.listView2.Name = "listView2"; + this.listView2.Size = new System.Drawing.Size(409, 201); + this.listView2.TabIndex = 2; + this.listView2.UseCompatibleStateImageBehavior = false; + this.listView2.View = System.Windows.Forms.View.Details; + // + // columnHeader4 + // + this.columnHeader4.Text = "ID"; + this.columnHeader4.Width = 146; + // + // columnHeader5 + // + this.columnHeader5.Text = "Name"; + this.columnHeader5.Width = 187; + // + // columnHeader6 + // + this.columnHeader6.Text = "Progress"; + // + // button2 + // + this.button2.Location = new System.Drawing.Point(421, 11); + this.button2.Name = "button2"; + this.button2.Size = new System.Drawing.Size(83, 23); + this.button2.TabIndex = 3; + this.button2.Text = "Download"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 16); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(20, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Url"; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(32, 13); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(383, 20); + this.textBox1.TabIndex = 5; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(528, 527); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Name = "Form1"; + this.Text = "VoidApp"; + this.groupBox1.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.ListView listView2; + private System.Windows.Forms.ColumnHeader columnHeader4; + private System.Windows.Forms.ColumnHeader columnHeader5; + private System.Windows.Forms.ColumnHeader columnHeader6; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label1; + } +} + diff --git a/tools/void_util/void_util_form/MainForm.cs b/tools/void_util/void_util_form/MainForm.cs new file mode 100644 index 0000000..d9a9504 --- /dev/null +++ b/tools/void_util/void_util_form/MainForm.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using void_lib; + +namespace void_util_form +{ + public partial class MainForm : Form + { + private static ObservableCollection Downloads { get; set; } = new ObservableCollection(); + + public MainForm() + { + InitializeComponent(); + + listView2.DataBindings = Downloads; + } + + private void button2_Click(object sender, EventArgs e) + { + + } + } + + internal class DownloadView + { + public DownloadView(Download dl) + { + dl.ProgressChanged += (s, e) => + { + switch (e) + { + case LogVoidProgress l: + { + Console.WriteLine(l.Log); + break; + } + case LabelVoidProgress l: + { + Label = l.Label; + break; + } + case PercentageVoidProgress p: + { + ProgressInner = p.Percentage; + break; + } + } + }; + } + + private decimal ProgressInner { get; set; } + public string Progress => $"{(100 * ProgressInner).ToString("0.0")}%"; + public string Label { get; set; } + } +} diff --git a/tools/void_util/void_util_form/MainForm.resx b/tools/void_util/void_util_form/MainForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/tools/void_util/void_util_form/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/tools/void_util/void_util_form/Program.cs b/tools/void_util/void_util_form/Program.cs new file mode 100644 index 0000000..5760b72 --- /dev/null +++ b/tools/void_util/void_util_form/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace void_util_form +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/tools/void_util/void_util_form/Properties/AssemblyInfo.cs b/tools/void_util/void_util_form/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c0c31a6 --- /dev/null +++ b/tools/void_util/void_util_form/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("void_util_form")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("void_util_form")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("35f4300a-a50e-4d66-96d4-f9d380b21728")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/tools/void_util/void_util_form/Properties/Resources.Designer.cs b/tools/void_util/void_util_form/Properties/Resources.Designer.cs new file mode 100644 index 0000000..8de4b33 --- /dev/null +++ b/tools/void_util/void_util_form/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace void_util_form.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("void_util_form.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/tools/void_util/void_util_form/Properties/Resources.resx b/tools/void_util/void_util_form/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/tools/void_util/void_util_form/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/tools/void_util/void_util_form/Properties/Settings.Designer.cs b/tools/void_util/void_util_form/Properties/Settings.Designer.cs new file mode 100644 index 0000000..8c9635b --- /dev/null +++ b/tools/void_util/void_util_form/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace void_util_form.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/tools/void_util/void_util_form/Properties/Settings.settings b/tools/void_util/void_util_form/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/tools/void_util/void_util_form/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tools/void_util/void_util_form/void_util_form.csproj b/tools/void_util/void_util_form/void_util_form.csproj new file mode 100644 index 0000000..8a62c94 --- /dev/null +++ b/tools/void_util/void_util_form/void_util_form.csproj @@ -0,0 +1,89 @@ + + + + + Debug + AnyCPU + {35F4300A-A50E-4D66-96D4-F9D380B21728} + WinExe + void_util_form + void_util_form + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + {af65f8e1-d7a7-4ee1-b6c2-31fc6047b8b0} + void_lib + + + + \ No newline at end of file diff --git a/utils/ga-page-view/ga-page-view/Program.cs b/utils/ga-page-view/ga-page-view/Program.cs index f341c77..cb852a5 100644 --- a/utils/ga-page-view/ga-page-view/Program.cs +++ b/utils/ga-page-view/ga-page-view/Program.cs @@ -13,24 +13,27 @@ namespace ga_page_view static ConnectionMultiplexer c { get; set; } static BatchBlock _queue = new BatchBlock(20); static string Token { get; set; } + static string Channel { get; set; } static Task Main(string[] args) { - if (args.Length != 1) + if (args.Length != 2) { - Console.WriteLine("Required args: token_auth"); + Console.WriteLine("Required args: channel token_auth"); return Task.CompletedTask; } - Token = args[0]; - Console.WriteLine($"Token is: {Token}"); + Channel = args[0]; + Token = args[1]; + + Console.WriteLine($"Token is: {Token}\nChannel is: {Channel}"); return startSvc(); } private static async Task startSvc() { c = await ConnectionMultiplexer.ConnectAsync("localhost"); - await c.GetSubscriber().SubscribeAsync("ga-page-view-matomo", queueMsg); + await c.GetSubscriber().SubscribeAsync(Channel, queueMsg); Console.WriteLine("Connected to redis"); diff --git a/utils/ga-page-view/ga-page-view/Properties/PublishProfiles/FolderProfile.pubxml b/utils/ga-page-view/ga-page-view/Properties/PublishProfiles/FolderProfile.pubxml index 8989bd8..680ed14 100644 --- a/utils/ga-page-view/ga-page-view/Properties/PublishProfiles/FolderProfile.pubxml +++ b/utils/ga-page-view/ga-page-view/Properties/PublishProfiles/FolderProfile.pubxml @@ -8,9 +8,9 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release Any CPU netcoreapp2.1 - bin\Release\netcoreapp2.1\publish\ + bin\publish\ linux-x64 - false - <_IsPortable>true + true + <_IsPortable>false \ No newline at end of file diff --git a/utils/ga_pageview/.gitignore b/utils/ga_pageview/.gitignore deleted file mode 100644 index 0196246..0000000 --- a/utils/ga_pageview/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ - -/target/ -**/*.rs.bk diff --git a/utils/ga_pageview/Cargo.toml b/utils/ga_pageview/Cargo.toml deleted file mode 100644 index 8960209..0000000 --- a/utils/ga_pageview/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "ga_pageview" -version = "0.1.0" -authors = ["v0l"] - -[dependencies] -redis = "0.8.0" \ No newline at end of file diff --git a/utils/ga_pageview/src/main.rs b/utils/ga_pageview/src/main.rs deleted file mode 100644 index 4b68e76..0000000 --- a/utils/ga_pageview/src/main.rs +++ /dev/null @@ -1,37 +0,0 @@ -extern crate redis; - -use std::process::Command; - -fn main() { - let ch = "ga-page-view"; - let mut q = Vec::new(); - - if let Ok(client) = redis::Client::open("redis://127.0.0.1/") { - if let Ok(mut pubsub) = client.get_pubsub() { - if let Ok(_) = pubsub.subscribe(ch) { - println!("Subscribed to {}", ch); - - loop { - if let Ok(msg) = pubsub.get_message() { - if let Ok(payload) = msg.get_payload::() { - //println!("channel '{}': {}", msg.get_channel_name(), payload); - - if q.len() >= 20 { - //push the rows to ga /batch - Command::new("curl").arg("-X").arg("POST").arg("--data").arg(q.join(" \\\r\n")).arg("https://www.google-analytics.com/batch").output().expect("failed to execute process"); - q.clear(); - } - q.push(payload); - } - } - } - }else { - println!("Failed to subscribe"); - } - }else { - println!("Failed to get pubsub"); - } - }else { - println!("Failed to connect to redis"); - } -} diff --git a/utils/logparser/.gitignore b/utils/logparser/.gitignore deleted file mode 100644 index 4470988..0000000 --- a/utils/logparser/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -Cargo.lock \ No newline at end of file diff --git a/utils/logparser/Cargo.toml b/utils/logparser/Cargo.toml deleted file mode 100644 index 612439f..0000000 --- a/utils/logparser/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "logparser" -version = "0.1.0" -authors = ["v0l"] - -[dependencies] -regex = "0.2" -chrono = "0.4" -getopts = "0.2" -serde = "^1.0" -serde_json = "^1.0" -serde_derive = "^1.0" -maxminddb = "0.8.1" \ No newline at end of file diff --git a/utils/logparser/block.html b/utils/logparser/block.html deleted file mode 100644 index 866abba..0000000 --- a/utils/logparser/block.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - Block report for void.cat - - - - - -

Stats per country

- -

Top 10 blocked Ips

- - - - - - - - - - -
CountryIpHits
- - - - diff --git a/utils/logparser/src/main.rs b/utils/logparser/src/main.rs deleted file mode 100644 index ad88663..0000000 --- a/utils/logparser/src/main.rs +++ /dev/null @@ -1,168 +0,0 @@ -extern crate regex; -extern crate chrono; -extern crate getopts; -extern crate serde; -extern crate serde_json; -extern crate maxminddb; - -use std::env; -use std::str::FromStr; -use std::process::Command; -use std::collections::HashMap; -use std::io::{BufReader, BufRead}; -use std::fs::File; -use std::io::prelude::*; -use regex::Regex; -use chrono::{DateTime, Utc}; -use getopts::Options; -use maxminddb::geoip2; - -#[macro_use] -extern crate serde_derive; - -const BLOCK_SINCE_DAYS : i64 = 30; -const BLOCK_STATUS_CODE : &str = "444"; -const IPSET_NAME : &str = "void_cat_block"; - -#[derive(Serialize, Deserialize)] -struct IpStats { - ip : String, - hits : u64, - country : String -} - -impl IpStats { - fn new(i : String, h : u64, mm : &mut Option) -> IpStats { - let mut c : String = String::from("XX"); - if let &mut Some(ref m) = mm { - if let Ok(ip) = FromStr::from_str(&i) { - if let Ok(city) = m.lookup::(ip) { - if city.country.is_some() { - c = city.country.unwrap().iso_code.unwrap().to_lowercase(); - } - } - } - } - - IpStats { ip: i, hits: h, country: c } - } -} - -fn gen_report(hm : HashMap, output : String) { - //convert hashmap into vector for sorting - let mut ordered_stats = Vec::new(); - ordered_stats.extend(hm.values()); - - ordered_stats.sort_by(|a, b| b.hits.cmp(&a.hits)); - - if let Ok(json) = serde_json::to_string(&ordered_stats) { - //send email report - println!("Saving report.."); - if let Ok(mut fout) = File::create(&output) { - match fout.write_all(json.as_bytes()) { - Ok(_) => println!("Report saved to: {}", &output), - Err(e) => println!("Report save failed: {}", e) - } - } - } -} - -fn main() { - let args: Vec = env::args().collect(); - - let mut opts = Options::new(); - opts.optopt("f", "file", "Log file to read", ""); - opts.optopt("d", "db", "MaxMind DB", ""); - opts.optopt("o", "out", "Output report path", ""); - opts.optflag("v", "verbose", "Print more info"); - - let flags = match opts.parse(&args[1..]) { - Ok(m) => { m } - Err(f) => { panic!(f.to_string()) } - }; - - let file_name = match flags.opt_str("f"){ - Some(x) => x, - None => String::from("access.log") - }; - - let re = Regex::new(r###"(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - - \[(?P.*)\] "(?P[A-Z]{1,5}) (?P.*) (?PHTTP/\d{1}\.[0-9]{1})" (?P\d{1,4}) (?P\d{1,11}) "(?P.*)" "(?P.*)""###).unwrap(); - if let Ok(f) = File::open(&file_name) { - println!("Reading file: {}", &file_name); - let file = BufReader::new(&f); - - let mut block_list = HashMap::::new(); - let local_time : DateTime = Utc::now(); - let mut lines = 0u64; - let mut hit_lines = 0u64; - - - //load max mind data - let maxmind_path = match flags.opt_str("d"){ - Some(x) => x, - None => String::from("GeoIP2-City.mmdb") - }; - let mut mmdb = match maxminddb::Reader::open(&maxmind_path) { - Ok(m) => { - println!("MaxMind DB loaded!"); - Some(m) - }, - Err(e) => { - println!("Could not load MaxMind DB: {}", e); - None - } - }; - - for (_, line) in file.lines().enumerate() { - if let Ok(l) = line { - lines += 1; - if l.contains(BLOCK_STATUS_CODE) { //simple check if the line contains the error code - hit_lines += 1; - if let Some(tokens) = re.captures(&l) { - if let (Some(ip), Some(date), Some(rsp)) = (tokens.get(1), tokens.get(2), tokens.get(6)) { - //println!("Got tokens: {} {} {}", ip.as_str(), date.as_str(), rsp.as_str()); - if let Ok(dt) = DateTime::parse_from_str(date.as_str(), "%d/%b/%Y:%H:%M:%S %z") { - let dt_utc = dt.with_timezone(&Utc); - let slog = local_time.signed_duration_since(dt_utc); - - //println!("Row match: {}", rsp.as_str() == BLOCK_STATUS_CODE); - if rsp.as_str() == BLOCK_STATUS_CODE && slog.num_days() <= BLOCK_SINCE_DAYS { - let mut host_stat = block_list.entry(ip.as_str().to_owned()).or_insert(IpStats::new(ip.as_str().to_owned(), 0u64, &mut mmdb)); - host_stat.hits += 1; - } - } - } - } - } - } - } - let verbose = flags.opt_present("v"); - - println!("Blocking {} ips, from {}/{} {:.2}% requests", block_list.len(), hit_lines, lines, 100f64 * (hit_lines as f64 / lines as f64)); - match Command::new("/sbin/ipset").args(&["flush", &IPSET_NAME]).output() { - Ok(_) => { - println!("[OK]\t:ipset flush"); - for (k,_) in &block_list { - match Command::new("/sbin/ipset").args(&["add", &IPSET_NAME, &k]).output() { - Ok(_) => { - if verbose { - println!("[OK]\t:ipset add {} {}", &IPSET_NAME, &k); - } - }, - Err(msg) => println!("[F]\t{} ({})", k, msg) - } - } - }, - Err(msg) => println!("Failed to run ipset flush command: {}", msg) - } - - let output = match flags.opt_str("o") { - Some(x) => x, - None => String::from("report.html") - }; - //send email report - gen_report(block_list, output); - }else{ - println!("File not found: {}", &file_name); - } -}