From e708220bc6118edc7b217c5bb465a4ffcf458a32 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Sun, 1 Sep 2019 21:18:14 +0100
Subject: [PATCH] Implement some theme update logic, but it's unfinished.

---
 module_index.json                 |  2 +-
 modules/feature-theme-gallery.php | 73 +++++++++++++++++++++++++++++--
 peppermint.guiconfig.json         |  1 +
 themes/blue/theme.css             |  2 +-
 themes/default/theme.css          |  2 +-
 themes/none/theme.css             |  2 +-
 6 files changed, 75 insertions(+), 7 deletions(-)

diff --git a/module_index.json b/module_index.json
index bc8a487..17ec967 100755
--- a/module_index.json
+++ b/module_index.json
@@ -155,7 +155,7 @@
         "version": "0.1",
         "author": "Starbeamrainbowlabs",
         "description": "Adds a theme gallery page and optional automatic theme updates. Contacts a remote server, where IP addresses are stored in automatic server logs for security and attack mitigation purposes.",
-        "lastupdate": 1567107944,
+        "lastupdate": 1567366716,
         "optional": false,
         "extra_data": []
     },
diff --git a/modules/feature-theme-gallery.php b/modules/feature-theme-gallery.php
index bffed46..5178eb5 100644
--- a/modules/feature-theme-gallery.php
+++ b/modules/feature-theme-gallery.php
@@ -30,8 +30,8 @@ register_module([
 			$gallery_urls = explode(" ", $settings->css_theme_gallery_index_url);
 			foreach($gallery_urls as $url) {
 				if(empty($url)) continue;
-				$next_obj = json_decode(file_get_contents($url));
-				if($next_obj === null) {
+				$next_obj = json_decode(@file_get_contents($url));
+				if(empty($next_obj)) {
 					http_response_code(503);
 					exit(page_renderer::render_main("Error - Theme Gallery - $settings->sitename", "<p>Error: Failed to download theme index file from <code>" . htmlentities($url) . "</code>."));
 				}
@@ -59,7 +59,7 @@ register_module([
 				$selected = $theme->id == $settings->css_theme_gallery_selected_id ? " selected" : "";
 				$content .= "<div class='theme-item'>
 					<a href='" . htmlentities($theme->preview_large) . "'><img src='" . htmlentities($theme->preview_small) . "' title='Click to enlarge' /></a><br />
-					<input type='radio' id='" . htmlentities($theme->id) . "' name='theme-selector' value='" . htmlentities($theme->id) . "'$selected />
+					<input type='radio' id='" . htmlentities($theme->id) . "' name='theme-selector' value='" . htmlentities($theme->id) . "' required$selected />
 					<label class='link-display-label' for='" . htmlentities($theme->id) . "'>" . htmlentities($theme->name) . "</label>
 					<p>" . str_replace("\n", "</p>\n<p>", htmlentities($theme->description)) . "</p>
 					<p>By <a href='" . htmlentities($theme->author_link) . "'>" . htmlentities($theme->author) . "</a> (<a href='" . htmlentities($theme->url) . "'>View CSS</a>, <a href='" . htmlentities($theme->index_url) . "'>View Index</a>)
@@ -73,8 +73,75 @@ register_module([
 			
 		});
 		
+		add_action("theme-gallery-select", function() {
+			global $env, $settings;
+			
+			if(!$env->is_admin) {
+				$errorMessage = "<p>You don't have permission to change $settings->sitename's theme.</p>\n";
+				if(!$env->is_logged_in)
+					$errorMessage .= "<p>You could try <a href='?action=login&returnto=%3Faction%3Dconfigure'>logging in</a>.</p>";
+				else
+					$errorMessage .= "<p>You could try <a href='?action=logout&returnto=%3Faction%3Dconfigure'>logging out</a> and then <a href='?action=login&returnto=%3Faction%3Dconfigure'>logging in</a> again with a different account that has the appropriate privileges.</a>.</p>";
+				exit(page_renderer::render_main("Error - $settings->sitename", $errorMessage));
+			}
+			
+			if(!isset($_GET["theme-selector"])) {
+				http_response_code(400);
+				exit(page_renderer::render_main("No theme selected - Error - $settings->sitename", "<p>Oops! Looks like you didn't select a theme. Try <a href='?action=theme-gallery'>going back</a> and selecting one.</p>"));
+			}
+			
+			// Set the new theme's id
+			$settings->css_theme_gallery_selected_id = $_GET["theme-selector"];
+			
+			// TODO: Set the autoupdate_url here
+			// TODO: Add option to disable theme updates
+			
+			if(!save_settings()) {
+				http_response_code(503);
+				exit(page_renderer::render_main("Server error - $settings->sitename", "<p>Oops! $settings->sitename wasn't able to save the <code>peppermint.json</code> settings file back to disk. If you're the administrator, try checking the permissions on disk. If not, try contacting $settings->sitename's administrator, who's contact details can be found at the bottom of every page.</p>"));
+			}
+			
+			
+		});
+		
 		add_help_section("26-random-redirect", "Jumping to a random page", "<p>$settings->sitename has a function that can send you to a random page. To use it, click <a href='?action=random'>here</a>. $settings->admindetails_name ($settings->sitename's adminstrator) may have added it to one of the menus.</p>");
 	}
 ]);
 
+function theme_update($force_update = false) : bool {
+	global $version, $settings;
+	
+	// If there's no url to update from or updates are disabled, then we're done here
+	if(empty($settings->css_theme_autoupdate_url) || $settings->css_theme_autoupdate_interval < 0)
+		return true;
+	
+	// If it's not time for an update, then end here
+	// ...unless we're supposed to force an update
+	if(time() - $settings->css_theme_autoupdate_lastcheck < $settings->css_theme_autoupdate_interval || !$force_update)
+		return true;
+	
+	// Fetch the new css
+	$new_css = @file_get_contents($settings->css_theme_autoupdate_url);
+	// Make sure it's valid
+	if(empty($new_css)) {
+		error_log("[Pepperminty Wiki/$settings->sitename] Error: Failed to update theme: Got an error while trying to download theme update from $settings->css_theme_autoupdate_url");
+		return false;
+	}
+	
+	// TODO: Check the hash against themeindex.json?
+	
+	$min_version_loc = strpos($new_css, "@minversion") + strlen("@minversion");
+	$min_version = substr($new_css, $min_version_loc, strpos($new_css, "\n", $min_version_loc));
+	if(version_compare($version, $min_version) == -1) {
+		error_log("[Pepperminty Wiki/$settings->sitename] Error: Failed to update theme: $settings->css_theme_gallery_selected_id requires Pepperminty Wiki $min_version, but $version is installed.");
+		return false;
+	}
+	
+	// If the css is identical to the string we've got stored already, then no point in updating
+	if($new_css == $settings->css)
+		return true;
+	
+	
+}
+
 ?>
diff --git a/peppermint.guiconfig.json b/peppermint.guiconfig.json
index aba8169..206ddd1 100644
--- a/peppermint.guiconfig.json
+++ b/peppermint.guiconfig.json
@@ -188,6 +188,7 @@
 	"disable_peppermint_access_check": { "type": "checkbox", "description": "Disables the access check for peppermint.json on first-run. <strong>VERY DANGEROUS</strong>. Use only for development. Note that it's recommend to block access to peppermint.json for a reason - it contains your site secret and password hashes, so an attacker could do all <em>sorts</em> of nefarious things if it's left unblocked.", "default": false },
 	"css_theme_autoupdate_url": { "type": "url", "description": "A url that points to the css theme file to check for updates. If blank, then automatic updates are disabled.", "default": "" },
 	"css_theme_autoupdate_interval": { "type": "number", "description": "The interval, in seconds, that updates to the theme should be checked for. Defaults to every week. A value of -1 disables automatic updates.", "default": 604800 },
+	"css_theme_autoupdate_lastcheck": { "type": "number", "description": "The timestamp of the last time that updates for the selected theme were last checked for. To disable automatic updates, you should set <code>css_theme_autoupdate_interval</code> to <code>-1</code> instead of changing this setting.", "default": 0 },
 	"css_theme_gallery_index_url": { "type": "text", "description": "A url that points  to an index file that contains a list of themes. Used to populate the gallary. Multiple urls are allowed - separate them with a space.", "default": "https://starbeamrainbowlabs.com/labs/peppermint/themes/themeindex.php" },
 	"css_theme_gallery_selected_id": { "type": "text", "description": "The id of the currently selected theme. Defaults to the internal default theme.", "default": "default" },
 	"css": { "type": "textarea", "description": "A string of css to include. Will be included in the &lt;head&gt; of every page inside a &lt;style&gt; tag. This may also be an absolute url - urls will be referenced via a &lt;link rel='stylesheet' /&gt; tag. If the theme gallery is installed and automatic updates enabled, then the value of this property is managed by the theme gallery and changes may be overwritten (try the css_custom setting instead).", "default": "auto" },
diff --git a/themes/blue/theme.css b/themes/blue/theme.css
index 2ff0732..e516159 100644
--- a/themes/blue/theme.css
+++ b/themes/blue/theme.css
@@ -4,7 +4,7 @@
  * @description	A more blue theme.
  * @author		ZestyclosePainting
  * @author_link	https://reddit.com/u/ZestyclosePainting
- * @minversion	0.20
+ * @minversion	v0.20
  * 
  * "A more blue theme for pepperminty if anyone's interested."
  * By u/ZestyclosePainting on Reddit: https://www.reddit.com/user/ZestyclosePainting/
diff --git a/themes/default/theme.css b/themes/default/theme.css
index 02e3932..e346ac9 100644
--- a/themes/default/theme.css
+++ b/themes/default/theme.css
@@ -4,7 +4,7 @@
  * @description		The default theme.
  * @author			Starbeamrainbowlabs
  * @author_link		https://starbeamrainbowlabs.com/
- * @minversion		0.20
+ * @minversion		v0.20
  */
 
 :root {
diff --git a/themes/none/theme.css b/themes/none/theme.css
index ac4e15e..d92aa80 100644
--- a/themes/none/theme.css
+++ b/themes/none/theme.css
@@ -4,5 +4,5 @@
  * @description		A special theme with no CSS. Useful if you want to create your own theme from scratch!
  * @author			Starbeamrainbowlabs
  * @author_link		https://starbeamrainbowlabs.com/
- * @minversion		0.20
+ * @minversion		v0.20
  */
