/
NDB_Client.class.inc
221 lines (200 loc) · 7.2 KB
/
NDB_Client.class.inc
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
<?php
/**
* This file contains the NDB_Client class
*
* PHP Version 5
*
* @category Main
* @package Main
* @author Sebastien <unknown@example.com>
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
* @link https://www.github.com/aces/Loris/
*/
/**
* NeuroDB client - takes care of loading the configuration, creating the first
* database connection, and including a lot of commonly used libraries.
* By default does web-appropriate setup (session management and user auth).
*
* @category Main
* @package Main
* @author Sebastien <unknown@example.com>
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
* @link https://www.github.com/aces/Loris/
*/
class NDB_Client
{
/**
* Defines whether session management and user authentication is performed
*/
var $_isWebClient = true;
/**
* Defines that the client is a command line client
*
* @return void
*/
function makeCommandLine(): void
{
$this->_isWebClient = false;
}
/**
* Initializes the environment
*
* @param string|null $configFile Path on filesystem to config.xml file
*
* @return bool true on success, false otherwise
*/
function initialize(?string $configFile = null)
{
// Load the config file.
$factory = NDB_Factory::singleton();
$config = $factory->config($configFile);
// Load the database object with settings from config
// so that after this we can just call Database::singleton()
// with no parameters
$DBSettings = $config->getSetting("database");
if (!defined("UNIT_TESTING")) {
$DB = Database::singleton(
$DBSettings['database'],
$DBSettings['username'],
$DBSettings['password'],
$DBSettings['host'],
true
);
}
// Now make sure the factory reference is the same as the
// singleton reference
$DB = $factory->database();
// add extra include paths. This must be done
// after the database is connected, since the setting
// can come from the database.
$extLibs = $config->getSetting('extLibs');
if (!empty($extLibs)) {
set_include_path($extLibs.":".get_include_path());
}
// This must be done after the extra includes, as those may
// include Smarty
include_once "Smarty_hook.class.inc";
$GLOBALS['DB'] =& $DB;
// stop here if this is a command line client
if (!$this->_isWebClient) {
// Set user as unix username.
// Requires Loris to have user with this username
User::singleton(getenv('USER'));
return true;
}
$config_additions = $DB->pselectOne(
"SELECT c.Value
FROM Config c
JOIN ConfigSettings cs ON (c.ConfigID=cs.ID)
WHERE cs.Name=:nm",
array("nm" => "CSPAdditionalHeaders")
);
if (empty($config_additions)) {
$config_additions = "";
}
$CaptchaDomains ="";
// Get reCATPCHA keys
$reCAPTCHAPrivate = $config->getSetting('reCAPTCHAPrivate');
$reCAPTCHAPublic = $config->getSetting('reCAPTCHAPublic');
// Display reCAPTCHA if both private and public keys are set
if ($reCAPTCHAPrivate && $reCAPTCHAPublic) {
$CaptchaDomains ="www.google.com www.gstatic.com";
}
// Content-Security policy for LORIS
// 1. By default, only allow things that are self-hosted
// 2. Allow inline CSS and JS (inline JS is required for
// the Loris base class to load smarty variables
// 3. Allow unsafe-eval because jQuery requires it to load
// our menus. It will be fixed in jQuery 3.0.0.
// See: https://github.com/jquery/jquery/issues/2012
// 4. Allow data URLs for fonts, because our bootstrap theme
// seems to load a font that way.
// 5. Allow reCAPTCHA domains iff the CAPTCHA keys were set
// up by the project
header(
"Content-Security-Policy: "
. "default-src 'self' 'unsafe-inline'; "
. "script-src 'self' 'unsafe-inline' 'unsafe-eval' $CaptchaDomains; "
. "font-src 'self' data:; "
. "img-src 'self' data:; "
. "frame-ancestors 'none'; "
. "form-action 'self'; "
. $config_additions
);
// start php session
$sessionOptions = ['cookie_httponly' => true];
$sessionOptions['cookie_samesite'] = "Strict";
// API Detect
if (strpos(
$_SERVER['REDIRECT_URL'] ?? $_SERVER['REQUEST_URI'] ?? '',
'/api/v0.0.3/'
) !== false
) {
session_cache_limiter('private');
}
session_start($sessionOptions);
// if exiting, destroy the php session
if (isset($_REQUEST['logout']) && $_REQUEST['logout']) {
session_destroy();
header("HTTP/1.1 303 See Other");
header("Location: /");
session_start($sessionOptions);
}
/**
* Log In procedures
*/
if (!isset($_SESSION['State'])) {
$_SESSION['State'] =& State::singleton();
$login = new SinglePointLogin();
$_SESSION['State']->setProperty('login', $login);
} else {
$login = $_SESSION['State']->getProperty('login');
}
if (!$login->isLoggedIn()) {
$auth = $login->authenticate();
if ($auth === true) {
if ($login->passwordExpired()) {
header("HTTP/1.1 302 Found");
header("Location: /login/password-expiry");
}
$login->setState();
} elseif ($auth === false) {
// only send a 403 error if they were attempting to log in,
// otherwise the login page returns a 403 when first accessing
// it.
if (!empty($_REQUEST['login'])) {
header("HTTP/1.1 403 Forbidden");
} else {
// authenticate set an "Incorrect username or password"
// error. We don't want it to be displayed on the login page
// if they didn't just try and log in, so as a hack clear
// it if $_REQUEST['login'] isn't set.
$login->_lastError = '';
}
$login->clearState();
}
}
if (!$login->isLoggedIn()) {
return false;
}
User::singleton($_SESSION['State']->getUsername());
// finished initializing
return true;
}
/**
* Returns true if the user is logged in
*
* @return true iff user is logged in
*/
function isLoggedIn()
{
if (!isset($_SESSION['State'])) {
$_SESSION['State'] =& State::singleton();
$login = new SinglePointLogin();
$_SESSION['State']->setProperty('login', $login);
} else {
$login = $_SESSION['State']->getProperty('login');
}
return $login->isLoggedIn();
}
}