Browse Source

First commit

Skylar Ittner 1 year ago
commit
e11c77026f
12 changed files with 951 additions and 0 deletions
  1. 1
    0
      .gitignore
  2. 12
    0
      README.md
  3. 3
    0
      cloud/README.md
  4. 3
    0
      configs/README.md
  5. 384
    0
      configs/cjdroute.conf
  6. 3
    0
      scripts/README.md
  7. 105
    0
      scripts/status
  8. 3
    0
      www/README.md
  9. 46
    0
      www/api.php
  10. 71
    0
      www/lib/login.php
  11. 305
    0
      www/required.php
  12. 15
    0
      www/settings.template.php

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
1
+*settings.php

+ 12
- 0
README.md View File

@@ -0,0 +1,12 @@
1
+# Netsyms Business Accelerator
2
+
3
+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.
4
+
5
+## About
6
+
7
+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.
8
+
9
+Modifications include:
10
+
11
+- Using [CJDNS](https://source.netsyms.com/Netsyms/prototype-cjdns-pi) to bypass NAT for secure cloud sync and remote tech support
12
+- Installing NGINX, PHP 7.0, and SQLite 3 for serving content

+ 3
- 0
cloud/README.md View File

@@ -0,0 +1,3 @@
1
+# Cloud Web Content
2
+
3
+This folder contains files for running on the Business Apps cloud server.

+ 3
- 0
configs/README.md View File

@@ -0,0 +1,3 @@
1
+# Configuration Files
2
+
3
+This folder contains Debian configuration files with notable changes from common defaults.

+ 384
- 0
configs/cjdroute.conf View File

@@ -0,0 +1,384 @@
1
+{
2
+	// Private key:
3
+	// Your confidentiality and data integrity depend on this key, keep it secret!
4
+	"privateKey": "<<<REDACTED>>>",
5
+	// This key corresponds to the public key and ipv6 address:
6
+	"publicKey": "<<<REDACTED>>>",
7
+	"ipv6": "<<<REDACTED>>>",
8
+	"authorizedPasswords":
9
+	[
10
+		{"password": "<<<REDACTED>>>", "user": "default-login"}
11
+	],
12
+
13
+	"admin":
14
+	{
15
+		"bind": "127.0.0.1:11234",
16
+		"password": "NONE"
17
+	},
18
+
19
+	// Interfaces to connect to the switch core.
20
+	"interfaces":
21
+	{
22
+		// The interface which connects over UDP/IP based VPN tunnel.
23
+		"UDPInterface":
24
+		[
25
+			{
26
+				// Bind to this port.
27
+				"bind": "0.0.0.0:2085",
28
+				// Set the DSCP value for Qos. Default is 0.
29
+				// "dscp": 46,
30
+
31
+				// Nodes to connect to (IPv4 only).
32
+				"connectTo":
33
+				{
34
+					"92.241.12.189:22569": {
35
+						"password": "6mDHySCSJYVgyJqphpgnokqKrCq045mF",
36
+						"publicKey": "9qz459vnkb1v36ypq84m29g2q7dn8gndg9bh0w1499urnkx9nmt0.k",
37
+						"peerName": "h.start-com.ru",
38
+						"Contact": "vvk@start-com.ru"
39
+					},
40
+					"173.208.215.53:6129": {
41
+						"login": "public",
42
+						"password":"wvmrnb31sgtw03d73buyjybwr6vrw1z",
43
+						"publicKey":"p2r0nst699p2gc9cztcmkr5z05522h51jvj5xw7z4x135cz4j9p0.k",
44
+						"peerName":"Don't Sell.Me"
45
+					},
46
+					"198.199.124.143:27313": {
47
+						"contact": "kasm@kasm.eu",
48
+						"location": "Europe/Amsterdam",
49
+						"login": "public-peer",
50
+						"password": "9md1m1sntffbrkq1brb85rw312fr5gb",
51
+						"peerName": "h.kasm.eu",
52
+						"publicKey": "g34d0nbyltxj3sqnc0t5gps32ks4tyl3m9w9qzpk832f9dmp6fh0.k"
53
+					},
54
+					"192.169.7.142:14400":{
55
+						"contact":"Igel@hyperboria.ca",
56
+						"gpg":"A84DFFE62B451511",
57
+						"password":"alfa-charlie-alfa-bravo",
58
+						"peerName":"igel-losangeles",
59
+						"publicKey":"mh9m0411cfcg7xhdc8n6ckls1tjgnvvbdfzdgqf5196tfkw96rr0.k"
60
+					},
61
+					"138.68.245.159:50505":{
62
+						"contact":"chapman.shoop@riseup.net",
63
+						"login":"public-peer",
64
+						"password":"7ztkh2m3p97z0fcyn50wmtx863n6b3j",
65
+						"peerName":"salesforce-tower",
66
+						"publicKey":"6d2kt2hbcp7v0pw9q6f1u2s039kfnt4m4123rjxg26hsgrc12v80.k"
67
+					},
68
+					"162.254.117.11:8351":{
69
+						"contact":"cornfeedhobo@fuzzlabs.org",
70
+						"gpg":"6610FE2B6BD98C42",
71
+						"location":"Chicago, IL, USA",
72
+						"login":"public-access",
73
+						"password":"39XBepVM7TxGWAoROgUzixlbAnkh7WRY",
74
+						"peerName":"vishnu",
75
+						"publicKey":"dhndkly9mhmckbcrb1rgl051ty9fg5zq0tmnms8wxns08fu7kvv0.k"
76
+					},
77
+					"192.34.85.155:2359":{
78
+						"contact":"Igel@hyperboria.ca",
79
+						"gpg":"A84DFFE62B451511",
80
+						"password":"alfa-charlie-alfa-bravo",
81
+						"peerName":"igel-boston",
82
+						"publicKey":"rdxg1nzvmjdj4fyguqydmnl659p7m3x26r6un4ql966q4xt988j0.k"
83
+					},
84
+					"104.200.29.163:53053":{
85
+						"contact":"ansuz@transitiontech.ca",
86
+						"gpg":"024A7C03E67ED8CF",
87
+						"password":"cLjDBorhsYJUmJrESGueHsRY4HXcFyj",
88
+						"peerName":"transitiontech",
89
+						"publicKey":"1941p5k8qqvj17vjrkb9z97wscvtgc1vp8pv1huk5120cu42ytt0.k"
90
+					},
91
+					"107.170.57.34:63472":{
92
+						"contact":"code@ventricle.us",
93
+						"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
94
+						"location":"digitalocean nyc2",
95
+						"login":"public-peer",
96
+						"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
97
+						"peerName":"cord.ventricle.us",
98
+						"publicKey":"1xkf13m9r9h502yuffsq1cg13s5648bpxrtf2c3xcq1mlj893s90.k"
99
+					},
100
+					"185.140.54.73:30800":{
101
+						"contact":"iczero4@gmail.com",
102
+						"gpg":"613CE9DA0E9A3F70EC97760E4BAC4EBB8461FC7E",
103
+						"login":"public",
104
+						"password":"fwlmbx2f3udkd0ymknq4pwwgu2bjklx",
105
+						"peerName":"ic2.hellomouse.cf",
106
+						"publicKey":"c15sfmskdpmj2qw5lfvgfuzggyyk1bjzj4lu3yf6h1x2ckclwdd0.k"
107
+					},
108
+					"173.62.245.186:55249":{
109
+						"contact":"natebrune@gmail.com",
110
+						"country":"us",
111
+						"gpg":"C95CE6BC6735BAD7",
112
+						"ipv6":"fcda:9958:9093:49f2:2677:6df6:2a5a:b01d",
113
+						"password":"Public",
114
+						"peerName":"NAT",
115
+						"publicKey":"vgxqyputh4ldhxktg9msmr61pw938l0ymhkmryljsyzvmr0dtwy0.k",
116
+						"website":"https://github.com/NateBrune"
117
+					},
118
+					"198.58.100.240:22237":{
119
+						"contact":"jhj@trnsz.com",
120
+						"login":"default-login",
121
+						"password":"pqr5brz16vzzu6vhjuj7tv3n078kr5f",
122
+						"peerName":"trnsz",
123
+						"publicKey":"ubbtkp0txwjh44v8kkznvhjqqwr1hd2jzv5ms9zlkfk25svxvtg0.k"
124
+					},
125
+					"149.56.98.167:3703":{
126
+						"contact":"code@ventricle.us",
127
+						"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
128
+						"location":"ovh beauharnois",
129
+						"login":"public-peer",
130
+						"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
131
+						"peerName":"larynx.ventricle.us",
132
+						"publicKey":"jg035j9hup776kwz1k4n0bwpggxp1qmts6t715x53g8vutxktzz0.k"
133
+					},
134
+					"165.227.44.84:34838":{
135
+						"contact":"wattersm@watters.ws",
136
+						"gpg":"E2A3328281D1DA0A08D34FC2058F0C51586CA8C6",
137
+						"location":"Digital Ocean tor1",
138
+						"login":"public-access",
139
+						"password":"8n2w2qu2lfndhgx8xwgp18vyq7fhvux",
140
+						"peerName":"linux1.tor1.watters.ws",
141
+						"publicKey":"b465hml7z3g1vj22ktqdrc3z17mwjxl44cg0mj903n9vycxzqpv0.k"
142
+					},
143
+					"149.56.19.79:55159":{
144
+						"contact":"infrastructure@stashcrypto.com",
145
+						"login":"default-login",
146
+						"password":"dgv86ktpblc2h4y93fsqpshcg2lbp5d",
147
+						"peerName":"git.stashcrypto.net",
148
+						"publicKey":"zbfurpx9n6whzwu6vrlfgmw8g56rmchfmhxxtpg0hwhl84vqf1y0.k"
149
+					},
150
+					"158.69.119.35:9218":{
151
+						"contact":"infrastructure@stashcrypto.com",
152
+						"login":"default-login",
153
+						"password":"w5huch4mn6tkgfp3j9sr8p8r13j3j33",
154
+						"peerName":"seed.stashcrypto.net",
155
+						"publicKey":"rzg61b3fsb675732g5rn8g1x61ypm1z7402n072qmrbbhgzm93f0.k"
156
+					},
157
+				}
158
+			},
159
+			{
160
+				// Bind to this port.
161
+				"bind": "[::]:2085",
162
+				// Set the DSCP value for Qos. Default is 0.
163
+				// "dscp": 46,
164
+
165
+				// Nodes to connect to (IPv6 only).
166
+				"connectTo":
167
+				{
168
+					"[2602:ff65:0:1::fc00]:2359":{
169
+						"contact":"Igel@hyperboria.ca",
170
+						"gpg":"A84DFFE62B451511",
171
+						"password":"alfa-charlie-alfa-bravo",
172
+						"peerName":"igel-boston",
173
+						"publicKey":"rdxg1nzvmjdj4fyguqydmnl659p7m3x26r6un4ql966q4xt988j0.k"
174
+					},
175
+					"[2604:a880:0:1010::f:4001]:63472":{
176
+						"contact":"code@ventricle.us",
177
+						"gpg":"7FE895160E3314027CD3B5D37392CF088BB4345C",
178
+						"location":"digitalocean nyc2",
179
+						"login":"public-peer",
180
+						"password":"ppm6j89mgvss7uvtntcd9scy6166mwb",
181
+						"peerName":"cord.ventricle.us",
182
+						"publicKey":"1xkf13m9r9h502yuffsq1cg13s5648bpxrtf2c3xcq1mlj893s90.k"
183
+					},
184
+					"[2a05:dfc7:dfc8:1d3::1]:30800":{
185
+						"contact":"iczero4@gmail.com",
186
+						"gpg":"613CE9DA0E9A3F70EC97760E4BAC4EBB8461FC7E",
187
+						"login":"public",
188
+						"password":"fwlmbx2f3udkd0ymknq4pwwgu2bjklx",
189
+						"peerName":"ic2.hellomouse.cf",
190
+						"publicKey":"c15sfmskdpmj2qw5lfvgfuzggyyk1bjzj4lu3yf6h1x2ckclwdd0.k"
191
+					},
192
+					"[2607:5300:61:44f::]:55159":{
193
+						"contact":"infrastructure@stashcrypto.com",
194
+						"login":"default-login",
195
+						"password":"dgv86ktpblc2h4y93fsqpshcg2lbp5d",
196
+						"peerName":"git.stashcrypto.net",
197
+						"publicKey":"zbfurpx9n6whzwu6vrlfgmw8g56rmchfmhxxtpg0hwhl84vqf1y0.k"
198
+					}
199
+				}
200
+			}
201
+		]
202
+,
203
+		"ETHInterface":
204
+		[
205
+			// Alternatively bind to just one device and either beacon and/or
206
+			// connect to a specified MAC address
207
+			{
208
+				// Bind to this device (interface name, not MAC)
209
+				// "all" is a pseudo-name which will try to connect to all devices.
210
+				"bind": "all",
211
+
212
+				// Auto-connect to other cjdns nodes on the same network.
213
+				// Options:
214
+				//
215
+				// 0 -- Disabled.
216
+				//
217
+				// 1 -- Accept beacons, this will cause cjdns to accept incoming
218
+				//	  beacon messages and try connecting to the sender.
219
+				//
220
+				// 2 -- Accept and send beacons, this will cause cjdns to broadcast
221
+				//	  messages on the local network which contain a randomly
222
+				//	  generated per-session password, other nodes which have this
223
+				//	  set to 1 or 2 will hear the beacon messages and connect
224
+				//	  automatically.
225
+				//
226
+				"beacon": 2,
227
+
228
+				// Node(s) to connect to manually
229
+				// Note: does not work with "all" pseudo-device-name
230
+				"connectTo":
231
+				{
232
+					// Credentials for connecting look similar to UDP credentials
233
+					// except they begin with the mac address, for example:
234
+					// "01:02:03:04:05:06":{"password":"a","publicKey":"b"}
235
+				}
236
+			}
237
+		]
238
+
239
+	},
240
+
241
+	// Configuration for the router.
242
+	"router":
243
+	{
244
+		// supernodes, if none are specified they'll be taken from your peers
245
+		"supernodes": [
246
+			//"6743gf5tw80ExampleExampleExampleExamplevlyb23zfnuzv0.k",
247
+		]
248
+
249
+		// The interface which is used for connecting to the cjdns network.
250
+		"interface":
251
+		{
252
+			// The type of interface (only TUNInterface is supported for now)
253
+			"type": "TUNInterface"
254
+			// The type of tunfd (only "android" for now)
255
+			// If "android" here, the tunDevice should be used as the pipe path
256
+			// to transfer the tun file description.
257
+			// "tunfd" : "android"
258
+
259
+			// The name of a persistent TUN device to use.
260
+			// This for starting cjdroute as its own user.
261
+			// *MOST USERS DON'T NEED THIS*
262
+			//"tunDevice": "tun0"
263
+		},
264
+
265
+		// System for tunneling IPv4 and ICANN IPv6 through cjdns.
266
+		// This is using the cjdns switch layer as a VPN carrier.
267
+		"ipTunnel":
268
+		{
269
+			// Nodes allowed to connect to us.
270
+			// When a node with the given public key connects, give them the
271
+			// ip4 and/or ip6 addresses listed.
272
+			"allowedConnections":
273
+			[
274
+				// Give the client an address on 192.168.1.0/24, and an address
275
+				// it thinks has all of IPv6 behind it.
276
+				// ip4Prefix is the set of addresses which are routable from the tun
277
+				// for example, if you're advertizing a VPN into a company network
278
+				// which exists in 10.123.45.0/24 space, ip4Prefix should be 24
279
+				// default is 32 for ipv4 and 128 for ipv6
280
+				// so by default it will not install a route
281
+				// ip4Alloc is the block of addresses which are allocated to the
282
+				// for example if you want to issue 4 addresses to the client, those
283
+				// being 192.168.123.0 to 192.168.123.3, you would set this to 30
284
+				// default is 32 for ipv4 and 128 for ipv6 (1 address)
285
+				// {
286
+				//	 "publicKey": "f64hfl7c4uxt6krmhPutTheRealAddressOfANodeHere7kfm5m0.k",
287
+				//	 "ip4Address": "192.168.1.24",
288
+				//	 "ip4Prefix": 0,
289
+				//	 "ip4Alloc": 32,
290
+				//	 "ip6Address": "2001:123:ab::10",
291
+				//	 "ip6Prefix": 0
292
+				//	 "ip6Alloc": 64,
293
+				// },
294
+
295
+				// It's ok to only specify one address and prefix/alloc are optional.
296
+				// {
297
+				//	 "publicKey": "ydq8csdk8p8ThisIsJustAnExampleAddresstxuyqdf27hvn2z0.k",
298
+				//	 "ip4Address": "192.168.1.25",
299
+				//	 "ip4Prefix": 0,
300
+				// }
301
+			],
302
+
303
+			"outgoingConnections":
304
+			[
305
+				// Connect to one or more machines and ask them for IP addresses.
306
+				// "6743gf5tw80ExampleExampleExampleExamplevlyb23zfnuzv0.k",
307
+				// "pw9tfmr8pcrExampleExampleExampleExample8rhg1pgwpwf80.k",
308
+				// "g91lxyxhq0kExampleExampleExampleExample6t0mknuhw75l0.k"
309
+			]
310
+		}
311
+	},
312
+
313
+	// Dropping permissions.
314
+	// In the event of a serious security exploit in cjdns, leak of confidential
315
+	// network traffic and/or keys is highly likely but the following rules are
316
+	// designed to prevent the attack from spreading to the system on which cjdns
317
+	// is running.
318
+	// Counter-intuitively, cjdns is *more* secure if it is started as root because
319
+	// non-root users do not have permission to use chroot or change usernames,
320
+	// limiting the effectiveness of the mitigations herein.
321
+	"security":
322
+	[
323
+		// Change the user id to sandbox the cjdns process after it starts.
324
+		// If keepNetAdmin is set to 0, IPTunnel will be unable to set IP addresses
325
+		// and ETHInterface will be unable to hot-add new interfaces
326
+		// Use { "setuser": 0 } to disable.
327
+		// Default: enabled with keepNetAdmin
328
+		{ "setuser": "nobody", "keepNetAdmin": 1 },
329
+
330
+		// Chroot changes the filesystem root directory which cjdns sees, blocking it
331
+		// from accessing files outside of the chroot sandbox, if the user does not
332
+		// have permission to use chroot(), this will fail quietly.
333
+		// Use { "chroot": 0 } to disable.
334
+		// Default: enabled (using "/var/run")
335
+		{ "chroot": "/var/run/" },
336
+
337
+		// Nofiles is a deprecated security feature which prevents cjdns from opening
338
+		// any files at all, using this will block setting of IP addresses and
339
+		// hot-adding ETHInterface devices but for users who do not need this, it
340
+		// provides a formidable sandbox.
341
+		// Default: disabled
342
+		{ "nofiles": 0 },
343
+
344
+		// Noforks will prevent cjdns from spawning any new processes or threads,
345
+		// this prevents many types of exploits from attacking the wider system.
346
+		// Default: enabled
347
+		{ "noforks": 1 },
348
+
349
+		// Seccomp is the most advanced sandboxing feature in cjdns, it uses
350
+		// SECCOMP_BPF to filter the system calls which cjdns is able to make on a
351
+		// linux system, strictly limiting it's access to the outside world
352
+		// This will fail quietly on any non-linux system
353
+		// Default: enabled
354
+		{ "seccomp": 1 },
355
+
356
+		// The client sets up the core using a sequence of RPC calls, the responses
357
+		// to these calls are verified but in the event that the client crashes
358
+		// setup of the core completes, it could leave the core in an insecure state
359
+		// This call constitutes the client telling the core that the security rules
360
+		// have been fully applied and the core may run. Without it, the core will
361
+		// exit within a few seconds with return code 232.
362
+		// Default: enabled
363
+		{ "setupComplete": 1 }
364
+	],
365
+
366
+	// Logging
367
+	"logging":
368
+	{
369
+		// Uncomment to have cjdns log to stdout rather than making logs available
370
+		// via the admin socket.
371
+		// "logTo":"stdout"
372
+	},
373
+
374
+	// If set to non-zero, cjdns will not fork to the background.
375
+	// Recommended for use in conjunction with "logTo":"stdout".
376
+	"noBackground":0
377
+
378
+	// Pipe file will store in this path, recommended value: /tmp (for unix),
379
+	// \\.\pipe (for windows) 
380
+	// /data/local/tmp (for rooted android) 
381
+	// /data/data/AppName (for non-root android)
382
+	// This only needs to be specified if cjdroute's guess is incorrect
383
+	// "pipe":"/tmp"
384
+}

+ 3
- 0
scripts/README.md View File

@@ -0,0 +1,3 @@
1
+# Scripts
2
+
3
+This folder contains custom scripts that do useful things.

+ 105
- 0
scripts/status View File

@@ -0,0 +1,105 @@
1
+#!/bin/bash
2
+# System status script
3
+# Feel free to copypaste, modify, and share; that's what we did.
4
+
5
+# Text colors
6
+RED='\e[1;31m'
7
+WHT='\e[1;37m'
8
+GRN='\e[1;32m'
9
+BLU='\e[0;34m'
10
+CLR='\e[0m'
11
+
12
+INACTIVE="$RED[INACTIVE]$CLR"
13
+ACTIVE="$GRN[ACTIVE]$CLR"
14
+
15
+echo -e "$BLU"
16
+toilet -f smblock.tlf "Netsyms Business"
17
+toilet -f smblock.tlf "Accelerator"
18
+echo -e "$CLR"
19
+echo -e "---------------------------------------------------$WHT"
20
+echo -e "Engineered by$BLU Netsyms Technologies$CLR"
21
+echo -e ''
22
+echo -e 'Home: https://netsyms.com'
23
+echo -e 'Support: https://support.netsyms.com'
24
+echo -e 'Source: https://source.netsyms.com'
25
+echo -e 'Business: https://netsyms.biz'
26
+echo -e '---------------------------------------------------'
27
+echo -e 'The programs included with this system are free'
28
+echo -e 'software; the exact distribution terms for each'
29
+echo -e 'program are described in the individual files in'
30
+echo -e '/usr/share/doc/*/copyright.'
31
+
32
+echo -e '---------------------------------------------------'
33
+upSeconds="$(/usr/bin/cut -d. -f1 /proc/uptime)"
34
+secs=$((${upSeconds}%60))
35
+mins=$((${upSeconds}/60%60))
36
+hours=$((${upSeconds}/3600%24))
37
+days=$((${upSeconds}/86400))
38
+UPTIME=`printf "%02d days, %02dh %02dm" "$days" "$hours" "$mins"`
39
+
40
+freekb=$(cat /proc/meminfo | grep MemFree | awk {'print $2'})
41
+totalkb=$(cat /proc/meminfo | grep MemTotal | awk {'print $2'})
42
+
43
+freemb=$(($freekb/1000))
44
+totalmb=$(($totalkb/1000))
45
+
46
+percentfree=$(echo "scale=0; $freekb*100/$totalkb" | bc)
47
+
48
+echo -e "Date .................................. $WHT$(date +%b\ %e\ %Y)$CLR"
49
+echo -e "Time ..................................... $WHT$(date +%H:%M:%S)$CLR"
50
+echo -e "Uptime ........................... $WHT$UPTIME$CLR"
51
+echo -e "Processes ..................................... $WHT$(ps ax | wc -l | tr -d " ")$CLR"
52
+echo -e "Load averages ....................$WHT$(uptime | awk -F'[a-z]:' '{ print $2}')$CLR"
53
+if (( $percentfree < 30 )); then
54
+    echo -e "Memory used .......................... $RED$(($totalmb-$freemb)) MB ($((100-$percentfree))%)$CLR"
55
+    echo -e "Memory free .......................... $RED$freemb MB ($percentfree%)$CLR"
56
+else
57
+    echo -e "Memory used .......................... $GRN$(($totalmb-$freemb)) MB ($((100-$percentfree))%)$CLR"
58
+    echo -e "Memory free .......................... $GRN$freemb MB ($percentfree%)$CLR"
59
+fi
60
+cpu=$(</sys/class/thermal/thermal_zone0/temp)
61
+cpu=$((cpu/1000))
62
+if (( $cpu > 45 )); then
63
+    cpu="$RED$cpu\u00b0C$CLR"
64
+else
65
+    cpu="$GRN$cpu\u00b0C$CLR"
66
+fi
67
+echo -e "CPU temperature .............................. $cpu"
68
+
69
+#
70
+# Service Status
71
+#
72
+if [ $(systemctl status cjdns.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
73
+    echo -e "cjdns Service ............................ $ACTIVE"
74
+else
75
+    echo -e "cjdns Service .......................... $INACTIVE"
76
+fi
77
+if [ $(systemctl status nginx.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
78
+    echo -e "nginx Service ............................ $ACTIVE"
79
+else
80
+    echo -e "nginx Service .......................... $INACTIVE"
81
+fi
82
+if [ $(systemctl status php7.0-fpm.service | grep 'Active: ' | awk '{ print $2 }') = 'active' ]; then
83
+    echo -e "php-fpm Service .......................... $ACTIVE"
84
+else
85
+    echo -e "php-fpm Service ........................ $INACTIVE"
86
+fi
87
+
88
+#
89
+# IP/Network Info
90
+#
91
+
92
+echo -e "---------------------------------------------------$WHT"
93
+echo -e "Local IP$CLR"
94
+ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'
95
+echo -e "---------------------------------------------------$WHT"
96
+echo -e "Public IP$CLR"
97
+dig +short myip.opendns.com @resolver1.opendns.com
98
+echo -e "---------------------------------------------------$WHT"
99
+echo -e "CJDNS IP$CLR"
100
+sudo grep -m 1 '"ipv6"' /etc/cjdroute.conf | awk '{ print $2 }' | sed 's/[",]//g'
101
+echo -e '---------------------------------------------------'
102
+echo -e "For network bandwidth usage data, run$WHT vnstat$CLR"
103
+echo -e "To refresh this status message, run$WHT status$CLR"
104
+#vnstat -i eth0+tun0+wlan0 --style 0
105
+echo -e '---------------------------------------------------'

+ 3
- 0
www/README.md View File

@@ -0,0 +1,3 @@
1
+# Local Web Content
2
+
3
+This folder contains files for the Accelerator's webroot.

+ 46
- 0
www/api.php View File

@@ -0,0 +1,46 @@
1
+<?php
2
+
3
+/* This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
+
7
+/**
8
+ * Simple JSON API to allow other apps to access accounts in this system.
9
+ *
10
+ * Requests can be sent via either GET or POST requests.  POST is recommended
11
+ * as it has a lower chance of being logged on the server, exposing unencrypted
12
+ * user passwords.
13
+ */
14
+require __DIR__ . '/required.php';
15
+require __DIR__ . '/lib/login.php';
16
+
17
+switch ($VARS['action']) {
18
+    case "ping":
19
+        exit(json_encode(["status" => "OK"]));
20
+        break;
21
+    case "auth":
22
+        $errmsg = "";
23
+        if (authenticate_user($VARS['username'], $VARS['password'], $errmsg)) {
24
+            exit(json_encode(["status" => "OK", "msg" => "Login successful."]));
25
+        } else {
26
+            exit(json_encode(["status" => "ERROR", "msg" => "Login incorrect."]));
27
+        }
28
+        break;
29
+    case "hastotp":
30
+        if (userHasTOTP($VARS['username'])) {
31
+            exit(json_encode(["status" => "OK", "otp" => true]));
32
+        } else {
33
+            exit(json_encode(["status" => "OK", "otp" => false]));
34
+        }
35
+        break;
36
+    case "verifytotp":
37
+        if (verifyTOTP($VARS['username'], $VARS['code'])) {
38
+            exit(json_encode(["status" => "OK", "valid" => true]));
39
+        } else {
40
+            exit(json_encode(["status" => "ERROR", "msg" => "Authentication code incorrect.", "valid" => false]));
41
+        }
42
+        break;
43
+    default:
44
+        http_response_code(404);
45
+        die(json_encode("404 Not Found: the requested action is not available."));
46
+}

+ 71
- 0
www/lib/login.php View File

@@ -0,0 +1,71 @@
1
+<?php
2
+
3
+/* This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
+
7
+/**
8
+ * Authentication and account functions
9
+ */
10
+use Base32\Base32;
11
+use OTPHP\TOTP;
12
+
13
+/**
14
+ * Checks the given credentials against the database.
15
+ * @param string $username
16
+ * @param string $password
17
+ * @return boolean True if OK, else false
18
+ */
19
+function authenticate_user($username, $password) {
20
+    global $database;
21
+    $username = strtolower($username);
22
+    if (is_empty($username) || is_empty($password)) {
23
+        return false;
24
+    }
25
+    $hash = $database->get('accounts', 'password', ['username' => $username]);
26
+    return (comparePassword($password, $hash));
27
+}
28
+
29
+function user_exists($username) {
30
+    return $database->has('accounts', ['username' => strtolower($username)]);
31
+}
32
+
33
+
34
+////////////////////////////////////////////////////////////////////////////////
35
+//                          2-factor authentication                           //
36
+////////////////////////////////////////////////////////////////////////////////
37
+
38
+/**
39
+ * Check if a user has TOTP setup
40
+ * @global $database $database
41
+ * @param string $username
42
+ * @return boolean true if TOTP secret exists, else false
43
+ */
44
+function userHasTOTP($username) {
45
+    global $database;
46
+    $username = strtolower($username);
47
+    $secret = $database->get('accounts', 'authsecret', ['username' => $username]);
48
+    if (is_empty($secret)) {
49
+        return false;
50
+    }
51
+    return true;
52
+}
53
+
54
+/**
55
+ * Verify a TOTP multiauth code
56
+ * @global $database
57
+ * @param string $username
58
+ * @param int $code
59
+ * @return boolean true if it's legit, else false
60
+ */
61
+function verifyTOTP($username, $code) {
62
+    global $database;
63
+    $username = strtolower($username);
64
+    $authsecret = $database->get('accounts', 'authsecret', ['username' => $username]);
65
+    if (is_empty($authsecret)) {
66
+        return false;
67
+    }
68
+    $totp = new TOTP(null, $authsecret);
69
+    return $totp->verify($code);
70
+}
71
+

+ 305
- 0
www/required.php View File

@@ -0,0 +1,305 @@
1
+<?php
2
+
3
+/* This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
+
7
+/**
8
+ * This file contains global settings and utility functions.
9
+ */
10
+ob_start(); // allow sending headers after content
11
+
12
+// Set default content type to JSON
13
+header('Content-Type: application/json; charset=utf-8');
14
+
15
+header('X-Content-Type-Options: nosniff');
16
+header('X-XSS-Protection: 1; mode=block');
17
+header('X-Powered-By: PHP');
18
+header('X-Frame-Options: "DENY"');
19
+header('Referrer-Policy: "no-referrer, strict-origin-when-cross-origin"');
20
+$SECURE_NONCE = base64_encode(random_bytes(8));
21
+
22
+header("Content-Security-Policy: "
23
+    . "default-src 'self';"
24
+    . "object-src 'none'; "
25
+    . "img-src * data:; "
26
+    . "media-src 'self'; "
27
+    . "frame-src 'none'; "
28
+    . "font-src 'self'; "
29
+    . "connect-src *; "
30
+    . "style-src 'self' 'nonce-$SECURE_NONCE'; "
31
+    . "script-src 'self' 'nonce-$SECURE_NONCE'");
32
+
33
+
34
+// Composer
35
+if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
36
+	die("\"Please run 'composer install' first\"");
37
+}
38
+require __DIR__ . '/vendor/autoload.php';
39
+
40
+// Settings file
41
+require __DIR__ . '/settings.php';
42
+
43
+function sendError($error) {
44
+    die('{"status": "ERROR", "msg": "A fatal application error has occurred: ' . htmlspecialchars($error) . '"}');
45
+}
46
+
47
+date_default_timezone_set(TIMEZONE);
48
+
49
+// Database settings
50
+// Also inits database and stuff
51
+use Medoo\Medoo;
52
+
53
+$database;
54
+try {
55
+    $database = new Medoo([
56
+    	'database_type' => 'sqlite',
57
+    	'database_file' => DB_FILE,
58
+        'charset' => DB_CHARSET
59
+    ]);
60
+} catch (Exception $ex) {
61
+    header('HTTP/1.1 500 Internal Server Error');
62
+    sendError("Database error.  $ex");
63
+}
64
+
65
+
66
+if (!DEBUG) {
67
+    error_reporting(0);
68
+} else {
69
+    error_reporting(E_ALL);
70
+    ini_set('display_errors', 'On');
71
+}
72
+
73
+
74
+$VARS;
75
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
76
+    $VARS = $_POST;
77
+    define("GET", false);
78
+} else {
79
+    $VARS = $_GET;
80
+    define("GET", true);
81
+}
82
+
83
+/**
84
+ * Checks if a string or whatever is empty.
85
+ * @param $str The thingy to check
86
+ * @return boolean True if it's empty or whatever.
87
+ */
88
+function is_empty($str) {
89
+    return (is_null($str) || !isset($str) || $str == '');
90
+}
91
+
92
+/**
93
+ * Securely verify a password and its hash
94
+ * @param String $password
95
+ * @param String $hash the hash to compare to
96
+ * @return boolean True if password OK, else false
97
+ */
98
+function comparePassword($password, $hash) {
99
+    return password_verify($password, $hash);
100
+}
101
+
102
+function dieifnotloggedin() {
103
+    if ($_SESSION['loggedin'] != true) {
104
+        sendError("Session expired.  Please log out and log in again.");
105
+    }
106
+}
107
+
108
+/**
109
+ * Check if the previous database action had a problem.
110
+ * @param array $specials int=>string array with special response messages for SQL errors
111
+ */
112
+function checkDBError($specials = []) {
113
+    global $database;
114
+    $errors = $database->error();
115
+    if (!is_null($errors[1])) {
116
+        foreach ($specials as $code => $text) {
117
+            if ($errors[1] == $code) {
118
+                sendError($text);
119
+            }
120
+        }
121
+        sendError("A database error occurred:<br /><code>" . $errors[2] . "</code>");
122
+    }
123
+}
124
+
125
+/*
126
+ * http://stackoverflow.com/a/20075147
127
+ */
128
+if (!function_exists('base_url')) {
129
+
130
+    function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) {
131
+        if (isset($_SERVER['HTTP_HOST'])) {
132
+            $http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
133
+            $hostname = $_SERVER['HTTP_HOST'];
134
+            $dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
135
+
136
+            $core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
137
+            $core = $core[0];
138
+
139
+            $tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
140
+            $end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
141
+            $base_url = sprintf($tmplt, $http, $hostname, $end);
142
+        } else
143
+            $base_url = 'http://localhost/';
144
+
145
+        if ($parse) {
146
+            $base_url = parse_url($base_url);
147
+            if (isset($base_url['path']))
148
+                if ($base_url['path'] == '/')
149
+                    $base_url['path'] = '';
150
+        }
151
+
152
+        return $base_url;
153
+    }
154
+
155
+}
156
+
157
+/**
158
+ * Check if a given ipv4 address is in a given cidr
159
+ * @param  string $ip    IP to check in IPV4 format eg. 127.0.0.1
160
+ * @param  string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
161
+ * @return boolean true if the ip is in this range / false if not.
162
+ * @author Thorsten Ott <https://gist.github.com/tott/7684443>
163
+ */
164
+function ip4_in_cidr($ip, $cidr) {
165
+    if (strpos($cidr, '/') == false) {
166
+        $cidr .= '/32';
167
+    }
168
+    // $range is in IP/CIDR format eg 127.0.0.1/24
169
+    list( $cidr, $netmask ) = explode('/', $cidr, 2);
170
+    $range_decimal = ip2long($cidr);
171
+    $ip_decimal = ip2long($ip);
172
+    $wildcard_decimal = pow(2, ( 32 - $netmask)) - 1;
173
+    $netmask_decimal = ~ $wildcard_decimal;
174
+    return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
175
+}
176
+
177
+/**
178
+ * Check if a given ipv6 address is in a given cidr
179
+ * @param string $ip IP to check in IPV6 format
180
+ * @param string $cidr CIDR netmask
181
+ * @return boolean true if the IP is in this range, false otherwise.
182
+ * @author MW. <https://stackoverflow.com/a/7952169>
183
+ */
184
+function ip6_in_cidr($ip, $cidr) {
185
+    $address = inet_pton($ip);
186
+    $subnetAddress = inet_pton(explode("/", $cidr)[0]);
187
+    $subnetMask = explode("/", $cidr)[1];
188
+
189
+    $addr = str_repeat("f", $subnetMask / 4);
190
+    switch ($subnetMask % 4) {
191
+        case 0:
192
+            break;
193
+        case 1:
194
+            $addr .= "8";
195
+            break;
196
+        case 2:
197
+            $addr .= "c";
198
+            break;
199
+        case 3:
200
+            $addr .= "e";
201
+            break;
202
+    }
203
+    $addr = str_pad($addr, 32, '0');
204
+    $addr = pack("H*", $addr);
205
+
206
+    $binMask = $addr;
207
+    return ($address & $binMask) == $subnetAddress;
208
+}
209
+
210
+/**
211
+ * Check if the REMOTE_ADDR is on Cloudflare's network.
212
+ * @return boolean true if it is, otherwise false
213
+ */
214
+function validateCloudflare() {
215
+    if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
216
+        // Using IPv6
217
+        $cloudflare_ips_v6 = [
218
+            "2400:cb00::/32",
219
+            "2405:8100::/32",
220
+            "2405:b500::/32",
221
+            "2606:4700::/32",
222
+            "2803:f800::/32",
223
+            "2c0f:f248::/32",
224
+            "2a06:98c0::/29"
225
+        ];
226
+        $valid = false;
227
+        foreach ($cloudflare_ips_v6 as $cidr) {
228
+            if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
229
+                $valid = true;
230
+                break;
231
+            }
232
+        }
233
+    } else {
234
+        // Using IPv4
235
+        $cloudflare_ips_v4 = [
236
+            "103.21.244.0/22",
237
+            "103.22.200.0/22",
238
+            "103.31.4.0/22",
239
+            "104.16.0.0/12",
240
+            "108.162.192.0/18",
241
+            "131.0.72.0/22",
242
+            "141.101.64.0/18",
243
+            "162.158.0.0/15",
244
+            "172.64.0.0/13",
245
+            "173.245.48.0/20",
246
+            "188.114.96.0/20",
247
+            "190.93.240.0/20",
248
+            "197.234.240.0/22",
249
+            "198.41.128.0/17"
250
+        ];
251
+        $valid = false;
252
+        foreach ($cloudflare_ips_v4 as $cidr) {
253
+            if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) {
254
+                $valid = true;
255
+                break;
256
+            }
257
+        }
258
+    }
259
+    return $valid;
260
+}
261
+
262
+/**
263
+ * Makes a good guess at the client's real IP address.
264
+ *
265
+ * @return string Client IP or `0.0.0.0` if we can't find anything
266
+ */
267
+function getClientIP() {
268
+    // If CloudFlare is in the mix, we should use it.
269
+    // Check if the request is actually from CloudFlare before trusting it.
270
+    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
271
+        if (validateCloudflare()) {
272
+            return $_SERVER["HTTP_CF_CONNECTING_IP"];
273
+        }
274
+    }
275
+
276
+    if (isset($_SERVER["REMOTE_ADDR"])) {
277
+        return $_SERVER["REMOTE_ADDR"];
278
+    }
279
+
280
+    return "0.0.0.0"; // This will not happen unless we aren't a web server
281
+}
282
+
283
+/**
284
+ * Check if the client's IP has been doing too many brute-force-friendly 
285
+ * requests lately.
286
+ * Kills the script with a "friendly" error and response code 429 
287
+ * (Too Many Requests) if the last access time in the DB is too near.
288
+ * 
289
+ * Also updates the rate_limit table with the latest data and purges old rows. 
290
+ * @global type $database
291
+ */
292
+function engageRateLimit() {
293
+    global $database;
294
+    $delay = date("Y-m-d H:i:s", strtotime("-2 seconds"));
295
+    $database->delete('rate_limit', ["lastaction[<]" => $delay]);
296
+    if ($database->has('rate_limit', ["AND" => ["ipaddr" => getClientIP()]])) {
297
+        http_response_code(429);
298
+        // JSONify it so API clients don't scream too loud
299
+        die(json_encode(["status" => "ERROR", "msg" => "You're going too fast.  Slow down, mkay?"]));
300
+    } else {
301
+        // Add a record for the IP address
302
+        $database->insert('rate_limit', ["ipaddr" => getClientIP(), "lastaction" => date("Y-m-d H:i:s")]);
303
+    }
304
+}
305
+

+ 15
- 0
www/settings.template.php View File

@@ -0,0 +1,15 @@
1
+<?php
2
+
3
+/* This Source Code Form is subject to the terms of the Mozilla Public
4
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
5
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
+
7
+
8
+// Whether to show debugging data in output.
9
+// DO NOT SET TO TRUE IN PRODUCTION!!!
10
+define("DEBUG", false);
11
+
12
+// Database connection settings
13
+// See http://medoo.in/api/new for info
14
+define("DB_FILE", "/var/sqlitedb/accounts.db");
15
+define("DB_CHARSET", "utf8");

Loading…
Cancel
Save