First commit
commit
e11c77026f
@ -0,0 +1 @@
|
|||||||
|
*settings.php
|
@ -0,0 +1,12 @@
|
|||||||
|
# Netsyms Business Accelerator
|
||||||
|
|
||||||
|
The Business Accelerator is a physical network device for installation at a small business. It helps combine the speed and offline benefits of local services with the reliability, availability, and ease of managed cloud services.
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
The Business Accelerator is based on the Raspberry Pi 3 B+, running an image based on Raspbian Stretch Lite. This repository contains notable modifications to the base image.
|
||||||
|
|
||||||
|
Modifications include:
|
||||||
|
|
||||||
|
- Using [CJDNS](https://source.netsyms.com/Netsyms/prototype-cjdns-pi) to bypass NAT for secure cloud sync and remote tech support
|
||||||
|
- Installing NGINX, PHP 7.0, and SQLite 3 for serving content
|
@ -0,0 +1,3 @@
|
|||||||
|
# Cloud Web Content
|
||||||
|
|
||||||
|
This folder contains files for running on the Business Apps cloud server.
|
@ -0,0 +1,3 @@
|
|||||||
|
# Configuration Files
|
||||||
|
|
||||||
|
This folder contains Debian configuration files with notable changes from common defaults.
|
@ -0,0 +1,384 @@
|
|||||||
|
{
|
||||||
|
// Private key:
|
||||||
|
// Your confidentiality and data integrity depend on this key, keep it secret!
|
||||||
|
"privateKey": "<<<REDACTED>>>",
|
||||||
|
// This key corresponds to the public key and ipv6 address:
|
||||||
|
"publicKey": "<<<REDACTED>>>",
|
||||||
|
"ipv6": "<<<REDACTED>>>",
|
||||||
|
"authorizedPasswords":
|
||||||
|
[
|
||||||
|
{"password": "<<<REDACTED>>>", "user": "default-login"}
|
||||||
|
],
|
||||||
|
|
||||||
|
"admin":
|
||||||
|
{
|
||||||
|
"bind": "127.0.0.1:11234",
|
||||||
|
"password": "NONE"
|
||||||
|
},
|
||||||
|
|
||||||
|
// Interfaces to connect to the switch core.
|
||||||
|
"interfaces":
|
||||||
|
{
|
||||||
|
// The interface which connects over UDP/IP based VPN tunnel.
|
||||||
|
"UDPInterface":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Bind to this port.
|
||||||
|
"bind": "0.0.0.0:2085",
|
||||||
|
// Set the DSCP value for Qos. Default is 0.
|
||||||
|
// "dscp": 46,
|
||||||
|
|
||||||
|
// Nodes to connect to (IPv4 only).
|
||||||
|
"connectTo":
|
||||||
|
{
|
||||||
|
"92.241.12.189:22569": {
|
||||||
|
"password": "6mDHySCSJYVgyJqphpgnokqKrCq045mF",
|
||||||
|
"publicKey": "9qz459vnkb1v36ypq84m29g2q7dn8gndg9bh0w1499urnkx9nmt0.k",
|
||||||
|
"peerName": "h.start-com.ru",
|
||||||
|
"Contact": "vvk@start-com.ru"
|
||||||
|
},
|
||||||
|
"173.208.215.53:6129": {
|
||||||
|
"login": "public",
|
||||||
|
"password":"wvmrnb31sgtw03d73buyjybwr6vrw1z",
|
||||||
|
"publicKey":"p2r0nst699p2gc9cztcmkr5z05522h51jvj5xw7z4x135cz4j9p0.k",
|
||||||
|
"peerName":"Don't Sell.Me"
|
||||||
|
},
|
||||||
|
"198.199.124.143:27313": {
|
||||||
|
"contact": "kasm@kasm.eu",
|
||||||
|
"location": "Europe/Amsterdam",
|
||||||
|
"login": "public-peer",
|
||||||
|
"password": "9md1m1sntffbrkq1brb85rw312fr5gb",
|
||||||
|
"peerName": "h.kasm.eu",
|
||||||
|
"publicKey": "g34d0nbyltxj3sqnc0t5gps32ks4tyl3m9w9qzpk832f9dmp6fh0.k"
|
||||||
|
},
|
||||||
|
"192.169.7.142:14400":{
|
||||||
|
"contact":"Igel@hyperboria.ca",
|
||||||
|
"gpg":"A84DFFE62B451511",
|
||||||
|
"password":"alfa-charlie-alfa-bravo",
|
||||||
|
"peerName":"igel-losangeles",
|
||||||
|
"publicKey":"mh9m0411cfcg7xhdc8n6ckls1tjgnvvbdfzdgqf5196tfkw96rr0.k"
|
||||||
|
},
|
||||||
|
"138.68.245.159:50505":{
|
||||||
|
"contact":"chapman.shoop@riseup.net",
|
||||||
|
"login":"public-peer",
|
||||||
|
"password":"7ztkh2m3p97z0fcyn50wmtx863n6b3j",
|
||||||
|
"peerName":"salesforce-tower",
|
||||||
|
"publicKey":"6d2kt2hbcp7v0pw9q6f1u2s039kfnt4m4123rjxg26hsgrc12v80.k"
|
||||||
|
},
|
||||||
|
"162.254.117.11:8351":{
|
||||||
|
"contact":"cornfeedhobo@fuzzlabs.org",
|
||||||
|
"gpg":"6610FE2B6BD98C42",
|
||||||
|
"location":"Chicago, IL, USA",
|
||||||
|
"login":"public-access",
|
||||||
|
"password":"39XBepVM7TxGWAoROgUzixlbAnkh7WRY",
|
||||||
|
"peerName":"vishnu",
|
||||||
|
"publicKey":"dhndkly9mhmckbcrb1rgl051ty9fg5zq0tmnms8wxns08fu7kvv0.k"
|
||||||
|
},
|
||||||
|
"192.34.85.155:2359":{
|
||||||
|
"contact":"Igel@hyperboria.ca",
|
||||||
|
"gpg":"A84DFFE62B451511",
|
||||||
|
"password":"alfa-charlie-alfa-bravo",
|
||||||
|
"peerName":"igel-boston",
|
||||||
|
"publicKey":"rdxg1nzvmjdj4fyguqydmnl659p7m3x26r6un4ql966q4xt988j0.k"
|
||||||
|
},
|
||||||
|
"104.200.29.163:53053":{
|
||||||
|
"contact":"ansuz@transitiontech.ca",
|
||||||
|
"gpg":"024A7C03E67ED8CF",
|
||||||
|
"password":"cLjDBorhsYJUmJrESGueHsRY4HXcFyj",
|
||||||
|
"peerName":"transitiontech",
|
||||||
|
"publicKey":"1941p5k8qqvj17vjrkb9z97wscvtgc1vp8pv1huk5120cu42ytt0.k"
|
||||||
|
},
|
||||||
|
"107.170.57.34:63472":{
|
||||||
|
"contact":"code@ventricle.us",
|
||||||
|
"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
|
||||||
|
"location":"digitalocean nyc2",
|
||||||
|
"login":"public-peer",
|
||||||
|
"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
|
||||||
|
"peerName":"cord.ventricle.us",
|
||||||
|
"publicKey":"1xkf13m9r9h502yuffsq1cg13s5648bpxrtf2c3xcq1mlj893s90.k"
|
||||||
|
},
|
||||||
|
"185.140.54.73:30800":{
|
||||||
|
"contact":"iczero4@gmail.com",
|
||||||
|
"gpg":"613CE9DA0E9A3F70EC97760E4BAC4EBB8461FC7E",
|
||||||
|
"login":"public",
|
||||||
|
"password":"fwlmbx2f3udkd0ymknq4pwwgu2bjklx",
|
||||||
|
"peerName":"ic2.hellomouse.cf",
|
||||||
|
"publicKey":"c15sfmskdpmj2qw5lfvgfuzggyyk1bjzj4lu3yf6h1x2ckclwdd0.k"
|
||||||
|
},
|
||||||
|
"173.62.245.186:55249":{
|
||||||
|
"contact":"natebrune@gmail.com",
|
||||||
|
"country":"us",
|
||||||
|
"gpg":"C95CE6BC6735BAD7",
|
||||||
|
"ipv6":"fcda:9958:9093:49f2:2677:6df6:2a5a:b01d",
|
||||||
|
"password":"Public",
|
||||||
|
"peerName":"NAT",
|
||||||
|
"publicKey":"vgxqyputh4ldhxktg9msmr61pw938l0ymhkmryljsyzvmr0dtwy0.k",
|
||||||
|
"website":"https://github.com/NateBrune"
|
||||||
|
},
|
||||||
|
"198.58.100.240:22237":{
|
||||||
|
"contact":"jhj@trnsz.com",
|
||||||
|
"login":"default-login",
|
||||||
|
"password":"pqr5brz16vzzu6vhjuj7tv3n078kr5f",
|
||||||
|
"peerName":"trnsz",
|
||||||
|
"publicKey":"ubbtkp0txwjh44v8kkznvhjqqwr1hd2jzv5ms9zlkfk25svxvtg0.k"
|
||||||
|
},
|
||||||
|
"149.56.98.167:3703":{
|
||||||
|
"contact":"code@ventricle.us",
|
||||||
|
"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
|
||||||
|
"location":"ovh beauharnois",
|
||||||
|
"login":"public-peer",
|
||||||
|
"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
|
||||||
|
"peerName":"larynx.ventricle.us",
|
||||||
|
"publicKey":"jg035j9hup776kwz1k4n0bwpggxp1qmts6t715x53g8vutxktzz0.k"
|
||||||
|
},
|
||||||
|
"165.227.44.84:34838":{
|
||||||
|
"contact":"wattersm@watters.ws",
|
||||||
|
"gpg":"E2A3328281D1DA0A08D34FC2058F0C51586CA8C6",
|
||||||
|
"location":"Digital Ocean tor1",
|
||||||
|
"login":"public-access",
|
||||||
|
"password":"8n2w2qu2lfndhgx8xwgp18vyq7fhvux",
|
||||||
|
"peerName":"linux1.tor1.watters.ws",
|
||||||
|
"publicKey":"b465hml7z3g1vj22ktqdrc3z17mwjxl44cg0mj903n9vycxzqpv0.k"
|
||||||
|
},
|
||||||
|
"149.56.19.79:55159":{
|
||||||
|
"contact":"infrastructure@stashcrypto.com",
|
||||||
|
"login":"default-login",
|
||||||
|
"password":"dgv86ktpblc2h4y93fsqpshcg2lbp5d",
|
||||||
|
"peerName":"git.stashcrypto.net",
|
||||||
|
"publicKey":"zbfurpx9n6whzwu6vrlfgmw8g56rmchfmhxxtpg0hwhl84vqf1y0.k"
|
||||||
|
},
|
||||||
|
"158.69.119.35:9218":{
|
||||||
|
"contact":"infrastructure@stashcrypto.com",
|
||||||
|
"login":"default-login",
|
||||||
|
"password":"w5huch4mn6tkgfp3j9sr8p8r13j3j33",
|
||||||
|
"peerName":"seed.stashcrypto.net",
|
||||||
|
"publicKey":"rzg61b3fsb675732g5rn8g1x61ypm1z7402n072qmrbbhgzm93f0.k"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Bind to this port.
|
||||||
|
"bind": "[::]:2085",
|
||||||
|
// Set the DSCP value for Qos. Default is 0.
|
||||||
|
// "dscp": 46,
|
||||||
|
|
||||||
|
// Nodes to connect to (IPv6 only).
|
||||||
|
"connectTo":
|
||||||
|
{
|
||||||
|
"[2602:ff65:0:1::fc00]:2359":{
|
||||||
|
"contact":"Igel@hyperboria.ca",
|
||||||
|
"gpg":"A84DFFE62B451511",
|
||||||
|
"password":"alfa-charlie-alfa-bravo",
|
||||||
|
"peerName":"igel-boston",
|
||||||
|
"publicKey":"rdxg1nzvmjdj4fyguqydmnl659p7m3x26r6un4ql966q4xt988j0.k"
|
||||||
|
},
|
||||||
|
"[2604:a880:0:1010::f:4001]:63472":{
|
||||||
|
"contact":"code@ventricle.us",
|
||||||
|
"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
|
||||||
|
"location":"digitalocean nyc2",
|
||||||
|
"login":"public-peer",
|
||||||
|
"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
|
||||||
|
"peerName":"cord.ventricle.us",
|
||||||
|
"publicKey":"1xkf13m9r9h502yuffsq1cg13s5648bpxrtf2c3xcq1mlj893s90.k"
|
||||||
|
},
|
||||||
|
"[2a05:dfc7:dfc8:1d3::1]:30800":{
|
||||||
|
"contact":"iczero4@gmail.com",
|
||||||
|
"gpg":"613CE9DA0E9A3F70EC97760E4BAC4EBB8461FC7E",
|
||||||
|
"login":"public",
|
||||||
|
"password":"fwlmbx2f3udkd0ymknq4pwwgu2bjklx",
|
||||||
|
"peerName":"ic2.hellomouse.cf",
|
||||||
|
"publicKey":"c15sfmskdpmj2qw5lfvgfuzggyyk1bjzj4lu3yf6h1x2ckclwdd0.k"
|
||||||
|
},
|
||||||
|
"[2607:5300:61:44f::]:55159":{
|
||||||
|
"contact":"infrastructure@stashcrypto.com",
|
||||||
|
"login":"default-login",
|
||||||
|
"password":"dgv86ktpblc2h4y93fsqpshcg2lbp5d",
|
||||||
|
"peerName":"git.stashcrypto.net",
|
||||||
|
"publicKey":"zbfurpx9n6whzwu6vrlfgmw8g56rmchfmhxxtpg0hwhl84vqf1y0.k"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
,
|
||||||
|
"ETHInterface":
|
||||||
|
[
|
||||||
|
// Alternatively bind to just one device and either beacon and/or
|
||||||
|
// connect to a specified MAC address
|
||||||
|
{
|
||||||
|
// Bind to this device (interface name, not MAC)
|
||||||
|
// "all" is a pseudo-name which will try to connect to all devices.
|
||||||
|
"bind": "all",
|
||||||
|
|
||||||
|
// Auto-connect to other cjdns nodes on the same network.
|
||||||
|
// Options:
|
||||||
|
//
|
||||||
|
// 0 -- Disabled.
|
||||||
|
//
|
||||||
|
// 1 -- Accept beacons, this will cause cjdns to accept incoming
|
||||||
|
// beacon messages and try connecting to the sender.
|
||||||
|
//
|
||||||
|
// 2 -- Accept and send beacons, this will cause cjdns to broadcast
|
||||||
|
// messages on the local network which contain a randomly
|
||||||
|
// generated per-session password, other nodes which have this
|
||||||
|
// set to 1 or 2 will hear the beacon messages and connect
|
||||||
|
// automatically.
|
||||||
|
//
|
||||||
|
"beacon": 2,
|
||||||
|
|
||||||
|
// Node(s) to connect to manually
|
||||||
|
// Note: does not work with "all" pseudo-device-name
|
||||||
|
"connectTo":
|
||||||
|
{
|
||||||
|
// Credentials for connecting look similar to UDP credentials
|
||||||
|
// except they begin with the mac address, for example:
|
||||||
|
// "01:02:03:04:05:06":{"password":"a","publicKey":"b"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// Configuration for the router.
|
||||||
|
"router":
|
||||||
|
{
|
||||||
|
// supernodes, if none are specified they'll be taken from your peers
|
||||||
|
"supernodes": [
|
||||||
|
//"6743gf5tw80ExampleExampleExampleExamplevlyb23zfnuzv0.k",
|
||||||
|
]
|
||||||
|
|
||||||
|
// The interface which is used for connecting to the cjdns network.
|
||||||
|
"interface":
|
||||||
|
{
|
||||||
|
// The type of interface (only TUNInterface is supported for now)
|
||||||
|
"type": "TUNInterface"
|
||||||
|
// The type of tunfd (only "android" for now)
|
||||||
|
// If "android" here, the tunDevice should be used as the pipe path
|
||||||
|
// to transfer the tun file description.
|
||||||
|
// "tunfd" : "android"
|
||||||
|
|
||||||
|
// The name of a persistent TUN device to use.
|
||||||
|
// This for starting cjdroute as its own user.
|
||||||
|
// *MOST USERS DON'T NEED THIS*
|
||||||
|
//"tunDevice": "tun0"
|
||||||
|
},
|
||||||
|
|
||||||
|
// System for tunneling IPv4 and ICANN IPv6 through cjdns.
|
||||||
|
// This is using the cjdns switch layer as a VPN carrier.
|
||||||
|
"ipTunnel":
|
||||||
|
{
|
||||||
|
// Nodes allowed to connect to us.
|
||||||
|
// When a node with the given public key connects, give them the
|
||||||
|
// ip4 and/or ip6 addresses listed.
|
||||||
|
"allowedConnections":
|
||||||
|
[
|
||||||
|
// Give the client an address on 192.168.1.0/24, and an address
|
||||||
|
// it thinks has all of IPv6 behind it.
|
||||||
|
// ip4Prefix is the set of addresses which are routable from the tun
|
||||||
|
// for example, if you're advertizing a VPN into a company network
|
||||||
|
// which exists in 10.123.45.0/24 space, ip4Prefix should be 24
|
||||||
|
// default is 32 for ipv4 and 128 for ipv6
|
||||||
|
// so by default it will not install a route
|
||||||
|
// ip4Alloc is the block of addresses which are allocated to the
|
||||||
|
// for example if you want to issue 4 addresses to the client, those
|
||||||
|
// being 192.168.123.0 to 192.168.123.3, you would set this to 30
|
||||||
|
// default is 32 for ipv4 and 128 for ipv6 (1 address)
|
||||||
|
// {
|
||||||
|
// "publicKey": "f64hfl7c4uxt6krmhPutTheRealAddressOfANodeHere7kfm5m0.k",
|
||||||
|
// "ip4Address": "192.168.1.24",
|
||||||
|
// "ip4Prefix": 0,
|
||||||
|
// "ip4Alloc": 32,
|
||||||
|
// "ip6Address": "2001:123:ab::10",
|
||||||
|
// "ip6Prefix": 0
|
||||||
|
// "ip6Alloc": 64,
|
||||||
|
// },
|
||||||
|
|
||||||
|
// It's ok to only specify one address and prefix/alloc are optional.
|
||||||
|
// {
|
||||||
|
// "publicKey": "ydq8csdk8p8ThisIsJustAnExampleAddresstxuyqdf27hvn2z0.k",
|
||||||
|
// "ip4Address": "192.168.1.25",
|
||||||
|
// "ip4Prefix": 0,
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
|
||||||
|
"outgoingConnections":
|
||||||
|
[
|
||||||
|
// Connect to one or more machines and ask them for IP addresses.
|
||||||
|
// "6743gf5tw80ExampleExampleExampleExamplevlyb23zfnuzv0.k",
|
||||||
|
// "pw9tfmr8pcrExampleExampleExampleExample8rhg1pgwpwf80.k",
|
||||||
|
// "g91lxyxhq0kExampleExampleExampleExample6t0mknuhw75l0.k"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Dropping permissions.
|
||||||
|
// In the event of a serious security exploit in cjdns, leak of confidential
|
||||||
|
// network traffic and/or keys is highly likely but the following rules are
|
||||||
|
// designed to prevent the attack from spreading to the system on which cjdns
|
||||||
|
// is running.
|
||||||
|
// Counter-intuitively, cjdns is *more* secure if it is started as root because
|
||||||
|
// non-root users do not have permission to use chroot or change usernames,
|
||||||
|
// limiting the effectiveness of the mitigations herein.
|
||||||
|
"security":
|
||||||
|
[
|
||||||
|
// Change the user id to sandbox the cjdns process after it starts.
|
||||||
|
// If keepNetAdmin is set to 0, IPTunnel will be unable to set IP addresses
|
||||||
|
// and ETHInterface will be unable to hot-add new interfaces
|
||||||
|
// Use { "setuser": 0 } to disable.
|
||||||
|
// Default: enabled with keepNetAdmin
|
||||||
|
{ "setuser": "nobody", "keepNetAdmin": 1 },
|
||||||
|
|
||||||
|
// Chroot changes the filesystem root directory which cjdns sees, blocking it
|
||||||
|
// from accessing files outside of the chroot sandbox, if the user does not
|
||||||
|
// have permission to use chroot(), this will fail quietly.
|
||||||
|
// Use { "chroot": 0 } to disable.
|
||||||
|
// Default: enabled (using "/var/run")
|
||||||
|
{ "chroot": "/var/run/" },
|
||||||
|
|
||||||
|
// Nofiles is a deprecated security feature which prevents cjdns from opening
|
||||||
|
// any files at all, using this will block setting of IP addresses and
|
||||||
|
// hot-adding ETHInterface devices but for users who do not need this, it
|
||||||
|
// provides a formidable sandbox.
|
||||||
|
// Default: disabled
|
||||||
|
{ "nofiles": 0 },
|
||||||
|
|
||||||
|
// Noforks will prevent cjdns from spawning any new processes or threads,
|
||||||
|
// this prevents many types of exploits from attacking the wider system.
|
||||||
|
// Default: enabled
|
||||||
|
{ "noforks": 1 },
|
||||||
|
|
||||||
|
// Seccomp is the most advanced sandboxing feature in cjdns, it uses
|
||||||
|
// SECCOMP_BPF to filter the system calls which cjdns is able to make on a
|
||||||
|
// linux system, strictly limiting it's access to the outside world
|
||||||
|
// This will fail quietly on any non-linux system
|
||||||
|
// Default: enabled
|
||||||
|
{ "seccomp": 1 },
|
||||||
|
|
||||||
|
// The client sets up the core using a sequence of RPC calls, the responses
|
||||||
|
// to these calls are verified but in the event that the client crashes
|
||||||
|
// setup of the core completes, it could leave the core in an insecure state
|
||||||
|
// This call constitutes the client telling the core that the security rules
|
||||||
|
// have been fully applied and the core may run. Without it, the core will
|
||||||
|
// exit within a few seconds with return code 232.
|
||||||
|
// Default: enabled
|
||||||
|
{ "setupComplete": 1 }
|
||||||
|
],
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
"logging":
|
||||||
|
{
|
||||||
|
// Uncomment to have cjdns log to stdout rather than making logs available
|
||||||
|
// via the admin socket.
|
||||||
|
// "logTo":"stdout"
|
||||||
|
},
|
||||||
|
|
||||||
|
// If set to non-zero, cjdns will not fork to the background.
|
||||||
|
// Recommended for use in conjunction with "logTo":"stdout".
|
||||||
|
"noBackground":0
|
||||||
|
|
||||||
|
// Pipe file will store in this path, recommended value: /tmp (for unix),
|
||||||
|
// \\.\pipe (for windows)
|
||||||
|
// /data/local/tmp (for rooted android)
|
||||||
|
// /data/data/AppName (for non-root android)
|
||||||
|
// This only needs to be specified if cjdroute's guess is incorrect
|
||||||
|
// "pipe":"/tmp"
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
# Scripts
|
||||||
|
|
||||||
|
This folder contains custom scripts that do useful things.
|
@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# System status script
|
||||||
|
# Feel free to copypaste, modify, and share; that's what we did.
|
||||||
|
|
||||||
|
# Text colors
|
||||||
|
RED='\e[1;31m'
|
||||||
|
WHT='\e[1;37m'
|
||||||
|
GRN='\e[1;32m'
|
||||||
|
BLU='\e[0;34m'
|
||||||
|
CLR='\e[0m'
|
||||||
|
|
||||||
|
INACTIVE="$RED[INACTIVE]$CLR"
|
||||||
|
ACTIVE="$GRN[ACTIVE]$CLR"
|
||||||
|
|
||||||
|
echo -e "$BLU"
|
||||||
|
toilet -f smblock.tlf "Netsyms Business"
|
||||||
|
toilet -f smblock.tlf "Accelerator"
|
||||||
|
echo -e "$CLR"
|
||||||
|
echo -e "---------------------------------------------------$WHT"
|
||||||
|
echo -e "Engineered by$BLU Netsyms Technologies$CLR"
|
||||||
|
echo -e ''
|
||||||
|
echo -e 'Home: https://netsyms.com'
|
||||||
|
echo -e 'Support: https://support.netsyms.com'
|
||||||
|
echo -e 'Source: https://source.netsyms.com'
|
||||||
|
echo -e 'Business: https://netsyms.biz'
|
||||||
|
echo -e '---------------------------------------------------'
|
||||||
|
echo -e 'The programs included with this system are free'
|
||||||
|
echo -e 'software; the exact distribution terms for each'
|
||||||
|
echo -e 'program are described in the individual files in'
|
||||||
|
echo -e '/usr/share/doc/*/copyright.'
|
||||||
|
|
||||||
|
echo -e '---------------------------------------------------'
|
||||||
|
upSeconds="$(/usr/bin/cut -d. -f1 /proc/uptime)"
|
||||||
|
secs=$((${upSeconds}%60))
|
||||||
|
mins=$((${upSeconds}/60%60))
|
||||||
|
hours=$((${upSeconds}/3600%24))
|
||||||
|
days=$((${upSeconds}/86400))
|
||||||
|
UPTIME=`printf "%02d days, %02dh %02dm" "$days" "$hours" "$mins"`
|
||||||
|
|
||||||
|
freekb=$(cat /proc/meminfo | grep MemFree | awk {'print $2'})
|
||||||
|
totalkb=$(cat /proc/meminfo | grep MemTotal | awk {'print $2'})
|
||||||
|
|
||||||
|
freemb=$(($freekb/1000))
|
||||||
|
totalmb=$(($totalkb/1000))
|
||||||
|
|
||||||
|
percentfree=$(echo "scale=0; $freekb*100/$totalkb" | bc)
|
||||||
|
|
||||||
|
echo -e "Date .................................. $WHT$(date +%b\ %e\ %Y)$CLR"
|
||||||
|
echo -e "Time ..................................... $WHT$(date +%H:%M:%S)$CLR"
|
||||||
|
echo -e "Uptime ........................... $WHT$UPTIME$CLR"
|
||||||
|
echo -e "Processes ..................................... $WHT$(ps ax | wc -l | tr -d " ")$CLR"
|
||||||
|
echo -e "Load averages ....................$WHT$(uptime | awk -F'[a-z]:' '{ print $2}')$CLR"
|
||||||
|
if (( $percentfree < 30 )); then
|
||||||
|
echo -e "Memory used .......................... $RED$(($totalmb-$freemb)) MB ($((100-$percentfree))%)$CLR"
|
||||||
|
echo -e "Memory free .......................... $RED$freemb MB ($percentfree%)$CLR"
|
||||||
|
else
|
||||||
|
echo -e "Memory used .......................... $GRN$(($totalmb-$freemb)) MB ($((100-$percentfree))%)$CLR"
|
||||||
|
echo -e "Memory free .......................... $GRN$freemb MB ($percentfree%)$CLR"
|
||||||
|
fi
|
||||||
|
cpu=$(</sys/class/thermal/thermal_zone0/temp)
|
||||||
|
cpu=$((cpu/1000))
|
||||||
|
if (( $cpu > 45 )); then
|
||||||
|
cpu="$RED$cpu\u00b0C$CLR"
|
||||||
|
else
|
||||||
|
cpu="$GRN$cpu\u00b0C$CLR"
|
||||||
|
fi
|
||||||
|
echo -e "CPU temperature .............................. $cpu"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Service Status
|
||||||
|
#
|
||||||
|
if [ $(systemctl status cjdns.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
|
||||||
|
echo -e "cjdns Service ............................ $ACTIVE"
|
||||||
|
else
|
||||||
|
echo -e "cjdns Service .......................... $INACTIVE"
|
||||||
|
fi
|
||||||
|
if [ $(systemctl status nginx.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
|
||||||
|
echo -e "nginx Service ............................ $ACTIVE"
|
||||||
|
else
|
||||||
|
echo -e "nginx Service .......................... $INACTIVE"
|
||||||
|
fi
|
||||||
|
if [ $(systemctl status php7.0-fpm.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
|
||||||
|
echo -e "php-fpm Service .......................... $ACTIVE"
|
||||||
|
else
|
||||||
|
echo -e "php-fpm Service ........................ $INACTIVE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# IP/Network Info
|
||||||
|
#
|
||||||
|
|
||||||
|
echo -e "---------------------------------------------------$WHT"
|
||||||
|
echo -e "Local IP$CLR"
|
||||||
|
ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
|
||||||
|
echo -e "---------------------------------------------------$WHT"
|
||||||
|
echo -e "Public IP$CLR"
|
||||||
|
dig +short myip.opendns.com @resolver1.opendns.com
|
||||||
|
echo -e "---------------------------------------------------$WHT"
|
||||||
|
echo -e "CJDNS IP$CLR"
|
||||||
|
sudo grep -m 1 '"ipv6"' /etc/cjdroute.conf | awk '{ print $2 }' | sed 's/[",]//g'
|
||||||
|
echo -e '---------------------------------------------------'
|
||||||
|
echo -e "For network bandwidth usage data, run$WHT vnstat$CLR"
|
||||||
|
echo -e "To refresh this status message, run$WHT status$CLR"
|
||||||
|
#vnstat -i eth0+tun0+wlan0 --style 0
|
||||||
|
echo -e '---------------------------------------------------'
|
@ -0,0 +1,3 @@
|
|||||||
|
# Local Web Content
|
||||||
|
|
||||||
|
This folder contains files for the Accelerator's webroot.
|
@ -0,0 +1,46 @@
|
|||||||
|
<?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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple JSON API to allow other apps to access accounts in this system.
|
||||||
|
*
|
||||||
|
* Requests can be sent via either GET or POST requests. POST is recommended
|
||||||
|
* as it has a lower chance of being logged on the server, exposing unencrypted
|
||||||
|
* user passwords.
|
||||||
|
*/
|
||||||
|
require __DIR__ . '/required.php';
|
||||||
|
require __DIR__ . '/lib/login.php';
|
||||||
|
|
||||||
|
switch ($VARS['action']) {
|
||||||
|
case "ping":
|
||||||
|
exit(json_encode(["status" => "OK"]));
|
||||||
|
break;
|
||||||
|
case "auth":
|
||||||
|
$errmsg = "";
|
||||||
|
if (authenticate_user($VARS['username'], $VARS['password'], $errmsg)) {
|
||||||
|
exit(json_encode(["status" => "OK", "msg" => "Login successful."]));
|
||||||
|
} else {
|
||||||
|
exit(json_encode(["status" => "ERROR", "msg" => "Login incorrect."]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "hastotp":
|
||||||
|
if (userHasTOTP($VARS['username'])) {
|
||||||
|
exit(json_encode(["status" => "OK", "otp" => true]));
|
||||||
|
} else {
|
||||||
|
exit(json_encode(["status" => "OK", "otp" => false]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "verifytotp":
|
||||||
|
if (verifyTOTP($VARS['username'], $VARS['code'])) {
|
||||||
|
exit(json_encode(["status" => "OK", "valid" => true]));
|
||||||
|
} else {
|
||||||
|
exit(json_encode(["status" => "ERROR", "msg" => "Authentication code incorrect.", "valid" => false]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
http_response_code(404);
|
||||||
|
die(json_encode("404 Not Found: the requested action is not available."));
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
<?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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication and account functions
|
||||||
|
*/
|
||||||
|
use Base32\Base32;
|
||||||
|
use OTPHP\TOTP;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the given credentials against the database.
|
||||||
|
* @param string $username
|
||||||
|
* @param string $password
|
||||||
|
* @return boolean True if OK, else false
|
||||||
|
*/
|
||||||
|
function authenticate_user($username, $password) {
|
||||||
|
global $database;
|
||||||
|
$username = strtolower($username);
|
||||||
|
if (is_empty($username) || is_empty($password)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$hash = $database->get('accounts', 'password', ['username' => $username]);
|
||||||
|
return (comparePassword($password, $hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
function user_exists($username) {
|
||||||
|
return $database->has('accounts', ['username' => strtolower($username)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 2-factor authentication //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a user has TOTP setup
|
||||||
|
* @global $database $database
|
||||||
|
* @param string $username
|
||||||
|
* @return boolean true if TOTP secret exists, else false
|
||||||
|
*/
|
||||||
|
function userHasTOTP($username) {
|
||||||
|
global $database;
|
||||||
|
$username = strtolower($username);
|
||||||
|
$secret = $database->get('accounts', 'authsecret', ['username' => $username]);
|
||||||
|
if (is_empty($secret)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a TOTP multiauth code
|
||||||
|
* @global $database
|
||||||
|
* @param string $username
|
||||||
|
* @param int $code
|
||||||
|
* @return boolean true if it's legit, else false
|
||||||
|
*/
|
||||||
|
function verifyTOTP($username, $code) {
|
||||||
|
global $database;
|
||||||
|
$username = strtolower($username);
|
||||||
|
$authsecret = $database->get('accounts', 'authsecret', ['username' => $username]);
|
||||||
|
if (is_empty($authsecret)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$totp = new TOTP(null, $authsecret);
|
||||||
|
return $totp->verify($code);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,305 @@
|
|||||||
|
<?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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains global settings and utility functions.
|
||||||
|
*/
|
||||||
|
ob_start(); // allow sending headers after content
|
||||||
|
|
||||||
|
// Set default content type to JSON
|
||||||
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
header('X-Content-Type-Options: nosniff');
|
||||||
|
header('X-XSS-Protection: 1; mode=block');
|
||||||
|
header('X-Powered-By: PHP');
|
||||||
|
header('X-Frame-Options: "DENY"');
|
||||||
|
header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
|
||||||
|
$SECURE_NONCE = base64_encode(random_bytes(8));
|
||||||
|
|
||||||
|
header("Content-Security-Policy: "
|
||||||
|
. "default-src 'self';"
|
||||||
|
. "object-src 'none'; "
|
||||||
|
. "img-src * data:; "
|
||||||
|
. "media-src 'self'; "
|
||||||
|
. "frame-src 'none'; "
|
||||||
|
. "font-src 'self'; "
|
||||||
|
. "connect-src *; "
|
||||||
|
. "style-src 'self' 'nonce-$SECURE_NONCE'; "
|
||||||
|
. "script-src 'self' 'nonce-$SECURE_NONCE'");
|
||||||
|
|
||||||
|
|
||||||
|
// Composer
|
||||||
|
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
die("\"Please run 'composer install' first\"");
|
||||||
|
}
|
||||||
|
require __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
// Settings file
|
||||||
|
require __DIR__ . '/settings.php';
|
||||||
|
|
||||||
|
function sendError($error) {
|
||||||
|
die('{"status": "ERROR", "msg": "A fatal application error has occurred: ' . htmlspecialchars($error) . '"}');
|
||||||
|
}
|
||||||
|
|
||||||
|
date_default_timezone_set(TIMEZONE);
|
||||||
|
|
||||||
|
// Database settings
|
||||||
|
// Also inits database and stuff
|
||||||
|
use Medoo\Medoo;
|
||||||
|
|
||||||
|
$database;
|
||||||
|
try {
|
||||||
|
$database = new Medoo([
|
||||||
|
'database_type' => 'sqlite',
|
||||||
|
'database_file' => DB_FILE,
|
||||||
|
'charset' => DB_CHARSET
|
||||||
|
]);
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
sendError("Database error. $ex");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!DEBUG) {
|
||||||
|
error_reporting(0);
|
||||||
|
} else {
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', 'On');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$VARS;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$VARS = $_POST;
|
||||||
|
define("GET", false);
|
||||||
|
} else {
|
||||||
|
$VARS = $_GET;
|
||||||
|
define("GET", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a string or whatever is empty.
|
||||||
|
* @param $str The thingy to check
|
||||||
|
* @return boolean True if it's empty or whatever.
|
||||||
|
*/
|
||||||
|
function is_empty($str) {
|
||||||
|
return (is_null($str) || !isset($str) || $str == '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Securely verify a password and its hash
|
||||||
|
* @param String $password
|
||||||
|
* @param String $hash the hash to compare to
|
||||||
|
* @return boolean True if password OK, else false
|
||||||
|
*/
|
||||||
|
function comparePassword($password, $hash) {
|
||||||
|
return password_verify($password, $hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dieifnotloggedin() {
|
||||||
|
if ($_SESSION['loggedin'] != true) {
|
||||||
|
sendError("Session expired. Please log out and log in again.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the previous database action had a problem.
|
||||||
|
* @param array $specials int=>string array with special response messages for SQL errors
|
||||||
|
*/
|
||||||
|
function checkDBError($specials = []) {
|
||||||
|
global $database;
|
||||||
|
$errors = $database->error();
|
||||||
|
if (!is_null($errors[1])) {
|
||||||
|
foreach ($specials as $code => $text) {
|
||||||
|
if ($errors[1] == $code) {
|
||||||
|
sendError($text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendError("A database error occurred:<br /><code>" . $errors[2] . "</code>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* http://stackoverflow.com/a/20075147
|
||||||
|
*/
|
||||||
|
if (!function_exists('base_url')) {
|
||||||
|
|
||||||
|
function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) {
|
||||||
|
if (isset($_SERVER['HTTP_HOST'])) {
|
||||||
|
$http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
|
||||||
|
$hostname = $_SERVER['HTTP_HOST'];
|
||||||
|
$dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
|
||||||
|
|
||||||
|
$core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
|
||||||
|
$core = $core[0];
|
||||||
|
|
||||||
|
$tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
|
||||||
|
$end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
|
||||||
|
$base_url = sprintf($tmplt, $http, $hostname, $end);
|
||||||
|
} else
|
||||||
|
$base_url = 'http://localhost/';
|
||||||
|
|
||||||
|
if ($parse) {
|
||||||
|
$base_url = parse_url($base_url);
|
||||||
|
if (isset($base_url['path']))
|
||||||
|
if ($base_url['path'] == '/')
|
||||||
|
$base_url['path'] = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $base_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client's IP has been doing too many brute-force-friendly
|
||||||
|
* requests lately.
|
||||||
|
* Kills the script with a "friendly" error and response code 429
|
||||||
|
* (Too Many Requests) if the last access time in the DB is too near.
|
||||||
|
*
|
||||||
|
* Also updates the rate_limit table with the latest data and purges old rows.
|
||||||
|
* @global type $database
|
||||||
|
*/
|
||||||
|
function engageRateLimit() {
|
||||||
|
global $database;
|
||||||
|
$delay = date("Y-m-d H:i:s", strtotime("-2 seconds"));
|
||||||
|
$database->delete('rate_limit', ["lastaction[<]" => $delay]);
|
||||||
|
if ($database->has('rate_limit', ["AND" => ["ipaddr" => getClientIP()]])) {
|
||||||
|
http_response_code(429);
|
||||||
|
// JSONify it so API clients don't scream too loud
|
||||||
|
die(json_encode(["status" => "ERROR", "msg" => "You're going too fast. Slow down, mkay?"]));
|
||||||
|
} else {
|
||||||
|
// Add a record for the IP address
|
||||||
|
$database->insert('rate_limit', ["ipaddr" => getClientIP(), "lastaction" => date("Y-m-d H:i:s")]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
|||||||
|
<?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/. */
|
||||||
|
|
||||||
|
|
||||||
|
// Whether to show debugging data in output.
|
||||||
|
// DO NOT SET TO TRUE IN PRODUCTION!!!
|
||||||
|
define("DEBUG", false);
|
||||||
|
|
||||||
|
// Database connection settings
|
||||||
|
// See http://medoo.in/api/new for info
|
||||||
|
define("DB_FILE", "/var/sqlitedb/accounts.db");
|
||||||
|
define("DB_CHARSET", "utf8");
|
Loading…
Reference in New Issue