Skip to content

Commit b85bc7f

Browse files
Initial commit
0 parents  commit b85bc7f

35 files changed

+1799
-0
lines changed

LICENSE

+632
Large diffs are not rendered by default.

README

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
STATIC BUT NOT REALLY
2+
=====================
3+
4+
Overview
5+
--------
6+
- This is a minimal PHP "framework"/template for creating websites that are mostly static and are functional without JavaScript.
7+
- It has many rough edges, it is basically a merge of all the stuff I was using in various other sites.
8+
- Follows a KISS development method :)
9+
10+
Features
11+
--------
12+
- No giant libraries, dependencies, or frameworks (eg. composer, node, etc.)
13+
- CSRF and XSS Protection
14+
- Light/Dark CSS
15+
- Contact Form Support via XMPP
16+
- Minification
17+
- Disabling right click and devtools
18+
- Broken Stripe Support
19+
- Analytics Support

assets/css/extras.css

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.h2o {
2+
color: #FF5722;
3+
}
4+
5+
.h3o {
6+
color: #4CAF50;
7+
}
8+
9+
.centero {
10+
display: block !important;
11+
margin-left: auto !important;
12+
margin-right: auto !important;
13+
text-align: center;
14+
}

assets/css/mini-dark.min.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/css/mini-default.min.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

assets/css/splash-dark.css

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
https://raw.githubusercontent.com/Chalarangelo/mini.css/master/src/flavors/mini-doc.scss
3+
*/
4+
.index-splash {
5+
width: 100%;
6+
height: 100vh;
7+
}
8+
9+
.index-splash-bg {
10+
background-position: center;
11+
background-repeat: no-repeat;
12+
background-size: cover;
13+
width: 100%;
14+
height: 100%;
15+
position: absolute;
16+
}
17+
18+
h1.splash {
19+
position: absolute;
20+
margin: 0;
21+
width: 100%;
22+
text-align: center;
23+
height: 100%;
24+
padding-top: 40vh;
25+
font-size: 10vmin;
26+
font-weight: bold;
27+
color: #FF5722;
28+
}
29+
30+
a.scroll {
31+
position: absolute;
32+
top: 90vh;
33+
width: 50vw;
34+
left: 25vw;
35+
text-align: center;
36+
font-size: 8vmin;
37+
font-weight: bold;
38+
color: #FF5722;
39+
}
40+
41+
p.splash {
42+
margin: 0;
43+
position: absolute;
44+
width: 100%;
45+
text-align: center;
46+
padding-top: 52vh;
47+
font-size: 4vmin;
48+
color: #FFFFFF;
49+
}

assets/css/splash.css

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
https://raw.githubusercontent.com/Chalarangelo/mini.css/master/src/flavors/mini-doc.scss
3+
*/
4+
.index-splash {
5+
width: 100%;
6+
height: 100vh;
7+
}
8+
9+
.index-splash-bg {
10+
background-position: center;
11+
background-repeat: no-repeat;
12+
background-size: cover;
13+
width: 100%;
14+
height: 100%;
15+
position: absolute;
16+
}
17+
18+
h1.splash {
19+
position: absolute;
20+
margin: 0;
21+
width: 100%;
22+
text-align: center;
23+
height: 100%;
24+
padding-top: 40vh;
25+
font-size: 10vmin;
26+
font-weight: bold;
27+
color: #FF5722;
28+
}
29+
30+
a.scroll {
31+
position: absolute;
32+
top: 90vh;
33+
width: 50vw;
34+
left: 25vw;
35+
text-align: center;
36+
font-size: 8vmin;
37+
font-weight: bold;
38+
color: #FF5722;
39+
}
40+
41+
p.splash {
42+
margin: 0;
43+
position: absolute;
44+
width: 100%;
45+
text-align: center;
46+
padding-top: 52vh;
47+
font-size: 4vmin;
48+
color: #212121;
49+
}

assets/js/devtools-detect.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* eslint-disable spaced-comment */
2+
/*!
3+
devtools-detect
4+
Detect if DevTools is open
5+
https://github.com/sindresorhus/devtools-detect
6+
by Sindre Sorhus
7+
MIT License
8+
*/
9+
(function () {
10+
'use strict';
11+
var devtools = {
12+
open: false,
13+
orientation: null
14+
};
15+
var threshold = 160;
16+
var emitEvent = function (state, orientation) {
17+
window.dispatchEvent(new CustomEvent('devtoolschange', {
18+
detail: {
19+
open: state,
20+
orientation: orientation
21+
}
22+
}));
23+
};
24+
25+
setInterval(function () {
26+
var widthThreshold = window.outerWidth - window.innerWidth > threshold;
27+
var heightThreshold = window.outerHeight - window.innerHeight > threshold;
28+
var orientation = widthThreshold ? 'vertical' : 'horizontal';
29+
30+
if (!(heightThreshold && widthThreshold) &&
31+
((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || widthThreshold || heightThreshold)) {
32+
if (!devtools.open || devtools.orientation !== orientation) {
33+
emitEvent(true, orientation);
34+
}
35+
36+
devtools.open = true;
37+
devtools.orientation = orientation;
38+
} else {
39+
if (devtools.open) {
40+
emitEvent(false, null);
41+
}
42+
43+
devtools.open = false;
44+
devtools.orientation = null;
45+
}
46+
}, 500);
47+
48+
if (typeof module !== 'undefined' && module.exports) {
49+
module.exports = devtools;
50+
} else {
51+
window.devtools = devtools;
52+
}
53+
})();

assets/js/nodev.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//requires https://github.com/sindresorhus/devtools-detect
2+
window.addEventListener('devtoolschange', function (e) {
3+
if(e.detail.open) {
4+
console.clear();
5+
console.log("%cWARNING: UNAUTHORIZED COPYING OF CONTENT FROM THIS SITE IS STRICTLY PROHIBITED", "font: 3em sans-serif; color: #f44336; background-color: #212121;");
6+
}
7+
});
8+
window.addEventListener("keydown", function(e) {//Credit: https://stackoverflow.com/a/38359924
9+
if (e.code == "F12") {
10+
e.preventDefault(); e.stopPropagation(); return false;
11+
}
12+
if (e.getModifierState("Control") && e.code == "KeyU") {
13+
e.preventDefault(); e.stopPropagation(); return false;
14+
}
15+
if (e.getModifierState("Control") && e.getModifierState("Shift") && event.code == "KeyI") {
16+
e.preventDefault(); e.stopPropagation(); return false;
17+
}
18+
if (e.getModifierState("Control") && e.getModifierState("Shift") && event.code == "KeyK") {
19+
e.preventDefault(); e.stopPropagation(); return false;
20+
}
21+
});

assets/js/purchase.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
function checkout() {
2+
var paymentAmount = 100;
3+
var paymentDescription = 'A purchase'
4+
var handler = StripeCheckout.configure({
5+
key: '[PLACEHOLDER_STRIPE_KEY_PUBLIC]',
6+
locale: 'auto',
7+
allowRememberMe: false,
8+
token: function(token) {
9+
var req = new XMLHttpRequest();
10+
req.onreadystatechange = function() {
11+
if (req.readyState == 4 && req.status == 200) {
12+
setTimeout(markPurchased, 500);
13+
}
14+
};
15+
req.open("POST", "stripe.php", true);
16+
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
17+
req.send("PAYMENT_TOKEN=" + token.id
18+
+ "&PAYMENT_AMOUNT=" + paymentAmount
19+
+ "&PAYMENT_DESCRIPTION=" + btoa(paymentDescription)
20+
+ "&CSRF_TOKEN=" + getCSRFToken());
21+
}
22+
});
23+
24+
handler.open({
25+
name: '[PLACEHOLDER_ORGANIZATION]',
26+
description: paymentDescription,
27+
zipCode: true,
28+
amount: paymentAmount
29+
});
30+
31+
window.addEventListener('popstate', function() {
32+
handler.close();
33+
});
34+
}
35+
36+
function markPurchased() {
37+
38+
}
39+
40+
function checkoutProxy() {
41+
var warning = "Payment processing is performed by Stripe. By continuing your browser will load proprietary code from their servers. Do you want to continue?";
42+
if(confirm(warning)) {
43+
loadExternalJS("https://checkout.stripe.com/checkout.js", checkout);
44+
} else {
45+
//Cancel
46+
}
47+
}

assets/js/utils.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
function loadExternalJS(url, callAfterLoad, integrity) {
2+
var tmpJS = document.createElement('script');
3+
tmpJS.type = "text/javascript";
4+
tmpJS.src = url;
5+
if(integrity !== undefined) {
6+
tmpJS.integrity = integrity;
7+
}
8+
tmpJS.onload = callAfterLoad;
9+
document.body.appendChild(tmpJS);
10+
}
11+
12+
//CREDIT: https://www.w3schools.com/js/js_cookies.asp
13+
function getCookie(cname) {
14+
var name = cname + "=";
15+
var ca = document.cookie.split(';');
16+
for(var i = 0; i < ca.length; i++) {
17+
var c = ca[i];
18+
while (c.charAt(0) == ' ') {
19+
c = c.substring(1);
20+
}
21+
if (c.indexOf(name) == 0) {
22+
return c.substring(name.length, c.length);
23+
}
24+
}
25+
return "";
26+
}
27+
28+
//CREDIT: https://www.w3schools.com/js/js_cookies.asp
29+
function setCookie(cname, cvalue, exdays) {
30+
var d = new Date();
31+
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
32+
var expires = "expires="+d.toUTCString();
33+
document.cookie = cname + "=" + cvalue + ";" + expires + ";SameSite=Strict;path=/";
34+
}
35+
36+
//CREDIT: https://stackoverflow.com/a/179514
37+
function deleteAllCookies() {
38+
var cookies = document.cookie.split(";");
39+
for (var i = 0; i < cookies.length; i++) {
40+
var cookie = cookies[i];
41+
var eqPos = cookie.indexOf("=");
42+
var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
43+
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT";
44+
}
45+
}

contact.php

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
include "sbnr/config.php";
4+
if($SBNR_CONTACT_ENABLED === false) { exit; }
5+
6+
include "sbnr/security.php";
7+
include "sbnr/utils.php";
8+
include "sbnr/pre.php";
9+
10+
if(isset($_POST["CSRF_TOKEN"], $_POST["txtName"], $_POST["txtPhone"], $_POST["txtMessage"])) {
11+
if(noHTML($_POST["CSRF_TOKEN"]) == $_SESSION['SBNR_CSRF_TOKEN']) {
12+
$name = noHTML(base64_decode(urldecode($_POST["txtName"])));
13+
$number = preg_replace("/[^0-9]/", '', noHTML(base64_decode(urldecode($_POST["txtPhone"]))));
14+
$message = noHTML(base64_decode(urldecode($_POST["txtMessage"])));
15+
if(strlen($name) <= $SBNR_CONTACT_MAX_LENGTH_NAME
16+
&& strlen($number) >= $SBNR_CONTACT_MIN_LENGTH_PHONE_NUMBER
17+
&& strlen($number) <= $SBNR_CONTACT_MAX_LENGTH_PHONE_NUMBER
18+
&& strlen($message) <= $SBNR_CONTACT_MAX_LENGTH_MESSAGE) {
19+
20+
$msentinel = generateRandomString($SBNR_CONTACT_MESSAGE_PREFIX_LENGTH);
21+
22+
if ($SBNR_CONTACT_GEOIP) {
23+
$geoIP = $_SERVER["MM_COUNTRY_CODE"];
24+
if(strlen($_SERVER["MM_CITY_NAME"] . $_SERVER["MM_REGION_CODE"]) > 1) {
25+
$geoIP = $_SERVER["MM_CITY_NAME"] . ", " . $_SERVER["MM_REGION_CODE"] . " " . $_SERVER["MM_COUNTRY_CODE"];
26+
}
27+
$location = "[" . $msentinel . "] Location: " . $geoIP . "\n";
28+
}
29+
30+
$message = "[" . $msentinel . "] MESSAGE START\n" .
31+
"[" . $msentinel . "] Name: " . $name . "\n" .
32+
"[" . $msentinel . "] Phone Number: " . $number . "\n" .
33+
$location .
34+
"[" . $msentinel . "] Message: \n" . $message . "\n" .
35+
"[" . $msentinel . "] MESSAGE END";
36+
37+
exec("echo " . escapeshellarg($message) . " | sendxmpp -f " . $SBNR_CONTACT_SENDXMPP_CONFIG . " -t " . $SBNR_CONTACT_SENDXMPP_RECEIPENT);
38+
print("Message Sent!");
39+
} else {
40+
generateErrorPageBasic(406);
41+
}
42+
} else {
43+
generateErrorPageBasic(401);
44+
}
45+
} else {
46+
generateErrorPageBasic(400);
47+
}
48+
49+
$_SESSION['SBNR_CSRF_TOKEN'] = bin2hex(random_bytes(32)); //Always renew the token to prevent brute forcing
50+
51+
?>

fragments/analytics.html

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!--
2+
Insert an analytics snippet here
3+
4+
Please take advantage of loadExternalJS(remote, callback) provided by utils.js
5+
and respect navigator.doNotTrack for the sake of your user's privacy!
6+
-->

fragments/error.html

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<div class="card fluid">
2+
<h2>Error [PLACEHOLDER_ERROR]</h2>
3+
<div class="section">
4+
<script type="text/javascript">
5+
document.write("<h3>Returning home in two seconds...</h3>");
6+
setTimeout(function() {
7+
window.location.href = "/index.php";
8+
}, 2000);
9+
</script>
10+
<noscript><h3><a href="/index.php">Click here to return home</a></h3></noscript>
11+
</div>
12+
</div>

0 commit comments

Comments
 (0)