|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
/** |
|
6
|
|
|
* Teampass - a collaborative passwords manager. |
|
7
|
|
|
* --- |
|
8
|
|
|
* This file is part of the TeamPass project. |
|
9
|
|
|
* |
|
10
|
|
|
* TeamPass is free software: you can redistribute it and/or modify it |
|
11
|
|
|
* under the terms of the GNU General Public License as published by |
|
12
|
|
|
* the Free Software Foundation, version 3 of the License. |
|
13
|
|
|
* |
|
14
|
|
|
* TeamPass is distributed in the hope that it will be useful, |
|
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17
|
|
|
* GNU General Public License for more details. |
|
18
|
|
|
* |
|
19
|
|
|
* You should have received a copy of the GNU General Public License |
|
20
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>. |
|
21
|
|
|
* |
|
22
|
|
|
* Certain components of this file may be under different licenses. For |
|
23
|
|
|
* details, see the `licenses` directory or individual file headers. |
|
24
|
|
|
* --- |
|
25
|
|
|
* @file api.php |
|
26
|
|
|
* @author Nils Laumaillé ([email protected]) |
|
27
|
|
|
* @copyright 2009-2025 Teampass.net |
|
28
|
|
|
* @license GPL-3.0 |
|
29
|
|
|
* @see https://www.teampass.net |
|
30
|
|
|
*/ |
|
31
|
|
|
|
|
32
|
|
|
use TeampassClasses\SessionManager\SessionManager; |
|
33
|
|
|
use Symfony\Component\HttpFoundation\Request as SymfonyRequest; |
|
34
|
|
|
use TeampassClasses\Language\Language; |
|
35
|
|
|
use TeampassClasses\NestedTree\NestedTree; |
|
36
|
|
|
use TeampassClasses\PerformChecks\PerformChecks; |
|
37
|
|
|
use TeampassClasses\ConfigManager\ConfigManager; |
|
38
|
|
|
|
|
39
|
|
|
// Load functions |
|
40
|
|
|
require_once __DIR__.'/../sources/main.functions.php'; |
|
41
|
|
|
|
|
42
|
|
|
// init |
|
43
|
|
|
loadClasses('DB'); |
|
44
|
|
|
$session = SessionManager::getSession(); |
|
45
|
|
|
$request = SymfonyRequest::createFromGlobals(); |
|
46
|
|
|
$lang = new Language($session->get('user-language') ?? 'english'); |
|
47
|
|
|
|
|
48
|
|
|
// Load config |
|
49
|
|
|
$configManager = new ConfigManager(); |
|
50
|
|
|
$SETTINGS = $configManager->getAllSettings(); |
|
51
|
|
|
|
|
52
|
|
|
// Do checks |
|
53
|
|
|
$checkUserAccess = new PerformChecks( |
|
54
|
|
|
dataSanitizer( |
|
55
|
|
|
[ |
|
56
|
|
|
'type' => htmlspecialchars($request->request->get('type', ''), ENT_QUOTES, 'UTF-8'), |
|
57
|
|
|
], |
|
58
|
|
|
[ |
|
59
|
|
|
'type' => 'trim|escape', |
|
60
|
|
|
], |
|
61
|
|
|
), |
|
62
|
|
|
[ |
|
63
|
|
|
'user_id' => returnIfSet($session->get('user-id'), null), |
|
64
|
|
|
'user_key' => returnIfSet($session->get('key'), null), |
|
65
|
|
|
] |
|
66
|
|
|
); |
|
67
|
|
|
// Handle the case |
|
68
|
|
|
echo $checkUserAccess->caseHandler(); |
|
69
|
|
|
if ($checkUserAccess->checkSession() === false || $checkUserAccess->userAccessPage('api') === false) { |
|
70
|
|
|
// Not allowed page |
|
71
|
|
|
$session->set('system-error_code', ERR_NOT_ALLOWED); |
|
72
|
|
|
include $SETTINGS['cpassman_dir'] . '/error.php'; |
|
73
|
|
|
exit; |
|
74
|
|
|
} |
|
75
|
|
|
|
|
76
|
|
|
// Define Timezone |
|
77
|
|
|
date_default_timezone_set($SETTINGS['timezone'] ?? 'UTC'); |
|
78
|
|
|
|
|
79
|
|
|
// Set header properties |
|
80
|
|
|
header('Content-type: text/html; charset=utf-8'); |
|
81
|
|
|
header('Cache-Control: no-cache, no-store, must-revalidate'); |
|
82
|
|
|
|
|
83
|
|
|
// --------------------------------- // |
|
84
|
|
|
|
|
85
|
|
|
// Get FQDN and API Key settings |
|
86
|
|
|
$browserFqdn = getDomainFromSettingsUrl($SETTINGS['cpassman_url'] ?? ''); |
|
87
|
|
|
|
|
88
|
|
|
/** |
|
89
|
|
|
* Extract the domain name (host) from the application URL setting. |
|
90
|
|
|
* * @param string $url The URL string to parse, typically from $SETTINGS['passman_url']. |
|
91
|
|
|
* @return string The extracted domain name (host) or an empty string if invalid. |
|
92
|
|
|
*/ |
|
93
|
|
|
function getDomainFromSettingsUrl(string $url): string |
|
94
|
|
|
{ |
|
95
|
|
|
if (empty($url)) { |
|
96
|
|
|
return 'localhost'; |
|
97
|
|
|
} |
|
98
|
|
|
|
|
99
|
|
|
// Ensure protocol exists for parse_url to work correctly |
|
100
|
|
|
if (strpos($url, 'http') !== 0 && strpos($url, '//') !== 0) { |
|
101
|
|
|
$url = 'http://' . $url; |
|
102
|
|
|
} |
|
103
|
|
|
|
|
104
|
|
|
$parsedUrl = parse_url($url); |
|
105
|
|
|
$host = isset($parsedUrl['host']) ? strtolower(trim($parsedUrl['host'], '.')) : 'localhost'; |
|
106
|
|
|
|
|
107
|
|
|
// Special handling for localhost to get the subfolder name (e.g., "TeamPass") |
|
108
|
|
|
if (in_array($host, ['localhost', '127.0.0.1', '::1'])) { |
|
109
|
|
|
$path = isset($parsedUrl['path']) ? trim($parsedUrl['path'], '/') : ''; |
|
110
|
|
|
if (!empty($path)) { |
|
111
|
|
|
$segments = explode('/', $path); |
|
112
|
|
|
// Check if the first segment is a directory and not the script name itself |
|
113
|
|
|
if (!empty($segments[0]) && strpos($segments[0], '.php') === false) { |
|
114
|
|
|
return $segments[0]; |
|
115
|
|
|
} |
|
116
|
|
|
} |
|
117
|
|
|
} |
|
118
|
|
|
|
|
119
|
|
|
return $host; |
|
120
|
|
|
} |
|
121
|
|
|
?> |
|
122
|
|
|
|
|
123
|
|
|
<!-- Content Header (Page header) --> |
|
124
|
|
|
<div class="content-header"> |
|
125
|
|
|
<div class="container-fluid"> |
|
126
|
|
|
<div class="row mb-2"> |
|
127
|
|
|
<div class="col-sm-6"> |
|
128
|
|
|
<h1 class="m-0 text-dark"> |
|
129
|
|
|
<i class="fas fa-cubes mr-2"></i><?php echo $lang->get('api'); ?> |
|
130
|
|
|
</h1> |
|
131
|
|
|
</div><!-- /.col --> |
|
132
|
|
|
</div><!-- /.row --> |
|
133
|
|
|
</div><!-- /.container-fluid --> |
|
134
|
|
|
</div> |
|
135
|
|
|
<!-- /.content-header --> |
|
136
|
|
|
|
|
137
|
|
|
<section class="content"> |
|
138
|
|
|
<div class="container-fluid"> |
|
139
|
|
|
<div class="row"> |
|
140
|
|
|
<div class="col-12"> |
|
141
|
|
|
<div class='card card-primary'> |
|
142
|
|
|
<div class='card-header'> |
|
143
|
|
|
<h3 class='card-title'><?php echo $lang->get('api_configuration'); ?></h3> |
|
144
|
|
|
</div> |
|
145
|
|
|
<!-- /.card-header --> |
|
146
|
|
|
<!-- form start --> |
|
147
|
|
|
<div class='card-body'> |
|
148
|
|
|
|
|
149
|
|
|
<div class='row mb-2'> |
|
150
|
|
|
<div class='col-10'> |
|
151
|
|
|
<?php echo $lang->get('settings_api'); ?> |
|
152
|
|
|
<small id='passwordHelpBlock' class='form-text text-muted'> |
|
153
|
|
|
<?php echo $lang->get('settings_api_tip'); ?> |
|
154
|
|
|
</small> |
|
155
|
|
|
</div> |
|
156
|
|
|
<div class='col-2'> |
|
157
|
|
|
<div class='toggle toggle-modern' id='api' data-toggle-on='<?php echo isset($SETTINGS['api']) === true && (int) $SETTINGS['api'] === 1 ? 'true' : 'false'; ?>'></div><input type='hidden' id='api_input' value='<?php echo isset($SETTINGS['api']) === true && (int) $SETTINGS['api'] === 1 ? '1' : '0'; ?>' /> |
|
158
|
|
|
</div> |
|
159
|
|
|
</div> |
|
160
|
|
|
|
|
161
|
|
|
<div class='row mb-3'> |
|
162
|
|
|
<div class='col-10'> |
|
163
|
|
|
<?php echo $lang->get('settings_api_token_duration'); ?> |
|
164
|
|
|
<small id='passwordHelpBlock' class='form-text text-muted'> |
|
165
|
|
|
<?php echo $lang->get('settings_api_token_duration_tip'); ?> |
|
166
|
|
|
</small> |
|
167
|
|
|
</div> |
|
168
|
|
|
<div class='col-2'> |
|
169
|
|
|
<input type='text' class='form-control form-control-sm' id='api_token_duration' value='<?php echo isset($SETTINGS['api_token_duration']) === true ? (int) $SETTINGS['api_token_duration'] : 60; ?>'> |
|
170
|
|
|
</div> |
|
171
|
|
|
</div> |
|
172
|
|
|
|
|
173
|
|
|
<ul class="nav nav-tabs"> |
|
174
|
|
|
<li class="nav-item"> |
|
175
|
|
|
<a class="nav-link active" data-toggle="tab" href="#users" role="tab" aria-controls="users"><?php echo $lang->get('users'); ?></a> |
|
176
|
|
|
</li> |
|
177
|
|
|
<li class="nav-item"> |
|
178
|
|
|
<a class="nav-link" data-toggle="tab" href="#extension" role="tab" aria-controls="extension"><?php echo $lang->get('browser_extension'); ?></a> |
|
179
|
|
|
</li> |
|
180
|
|
|
<li class="nav-item"> |
|
181
|
|
|
<a class="nav-link" data-toggle="tab" href="#keys" role="tab" aria-controls="keys"><?php echo $lang->get('settings_api_keys_list'); ?></a> |
|
182
|
|
|
</li> |
|
183
|
|
|
<!--<li class="nav-item"> |
|
184
|
|
|
<a class="nav-link" data-toggle="tab" href="#ips" role="tab" aria-controls="ips"><?php echo $lang->get('api_whitelist_ips'); ?></a> |
|
185
|
|
|
</li>--> |
|
186
|
|
|
</ul> |
|
187
|
|
|
|
|
188
|
|
|
<div class="tab-content"> |
|
189
|
|
|
<div class="tab-pane fade show" id="keys" role="tabpanel" aria-labelledby="keys-tab"> |
|
190
|
|
|
<small id="passwordHelpBlock" class="form-text text-muted mt-4"> |
|
191
|
|
|
<?php echo $lang->get('settings_api_keys_list_tip'); ?> |
|
192
|
|
|
</small> |
|
193
|
|
|
|
|
194
|
|
|
<div class="mt-4 text-orange"> |
|
195
|
|
|
<i class="fa-solid fa-bullhorn mr-2"></i>Those keys are not anymore allowed to use the API. You should use API with a User account. |
|
196
|
|
|
</div> |
|
197
|
|
|
<div class="mt-4"> |
|
198
|
|
|
<?php |
|
199
|
|
|
$rowsKeys = DB::query( |
|
200
|
|
|
'SELECT * |
|
201
|
|
|
FROM ' . prefixTable('api') . ' |
|
202
|
|
|
WHERE type = %s |
|
203
|
|
|
ORDER BY timestamp ASC', |
|
204
|
|
|
'key' |
|
205
|
|
|
); |
|
206
|
|
|
?> |
|
207
|
|
|
<table class="table table-hover table-striped<?php echo DB::count() > 0 ? '' : ' hidden'; ?> table-responsive" style="width:100%" id="table-api-keys"> |
|
208
|
|
|
<thead> |
|
209
|
|
|
<tr> |
|
210
|
|
|
<th width="50px"></th> |
|
211
|
|
|
<th><?php echo $lang->get('label'); ?></th> |
|
212
|
|
|
<th><?php echo $lang->get('settings_api_key'); ?></th> |
|
213
|
|
|
<th><i class="fa-solid fa-user-check infotip" title="<?php echo $lang->get('enabled'); ?>"></i></th> |
|
214
|
|
|
<th><i class="fa-regular fa-square-plus infotip" title="<?php echo $lang->get('allowed_to_create'); ?>"></i></th> |
|
215
|
|
|
<th><i class="fa-solid fa-glasses infotip" title="<?php echo $lang->get('allowed_to_read'); ?>"></i></th> |
|
216
|
|
|
<th><i class="fa-solid fa-pencil infotip" title="<?php echo $lang->get('allowed_to_update'); ?>"></i></th> |
|
217
|
|
|
<th><i class="fa-solid fa-trash infotip" title="<?php echo $lang->get('allowed_to_delete'); ?>"></i></th> |
|
218
|
|
|
</tr> |
|
219
|
|
|
</thead> |
|
220
|
|
|
<tbody> |
|
221
|
|
|
<?php |
|
222
|
|
|
foreach ($rowsKeys as $key) { |
|
223
|
|
|
echo ' |
|
224
|
|
|
<tr data-id="' . $key['increment_id'] . '"> |
|
225
|
|
|
<td width="50px"><i class="fas fa-trash infotip pointer delete-api-key" title="' . $lang->get('del_button') . '"></i></td> |
|
226
|
|
|
<td><span class="edit-api-key pointer">' . $key['label'] . '</span></td> |
|
227
|
|
|
<td>' . $key['value']. '</td> |
|
228
|
|
|
<td><i class="fas '.((int) $key['enabled'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="enabled" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
229
|
|
|
<td><i class="fas '.((int) $key['allowed_to_create'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_create" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
230
|
|
|
<td><i class="fas '.((int) $key['allowed_to_read'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_read" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
231
|
|
|
<td><i class="fas '.((int) $key['allowed_to_update'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_update" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
232
|
|
|
<td><i class="fas '.((int) $key['allowed_to_delete'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_delete" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
233
|
|
|
</tr>'; |
|
234
|
|
|
} ?> |
|
235
|
|
|
</tbody> |
|
236
|
|
|
</table> |
|
237
|
|
|
|
|
238
|
|
|
<div class="mt-2<?php echo DB::count() > 0 ? ' hidden' : ''; ?>" id="api-no-keys"> |
|
239
|
|
|
<i class="fas fa-info mr-2 text-warning"></i><?php echo $lang->get('no_data_defined'); ?> |
|
240
|
|
|
</div> |
|
241
|
|
|
|
|
242
|
|
|
</div> |
|
243
|
|
|
|
|
244
|
|
|
<div class="form-group mt-4"> |
|
245
|
|
|
<div class="callout callout-info"> |
|
246
|
|
|
<span class="text-bold"><?php echo $lang->get('adding_new_api_key'); ?></span> |
|
247
|
|
|
|
|
248
|
|
|
<div class="row mt-1 ml-1"> |
|
249
|
|
|
<input type="text" placeholder="<?php echo $lang->get('label'); ?>" class="col-4 form-control form-control-sm purify" id="new_api_key_label" data-field="label"> |
|
250
|
|
|
<span class="fa-stack ml-2 infotip pointer" title="<?php echo $lang->get('adding_new_api_key'); ?>" id="button-new-api-key"> |
|
251
|
|
|
<i class="fas fa-square fa-stack-2x"></i> |
|
252
|
|
|
<i class="fas fa-plus fa-stack-1x fa-inverse"></i> |
|
253
|
|
|
</span> |
|
254
|
|
|
</div> |
|
255
|
|
|
</div> |
|
256
|
|
|
</div> |
|
257
|
|
|
|
|
258
|
|
|
</div> |
|
259
|
|
|
|
|
260
|
|
|
<div class="tab-pane fade show mb-4" id="ips" role="tabpanel" aria-labelledby="ips-tab"> |
|
261
|
|
|
<small id="passwordHelpBlock" class="form-text text-muted mt-4"> |
|
262
|
|
|
<?php echo $lang->get('api_whitelist_ips_tip'); ?> |
|
263
|
|
|
</small> |
|
264
|
|
|
<div class="col-12 mt-4" id="table-api-ip"> |
|
265
|
|
|
<?php |
|
266
|
|
|
$rowsIps = DB::query( |
|
267
|
|
|
'SELECT increment_id, label, timestamp value FROM ' . prefixTable('api') . ' |
|
268
|
|
|
WHERE type = %s |
|
269
|
|
|
ORDER BY timestamp ASC', |
|
270
|
|
|
'ip' |
|
271
|
|
|
); |
|
272
|
|
|
?> |
|
273
|
|
|
<table class="table table-hover table-striped<?php echo DB::count() > 0 ? '' : ' hidden'; ?> table-responsive" style="width:100%" id="table-api-ips"> |
|
274
|
|
|
<thead> |
|
275
|
|
|
<tr> |
|
276
|
|
|
<th width="50px"></th> |
|
277
|
|
|
<th><?php echo $lang->get('label'); ?></th> |
|
278
|
|
|
<th><?php echo $lang->get('settings_api_ip'); ?></th> |
|
279
|
|
|
</tr> |
|
280
|
|
|
</thead> |
|
281
|
|
|
<tbody> |
|
282
|
|
|
<?php |
|
283
|
|
|
foreach ($rowsIps as $ip) { |
|
284
|
|
|
echo ' |
|
285
|
|
|
<tr data-id="' . $ip['increment_id'] . '"> |
|
286
|
|
|
<td width="50px"><i class="fas fa-trash infotip pointer delete-api-ip" title="' . $lang->get('del_button') . '"></i></td> |
|
287
|
|
|
<td><span class="edit-api-ip pointer" data-field="label">' . $ip['label'] . '</span></td> |
|
288
|
|
|
<td><span class="edit-api-ip pointer" data-field="value">' . $ip['value'] . '</span></td> |
|
289
|
|
|
</tr>'; |
|
290
|
|
|
} ?> |
|
291
|
|
|
</tbody> |
|
292
|
|
|
</table> |
|
293
|
|
|
|
|
294
|
|
|
<div class="mt-2<?php echo DB::count() > 0 ? ' hidden' : ''; ?>" id="api-no-ips"> |
|
295
|
|
|
<i class="fas fa-info mr-2 text-warning"></i><?php echo $lang->get('no_data_defined'); ?> |
|
296
|
|
|
</div> |
|
297
|
|
|
</div> |
|
298
|
|
|
|
|
299
|
|
|
<div class="form-group mt-4" id="new-api-ip"> |
|
300
|
|
|
<div class="callout callout-info"> |
|
301
|
|
|
<span class="text-bold"><?php echo $lang->get('adding_new_api_ip'); ?></span> |
|
302
|
|
|
|
|
303
|
|
|
<div class="row mt-1 ml-1"> |
|
304
|
|
|
<input type="text" placeholder="<?php echo $lang->get('ip'); ?>" class="col-4 form-control" id="new_api_ip_value" data-inputmask="'alias': 'ip'"> |
|
305
|
|
|
<input type="text" placeholder="<?php echo $lang->get('label'); ?>" class="col-4 form-control ml-2 purify" id="new_api_ip_label" data-field="label"> |
|
306
|
|
|
<span class="fa-stack ml-2 infotip pointer" title="<?php echo $lang->get('settings_api_add_ip'); ?>" id="button-new-api-ip"> |
|
307
|
|
|
<i class="fas fa-square fa-stack-2x"></i> |
|
308
|
|
|
<i class="fas fa-plus fa-stack-1x fa-inverse"></i> |
|
309
|
|
|
</span> |
|
310
|
|
|
</div> |
|
311
|
|
|
</div> |
|
312
|
|
|
</div> |
|
313
|
|
|
|
|
314
|
|
|
</div> |
|
315
|
|
|
|
|
316
|
|
|
<div class="tab-pane fade show active" id="users" role="tabpanel" aria-labelledby="keys-tab"> |
|
317
|
|
|
<div class="row mb-4 mt-4"> |
|
318
|
|
|
<div class="col-6 text-muted"> |
|
319
|
|
|
<?php echo $lang->get('users_api_access_info'); ?> |
|
320
|
|
|
</div> |
|
321
|
|
|
<div class="col-6"> |
|
322
|
|
|
<button type="button" class="btn btn-default pointer infotip" title="<?php echo $lang->get('build_missing_api_keys'); ?>" id="button-refresh-users-api"> |
|
323
|
|
|
<i class="fas fa-sync-alt"></i> |
|
324
|
|
|
</button> |
|
325
|
|
|
</div> |
|
326
|
|
|
</div> |
|
327
|
|
|
|
|
328
|
|
|
<div class="mt-4"> |
|
329
|
|
|
<?php |
|
330
|
|
|
$rowsKeys = DB::query( |
|
331
|
|
|
'SELECT a.*, u.name, u.lastname, u.login |
|
332
|
|
|
FROM ' . prefixTable('api') . ' AS a |
|
333
|
|
|
INNER JOIN ' . prefixTable('users') . ' AS u ON a.user_id = u.id |
|
334
|
|
|
WHERE a.type = %s AND u.disabled = %i AND u.deleted_at IS NULL AND u.id NOT IN %li AND u.admin = %i |
|
335
|
|
|
ORDER BY u.login ASC', |
|
336
|
|
|
'user', |
|
337
|
|
|
0, |
|
338
|
|
|
[API_USER_ID, SSH_USER_ID, SSH_USER_ID, TP_USER_ID], |
|
339
|
|
|
0 |
|
340
|
|
|
); |
|
341
|
|
|
?> |
|
342
|
|
|
<table class="table table-hover table-striped<?php echo DB::count() > 0 ? '' : ' hidden'; ?> table-responsive" style="width:100%" id="table-api-keys"> |
|
343
|
|
|
<thead> |
|
344
|
|
|
<tr> |
|
345
|
|
|
<th><?php echo $lang->get('user'); ?></th> |
|
346
|
|
|
<th><i class="fa-solid fa-user-check infotip" title="<?php echo $lang->get('enabled'); ?>"></i></th> |
|
347
|
|
|
<th><i class="fa-regular fa-square-plus infotip" title="<?php echo $lang->get('allowed_to_create'); ?>"></i></th> |
|
348
|
|
|
<th><i class="fa-solid fa-glasses infotip" title="<?php echo $lang->get('allowed_to_read'); ?>"></i></th> |
|
349
|
|
|
<th><i class="fa-solid fa-pencil infotip" title="<?php echo $lang->get('allowed_to_update'); ?>"></i></th> |
|
350
|
|
|
<th><i class="fa-solid fa-trash infotip" title="<?php echo $lang->get('allowed_to_delete'); ?>"></i></th> |
|
351
|
|
|
</tr> |
|
352
|
|
|
</thead> |
|
353
|
|
|
<tbody> |
|
354
|
|
|
<?php |
|
355
|
|
|
foreach ($rowsKeys as $key) { |
|
356
|
|
|
echo ' |
|
357
|
|
|
<tr data-id="' . $key['increment_id'] . '"> |
|
358
|
|
|
<td>' . $key['name'] . ' ' . $key['lastname'] . ' (<i>'.$key['login'].'</i>)</td> |
|
359
|
|
|
<td><i class="fas '.((int) $key['enabled'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="enabled" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
360
|
|
|
<td><i class="fas '.((int) $key['allowed_to_create'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_create" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
361
|
|
|
<td><i class="fas '.((int) $key['allowed_to_read'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_read" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
362
|
|
|
<td><i class="fas '.((int) $key['allowed_to_update'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_update" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
363
|
|
|
<td><i class="fas '.((int) $key['allowed_to_delete'] === 1 ? 'fa-toggle-on text-info' : 'fa-toggle-off').' mr-1 text-center pointer api-clickme-action" data-field="allowed_to_delete" data-increment-id="' . $key['increment_id'] . '"></i></td> |
|
364
|
|
|
</tr>'; |
|
365
|
|
|
} ?> |
|
366
|
|
|
</tbody> |
|
367
|
|
|
</table> |
|
368
|
|
|
|
|
369
|
|
|
<div class="mt-2<?php echo DB::count() > 0 ? ' hidden' : ''; ?>" id="api-no-keys"> |
|
370
|
|
|
<i class="fas fa-info mr-2 text-warning"></i><?php echo $lang->get('no_data_defined'); ?> |
|
371
|
|
|
</div> |
|
372
|
|
|
|
|
373
|
|
|
</div> |
|
374
|
|
|
</div> |
|
375
|
|
|
|
|
376
|
|
|
<div class="tab-pane fade show" id="extension" role="tabpanel" aria-labelledby="extension-tab"> |
|
377
|
|
|
<div class='col-12 mt-2'> |
|
378
|
|
|
<div class="alert alert-info" role="alert"> |
|
379
|
|
|
<?php echo $lang->get('browser_extension_instructions'); ?> |
|
380
|
|
|
</div> |
|
381
|
|
|
</div> |
|
382
|
|
|
|
|
383
|
|
|
<div class='row mt-2 mb-2'> |
|
384
|
|
|
<div class='col-7'> |
|
385
|
|
|
<?php echo $lang->get('browser_extension_fqdn'); ?> |
|
386
|
|
|
<small id='passwordHelpBlock' class='form-text text-muted'> |
|
387
|
|
|
<?php echo $lang->get('browser_extension_fqdn_tip'); ?> |
|
388
|
|
|
</small> |
|
389
|
|
|
</div> |
|
390
|
|
|
<div class='col-5'> |
|
391
|
|
|
<input type='text' class='form-control form-control-sm' id='browser_extension_fqdn' value='<?php echo isset($SETTINGS['browser_extension_fqdn']) === true ? (string) $SETTINGS['browser_extension_fqdn'] : $browserFqdn; ?>'> |
|
392
|
|
|
</div> |
|
393
|
|
|
</div> |
|
394
|
|
|
|
|
395
|
|
|
<div class='row mt-2 mb-2'> |
|
396
|
|
|
<div class='col-5'> |
|
397
|
|
|
<?php echo $lang->get('browser_extension_key'); ?> |
|
398
|
|
|
<small id='passwordHelpBlock' class='form-text text-muted'> |
|
399
|
|
|
<?php echo $lang->get('browser_extension_key_tip'); ?> |
|
400
|
|
|
</small> |
|
401
|
|
|
</div> |
|
402
|
|
|
<div class='col-5'> |
|
403
|
|
|
<input type='text' class='form-control form-control-sm' disabled="disabled" id='browser_extension_key' value='<?php echo isset($SETTINGS['browser_extension_key']) === true ? (string) $SETTINGS['browser_extension_key'] : 'Please upgrade'; ?>'> |
|
404
|
|
|
</div> |
|
405
|
|
|
<div class='col-2'> |
|
406
|
|
|
<button class="btn btn-sm btn-primary ml-1" id="copy-extension-key"><i class="fa-regular fa-copy pointer"></i></button> |
|
407
|
|
|
<button class="btn btn-sm btn-primary ml-1" id="generate-extension-key"><i class="fa-solid fa-rotate pointer"></i></button> |
|
408
|
|
|
</div> |
|
409
|
|
|
</div> |
|
410
|
|
|
|
|
411
|
|
|
</div> |
|
412
|
|
|
</div> |
|
413
|
|
|
|
|
414
|
|
|
<div class="form-group"> |
|
415
|
|
|
|
|
416
|
|
|
</div> |
|
417
|
|
|
|
|
418
|
|
|
<div class="form-group mt-8"> |
|
419
|
|
|
|
|
420
|
|
|
</div> |
|
421
|
|
|
|
|
422
|
|
|
</div> |
|
423
|
|
|
</div> |
|
424
|
|
|
</div> |
|
425
|
|
|
</div> |
|
426
|
|
|
</div> |
|
427
|
|
|
</div> |
|
428
|
|
|
|