devshort

private self-hosted shortlink service
git clone https://git.clttr.info/devshort.git
Log (Feed) | Files | Refs (Tags) | README | LICENSE

commit b5d982065d5af11fc1f5f08a552d6161ce228059
parent a7bbc7d0b1df1fee5f84448a2eb4ae2f21e5228e
Author: Florian <flokX@users.noreply.github.com>
Date:   Wed,  2 Jan 2019 16:51:57 +0100

Initial commit
Diffstat:
A.htaccess | 23+++++++++++++++++++++++
Ainstaller.php | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aredirect.php | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 226 insertions(+), 0 deletions(-)

diff --git a/.htaccess b/.htaccess @@ -0,0 +1,22 @@ +# Headers + +# Only connect to this site and subdomains via HTTPS for the next two years +# If your page have no https enabled, comment this line. +Header set Strict-Transport-Security: "max-age=63072000; includeSubDomains" + +# Send only the domain as referrer +Header set Referrer-Policy: "strict-origin" + +# Prevent browsers from incorrectly detecting non-scripts as scripts +Header set X-Content-Type-Options: "nosniff" + +# Block site from being framed with X-Frame-Options +Header set X-Frame-Options: "DENY" + +# Block pages from loading when they detect reflected XSS attacks +Header set X-XSS-Protection: "1; mode=block" + +# Other + +# Disable directory indexing +Options -Indexes +\ No newline at end of file diff --git a/installer.php b/installer.php @@ -0,0 +1,111 @@ +<?php + +// All relevant changes can be made in the data file. Please read the docs: https://github.com/flokX/devShort/wiki + +$success = false; +$data_path = implode(DIRECTORY_SEPARATOR, array(__DIR__, "secure", "config.json")); +$data = json_decode(file_get_contents($data_path), true); + +if ($data["installer"]["password"]) { + + // Create root .htaccess with the rewrite rules + $installation_path = rtrim($_SERVER["REQUEST_URI"], "installer.php"); + $root_htaccess = " + +# The entrys below were set by the installer. + +# Rewrite rule to get the short URLs +RewriteEngine On +RewriteBase $installation_path +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule ^(.*)$ {$installation_path}redirect.php?short=$1 [R=301,L]"; + file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . ".htaccess", $root_htaccess, FILE_APPEND); + + // Create the .htpasswd for the secure directory. If already a hashed password is there, copy it. + $htpasswd_path = implode(DIRECTORY_SEPARATOR, array(__DIR__, "secure", ".htpasswd")); + $data_password = $data["installer"]["password"]; + if (password_get_info($data_password)["algo"] === 0) { + $hash = password_hash($data_password, PASSWORD_DEFAULT); + } else { + $hash = $data_password; + } + file_put_contents($htpasswd_path, $data["installer"]["username"] . ":" . $hash); + + // Create the .htaccess for the secure directory. + $secure_htaccess = "# Authentication +AuthType Basic +AuthName \"devShort admin area\" +AuthUserFile $htpasswd_path +require valid-user"; + file_put_contents(implode(DIRECTORY_SEPARATOR, array(__DIR__, "secure", ".htaccess")), $secure_htaccess); + + // Change password entry to the hash and remove installer file. + $data["installer"]["password"] = $hash; + file_put_contents($data_path, json_encode($data, JSON_PRETTY_PRINT)); + unlink(__DIR__ . DIRECTORY_SEPARATOR . "installer.php"); + $success = true; +} + +// Generator for page customization +$links_string = ""; +if ($data["settings"]["custom_links"]) { + foreach ($data["settings"]["custom_links"] as $name => $url) { + $links_string = $links_string . "<a href=\"$url\" class=\"badge badge-secondary\">$name</a> "; + } + $links_string = substr($links_string, 0, -1); +} + +?> + +<!doctype html> +<html lang="en" class="h-100"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="robots" content="noindex, nofollow"> + <meta name="author" content="<?php echo $data["settings"]["author"]; ?> and the devShort team"> + <link rel="icon" href="<?php echo $data["settings"]["favicon"]; ?>"> + <title>Installer | <?php echo $data["settings"]["name"]; ?></title> + <link href="assets/vendor/bootstrap/bootstrap.min.css" rel="stylesheet"> + <link href="assets/main.min.css" rel="stylesheet"> +</head> + +<body class="d-flex flex-column h-100"> + + <main role="main" class="flex-shrink-0"> + <div class="container"> + <nav class="mt-3" aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a href="<?php echo $data["settings"]["home_link"]; ?>">Home</a></li> + <li class="breadcrumb-item"><?php echo $data["settings"]["name"]; ?></li> + <li class="breadcrumb-item active" aria-current="page">Installer</li> + </ol> + </nav> + <?php + + if ($success) { + echo "<h1 class=\"mt-5\">Successful installed!</h1> +<p class=\"lead\">Now you can start the link shortening. For more information visit the <a href=\"https://github.com/flokx/devShort/wiki\">devShort wiki</a>.</p>"; + } else { + echo "<h1 class=\"mt-5\">Error while installing.</h1> +<p class=\"lead\">Please configure the <i>config.json</i> as written in the <a href=\"https://github.com/flokx/devShort/wiki/Installation\">devShort wiki</a>.</p>"; + } + + ?> + </div> + </main> + + <footer class="footer mt-auto py-3"> + <div class="container"> + <div class="d-flex justify-content-between align-items-center"> + <span class="text-muted">&copy; <?php echo date("Y") . " " . $data["settings"]["author"]; ?> and <a href="https://github.com/flokx/devShort">devShort</a></span> + <?php if ($links_string) { echo "<span class=\"text-muted\">$links_string</span>"; } ?> + </div> + </div> + </footer> + +</body> + +</html> +\ No newline at end of file diff --git a/redirect.php b/redirect.php @@ -0,0 +1,90 @@ +<?php + +// All relevant changes can be made in the data file. Please read the docs: https://github.com/flokX/devShort/wiki + +$short = htmlspecialchars($_GET["short"]); + +// If the robots.txt is requested, return it +if ($short === "robots.txt") { + header("Content-Type: text/plain; charset=utf-8"); + echo "User-agent: *\n"; + echo "Disallow: /\n"; + exit; +} else if ($short === 'favicon.ico') { + header("HTTP/1.1 404 Not Found"); + exit; +} + +// Counts the access to the given $name +function count_access($base_path, $name) { + $filename = $base_path . DIRECTORY_SEPARATOR . "stats.json"; + $stats = json_decode(file_get_contents($filename), true); + $stats[$name][date("Y-m-d")] += 1; + file_put_contents($filename, json_encode($stats)); +} + +$base_path = implode(DIRECTORY_SEPARATOR, array(__DIR__, "secure")); +$data = json_decode(file_get_contents($base_path . DIRECTORY_SEPARATOR . "configjson"), true); + +if (array_key_exists($short, $data["shortlinks"])) { + header("Location: " . $data["shortlinks"][$short], $http_response_code=303); + count_access($base_path, $short); + exit; +} else { + header("HTTP/1.1 404 Not Found"); + count_access($base_path, "404 request"); + + // Generator for page customization + $links_string = ""; + if ($data["settings"]["custom_links"]) { + foreach ($data["settings"]["custom_links"] as $name => $url) { + $links_string = $links_string . "<a href=\"$url\" class=\"badge badge-secondary\">$name</a> "; + } + $links_string = substr($links_string, 0, -1); + } +} + +?> + +<!doctype html> +<html lang="en" class="h-100"> + +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="robots" content="noindex, nofollow"> + <meta name="author" content="<?php echo $data["settings"]["author"]; ?> and the devShort team"> + <link rel="icon" href="<?php echo $data["settings"]["favicon"]; ?>"> + <title>404 | <?php echo $data["settings"]["name"]; ?></title> + <link href="assets/vendor/bootstrap/bootstrap.min.css" rel="stylesheet"> + <link href="assets/main.min.css" rel="stylesheet"> +</head> + +<body class="d-flex flex-column h-100"> + + <main role="main" class="flex-shrink-0"> + <div class="container"> + <nav class="mt-3" aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a href="<?php echo $data["settings"]["home_link"]; ?>">Home</a></li> + <li class="breadcrumb-item"><?php echo $data["settings"]["name"]; ?></li> + <li class="breadcrumb-item active" aria-current="page">404</li> + </ol> + </nav> + <h1 class="mt-5">404 | Shortlink Not Found.</h1> + <p class="lead">The requested shortlink <i><?php echo $short; ?></i> was not found on this server. It was either deleted, expired, misspelled, or eaten by a monster.</p> + </div> + </main> + + <footer class="footer mt-auto py-3"> + <div class="container"> + <div class="d-flex justify-content-between align-items-center"> + <span class="text-muted">&copy; <?php echo date("Y") . " " . $data["settings"]["author"]; ?> and <a href="https://github.com/flokx/devShort">devShort</a></span> + <?php if ($links_string) { echo "<span class=\"text-muted\">$links_string</span>"; } ?> + </div> + </div> + </footer> + +</body> + +</html> +\ No newline at end of file