Browse Source

Merge BusinessAppTemplate

# Conflicts:
#	.gitignore
#	README.md
#	action.php
#	api.php
#	app.php
#	composer.json
#	composer.lock
#	index.php
#	langs/en/core.json
#	langs/en/titles.json
#	langs/messages.php
#	lib/Exceptions.lib.php
#	lib/Login.lib.php
#	lib/Notifications.lib.php
#	lib/Strings.lib.php
#	lib/User.lib.php
#	mobile/index.php
#	nbproject/project.properties
#	nbproject/project.xml
#	pages.php
#	pages/home.php
#	required.php
#	settings.template.php
#	static/css/bootstrap.min.css
#	static/img/logo.svg
#	static/js/app.js
master
Skylar Ittner 10 months ago
parent
commit
f1f682780c
16 changed files with 264 additions and 22 deletions
  1. 1
    1
      .gitignore
  2. 1
    1
      action.php
  3. 1
    1
      api.php
  4. 1
    1
      app.php
  5. BIN
      database.mwb
  6. 1
    1
      lib/Exceptions.lib.php
  7. 135
    0
      lib/IPUtils.lib.php
  8. 4
    0
      lib/Strings.lib.php
  9. 1
    1
      mobile/index.php
  10. 1
    1
      pages/home.php
  11. 19
    12
      required.php
  12. 1
    1
      settings.template.php
  13. 1
    1
      static/css/bootstrap.min.css
  14. BIN
      static/img/logo.png
  15. 1
    1
      static/js/app.js
  16. 96
    0
      tests/User.test.php

+ 1
- 1
.gitignore View File

@@ -4,4 +4,4 @@
/nbproject/private
*.sync-conflict*
test*
/conf/
/conf/

+ 1
- 1
action.php View File

@@ -117,4 +117,4 @@ switch ($VARS['action']) {
$database->delete('userkeys', ['AND' => ['uid' => $_SESSION['uid'], 'typeid' => 1]]);
returnToSender("feed_key_reset");
break;
}
}

+ 1
- 1
api.php View File

@@ -439,4 +439,4 @@ switch ($VARS['action']) {
default:
http_response_code(404);
die(json_encode("404 Not Found: the requested action is not available."));
}
}

+ 1
- 1
app.php View File

@@ -194,4 +194,4 @@ END;
}
?>
</body>
</html>
</html>

BIN
database.mwb View File


+ 1
- 1
lib/Exceptions.lib.php View File

@@ -32,4 +32,4 @@ class PasswordMismatchException extends Exception {
parent::__construct($message, $code, $previous);
}

}
}

+ 135
- 0
lib/IPUtils.lib.php View File

@@ -0,0 +1,135 @@
<?php

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

class IPUtils {

/**
* Check if a given ipv4 address is in a given cidr
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
* @return boolean true if the ip is in this range / false if not.
* @author Thorsten Ott <https://gist.github.com/tott/7684443>
*/
public static function ip4_in_cidr($ip, $cidr) {
if (strpos($cidr, '/') == false) {
$cidr .= '/32';
}
// $range is in IP/CIDR format eg 127.0.0.1/24
list( $cidr, $netmask ) = explode('/', $cidr, 2);
$range_decimal = ip2long($cidr);
$ip_decimal = ip2long($ip);
$wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
$netmask_decimal = ~ $wildcard_decimal;
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
}

/**
* Check if a given ipv6 address is in a given cidr
* @param string $ip IP to check in IPV6 format
* @param string $cidr CIDR netmask
* @return boolean true if the IP is in this range, false otherwise.
* @author MW. <https://stackoverflow.com/a/7952169>
*/
public static function ip6_in_cidr($ip, $cidr) {
$address = inet_pton($ip);
$subnetAddress = inet_pton(explode("/", $cidr)[0]);
$subnetMask = explode("/", $cidr)[1];

$addr = str_repeat("f", $subnetMask / 4);
switch ($subnetMask % 4) {
case 0:
break;
case 1:
$addr .= "8";
break;
case 2:
$addr .= "c";
break;
case 3:
$addr .= "e";
break;
}
$addr = str_pad($addr, 32, '0');
$addr = pack("H*", $addr);

$binMask = $addr;
return ($address & $binMask) == $subnetAddress;
}

/**
* Check if the REMOTE_ADDR is on Cloudflare's network.
* @return boolean true if it is, otherwise false
*/
public static function validateCloudflare() {
if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
// Using IPv6
$cloudflare_ips_v6 = [
"2400:cb00::/32",
"2405:8100::/32",
"2405:b500::/32",
"2606:4700::/32",
"2803:f800::/32",
"2c0f:f248::/32",
"2a06:98c0::/29"
];
$valid = false;
foreach ($cloudflare_ips_v6 as $cidr) {
if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
$valid = true;
break;
}
}
} else {
// Using IPv4
$cloudflare_ips_v4 = [
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"104.16.0.0/12",
"108.162.192.0/18",
"131.0.72.0/22",
"141.101.64.0/18",
"162.158.0.0/15",
"172.64.0.0/13",
"173.245.48.0/20",
"188.114.96.0/20",
"190.93.240.0/20",
"197.234.240.0/22",
"198.41.128.0/17"
];
$valid = false;
foreach ($cloudflare_ips_v4 as $cidr) {
if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
$valid = true;
break;
}
}
}
return $valid;
}

/**
* Makes a good guess at the client's real IP address.
*
* @return string Client IP or `0.0.0.0` if we can't find anything
*/
public static function getClientIP() {
// If CloudFlare is in the mix, we should use it.
// Check if the request is actually from CloudFlare before trusting it.
if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
if (validateCloudflare()) {
return $_SERVER["HTTP_CF_CONNECTING_IP"];
}
}

if (isset($_SERVER["REMOTE_ADDR"])) {
return $_SERVER["REMOTE_ADDR"];
}

return "0.0.0.0"; // This will not happen unless we aren't a web server
}

}

+ 4
- 0
lib/Strings.lib.php View File

@@ -21,6 +21,10 @@ class Strings {

$this->load("en");

if ($language == "en") {
return;
}

if (file_exists(__DIR__ . "/../langs/$language/")) {
$this->language = $language;
$this->load($language);

+ 1
- 1
mobile/index.php View File

@@ -241,4 +241,4 @@ switch ($VARS['action']) {
default:
http_response_code(404);
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
}
}

+ 1
- 1
pages/home.php View File

@@ -153,4 +153,4 @@
<?php
}
?>
</div>
</div>

+ 19
- 12
required.php View File

@@ -8,31 +8,30 @@
* This file contains global settings and utility functions.
*/
ob_start(); // allow sending headers after content
//
// Composer
require __DIR__ . '/vendor/autoload.php';

// Settings file
require __DIR__ . '/settings.php';

// Unicode, solves almost all stupid encoding problems
header('Content-Type: text/html; charset=utf-8');

// l33t $ecurity h4x
// Strip PHP version
header('X-Powered-By: PHP');

// Security
header('X-Content-Type-Options: nosniff');
header('X-XSS-Protection: 1; mode=block');
header('X-Powered-By: PHP'); // no versions makes it harder to find vulns
header('X-Frame-Options: "DENY"');
header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
$SECURE_NONCE = base64_encode(random_bytes(8));


$session_length = 60 * 60; // 1 hour
$session_length = 60 * 60 * 1; // 1 hour
ini_set('session.gc_maxlifetime', $session_length);
session_set_cookie_params($session_length, "/", null, false, false);

session_start(); // stick some cookies in it
//// renew session cookie
setcookie(session_name(), session_id(), time() + $session_length);
// renew session cookie
setcookie(session_name(), session_id(), time() + $session_length, "/", false, false);

$captcha_server = (CAPTCHA_ENABLED === true ? preg_replace("/http(s)?:\/\//", "", CAPTCHA_SERVER) : "");
if ($_SESSION['mobile'] === TRUE) {
@@ -44,7 +43,7 @@ if ($_SESSION['mobile'] === TRUE) {
. "frame-src 'none'; "
. "font-src 'self'; "
. "connect-src *; "
. "style-src 'self' 'unsafe-inline'; "
. "style-src 'self' 'unsafe-inline' $captcha_server; "
. "script-src 'self' 'unsafe-inline' $captcha_server");
} else {
header("Content-Security-Policy: "
@@ -55,10 +54,14 @@ if ($_SESSION['mobile'] === TRUE) {
. "frame-src 'none'; "
. "font-src 'self'; "
. "connect-src *; "
. "style-src 'self' 'nonce-$SECURE_NONCE'; "
. "style-src 'self' 'nonce-$SECURE_NONCE' $captcha_server; "
. "script-src 'self' 'nonce-$SECURE_NONCE' $captcha_server");
}

//
// Composer
require __DIR__ . '/vendor/autoload.php';

// List of alert messages
require __DIR__ . '/langs/messages.php';

@@ -69,6 +72,10 @@ foreach ($libs as $lib) {

$Strings = new Strings(LANGUAGE);

/**
* Kill off the running process and spit out an error message
* @param string $error error message
*/
function sendError($error) {
global $SECURE_NONCE;
die("<!DOCTYPE html>"
@@ -379,4 +386,4 @@ function engageRateLimit() {
// Add a record for the IP address
$database->insert('rate_limit', ["ipaddr" => getClientIP(), "lastaction" => date("Y-m-d H:i:s")]);
}
}
}

+ 1
- 1
settings.template.php View File

@@ -166,4 +166,4 @@ define("QUERY_LIMIT", 1000);

define("FOOTER_TEXT", "");
define("COPYRIGHT_NAME", "Netsyms Technologies");
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

+ 1
- 1
static/css/bootstrap.min.css
File diff suppressed because it is too large
View File


BIN
static/img/logo.png View File


+ 1
- 1
static/js/app.js View File

@@ -80,4 +80,4 @@ try {
window.history.replaceState("", "", getniceurl());
} catch (ex) {

}
}

+ 96
- 0
tests/User.test.php View File

@@ -0,0 +1,96 @@
<?php

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

// Fill these in with valid credentials for an account with NORMAL status
$valid_user = "";
$valid_pass = "";

require __DIR__ . "/../required.php";
error_reporting(E_ALL);
ini_set('display_errors', 'On');
header("Content-Type: text/plain");

// Test invalid user responses

$user = new User(784587254);
if ($user->exists()) {
echo "FAIL: Invalid user ID marked as existing\n";
} else {
echo "OK\n";
}
if ($user->getUID() != 784587254) {
echo "FAIL: Invalid user has mismatched UID\n";
} else {
echo "OK\n";
}

$user = User::byUsername("r9483yt8934t");
if ($user->exists()) {
echo "FAIL: Invalid username marked as existing\n";
} else {
echo "OK\n";
}

if ($user->checkPassword("gbirg4wre") != false) {
echo "FAIL: Invalid user and invalid password allowed\n";
} else {
echo "OK\n";
}

if ($user->has2fa() != false) {
echo "FAIL: Invalid user has 2fa\n";
} else {
echo "OK\n";
}

if ($user->getUsername() != "r9483yt8934t") {
echo "FAIL: Invalid user has mismatched username\n";
} else {
echo "OK\n";
}

if ($user->getStatus()->get() != 0) {
echo "FAIL: Invalid user has real account status\n";
} else {
echo "OK\n";
}

if ($user->getStatus()->getString() != "OTHER_0") {
echo "FAIL: Invalid user has wrong account status string\n";
} else {
echo "OK\n";
}

// Test valid user responses

$user = User::byUsername($valid_user);
if (!$user->exists()) {
echo "FAIL: Valid user does not exist\n";
} else {
echo "OK\n";
}

if ($user->checkPassword($valid_pass) !== true) {
echo "FAIL: Valid user and password not allowed\n";
} else {
echo "OK\n";
}

if ($user->getUsername() != $valid_user) {
echo "FAIL: Valid user has mismatched username\n";
} else {
echo "OK\n";
}

if ($user->getStatus()->getString() != "NORMAL") {
echo "FAIL: Valid user has wrong account status string\n";
} else {
echo "OK\n";
}

exit("ALL OK");

Loading…
Cancel
Save