-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.php
More file actions
193 lines (178 loc) · 6.17 KB
/
Copy pathindex.php
File metadata and controls
193 lines (178 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<?php
//Authenticate and load config first.
$admin = new Admin( isset($_POST['pass']) ? $_POST['pass'] : false );
if ( $admin->not_set_up ) {
include ( 'form-setup.php' );
die();
}
$message = '';
if ( isset( $_POST['action'] ) ) {
switch ($_POST['action']) {
case 'unmount':
if ( $result = $admin->unmount() ) {
$message = "There was an error (#$result). The USB Stick was not dismounted. You'll need to turn off the BibleBox and then remove the USB stick";
include('form-admin.php');
die();
}
//And the config and everything are on the usb stick. No need to show them the admin form again.
die("USB Stick unmounted.");
break;
case 'logout':
$admin->logout();
die("Logged Out.");
break;
case 'admin';
if ($_POST['pass1'] && $_POST['pass1'] == $_POST['pass2']) {
$admin->config['hash'] = password_hash($_POST['pass1'], PASSWORD_DEFAULT);
$message .= "<div class='message'>Password Updated</div>";
} elseif ($_POST['pass1'] || $_POST['pass2']) {
$message .= "<div class='message'>Passwords didn't match. The password was not updated.</div>";
}
$message .= "<div class='message'>Configuration Updated</div>";
$admin->update_config_from_post();
$admin->save_config();
include('form-admin.php');
break;
}
} else {
include('form-admin.php');
}
class Admin {
public $config = null;
private $config_dirs = array( // use trailing slashes
"/media/usb0/config/", // usb config
"/media/usb0/Config/", // usb config
"/etc/biblebox/" // default config
);
private $config_dir = null;
public $not_set_up = true;
public $error = false;
function __construct( $password ) {
foreach($this->config_dirs as $dir) {
if ( is_dir($dir) ) {
$this->config_dir = $dir;
break;
}
}
if ( ! $this->config_dir ) {
die("Config dir not found!");
}
$this->get_config();
//If the config file is missing, $this->config will still be null. Show setup form or run setup
if ( ! $this->config['hash'] ) {
if ( 'setup' == $_POST['action'] && $_POST['pass1'] && $_POST['pass1'] == $_POST['pass2'] ) {
//Do setup (create config variable, dump it to config file)
$this->config['hash'] = password_hash($_POST['pass1'], PASSWORD_DEFAULT );
$this->update_config_from_post();
$this->save_config();
header("Location: setup-complete.html");
die();
} elseif ( 'setup' == $_POST['action'] && $_POST['pass1'] != $_POST['pass2'] ) {
$this->error = "Passwords did not match";
} elseif ( 'setup' == $_POST['action'] ) {
$this->error = "You must set up a password";
}
} else {
$this->not_set_up = false;
// There is a config file. So authenticate the user.
$this->authenticate( $password );
}
}
function authenticate($pass = false) {
session_start();
if ($pass) {
if ( $this->too_many_failures() ) {
die("Too Many Password Attempts. Wait a bit, go back and try again.");
}
if ( password_verify($pass, $this->config['hash']) ) {
$this->config['token'] = $_SESSION['token'] = uniqid();
$this->save_config();
return true;
} else {
// They passed a password that's wrong. Send them to login-fail
$this->config['login-fails'] .= time() . "\n";
header('Location: login-fail.html?entered=');
die();
}
} else {
// Use simple session variable to validate user? Do we need to worry about session hijacking and stuff?
// We probably won't be working in an SSL environment (imagine getting to a real internet connection
// often enough to update your SSL certs. Not ideal)
if ( $this->config['token'] && $_SESSION['token'] == $this->config['token'] ) {
return true;
} else {
// They're not trying to log in or anything. They're simply not logged in. Send them to login.
header('Location: login.html');
die();
}
}
}
function update_config_from_post() {
$skip_fields = array('action', 'pass1', 'pass2');
foreach ( $_POST as $field => $value ) {
if ( ! in_array( $field, $skip_fields ) ) {
// Not a skipped field. Add it to the config variable
$this->config[ $field ] = $value;
}
}
}
function save_config() {
// No sanitizing necessary. It's just being written to a text file, so no security hole really.
// We'll sanitize them when retrieving the config vars
foreach( $this->config as $k => $v ) {
$v = substr( $v, 0, 1000 ); // 1,000 character limit per variable, just to be sane.
file_put_contents( $this->config_dir . $k . '.txt', $v );
}
}
function get_config() {
$dir = opendir( $this->config_dir );
if ( $dir === false ) {
die("Config dir not found");
}
$this->config = array();
while ( ( $file = strtolower( readdir($dir) ) ) != false ) {
if ( '.txt' == substr($file,-4) ) {
$this->config[ substr($file, 0, -4) ] = file_get_contents( $this->config_dir . $file );
}
}
//Todo: Sanitize config vars where necessary
}
function unmount() {
exec('sudo -u www-data pumount /media/usb0', $return_text, $result_int);
return $result_int;
}
function logout() {
$this->config['token'] = '';
$this->save_config();
unset($_SESSION['token']);
session_destroy();
}
function too_many_failures() {
$now = time();
$fails = explode("\n", $this->config['login-fails']);
$fails_day = $fails_hour = $fails_minute = $fails_5_seconds = 0;
foreach( $fails as $k => $fail ) {
if ( $fail < $now - 86400 ) {
unset( $fails[$k] );
continue;
}
$fails_day ++;
if ( $fail > $now - 5 ) {
$fails_5_seconds++;
} elseif ( $fail > $now - 60 ) {
$fails_minute++;
$fails_5_seconds++;
} elseif ( $fail > $now - 3600 ) {
$fails_hour++;
$fails_minute++;
$fails_5_seconds++;
}
}
$this->config['login-fails'] = implode( "\n", $fails );
$this->save_config();
if ( $fails_day > 100 || $fails_hour > 30 || $fails_minute > 5 || $fails_5_seconds > 0 ) {
return true;
}
return false;
}
}