Merge ssh://source.netsyms.com:2322/Business/BusinessAppTemplate

# Conflicts:
#	.gitignore
#	LICENSE.md
#	README.md
#	api.php
#	app.php
#	composer.json
#	composer.lock
#	lang/en_us.php
#	lib/login.php
#	lib/userinfo.php
#	mobile/index.php
#	pages.php
#	pages/404.php
#	required.php
#	settings.template.php
#	static/css/app.css
#	static/img/logo.png
#	static/js/app.js
This commit is contained in:
Skylar Ittner 2018-04-08 16:49:59 -06:00
commit c99b739532
16 changed files with 188 additions and 36 deletions

2
.gitignore vendored
View File

@ -2,4 +2,4 @@ vendor
settings.php
nbproject/private
database.mwb.bak
*.sync-conflict*
*.sync-conflict*

View File

@ -1,18 +1,18 @@
Copyright (c) 2017 Netsyms Technologies.
Copyright (c) 2018 Netsyms Technologies.
If you modify and redistribute this project, you must replace the branding
If you modify and redistribute this project, you must replace the branding
assets with your own.
The branding assets include:
The branding assets include:
* the application icon
* the Netsyms N punchcard logo
* the Netsyms for Business graph logo
If you are unsure if your usage is allowed, please contact us:
If you are unsure if your usage is allowed, please contact us:
https://netsyms.com/contact
legal@netsyms.com
All other portions of this application,
All other portions of this application,
unless otherwise noted (in comments, headers, etc), are licensed as follows:
Mozilla Public License Version 2.0
@ -20,24 +20,24 @@ Mozilla Public License Version 2.0
### 1. Definitions
**1.1. “Contributor”**
**1.1. “Contributor”**
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
**1.2. “Contributor Version”**
**1.2. “Contributor Version”**
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
**1.3. “Contribution”**
**1.3. “Contribution”**
means Covered Software of a particular Contributor.
**1.4. “Covered Software”**
**1.4. “Covered Software”**
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
**1.5. “Incompatible With Secondary Licenses”**
**1.5. “Incompatible With Secondary Licenses”**
means
* **(a)** that the initial Contributor has attached the notice described
@ -46,22 +46,22 @@ Mozilla Public License Version 2.0
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
**1.6. “Executable Form”**
**1.6. “Executable Form”**
means any form of the work other than Source Code Form.
**1.7. “Larger Work”**
means a work that combines Covered Software with other material, in
**1.7. “Larger Work”**
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
**1.8. “License”**
**1.8. “License”**
means this document.
**1.9. “Licensable”**
**1.9. “Licensable”**
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
**1.10. “Modifications”**
**1.10. “Modifications”**
means any of the following:
* **(a)** any file in Source Code Form that results from an addition to,
@ -70,7 +70,7 @@ Mozilla Public License Version 2.0
* **(b)** any new file in Source Code Form that contains any Covered
Software.
**1.11. “Patent Claims” of a Contributor**
**1.11. “Patent Claims” of a Contributor**
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
@ -78,16 +78,16 @@ Mozilla Public License Version 2.0
made, import, or transfer of either its Contributions or its
Contributor Version.
**1.12. “Secondary License”**
**1.12. “Secondary License”**
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
**1.13. “Source Code Form”**
**1.13. “Source Code Form”**
means the form of the work preferred for making modifications.
**1.14. “You” (or “Your”)**
**1.14. “You” (or “Your”)**
means an individual or a legal entity exercising rights under this
License. For legal entities, “You” includes any entity that
controls, is controlled by, or is under common control with You. For

View File

@ -17,6 +17,12 @@ if ($VARS['action'] !== "signout") {
dieifnotloggedin();
}
/**
* Redirects back to the page ID in $_POST/$_GET['source'] with the given message ID.
* The message will be displayed by the app.
* @param string $msg message ID (see lang/messages.php)
* @param string $arg If set, replaces "{arg}" in the message string when displayed to the user.
*/
function returnToSender($msg, $arg = "") {
global $VARS;
if ($arg == "") {

View File

@ -165,4 +165,4 @@ switch ($VARS['action']) {
default:
header("HTTP/1.1 400 Bad Request");
die("\"400 Bad Request\"");
}
}

10
app.php
View File

@ -18,6 +18,12 @@ if (!is_empty($_GET['page'])) {
$pageid = "404";
}
}
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
header("Link: <static/css/app.css>; rel=preload; as=style", false);
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
?>
<!DOCTYPE html>
<html>
@ -43,6 +49,7 @@ if (!is_empty($_GET['page'])) {
if (isset(PAGES[$pageid]['styles'])) {
foreach (PAGES[$pageid]['styles'] as $style) {
echo "<link href=\"$style\" rel=\"stylesheet\">\n";
header("Link: <$style>; rel=preload; as=style", false);
}
}
?>
@ -169,8 +176,9 @@ END;
if (isset(PAGES[$pageid]['scripts'])) {
foreach (PAGES[$pageid]['scripts'] as $script) {
echo "<script src=\"$script\"></script>\n";
header("Link: <$script>; rel=preload; as=script", false);
}
}
?>
</body>
</html>
</html>

View File

@ -72,6 +72,11 @@ if (checkLoginServer()) {
} else {
$alert = lang("login server unavailable", false);
}
header("Link: <static/css/bootstrap.min.css>; rel=preload; as=style", false);
header("Link: <static/css/material-color/material-color.min.css>; rel=preload; as=style", false);
header("Link: <static/css/index.css>; rel=preload; as=style", false);
header("Link: <static/js/jquery-3.3.1.min.js>; rel=preload; as=script", false);
header("Link: <static/js/bootstrap.min.js>; rel=preload; as=script", false);
?>
<!DOCTYPE html>
<html>

View File

@ -82,4 +82,4 @@ define("STRINGS", [
"finished on" => "Finished on: {date}",
"started on" => "Started on: {date}",
"add task" => "Add Task"
]);
]);

127
lib/iputils.php Normal file
View File

@ -0,0 +1,127 @@
<?php
/**
* 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>
*/
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>
*/
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
*/
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
*/
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
}

View File

@ -6,7 +6,7 @@
/**
* Authentication and account functions. Connects to a Portal instance.
* Authentication and account functions. Connects to an AccountHub instance.
*/
/**

View File

@ -124,4 +124,4 @@ function getManagedUIDs($manageruid) {
} else {
return [];
}
}
}

View File

@ -9,6 +9,10 @@
* Mobile app API
*/
// The name of the permission needed to log in.
// Set to null if you don't need it.
$access_permission = "TASKFLOOR";
require __DIR__ . "/../required.php";
require __DIR__ . "/../lib/login.php";
@ -93,7 +97,7 @@ switch ($VARS['action']) {
if (user_exists($VARS['username'])) {
if (get_account_status($VARS['username']) == "NORMAL") {
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
if (account_has_permission($VARS['username'], "TASKFLOOR")) {
if (is_null($access_permission) || account_has_permission($VARS['username'], $access_permission)) {
doLoginUser($VARS['username'], $VARS['password']);
$_SESSION['mobile'] = true;
exit(json_encode(["status" => "OK"]));
@ -107,4 +111,4 @@ switch ($VARS['action']) {
default:
http_response_code(404);
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
}
}

View File

@ -9,4 +9,4 @@
<div class="col-12 col-sm-6 col-md-4 col-lg-4">
<div class="alert alert-warning"><b><?php lang("404 error");?></b><br /> <?php lang("page not found"); ?></div>
</div>
</div>
</div>

View File

@ -12,10 +12,12 @@ ob_start(); // allow sending headers after content
// 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));
@ -80,7 +82,7 @@ function sendError($error) {
. "<h1>A fatal application error has occurred.</h1>"
. "<i>(This isn't your fault.)</i>"
. "<h2>Details:</h2>"
. "<p>". htmlspecialchars($error) . "</p>");
. "<p>" . htmlspecialchars($error) . "</p>");
}
date_default_timezone_set(TIMEZONE);

View File

@ -57,4 +57,4 @@ define('LANGUAGE', "en_us");
define("FOOTER_TEXT", "");
define("COPYRIGHT_NAME", "Netsyms Technologies");
define("COPYRIGHT_NAME", "Netsyms Technologies");

View File

@ -122,4 +122,4 @@ body {
.easy-autocomplete input {
border-radius: 0px !important;
}
}

View File

@ -11,7 +11,7 @@ function setupTooltips() {
$(document).ready(function () {
/* Fade out alerts */
$(".alert .close").click(function (e) {
$(this).parent().fadeOut('slow');
$(this).parent().fadeOut("slow");
});
/* Activate tooltips */
@ -31,4 +31,4 @@ try {
window.history.replaceState("", "", getniceurl());
} catch (ex) {
}
}