Merge ssh://source.netsyms.com:2322/Business/BusinessAppTemplate
# Conflicts: # .gitignore # README.md # action.php # api.php # app.php # composer.json # composer.lock # index.php # lang/en_us.php # lang/messages.php # lib/login.php # lib/userinfo.php # mobile/index.php # nbproject/project.properties # nbproject/project.xml # pages.php # pages/404.php # pages/home.php # required.php # settings.template.php # static/css/app.css # static/img/logo.png # static/img/logo.svg # static/js/app.js
This commit is contained in:
commit
0593f4c6d4
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,4 +2,4 @@ vendor
|
|||||||
settings.php
|
settings.php
|
||||||
nbproject/private
|
nbproject/private
|
||||||
database.mwb.bak
|
database.mwb.bak
|
||||||
*.sync-conflict*
|
*.sync-conflict*
|
||||||
|
18
README.md
18
README.md
@ -1,7 +1,7 @@
|
|||||||
BinStack
|
BinStack
|
||||||
========
|
========
|
||||||
|
|
||||||
BinStack is the easy way to keep track of your business assets.
|
BinStack is the easy way to keep track of your business assets.
|
||||||
Never wander in search of the stapler again.
|
Never wander in search of the stapler again.
|
||||||
|
|
||||||
https://netsyms.biz/apps/binstack
|
https://netsyms.biz/apps/binstack
|
||||||
@ -9,20 +9,20 @@ https://netsyms.biz/apps/binstack
|
|||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
**Asset Tracking**
|
**Asset Tracking**
|
||||||
Easily manage locations, tag numbers, assigned users, and other important item
|
Easily manage locations, tag numbers, assigned users, and other important item
|
||||||
properties.
|
properties.
|
||||||
|
|
||||||
**Fully Searchable**
|
**Fully Searchable**
|
||||||
Start typing in the search box to instantly filter hundreds of results down to
|
Start typing in the search box to instantly filter hundreds of results down to
|
||||||
only a few. Sorting also built in.
|
only a few. Sorting also built in.
|
||||||
|
|
||||||
**Autofill**
|
**Autofill**
|
||||||
You don't need to remember category codes or usernames. Just start typing and
|
You don't need to remember category codes or usernames. Just start typing and
|
||||||
BinStack will figure out what you're looking for.
|
BinStack will figure out what you're looking for.
|
||||||
|
|
||||||
**Mobile-ready**
|
**Mobile-ready**
|
||||||
Take inventory or find what you need on the go. BinStack looks and works
|
Take inventory or find what you need on the go. BinStack looks and works
|
||||||
great on modern smartphones and tablets.
|
great on modern smartphones and tablets.
|
||||||
|
|
||||||
Installing
|
Installing
|
||||||
|
@ -223,4 +223,4 @@ switch ($VARS['action']) {
|
|||||||
session_destroy();
|
session_destroy();
|
||||||
header('Location: index.php');
|
header('Location: index.php');
|
||||||
die("Logged out.");
|
die("Logged out.");
|
||||||
}
|
}
|
||||||
|
2
api.php
2
api.php
@ -38,4 +38,4 @@ switch ($VARS['action']) {
|
|||||||
default:
|
default:
|
||||||
header("HTTP/1.1 400 Bad Request");
|
header("HTTP/1.1 400 Bad Request");
|
||||||
die("\"400 Bad Request\"");
|
die("\"400 Bad Request\"");
|
||||||
}
|
}
|
||||||
|
10
app.php
10
app.php
@ -18,6 +18,12 @@ if (!is_empty($_GET['page'])) {
|
|||||||
$pageid = "404";
|
$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>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@ -43,6 +49,7 @@ if (!is_empty($_GET['page'])) {
|
|||||||
if (isset(PAGES[$pageid]['styles'])) {
|
if (isset(PAGES[$pageid]['styles'])) {
|
||||||
foreach (PAGES[$pageid]['styles'] as $style) {
|
foreach (PAGES[$pageid]['styles'] as $style) {
|
||||||
echo "<link href=\"$style\" rel=\"stylesheet\">\n";
|
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'])) {
|
if (isset(PAGES[$pageid]['scripts'])) {
|
||||||
foreach (PAGES[$pageid]['scripts'] as $script) {
|
foreach (PAGES[$pageid]['scripts'] as $script) {
|
||||||
echo "<script src=\"$script\"></script>\n";
|
echo "<script src=\"$script\"></script>\n";
|
||||||
|
header("Link: <$script>; rel=preload; as=script", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -72,6 +72,11 @@ if (checkLoginServer()) {
|
|||||||
} else {
|
} else {
|
||||||
$alert = lang("login server unavailable", false);
|
$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>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@ -147,4 +152,4 @@ if (checkLoginServer()) {
|
|||||||
<script src="static/js/jquery-3.3.1.min.js"></script>
|
<script src="static/js/jquery-3.3.1.min.js"></script>
|
||||||
<script src="static/js/bootstrap.min.js"></script>
|
<script src="static/js/bootstrap.min.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
127
lib/iputils.php
Normal file
127
lib/iputils.php
Normal 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/2534036>
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
}
|
@ -40,6 +40,33 @@ function checkLoginServer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given AccountHub API key is valid by attempting to
|
||||||
|
* access the API with it.
|
||||||
|
* @param String $key The API key to check
|
||||||
|
* @return boolean TRUE if the key is valid, FALSE if invalid or something went wrong
|
||||||
|
*/
|
||||||
|
function checkAPIKey($key) {
|
||||||
|
try {
|
||||||
|
$client = new GuzzleHttp\Client();
|
||||||
|
|
||||||
|
$response = $client
|
||||||
|
->request('POST', PORTAL_API, [
|
||||||
|
'form_params' => [
|
||||||
|
'key' => $key,
|
||||||
|
'action' => "ping"
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->getStatusCode() === 200) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Account handling //
|
// Account handling //
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -124,4 +124,4 @@ function getManagedUIDs($manageruid) {
|
|||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<?php
|
<?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/. */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mobile app API
|
* Mobile app API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// The name of the permission needed to log in.
|
||||||
|
// Set to null if you don't need it.
|
||||||
|
$access_permission = "INV_VIEW";
|
||||||
|
|
||||||
require __DIR__ . "/../required.php";
|
require __DIR__ . "/../required.php";
|
||||||
|
|
||||||
require __DIR__ . "/../lib/login.php";
|
require __DIR__ . "/../lib/login.php";
|
||||||
@ -93,7 +92,7 @@ switch ($VARS['action']) {
|
|||||||
if (user_exists($VARS['username'])) {
|
if (user_exists($VARS['username'])) {
|
||||||
if (get_account_status($VARS['username']) == "NORMAL") {
|
if (get_account_status($VARS['username']) == "NORMAL") {
|
||||||
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
|
if (authenticate_user($VARS['username'], $VARS['password'], $autherror)) {
|
||||||
if (account_has_permission($VARS['username'], "INV_VIEW")) {
|
if (is_null($access_permission) || account_has_permission($VARS['username'], $access_permission)) {
|
||||||
doLoginUser($VARS['username'], $VARS['password']);
|
doLoginUser($VARS['username'], $VARS['password']);
|
||||||
$_SESSION['mobile'] = true;
|
$_SESSION['mobile'] = true;
|
||||||
exit(json_encode(["status" => "OK"]));
|
exit(json_encode(["status" => "OK"]));
|
||||||
@ -107,4 +106,4 @@ switch ($VARS['action']) {
|
|||||||
default:
|
default:
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
|
die(json_encode(["status" => "ERROR", "msg" => "The requested action is not available."]));
|
||||||
}
|
}
|
||||||
|
@ -52,4 +52,4 @@ redirectifnotloggedin();
|
|||||||
<a href="app.php?page=items&filter=stock" class="text-light"><i class="fas fa-arrow-right"></i> <?php lang("view understocked"); ?></a>
|
<a href="app.php?page=items&filter=stock" class="text-light"><i class="fas fa-arrow-right"></i> <?php lang("view understocked"); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,10 +12,12 @@ ob_start(); // allow sending headers after content
|
|||||||
// Unicode, solves almost all stupid encoding problems
|
// Unicode, solves almost all stupid encoding problems
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
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-Content-Type-Options: nosniff');
|
||||||
header('X-XSS-Protection: 1; mode=block');
|
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('X-Frame-Options: "DENY"');
|
||||||
header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
|
header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
|
||||||
$SECURE_NONCE = base64_encode(random_bytes(8));
|
$SECURE_NONCE = base64_encode(random_bytes(8));
|
||||||
@ -142,6 +144,7 @@ function lang($key, $echo = true) {
|
|||||||
if (array_key_exists($key, STRINGS)) {
|
if (array_key_exists($key, STRINGS)) {
|
||||||
$str = STRINGS[$key];
|
$str = STRINGS[$key];
|
||||||
} else {
|
} else {
|
||||||
|
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
||||||
$str = $key;
|
$str = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +167,7 @@ function lang2($key, $replace, $echo = true) {
|
|||||||
if (array_key_exists($key, STRINGS)) {
|
if (array_key_exists($key, STRINGS)) {
|
||||||
$str = STRINGS[$key];
|
$str = STRINGS[$key];
|
||||||
} else {
|
} else {
|
||||||
|
trigger_error("Language key \"$key\" does not exist in " . LANGUAGE, E_USER_WARNING);
|
||||||
$str = $key;
|
$str = $key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,4 +54,4 @@ define('LANGUAGE', "en_us");
|
|||||||
|
|
||||||
define("FOOTER_TEXT", "");
|
define("FOOTER_TEXT", "");
|
||||||
define("COPYRIGHT_NAME", "Netsyms Technologies");
|
define("COPYRIGHT_NAME", "Netsyms Technologies");
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
|
@ -65,4 +65,4 @@ body {
|
|||||||
|
|
||||||
.mobile-app-display {
|
.mobile-app-display {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,4 @@ try {
|
|||||||
window.history.replaceState("", "", getniceurl());
|
window.history.replaceState("", "", getniceurl());
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user