From 77ffa2bcfc52e1492570dd3cdaf3f41001143a00 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Sun, 12 Jun 2016 21:15:43 +0100
Subject: [PATCH] apidoc is awesome. document a bunch of stuff, more to go

---
 build/index.php                    | 515 ++++++++---------------------
 core.php                           |  20 ++
 module_index.json                  |  16 +-
 modules/action-hash.php            |   6 +-
 modules/action-protect.php         |   8 +
 modules/action-raw.php             |   8 +
 modules/feature-history.php        |   8 +
 modules/feature-recent-changes.php |   7 +
 modules/feature-search.php         |  25 ++
 modules/feature-upload.php         |  22 ++
 10 files changed, 242 insertions(+), 393 deletions(-)

diff --git a/build/index.php b/build/index.php
index 22245ae..7c7598d 100644
--- a/build/index.php
+++ b/build/index.php
@@ -18,389 +18,29 @@ $start_time = microtime(true);
 	* #2 - Incorrect closing tag - nibreh <https://github.com/nibreh/>
 	* #8 - Rogue <datalist /> tag - nibreh <https://github.com/nibreh/>
  */
-// Initialises a new object to store your wiki's settings in. Please don't touch this.
+$guiConfig = <<<GUICONFIG
+{guiconfig}
+GUICONFIG;
+$guiConfig = json_decode($guiConfig);
 $settings = new stdClass();
-
-////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// Basic Settings ////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// The site's name. Used all over the place.
-$settings->sitename = "Pepperminty Wiki";
-
-// The name of the page that will act as the home page for the wiki. This page
-// will be served if the user didn't specify a page.
-$settings->defaultpage = "Main Page";
-
-// Contact details for the site administrator. Since users can only be added by
-// editing this file, people will need a contact address to use to ask for an
-// account.
-$settings->admindetails = [
-	"name" => "Administrator",
-	"email" => "admin@localhost"
-];
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////// Appearance //////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// A url that points to the favicon you want to use for your wiki. By default
-// this is set to a data: url of a Peppermint.
-// Default favicon credit: Peppermint by bluefrog23
-//	Link: https://openclipart.org/detail/19571/peppermint-candy-by-bluefrog23
-$settings->favicon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAB3VBMVEXhERHbKCjeVVXjb2/kR0fhKirdHBziDg6qAADaHh7qLy/pdXXUNzfMAADYPj7ZPDzUNzfbHx/fERHpamrqMTHgExPdHx/bLCzhLS3fVFTjT0/ibm7kRkbiLi7aKirdISHeFBTqNDTpeHjgERHYJCTVODjYQkLaPj6/AADVOTnpbW3cIyPdFRXcJCThMjLiTU3ibW3fVVXaKyvcERH4ODj+8fH/////fHz+Fxf4KSn0UFD/CAj/AAD/Xl7/wMD/EhL//v70xMT/+Pj/iYn/HBz/g4P/IyP/Kyv/7Oz0QUH/9PT/+vr/ior/Dg7/vr7/aGj/QED/bGz/AQH/ERH/Jib/R0f/goL/0dH/qan/YWH/7e3/Cwv4R0f/MTH/enr/vLz/u7v/cHD/oKD/n5//aWn+9/f/k5P/0tL/trb/QUH/cXH/dHT/wsL/DQ3/p6f/DAz/1dX/XV3/kpL/i4v/Vlb/2Nj/9/f/pKT+7Oz/V1f/iIj/jIz/r6//Zmb/lZX/j4//T0//Dw/4MzP/GBj/+fn/o6P/TEz/xMT/b2//Tk7/OTn/HR3/hIT/ODj/Y2P/CQn/ZGT/6Oj0UlL/Gxv//f3/Bwf/YmL/6+v0w8P/Cgr/tbX0QkL+9fX4Pz/qNzd0dFHLAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfeCxINNSdmw510AAAA5ElEQVQYGQXBzSuDAQCA8eexKXOwmSZepa1JiPJxsJOrCwcnuchBjg4O/gr7D9zk4uAgJzvuMgcTpYxaUZvSm5mUj7TX7ycAqvoLIJBwStVbP0Hom1Z/ejoxrbaR1Jz6nWinbKWttGRgMSSjanPktRY6mB9WtRNTn7Ilh7LxnNpKq2/x5LnBitfz+hx0qxUaxhZ6vwqq9bx6f2XXvuUl9SVQS38NR7cvln3v15tZ9bQpuWDtZN3Lgh5DWJex3Y+z1KrVhw21+CiM74WZo83DiXq0dVBDYNJkFEU7WrwDAZhRtQrwDzwKQbT6GboLAAAAAElFTkSuQmCC";
-
-// A url that points to the site's logo. Leave blank to disable. When enabled
-// the logo will be inserted next to the site name on every page.
-$settings->logo_url = "//starbeamrainbowlabs.com/images/logos/peppermint.png";
-
-// The side of the site name at which the logo should be placed.
-$settings->logo_position = "left";
-
-// Whether to show a list of subpages at the bottom of the page.
-$settings->show_subpages = true;
-
-// The depth to which we should display when listing subpages at the bottom of
-// the page.
-$settings->subpages_display_depth = 3;
-
-// A message that will appear at the bottom of every page. May contain HTML.
-$settings->footer_message = "All content is under <a href='?page=License' target='_blank'>this license</a>. Please make sure that you read and understand the license, especially if you are thinking about copying some (or all) of this site's content, as it may restrict you from doing so.";
-
-// A message that will appear just before the submit button on the editing
-// page. May contain HTML.
-$settings->editing_message = "<a href='?action=help#20-parser-default' target='_blank'>Formatting help</a> (<a href='https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet' target='_blank'>Markdown Cheatsheet</a>)<br />
-By submitting your edit or uploading your file, you are agreeing to release your changes under <a href='?action=view&page=License' target='_blank'>this license</a>. Also note that if you don't want your work to be edited by other users of this site, please don't submit it here!";
-
-// The string that is prepended before an admin's name on the nav bar. Defaults
-// to a diamond shape (&#9670;).
-$settings->admindisplaychar = "&#9670;";
-
-// The string that is prepended a page's name in the page title if it is
-// protected. Defaults to a lock symbol. (&#128274;)
-$settings->protectedpagechar = "&#128274;";
-
-
-///////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////// Editing ///////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// Whether editing is enabled.
-$settings->editing = true;
-
-// Whether users who aren't logged in are allowed to edit your wiki.
-$settings->anonedits = false;
-
-// The maximum page size in characters.
-$settings->maxpagesize = 135000;
-
-// The parser to use when rendering pages. Defaults to a modified version of
-// slimdown, originally written by Johnny Broadway <johnny@johnnybroadway.com>.
-$settings->parser = "parsedown";
-
-// Whether page sources should be cleaned of HTML before rendering. It is
-// STRONGLY recommended that you keep this option turned on.
-$settings->clean_raw_html = true;
-
-// Whether to enable client side rendering of methematical expressions.
-// Math expressions should be enclosed inside of dollar signs ($).
-// Turn off if you don't use it.
-$settings->enable_math_rendering = true;
-
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////// Access and Security /////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// An array of usernames and passwords - passwords should be hashed with
-// sha256.
-$settings->users = [
-	"admin" => "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", //password
-	"user" => "873ac9ffea4dd04fa719e8920cd6938f0c23cd678af330939cff53c3d2855f34" //cheese
-];
-
-// An array of usernames that are administrators. Administrators can delete and
-// move pages.
-$settings->admins = [ "admin" ];
-
-// Whether to use the new sha3 hashing algorithm for passwords etc.
-$settings->use_sha3 = false;
-
-// Whether to require that users login before they do anything else.
-$settings->require_login_view = false;
-
-// The directory in which to store all files, except this main index.php.
-$settings->data_storage_dir = ".";
-
-// The secret key used to perform 'dangerous' actions, like updating the wiki.
-// It is strongly advised that you change this!
-$settings->sitesecret = "ed420502615bac9037f8f12abd4c9f02";
-
-// The amount of time, in seconds, that pages should be blocked from being
-// indexed by search engines after their last edit. Aka delayed indexing.
-$settings->delayed_indexing_time = 0;
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////// Navigation //////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// An array of links and display text to display at the top of the site.
-// Format:
-//		[ "Display Text", "Link" ]
-// You can also use strings here and they will be printed as-is, except the
-// following special strings:
-// 		user-status		Expands to the user's login information
-//						e.g. "Logged in as {name}. | Logout".
-//						e.g. "Browsing as Anonymous. | Login".
-//
-//		search			Expands to a search box.
-//
-//		divider			Expands to a divider to separate stuff.
-//
-//		more			Expands to the "More..." submenu.
-$settings->nav_links = [
-	"user-status",
-	[ "Home", "index.php" ],
-//	[ "Login", "index.php?action=login" ],
-	"search",
-	[ "Read", "index.php?page={page}" ],
-	[ "Edit", "index.php?action=edit&page={page}" ],
-	//"divider",
-	[ "All&nbsp;Pages", "index.php?action=list" ],
-	"menu"
-];
-// An array of additional links in the above format that will be shown under
-// "More" subsection.
-$settings->nav_links_extra = [
-	[ "&#x1f553; Page History", "?action=history&page={page}" ],
-	[ "&#x1f3ab; All&nbsp;Tags", "index.php?action=list-tags" ],
-	[ "Recent changes", "?action=recent-changes" ],
-	[ "&#x1f845; Upload", "index.php?action=upload" ],
-	[ "&#x2327; $settings->admindisplaychar" . "Delete", "index.php?action=delete&page={page}" ],
-	[ "&#x2398; $settings->admindisplaychar" . "Move", "index.php?action=move&page={page}" ],
-	[ "&#x1f510; $settings->admindisplaychar" . "Toggle Protection", "index.php?action=protect&page={page}" ]
-];
-
-// An array of links in the above format that will be shown at the bottom of
-// the page.
-$settings->nav_links_bottom = [
-	[ "&#x1f5b6; Printable version", "index.php?action=view&printable=yes&page={page}" ],
-	[ "Credits", "index.php?action=credits" ],
-	[ "Help", "index.php?action=help" ]
-];
-
-
-///////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////// Uploads ///////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// Whether to allow image uploads to the server.
-$settings->upload_enabled = true;
-
-// An array of mime types that are allowed to be uploaded.
-$settings->upload_allowed_file_types = [
-	"image/jpeg",
-	"image/png",
-	"image/gif",
-	"image/webp",
-	"image/svg+xml",
-	"video/mp4",
-	"video/webm",
-	"audio/mp4",
-	"audio/mpeg"
-];
-
-// The default file type for previews.
-$settings->preview_file_type = "image/png";
-
-// The default size of preview images.
-$settings->default_preview_size = 640;
-
-// The location of a file that maps mime types onto file extensions and vice
-// versa. Used to generate the file extension for an uploaded file. See the
-// configuration guide for windows instructions.
-$settings->mime_extension_mappings_location = "/etc/mime.types";
-
-// Override mappings to convert mime types into the appropriate file extension.
-// Used to override the above file if it assigns weird extensions
-// to any mime types.
-$settings->mime_mappings_overrides = [
-	"text/plain" => "txt",
-	"audio/mpeg" => "mp3"
-];
-
-// The minimum and maximum allowed sizes of generated preview images in pixels.
-$settings->min_preview_size = 1;
-$settings->max_preview_size = 2048;
-
-
-////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////// Search ////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// The number of characters that should be displayed either side of a matching
-// term in the context below each search result.
-$settings->search_characters_context = 200;
-
-// The weighting to give to search term matches found in a page's title.
-$settings->search_title_matches_weighting = 10;
-
-// The weighting to give to search term matches found in a page's tags.
-$settings->search_tags_matches_weighting = 3;
-
-
-////////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////// Advanced ///////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-// The default action. This action will be performed if no other action is
-// specified. It is recommended you set this to "view" - that way the user
-// automatically views the default page (see above).
-$settings->defaultaction = "view";
-
-// The url from which to fetch updates. Defaults to the master (development)
-// branch.
-// MAKE SURE THAT THIS POINTS TO A *HTTPS* URL, OTHERWISE SOMEONE COULD INJECT
-// A VIRUS INTO YOUR WIKI
-$settings->updateurl = "https://raw.githubusercontent.com/sbrl/pepperminty-wiki/master/index.php";
-
-// Whether to optimise all webpages generated.
-$settings->optimize_pages = true;
-
-///////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// Other Modules ////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// The maximum number of recent changes to display on the recent changes page.
-$settings->max_recent_changes = 512;
-
-// Whether to only allow adminstrators to export the your wiki as a zip using
-// the page-export module.
-$settings->export_allow_only_admins = false;
-
-// The prefix that should be used in the names of the session variables. See
-// the readme for more information.
-$settings->sessionprefix = preg_replace("/[^0-9a-z]/i", "", strtolower($settings->sitename));
-
-
-///////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////// Theme ////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-
-// A string of css to include. Will be included in the <head> of every page
-// inside a <style> tag. This may also be a url - urls will be referenced via a
-// <link rel='stylesheet' /> tag.
-$settings->css = <<<THEMECSS
-body { margin: 2rem 0; background: #eee8f2; line-height: 1.45em; color: #111111; font-family: sans-serif; }
-
-nav { display: flex; background-color: #8a62a7; color: #ffa74d;  }
-nav.top { position: absolute; top: 0; left: 0; right: 0; box-shadow: inset 0 -0.6rem 0.8rem -0.5rem rgba(50, 50, 50, 0.5); }
-nav.bottom { position: absolute; left: 0; right: 0; box-shadow: inset 0 0.8rem 0.8rem -0.5rem rgba(50, 50, 50, 0.5); }
-
-nav > span { flex: 1; text-align: center; line-height: 2; display: inline-block; margin: 0; padding: 0.3rem 0.5rem; border-left: 3px solid #442772; border-right: 3px solid #442772; }
-nav:not(.nav-more-menu) a { text-decoration: none; font-weight: bolder; color: inherit; }
-.nav-divider { color: transparent; }
-
-.nav-more { position: relative; background-color: #442772; }
-.nav-more label { cursor: pointer; }
-.nav-more-menu { display: none; position: absolute; flex-direction: column; top: 2.6rem; right: -0.2rem; background-color: #8a62a7; border-top: 3px solid #442772; border-bottom: 3px solid #442772;}
-input[type=checkbox]:checked ~ .nav-more-menu { display: block; box-shadow: 0.4rem 0.4rem 1rem 0 rgba(50, 50, 50, 0.5); }
-.nav-more-menu span { min-width: 10rem; }
-
-.inflexible { flex: none; }
-.off-screen { position: absolute; top: -1000px; left: -1000px;}
-
-input[type=search] { width: 14rem; padding: 0.3rem 0.4rem; font-size: 1rem; color: white; background: rgba(255, 255, 255, 0.4); border: 0; border-radius: 0.3rem; }
-input[type=search]::-webkit-input-placeholder { color : rgba(255, 255, 255, 0.75); }
-input[type=button], input[type=submit] { cursor: pointer; }
-
-.sidebar { position: relative; z-index: 100; margin-top: 0.6rem; padding: 1rem 3rem 2rem 0.4rem; background: #9e7eb4; box-shadow: inset -0.6rem 0 0.8rem -0.5rem rgba(50, 50, 50, 0.5); }
-.sidebar a { color: #ffa74d; }
-
-.sidebar ul { position: relative; margin: 0.3rem 0.3rem 0.3rem 1rem; padding: 0.3rem 0.3rem 0.3rem 1rem; list-style-type: none; }
-.sidebar li { position: relative; margin: 0.3rem; padding: 0.3rem; }
-
-.sidebar ul:before { content: ""; position: absolute; top: 0; left: 0; height: 100%; border-left: 2px dashed rgba(50, 50, 50, 0.4); }
-.sidebar li:before { content: ""; position: absolute; width: 1rem; top: 0.8rem; left: -1.2rem; border-bottom: 2px dashed rgba(50, 50, 50, 0.4); }
-
-.preview { text-align: center; }
-.preview:hover img, .preview:hover video, .preview:hover audio { --checkerboard-bg: rgba(200, 200, 200, 0.2); max-width: 100%; background-color: #eee; background-image: linear-gradient(45deg, var(--checkerboard-bg) 25%, transparent 25%, transparent 75%, var(--checkerboard-bg) 75%, var(--checkerboard-bg)), linear-gradient(45deg, var(--checkerboard-bg) 25%, transparent 25%, transparent 75%, var(--checkerboard-bg) 75%, var(--checkerboard-bg)); background-size:2em 2em; background-position:0 0, 1em 1em; }
-.image-controls ul { list-style-type: none; margin: 5px; padding: 5px; }
-.image-controls li { display: inline-block; margin: 5px; padding: 5px; }
-.link-display { margin-left: 0.5rem; }
-
-figure:not(.preview) { display: inline-block; }
-figure:not(.preview) > :first-child { display: block; }
-figcaption { text-align: center; }
-
-.printable { padding: 2rem; }
-
-h1 { text-align: center; }
-.sitename { margin-top: 5rem; margin-bottom: 3rem; font-size: 2.5rem; }
-.logo { max-width: 4rem; max-height: 4rem; vertical-align: middle; }
-.logo.small { max-width: 2rem; max-height: 2rem; }
-main:not(.printable) { padding: 2rem 2rem 0.5rem 2rem; background: #faf8fb; box-shadow: 0 0.1rem 1rem 0.3rem rgba(50, 50, 50, 0.5); }
-
-blockquote { padding-left: 1em; border-left: 0.2em solid #442772; border-radius: 0.2rem; }
-
-a.redlink:link { color: rgb(230, 7, 7); }
-a.redlink:visited { color: rgb(130, 15, 15); #8b1a1a }
-
-.search-result { position: relative; }
-.search-result::before { content: attr(data-result-number); position: relative; top: 3.2rem; color: rgba(33, 33, 33, 0.3); font-size: 2rem; }
-.search-result::after { content: "Rank: " attr(data-rank); position: absolute; top: 3.8rem; right: 0.7rem; color: rgba(50, 50, 50, 0.3); }
-.search-result > h2 { margin-left: 2rem; }
-
-label:not(.link-display-label) { display: inline-block; min-width: 7rem; }
-input[type=text]:not(.link-display), input[type=password], textarea { margin: 0.5rem 0; }
-input[type=text], input[type=password], textarea, #search-box { padding: 0.5rem 0.8rem; background: #d5cbf9; border: 0; border-radius: 0.3rem; font-size: 1rem; color: #442772; }
-textarea { min-height: 35rem; line-height: 1.3em; font-size: 1.25rem; }
-textarea, textarea ~ input[type=submit], #search-box { width: calc(100% - 0.3rem); box-sizing: border-box; }
-textarea ~ input[type=submit] { margin: 0.5rem 0; padding: 0.5rem; font-weight: bolder; }
-.editform input[type=text] { width: calc(100% - 0.3rem); box-sizing: border-box; }
-
-.file-gallery { margin: 0.5em; padding: 0.5em; list-style-type: none; }
-.file-gallery > li { display: inline-block; min-width: attr(data-gallery-width); padding: 1em; text-align: center; }
-.file-gallery > li img, .file-gallery > li video, .file-gallery > li audio { display: block; margin: 0 auto; background-color: white; }
-
-.page-tags-display { margin: 0.5rem 0 0 0; padding: 0; list-style-type: none; }
-.page-tags-display li { display: inline-block; margin: 0.5rem; padding: 0.5rem; background: #D2C3DD; white-space: nowrap; }
-.page-tags-display li a { color: #FB701A; text-decoration: none; }
-.page-tags-display li::before { content: "\\A"; position: relative; top: 0.03rem; left: -0.9rem; width: 0; height: 0; border-top: 0.6rem solid transparent; border-bottom: 0.6rem solid transparent; border-right: 0.5rem solid #D2C3DD; }
-
-.page-list { list-style-type: none; margin: 0.3rem; padding: 0.3rem; }
-.page-list li:not(.header) { margin: 0.3rem; padding: 0.3rem; }
-.page-list li .size { margin-left: 0.7rem; color: rgba(30, 30, 30, 0.5); }
-.page-list li .editor { display: inline-block; margin: 0 0.5rem; }
-.page-list li .tags { margin: 0 1rem; }
-.tag-list { list-style-type: none; margin: 0.5rem; padding: 0.5rem; }
-.tag-list li { display: inline-block; margin: 1rem; }
-.mini-tag { background: #d2c3dd; padding: 0.2rem 0.4rem; color: #fb701a; text-decoration: none; }
-
-.help-section-header::after { content: "#" attr(id); float: right; color: rgba(0, 0, 0, 0.4); font-size: 0.8rem; font-weight: normal; }
-
-.cursor-query { cursor: help; }
-
-summary { cursor: pointer; }
-
-.larger { color: rgb(9, 180, 0); }
-.smaller, .deletion { color: rgb(207, 28, 17); }
-.nochange { color: rgb(132, 123, 199); font-style: italic; }
-.significant { font-weight: bolder; font-size: 1.1rem; }
-.deletion, .deletion > .editor { text-decoration: line-through; }
-
-.highlighted-diff { white-space: pre-wrap; }
-.diff-added { background-color: rgba(31, 171, 36, 0.6); color: rgba(23, 125, 27, 1); }
-.diff-removed { background-color: rgba(255, 96, 96, 0.6); color: rgba(191, 38, 38, 1); }
-
-.newpage::before { content: "N"; margin: 0 0.3em 0 -1em; font-weight: bolder; text-decoration: underline dotted; }
-.upload::before { content: "\\1f845"; margin: 0 0.1em 0 -1.1em; }
-
-footer { padding: 2rem; }
-/* #ffdb6d #36962c */
-THEMECSS;
+if(!file_exists("peppermint.json"))
+{
+	// Copy the default settings over to the main settings array
+	foreach ($guiConfig as $key => $value)
+		$settings->$key = $value->default
+	// Generate a random secret
+	$settings->secret = bin2hex(openssl_random_pseudo_bytes($bits));
+	file_put_contents("peppermint.json", json_encode($settings, JSON_PRETTY_PRINT));
+}
+else
+	$settings = json_decode(file_get_contents("peppermint.json"));
+
+if($settings->css === "auto")
+{
+	$settings->css = <<<THEMECSS
+	{defaults-css}
+	THEMECSS;
+}
 
 /*** Notes ***
 Actions:
@@ -511,6 +151,26 @@ if($env->is_logged_in)
 }
 /////// Login System End ///////
 
+////////////////////
+// APIDoc strings //
+////////////////////
+/**
+ * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+ */
+/**
+* @apiDefine User		Only users loggged in may use this call.
+*/
+/**
+* @apiDefine Anonymous	Anybody may use this call.
+*/
+/**
+ * @apiDefine UserNotLoggedInError
+ * @apiError	UserNotLoggedIn	You didn't log in before sending this request.
+ */
+
+
+////////////////////
+
 ///////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////// Functions //////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
@@ -1533,11 +1193,22 @@ if(!empty($settings->enable_math_rendering))
 
 register_module([
 	"name" => "Password hashing action",
-	"version" => "0.5",
+	"version" => "0.6",
 	"author" => "Starbeamrainbowlabs",
 	"description" => "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.",
 	"id" => "action-hash",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=hash&string={text} Hash a password
+		 * @apiName Hash
+		 * @apiGroup Utility
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	string	The string to hash.
+		 * @apiParam {boolean}	raw		Whether to return the hashed password as a raw string instead of as part of an HTML page.
+		 *
+		 * @apiError	ParamNotFound	The string parameter was not specified.
+		 */
 		
 		/*
 		 * ██   ██  █████  ███████ ██   ██ 
@@ -1546,7 +1217,6 @@ register_module([
 		 * ██   ██ ██   ██      ██ ██   ██ 
 		 * ██   ██ ██   ██ ███████ ██   ██
 		 */
-		
 		add_action("hash", function() {
 			global $settings;
 			
@@ -1556,6 +1226,11 @@ register_module([
 				exit(page_renderer::render_main("Missing parameter", "<p>The <code>GET</code> parameter <code>string</code> must be specified.</p>
 		<p>It is strongly recommended that you utilise this page via a private or incognito window in order to prevent your password from appearing in your browser history.</p>"));
 			}
+			else if(!empty($_GET["raw"]))
+			{
+				header("content-type: text/plain");
+				exit(hash_password($_GET["string"]));
+			}
 			else
 			{
 				exit(page_renderer::render_main("Hashed string", "<p>Algorithm: " . ($settings->use_sha3 ? "sha3" : "sha256") . "</p>\n<p><code>" . $_GET["string"] . "</code> → <code>" . hash_password($_GET["string"]) . "</code></p>"));
@@ -1574,6 +1249,14 @@ register_module([
 	"description" => "Exposes Pepperminty Wiki's new page protection mechanism and makes the protect button in the 'More...' menu on the top bar work.",
 	"id" => "action-protect",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=protect&page={pageName} Toggle the protection of a page.
+		 * @apiName Protect
+		 * @apiGroup Page
+		 * @apiPermission Moderator
+		 * 
+		 * @apiParam {string}	page	The page name to toggle the protection of.
+		 */
 		
 		/*
 		 * ██████  ██████   ██████  ████████ ███████  ██████ ████████ 
@@ -1630,6 +1313,14 @@ register_module([
 	"id" => "action-raw",
 	"code" => function() {
 		global $settings;
+		/**
+		 * @api {get} ?action=raw&page={pageName} Get the raw source code of a page
+		 * @apiName RawSource
+		 * @apiGroup Page
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page to return the source of.
+		 */
 		
 		/*
 		 * ██████   █████  ██     ██ 
@@ -1782,6 +1473,14 @@ register_module([
 	"description" => "Adds the ability to keep unlimited page history, limited only by your disk space. Note that this doesn't store file history (yet). Currently depends on feature-recent-changes for rendering of the history page.",
 	"id" => "feature-history",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=history&page={pageName} Get a list of revisions for a page
+		 * @apiName History
+		 * @apiGroup Page
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page name to return a revision list for.
+		 */
 		
 		/*
 		 * ██   ██ ██ ███████ ████████  ██████  ██████  ██    ██
@@ -1873,6 +1572,13 @@ register_module([
 	"id" => "feature-recent-changes",
 	"code" => function() {
 		global $settings, $env, $paths;
+		/**
+		 * @api {get} ?action=recentchanges Get a list of recent changes
+		 * @apiName RecentChanges
+		 * @apiGroup Stats
+		 * @apiPermission Anonymous
+		 */
+		
 		// Add the recent changes json file to $paths for convenience.
 		$paths->recentchanges = $env->storage_prefix . "recent-changes.json";
 		// Create the recent changes json file if it doesn't exist
@@ -2135,6 +1841,14 @@ register_module([
 	"description" => "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
 	"id" => "feature-search",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=index&page={pageName} Get an index of words for a given page
+		 * @apiName SearchIndex
+		 * @apiGroup Search
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page to generate a word index page.
+		 */
 		
 		/*
 		 * ██ ███    ██ ██████  ███████ ██   ██ 
@@ -2160,6 +1874,14 @@ register_module([
 			var_dump($index);
 		});
 		
+		/**
+		 * @api {get} ?action=invindex-rebuild Rebuild the inverted search index from scratch
+		 * @apiDescription	Causes the inverted search index to be completely rebuilt from scratch. Can take a while for large wikis!
+		 * @apiName			SearchInvindexRebuild
+		 * @apiGroup		Search
+		 * @apiPermission Anonymous
+		 */
+		
 		/*
 		 * ██ ███    ██ ██    ██ ██ ███    ██ ██████  ███████ ██   ██          
 		 * ██ ████   ██ ██    ██ ██ ████   ██ ██   ██ ██       ██ ██           
@@ -2177,6 +1899,15 @@ register_module([
 			search::rebuild_invindex();
 		});
 		
+		/**
+		 * @api {get} ?action=search&query={text}	Search the wiki for a given query string
+		 * @apiName Search
+		 * @apiGroup Search
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	query	The query string to search for.
+		 */
+		
 		/*
 		 * ███████ ███████  █████  ██████   ██████ ██   ██ 
 		 * ██      ██      ██   ██ ██   ██ ██      ██   ██ 
@@ -2665,6 +2396,22 @@ register_module([
 	"id" => "feature-upload",
 	"code" => function() {
 		global $settings;
+		/**
+		 * @api {get} ?action=upload Get a page to let you upload a file.
+		 * @apiName UploadFilePage
+		 * @apiGroup Upload
+	 */
+		
+ 		/**
+ 		 * @api {post} ?action=upload Upload a file
+ 		 * @apiName UploadFile
+ 		 * @apiGroup Upload
+ 		 * @apiPermission User
+ 		 *
+ 		 * @apiParam {file} file		The file to upload.
+ 		 *
+ 		 * @apiUse UserNotLoggedInError
+ 		 */
 		
 		/*
 		 * ██    ██ ██████  ██       ██████   █████  ██████  
diff --git a/core.php b/core.php
index 5e1f9cc..f61e964 100644
--- a/core.php
+++ b/core.php
@@ -84,6 +84,26 @@ if($env->is_logged_in)
 }
 /////// Login System End ///////
 
+////////////////////
+// APIDoc strings //
+////////////////////
+/**
+ * @apiDefine Moderator	Only users loggged with a moderator account may use this call.
+ */
+/**
+* @apiDefine User		Only users loggged in may use this call.
+*/
+/**
+* @apiDefine Anonymous	Anybody may use this call.
+*/
+/**
+ * @apiDefine UserNotLoggedInError
+ * @apiError	UserNotLoggedIn	You didn't log in before sending this request.
+ */
+
+
+////////////////////
+
 ///////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////// Functions //////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/module_index.json b/module_index.json
index 5bfad0d..c8a21d4 100644
--- a/module_index.json
+++ b/module_index.json
@@ -1,11 +1,11 @@
 [
     {
         "name": "Password hashing action",
-        "version": "0.5",
+        "version": "0.6",
         "author": "Starbeamrainbowlabs",
         "description": "Adds a utility action (that anyone can use) called hash that hashes a given string. Useful when changing a user's password.",
         "id": "action-hash",
-        "lastupdate": 1451133514,
+        "lastupdate": 1465757909,
         "optional": false
     },
     {
@@ -14,7 +14,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Exposes Pepperminty Wiki's new page protection mechanism and makes the protect button in the 'More...' menu on the top bar work.",
         "id": "action-protect",
-        "lastupdate": 1451133581,
+        "lastupdate": 1465751051,
         "optional": false
     },
     {
@@ -23,7 +23,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds a 'raw' action that shows you the raw source of a page.",
         "id": "action-raw",
-        "lastupdate": 1453559572,
+        "lastupdate": 1465757909,
         "optional": false
     },
     {
@@ -41,7 +41,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds the ability to keep unlimited page history, limited only by your disk space. Note that this doesn't store file history (yet). Currently depends on feature-recent-changes for rendering of the history page.",
         "id": "feature-history",
-        "lastupdate": 1465405521,
+        "lastupdate": 1465757909,
         "optional": false
     },
     {
@@ -50,7 +50,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds recent changes. Access through the 'recent-changes' action.",
         "id": "feature-recent-changes",
-        "lastupdate": 1465404004,
+        "lastupdate": 1465757910,
         "optional": false
     },
     {
@@ -68,7 +68,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
         "id": "feature-search",
-        "lastupdate": 1458824925,
+        "lastupdate": 1465757892,
         "optional": false
     },
     {
@@ -77,7 +77,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds the ability to upload files to Pepperminty Wiki. Uploaded files act as pages and have the special 'File\/' prefix.",
         "id": "feature-upload",
-        "lastupdate": 1465044942,
+        "lastupdate": 1465761247,
         "optional": false
     },
     {
diff --git a/modules/action-hash.php b/modules/action-hash.php
index 30fb53d..ecfbe48 100644
--- a/modules/action-hash.php
+++ b/modules/action-hash.php
@@ -10,8 +10,12 @@ register_module([
 		 * @api {get} ?action=hash&string={text} Hash a password
 		 * @apiName Hash
 		 * @apiGroup Utility
+		 * @apiPermission Anonymous
+		 * 
 		 * @apiParam {string}	string	The string to hash.
-		 * @apiParam {boolean}	raw		Wherher to return the hashed password as a raw string instead of as part of an HTML page.
+		 * @apiParam {boolean}	raw		Whether to return the hashed password as a raw string instead of as part of an HTML page.
+		 *
+		 * @apiError	ParamNotFound	The string parameter was not specified.
 		 */
 		
 		/*
diff --git a/modules/action-protect.php b/modules/action-protect.php
index 6b28259..927a11c 100644
--- a/modules/action-protect.php
+++ b/modules/action-protect.php
@@ -6,6 +6,14 @@ register_module([
 	"description" => "Exposes Pepperminty Wiki's new page protection mechanism and makes the protect button in the 'More...' menu on the top bar work.",
 	"id" => "action-protect",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=protect&page={pageName} Toggle the protection of a page.
+		 * @apiName Protect
+		 * @apiGroup Page
+		 * @apiPermission Moderator
+		 * 
+		 * @apiParam {string}	page	The page name to toggle the protection of.
+		 */
 		
 		/*
 		 * ██████  ██████   ██████  ████████ ███████  ██████ ████████ 
diff --git a/modules/action-raw.php b/modules/action-raw.php
index a21de3a..0999b9a 100644
--- a/modules/action-raw.php
+++ b/modules/action-raw.php
@@ -7,6 +7,14 @@ register_module([
 	"id" => "action-raw",
 	"code" => function() {
 		global $settings;
+		/**
+		 * @api {get} ?action=raw&page={pageName} Get the raw source code of a page
+		 * @apiName RawSource
+		 * @apiGroup Page
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page to return the source of.
+		 */
 		
 		/*
 		 * ██████   █████  ██     ██ 
diff --git a/modules/feature-history.php b/modules/feature-history.php
index a904361..0d61527 100644
--- a/modules/feature-history.php
+++ b/modules/feature-history.php
@@ -6,6 +6,14 @@ register_module([
 	"description" => "Adds the ability to keep unlimited page history, limited only by your disk space. Note that this doesn't store file history (yet). Currently depends on feature-recent-changes for rendering of the history page.",
 	"id" => "feature-history",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=history&page={pageName} Get a list of revisions for a page
+		 * @apiName History
+		 * @apiGroup Page
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page name to return a revision list for.
+		 */
 		
 		/*
 		 * ██   ██ ██ ███████ ████████  ██████  ██████  ██    ██
diff --git a/modules/feature-recent-changes.php b/modules/feature-recent-changes.php
index c3526fd..3138e58 100644
--- a/modules/feature-recent-changes.php
+++ b/modules/feature-recent-changes.php
@@ -7,6 +7,13 @@ register_module([
 	"id" => "feature-recent-changes",
 	"code" => function() {
 		global $settings, $env, $paths;
+		/**
+		 * @api {get} ?action=recentchanges Get a list of recent changes
+		 * @apiName RecentChanges
+		 * @apiGroup Stats
+		 * @apiPermission Anonymous
+		 */
+		
 		// Add the recent changes json file to $paths for convenience.
 		$paths->recentchanges = $env->storage_prefix . "recent-changes.json";
 		// Create the recent changes json file if it doesn't exist
diff --git a/modules/feature-search.php b/modules/feature-search.php
index 196d2b8..6305fc3 100644
--- a/modules/feature-search.php
+++ b/modules/feature-search.php
@@ -6,6 +6,14 @@ register_module([
 	"description" => "Adds proper search functionality to Pepperminty Wiki using an inverted index to provide a full text search engine. If pages don't show up, then you might have hit a stop word. If not, try requesting the `invindex-rebuild` action to rebuild the inverted index from scratch.",
 	"id" => "feature-search",
 	"code" => function() {
+		/**
+		 * @api {get} ?action=index&page={pageName} Get an index of words for a given page
+		 * @apiName SearchIndex
+		 * @apiGroup Search
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	page	The page to generate a word index page.
+		 */
 		
 		/*
 		 * ██ ███    ██ ██████  ███████ ██   ██ 
@@ -31,6 +39,14 @@ register_module([
 			var_dump($index);
 		});
 		
+		/**
+		 * @api {get} ?action=invindex-rebuild Rebuild the inverted search index from scratch
+		 * @apiDescription	Causes the inverted search index to be completely rebuilt from scratch. Can take a while for large wikis!
+		 * @apiName			SearchInvindexRebuild
+		 * @apiGroup		Search
+		 * @apiPermission Anonymous
+		 */
+		
 		/*
 		 * ██ ███    ██ ██    ██ ██ ███    ██ ██████  ███████ ██   ██          
 		 * ██ ████   ██ ██    ██ ██ ████   ██ ██   ██ ██       ██ ██           
@@ -48,6 +64,15 @@ register_module([
 			search::rebuild_invindex();
 		});
 		
+		/**
+		 * @api {get} ?action=search&query={text}	Search the wiki for a given query string
+		 * @apiName Search
+		 * @apiGroup Search
+		 * @apiPermission Anonymous
+		 * 
+		 * @apiParam {string}	query	The query string to search for.
+		 */
+		
 		/*
 		 * ███████ ███████  █████  ██████   ██████ ██   ██ 
 		 * ██      ██      ██   ██ ██   ██ ██      ██   ██ 
diff --git a/modules/feature-upload.php b/modules/feature-upload.php
index 80e6cde..88d6e87 100644
--- a/modules/feature-upload.php
+++ b/modules/feature-upload.php
@@ -7,6 +7,28 @@ register_module([
 	"id" => "feature-upload",
 	"code" => function() {
 		global $settings;
+		/**
+		 * @api {get} ?action=upload Get a page to let you upload a file.
+		 * @apiName UploadFilePage
+		 * @apiGroup Upload
+		*/
+		
+		/**
+		 * @api {post} ?action=upload Upload a file
+		 * @apiName UploadFile
+		 * @apiGroup Upload
+		 * @apiPermission User
+		 *
+		 * @apiParam {file} file		The file to upload.
+		 *
+		 * @apiUse	UserNotLoggedInError
+		 * @apiError	UploadsDisabledError	Uploads are currently disabled in the wiki's settings.
+		 * @apiError	UnknownFileTypeError	The type of the file you uploaded is not currently allowed in the wiki's settings.
+		 * @apiError	ImageDimensionsFiledError	PeppermintyWiki couldn't obtain the dimensions of the image you uploaded.
+		 * @apiError	DangerousFileError		The file uploaded appears to be dangerous.
+		 * @apiError	DuplicateFileError		The filename specified is a duplicate of a file that already exists.
+		 * @apiError	FileTamperedError		Pepperminty Wiki couldn't verify that the file wasn't tampered with during theupload process.
+		 */
 		
 		/*
 		 * ██    ██ ██████  ██       ██████   █████  ██████  
