diff --git a/build.php b/build.php index d45840c..3313adf 100644 --- a/build.php +++ b/build.php @@ -27,7 +27,7 @@ $modules = glob("modules/*.php"); $module_index = []; // Defined just in case a module needs to reference them when we require() them // to gain information -$env = $paths = new stdClass(); +$env = new stdClass(); $paths = new stdClass(); $paths->extra_data_directory = "build/._extra_data"; /** diff --git a/core/01-settings.fragment.php b/core/01-settings.fragment.php index 029ff9b..0d7b7f0 100644 --- a/core/01-settings.fragment.php +++ b/core/01-settings.fragment.php @@ -37,7 +37,8 @@ if(!file_exists($settingsFilename)) { // Copy the default settings over to the main settings array foreach ($guiConfig as $key => $value) $settings->$key = $value->default; - if(file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)) === false) { + // From below if statement: file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)) + if(save_settings() === false) { http_response_code(503); header("content-type: text/plain"); exit("Oops! It looks like $settings->sitename wasn't able to write peppermint.json to disk.\nThis file contains all of $settings->sitename's settings, so it's really important!\nHave you checked that PHP has write access to the directory that index.php is located in (and all it's contents and subdirectories)? Try\n\nsudo chown USERNAME:USERNAME -R path/to/directory\n\nand\n\nsudo chmod -R 0644 path/to/directory;\nsudo chmod -R +X path/to/directory\n\n....where USERNAME is the username that the PHP process is running under."); @@ -68,8 +69,10 @@ if(!property_exists($settings, "secret")) { $settings->secret = bin2hex(random_bytes(16)); $settings_upgraded = true; } -if($settings_upgraded) - file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)); +if($settings_upgraded) { + save_settings(); + // file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)); +} // If: // * The first-run wizard hasn't been completed @@ -80,7 +83,8 @@ if($settings_upgraded) // Note we added this additional specific check because in Docker containers we recommend that firstrun_complete be manually preset to false, which would previously get autset to true as we thought it was a pre-existing wiki when it isn't! Note also we don't yet have access to the pageindex at this stage, so we can't check that either. if(!$settings->firstrun_complete && $settings_upgraded && $did_upgrade_firstrun_key) { $settings->firstrun_complete = true; - file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)); + save_settings(); + // file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT)); } // Insert the default CSS if requested diff --git a/core/05-functions.php b/core/05-functions.php index 417c3cd..07f9ecd 100644 --- a/core/05-functions.php +++ b/core/05-functions.php @@ -724,11 +724,23 @@ function minify_css(string $css_str) : string { /** * Saves the settings file back to peppermint.json. * @package core + * @param stdObject [$new_settings=null] A new settings object to REPLACE the old one with - use with extreme care! A value of null (default) indicates that the existing global $settings object will be saved. * @return bool Whether the settings were saved successfully. */ -function save_settings() { +function save_settings($new_settings=null, $filepath=null) { global $paths, $settings; - return file_put_contents($paths->settings_file, json_encode($settings, JSON_PRETTY_PRINT)) !== false; + $result = file_put_contents( + isset($paths->settings_file) ? $paths->settings_file : "peppermint.json", + json_encode( + $new_settings == null ? $settings : $new_settings, + JSON_PRETTY_PRINT) + ) !== false; + if($settings->peppermint_json_perms !== null) { + $perms = octdec($settings->peppermint_json_perms); + if(!chmod($paths->settings_file, $perms)) + error_log("Warning: Failed to chmod peppermint.json at {$paths->settings_file}"); // Complain about inability to chmod but don't claim we can't save + } + return $result; } /** * Save the page index back to disk, respecting $settings->minify_pageindex diff --git a/modules/feature-guiconfig.php b/modules/feature-guiconfig.php index 186f8af..648f06a 100644 --- a/modules/feature-guiconfig.php +++ b/modules/feature-guiconfig.php @@ -196,7 +196,8 @@ SCRIPT; // Take a backup of the current settings file rename($paths->settings_file, "$paths->settings_file.bak"); // Save the new settings file - file_put_contents($paths->settings_file, json_encode($newSettings, JSON_PRETTY_PRINT)); + save_settings($newSettings); + // file_put_contents($paths->settings_file, json_encode($newSettings, JSON_PRETTY_PRINT)); $content = "

Master settings updated successfully

\n"; $content .= "

$settings->sitename's master settings file has been updated successfully. A backup of the original settings has been created under the name peppermint.json.bak, just in case. You can go back and continue editing the master settings file, or you can go to the " . htmlentities($settings->defaultpage) . ".

\n"; diff --git a/modules/page-login.php b/modules/page-login.php index 4cf29cb..15a5878 100644 --- a/modules/page-login.php +++ b/modules/page-login.php @@ -238,7 +238,7 @@ function do_password_hash_code_update() { $settings->password_cost = $new_cost; // Save the current time in the settings $settings->password_cost_time_lastcheck = time(); - file_put_contents($paths->settings_file, json_encode($settings, JSON_PRETTY_PRINT)); + save_settings(); } /** diff --git a/peppermint.guiconfig.json b/peppermint.guiconfig.json index c58999e..df84e7c 100644 --- a/peppermint.guiconfig.json +++ b/peppermint.guiconfig.json @@ -270,6 +270,7 @@ "sessionlifetime": { "type": "number", "description": "Again, you shouldn't need to change this under normal circumstances. This setting controls the lifetime of a login session. Defaults to 24 hours, but it may get cut off sooner depending on the underlying PHP session lifetime.", "default": 86400 }, "cookie_secure": { "type": "text", "description": "Whether to set the 'Secure' flag on all cookies. This prevents cookies from being transmitted over an unencrypted connection. Default: auto (sets the flag if HTTPS is detected). Other possible values: false (the flag is never set), true (the flag will always be set, regardless of whether HTTPS is detected or not)", "default": "auto" }, "disable_peppermint_access_check": { "type": "checkbox", "description": "Disables the access check for peppermint.json on first-run. VERY DANGEROUS. 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 sorts of nefarious things if it's left unblocked.", "default": false }, + "peppermint_json_perms": { "type": "text", "description": "The permissions to chmod peppermint.json to after saving it. Defaults to null, which means do not alter permissions. String must be a linux octal string with a leading 0: for example 0640. WARNING: Do NOT mark peppermint.json as 0777 - this is very insecure! Generally 0660, 0640, and 0600 work well for most purposes. Do not edit this setting unless you know what you're doing!", "default": null }, "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 css_theme_autoupdate_interval to -1 instead of changing this setting.", "default": 0 },