From c7bcedff5af170593f91060a65af2b634e7286c3 Mon Sep 17 00:00:00 2001 From: Crash0v3r1de Date: Fri, 24 Jun 2022 00:18:46 -0600 Subject: [PATCH] API update only now --- Core/Balena.cs | 131 ++++++++++++++++++++++++++++++++- Objs/BalenaFleetBuildReturn.cs | 14 ++++ Objs/GithubCommits.cs | 103 ++++++++++++++++++++++++++ Program.cs | 90 ++++++++++++++++------ Tools/ConsoleHelp.cs | 14 ++++ Tools/Discord.cs | 2 +- Tools/LoadingUnloading.cs | 10 ++- Tracking/Settings.cs | 2 + Tracking/StaticDebugger.cs | 13 ++++ 9 files changed, 349 insertions(+), 30 deletions(-) create mode 100644 Objs/BalenaFleetBuildReturn.cs create mode 100644 Objs/GithubCommits.cs create mode 100644 Tracking/StaticDebugger.cs diff --git a/Core/Balena.cs b/Core/Balena.cs index c8dd105..0874adb 100644 --- a/Core/Balena.cs +++ b/Core/Balena.cs @@ -1,16 +1,18 @@ using BalenaNebraUpdater.Tracking; -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; +using System.Net; +using System.Net.Http.Headers; using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using BalenaNebraUpdater.Objs; namespace BalenaNebraUpdater.Core { public class Balena { private readonly string _gitLoc = Environment.CurrentDirectory + "\\helium-rak"; + private string ApiKey { get; set; } public bool NeedsAuth() { ProcessStartInfo gitInfo = new ProcessStartInfo(); @@ -87,5 +89,126 @@ public bool FleetPush() { return true; } + + public string ApiPushRepoUpdate() { + try + { + var httpClientHandler = new HttpClientHandler(); + if (StaticDebugger.CurrentlyDebugging) { + var proxy = new WebProxy + { + Address = new Uri("http://127.0.0.1:8888"), + BypassProxyOnLocal = false, + UseDefaultCredentials = true, + Credentials = new NetworkCredential(userName: "", password: "") + }; + httpClientHandler.Proxy = proxy; + } + var web = new HttpClient(httpClientHandler); + var content = new StringContent("{\"shouldFlatten\":true,\"url\":\"https://github.com/NebraLtd/helium-rak/archive/master.tar.gz\"}", Encoding.UTF8, "application/json"); // statically set URL string, can code to grab this at some point if it ever changes + web.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", SettingsStatic.Settings.ApiKey); + var result = web.PostAsync($"https://builder.balena-cloud.com/v3/buildFromUrl?headless=true&owner={SettingsStatic.Settings.OrgName}&app={SettingsStatic.Settings.FleetName}", content).Result; + return result.Content.ReadAsStringAsync().Result; + } catch { } + + + return null; + } + public string GetOrgName(string api) { + ApiKey = api; + try + { + var httpClientHandler = new HttpClientHandler(); + if (StaticDebugger.CurrentlyDebugging) + { + var proxy = new WebProxy + { + Address = new Uri("http://127.0.0.1:8888"), + BypassProxyOnLocal = false, + UseDefaultCredentials = true, + Credentials = new NetworkCredential(userName: "", password: "") + }; + httpClientHandler.Proxy = proxy; + } + var web = new HttpClient(httpClientHandler); + web.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", api); + var result = web.GetAsync("https://api.balena-cloud.com/v6/organization").Result; + var tmp = result.Content.ReadAsStringAsync().Result; + + return Regex.Match(tmp, "handle\":\"(.*?)\"").Groups[1].Value; // fuck making an object for this + } + catch { } + + + return null; + } + public string GetCurrentCommit() + { + try + { + var httpClientHandler = new HttpClientHandler(); + if (StaticDebugger.CurrentlyDebugging) + { + var proxy = new WebProxy + { + Address = new Uri("http://127.0.0.1:8888"), + BypassProxyOnLocal = false, + UseDefaultCredentials = true, + Credentials = new NetworkCredential(userName: "", password: "") + }; + httpClientHandler.Proxy = proxy; + } + var web = new HttpClient(httpClientHandler); + web.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("BalenaUpdaterTool","1.0")); + var result = web.GetAsync("https://api.github.com/repos/NebraLtd/helium-rak/commits").Result; + var commits = JsonConvert.DeserializeObject>(result.Content.ReadAsStringAsync().Result); + + return commits[0].sha; + } + catch { } + + + return null; + } + public List GetFleets(string api) + { + ApiKey = api; + try + { + List ours = new List(); + var httpClientHandler = new HttpClientHandler(); + if (StaticDebugger.CurrentlyDebugging) + { + var proxy = new WebProxy + { + Address = new Uri("http://127.0.0.1:8888"), + BypassProxyOnLocal = false, + UseDefaultCredentials = true, + Credentials = new NetworkCredential(userName: "", password: "") + }; + httpClientHandler.Proxy = proxy; + } + var web = new HttpClient(httpClientHandler); + web.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", api); + var result = web.GetAsync("https://api.balena-cloud.com/v6/application").Result; + var tmp = result.Content.ReadAsStringAsync().Result; + + var found = Regex.Matches(tmp, "slug\":\"(.*?)\""); + foreach (Match match in found) { + if (match.Groups[1].Value.Contains(SettingsStatic.Settings.OrgName)) { + // we own this fleet + ours.Add(match.Groups[1].Value); + } + } + + + + return ours; + } + catch { } + + + return null; + } } } diff --git a/Objs/BalenaFleetBuildReturn.cs b/Objs/BalenaFleetBuildReturn.cs new file mode 100644 index 0000000..2b65ad8 --- /dev/null +++ b/Objs/BalenaFleetBuildReturn.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BalenaNebraUpdater.Objs +{ + public class BalenaFleetBuildReturn + { + public bool started { get; set; } + public int releaseId { get; set; } + } +} diff --git a/Objs/GithubCommits.cs b/Objs/GithubCommits.cs new file mode 100644 index 0000000..6efa2d8 --- /dev/null +++ b/Objs/GithubCommits.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BalenaNebraUpdater.Objs +{ + public class Author + { + public string name { get; set; } + public string email { get; set; } + public DateTime date { get; set; } + public string login { get; set; } + public int id { get; set; } + public string node_id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class Commit + { + public Author author { get; set; } + public Committer committer { get; set; } + public string message { get; set; } + public Tree tree { get; set; } + public string url { get; set; } + public int comment_count { get; set; } + public Verification verification { get; set; } + } + + public class Committer + { + public string name { get; set; } + public string email { get; set; } + public DateTime date { get; set; } + public string login { get; set; } + public int id { get; set; } + public string node_id { get; set; } + public string avatar_url { get; set; } + public string gravatar_id { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string followers_url { get; set; } + public string following_url { get; set; } + public string gists_url { get; set; } + public string starred_url { get; set; } + public string subscriptions_url { get; set; } + public string organizations_url { get; set; } + public string repos_url { get; set; } + public string events_url { get; set; } + public string received_events_url { get; set; } + public string type { get; set; } + public bool site_admin { get; set; } + } + + public class Parent + { + public string sha { get; set; } + public string url { get; set; } + public string html_url { get; set; } + } + + public class GithubCommits + { + public string sha { get; set; } + public string node_id { get; set; } + public Commit commit { get; set; } + public string url { get; set; } + public string html_url { get; set; } + public string comments_url { get; set; } + public Author author { get; set; } + public Committer committer { get; set; } + public List parents { get; set; } + } + + public class Tree + { + public string sha { get; set; } + public string url { get; set; } + } + + public class Verification + { + public bool verified { get; set; } + public string reason { get; set; } + public string signature { get; set; } + public string payload { get; set; } + } +} diff --git a/Program.cs b/Program.cs index 526f2a4..2b227ff 100644 --- a/Program.cs +++ b/Program.cs @@ -1,5 +1,4 @@ -// See https://aka.ms/new-console-template for more information -using BalenaNebraUpdater.Core; +using BalenaNebraUpdater.Core; using BalenaNebraUpdater.Tools; using BalenaNebraUpdater.Tracking; Console.CancelKeyPress += delegate { @@ -12,32 +11,77 @@ Github git = new Github(); Balena bel = new Balena(); -if (ld.Loaded()) { // No settings - prompt for initial config +if (args.Length != 0) { +if(args[0] == "true") StaticDebugger.CurrentlyDebugging = true; +} +// When console menu is made a menu for picking the fleet name from API will also be added so this is commented for that process +//bel.GetFleets("key"); + + + +if (!ld.Loaded()) { // No settings - prompt for initial config + SettingsStatic.Settings.ApiKey = con.BalenaApiKey(); + SettingsStatic.Settings.OrgName = bel.GetOrgName(SettingsStatic.Settings.ApiKey); SettingsStatic.Settings.webhook = con.PromptWebhook(); - SettingsStatic.Settings.BalenaPath = con.BalenaPath(); + // Bellow is commented out since balenacli option is not coded as an option yet + //SettingsStatic.Settings.BalenaPath = con.BalenaPath(); SettingsStatic.Settings.FleetName = con.FleetName(); ld.Save(); } -BalenaStatus.NeedsAuth = true; -if (bel.NeedsAuth()) bel.BalenaLogin(); BalenaStatus.NeedsAuth = false; +//BalenaStatus.NeedsAuth = true; +//if (bel.NeedsAuth()) bel.BalenaLogin(); BalenaStatus.NeedsAuth = false; while (true) { - // Version checking with github logic - may be organized into it's own class down the road - bool updated = false; - if (git.NeedsCloned()) - { - git.CloneRepo(); - } - if (git.NeedsPulled()) - { - git.PullRepo(); // Update - if (BalenaStatus.NeedsAuth) bel.BalenaLogin(); BalenaStatus.NeedsAuth = false; // Prompt for login if initial run - bel.FleetPush(); // Push update to balena for building - if (!String.IsNullOrEmpty(SettingsStatic.Settings.webhook)) Discord.SendWebhook(); - Console.WriteLine($"{DateTime.Now} | Fleet updated!"); - updated = true; - } - if (!updated) { Console.WriteLine($"{DateTime.Now} | Update not needed"); } - Thread.Sleep(60000); + try { + bool updated = false; + string output; + string currentCommit = bel.GetCurrentCommit(); + if (SettingsStatic.Settings.CurrentCommit != null & SettingsStatic.Settings.CurrentCommit != currentCommit) + { + // new commit found + output = bel.ApiPushRepoUpdate(); + if (output.Contains("started\":true")) { + Console.WriteLine($"{DateTime.Now} | Build image has been updated to the newest repo commit"); + SettingsStatic.Settings.CurrentCommit = currentCommit; + try { ld.Save(); } catch { Console.WriteLine($"{DateTime.Now} | Failed to save settings after commit update - please report this as an issue on Github"); } + Discord.SendWebhook(); + } + else Console.WriteLine($"{DateTime.Now} | Commit update push failed - please report this as an issue on Github"); + } + else + { + if (SettingsStatic.Settings.CurrentCommit == null) + { + output = bel.ApiPushRepoUpdate(); + if (output.Contains("started\":true")) { + Console.WriteLine($"{DateTime.Now} | Initial build started, commit is now current"); + SettingsStatic.Settings.CurrentCommit = currentCommit; + try { ld.Save(); } catch { Console.WriteLine($"{DateTime.Now} | Failed to save settings after initial commit update - please report this as an issue on Github"); } + Discord.SendWebhook(); + } + else Console.WriteLine($"{DateTime.Now} | Initial build failed - please report this as an issue on Github"); + } + else Console.WriteLine($"{DateTime.Now} | Update not needed"); + + } + } catch { Console.WriteLine("FATAL ERROR! Please report an issue to github | Failed logic loop"); } + + // Add console menu options to use the balenacli option, this code would then be used. Api is just better for easability + //if (git.NeedsCloned()) + //{ + // git.CloneRepo(); + //} + //if (git.NeedsPulled()) + //{ + // // Make commit comparison method + // git.PullRepo(); // Update + // if (BalenaStatus.NeedsAuth) bel.BalenaLogin(); BalenaStatus.NeedsAuth = false; // Prompt for login if initial run + // bel.FleetPush(); // Push update to balena for building + // if (!String.IsNullOrEmpty(SettingsStatic.Settings.webhook)) Discord.SendWebhook(); + // Console.WriteLine($"{DateTime.Now} | Fleet updated!"); + // updated = true; + //} + //if (!updated) { Console.WriteLine($"{DateTime.Now} | Update not needed"); } + Thread.Sleep(3600000); // hard coded hour wait for now } \ No newline at end of file diff --git a/Tools/ConsoleHelp.cs b/Tools/ConsoleHelp.cs index 4327dd2..152afe5 100644 --- a/Tools/ConsoleHelp.cs +++ b/Tools/ConsoleHelp.cs @@ -28,5 +28,19 @@ public string BalenaPath() Console.WriteLine(""); return raw; } + public string BalenaFleetName() + { + Console.Write("Enter Fleet Name: "); + string raw = Console.ReadLine(); + Console.WriteLine(""); + return raw; + } + public string BalenaApiKey() + { + Console.Write("Enter Api Key: "); + string raw = Console.ReadLine(); + Console.WriteLine(""); + return raw; + } } } diff --git a/Tools/Discord.cs b/Tools/Discord.cs index 506ef45..5385864 100644 --- a/Tools/Discord.cs +++ b/Tools/Discord.cs @@ -15,7 +15,7 @@ public static void SendWebhook() { if (!String.IsNullOrEmpty(SettingsStatic.Settings.webhook)) { WebhookBasicJSON tmp = new WebhookBasicJSON(); tmp.avatar_url = "https://991tech.org/cdn-img/winbox.png"; - tmp.content = $"Balena fleet has been updated to recent commit | Hash: {SettingsStatic.Settings.CurrentCommit}"; + tmp.content = $"New balena image update (fleet updated) | Hash: {SettingsStatic.Settings.CurrentCommit}"; tmp.username = "Balena Helium-Rak Auto Updater"; var web = new HttpClient(); diff --git a/Tools/LoadingUnloading.cs b/Tools/LoadingUnloading.cs index 7b29c74..ae5f4c7 100644 --- a/Tools/LoadingUnloading.cs +++ b/Tools/LoadingUnloading.cs @@ -15,7 +15,12 @@ public class LoadingUnloading public void Save() { if(File.Exists(config)) File.Delete(config); using (var sw = new StreamWriter(config)) { - sw.WriteLine(JsonConvert.SerializeObject(SettingsStatic.Settings)); + Settings tmpParse = new Settings(); + tmpParse = SettingsStatic.Settings; + string encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(tmpParse.ApiKey)); + tmpParse.ApiKey = encoded; + encoded = null; + sw.WriteLine(JsonConvert.SerializeObject(tmpParse)); } } public bool Loaded() @@ -25,9 +30,10 @@ public bool Loaded() try { var raw = File.ReadAllText(config); var set = JsonConvert.DeserializeObject(raw); + set.ApiKey = Encoding.UTF8.GetString(Convert.FromBase64String(set.ApiKey)); SettingsStatic.Settings = set; return true; - } catch { return false; } + } catch { return false; } } return false; } diff --git a/Tracking/Settings.cs b/Tracking/Settings.cs index 27dd1ec..7bc451e 100644 --- a/Tracking/Settings.cs +++ b/Tracking/Settings.cs @@ -12,6 +12,8 @@ public class Settings public string? CurrentCommit { get; set; } public string? FleetName { get; set; } public string? BalenaPath { get; set; } + public string? OrgName { get; set; } + public string? ApiKey { get; set; } } public class Setting { diff --git a/Tracking/StaticDebugger.cs b/Tracking/StaticDebugger.cs new file mode 100644 index 0000000..c3e079c --- /dev/null +++ b/Tracking/StaticDebugger.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BalenaNebraUpdater.Tracking +{ + public static class StaticDebugger + { + public static bool CurrentlyDebugging { get; set; } + } +}