'Pi-hole',
'enabled' => true,
'image' => 'plugins/images/tabs/pihole.png',
'category' => 'Monitor',
'settingsArray' => __FUNCTION__
];
if ($infoOnly) {
return $homepageInformation;
}
$homepageSettings = [
'debug' => true,
'settings' => [
'Enable' => [
$this->settingsOption('enable', 'homepagePiholeEnabled'),
$this->settingsOption('auth', 'homepagePiholeAuth'),
],
'Connection' => [
$this->settingsOption('multiple-url', 'piholeURL', ['help' => 'Please make sure to use local IP address and port at the end of the URL. You can add multiple Pi-holes by comma separating the URLs.', 'placeholder' => 'http(s)://hostname:port/']),
$this->settingsOption('multiple-token', 'piholeToken'),
],
'Misc' => [
$this->settingsOption('toggle-title', 'piholeHeaderToggle'),
$this->settingsOption('switch', 'homepagePiholeCombine', ['label' => 'Combine stat cards', 'help' => 'This controls whether to combine the stats for multiple pihole instances into 1 card.']),
],
'Test Connection' => [
$this->settingsOption('blank', null, ['label' => 'Please Save before Testing']),
$this->settingsOption('test', 'pihole'),
]
]
];
return array_merge($homepageInformation, $homepageSettings);
}
public function testConnectionPihole()
{
if (empty($this->config['piholeURL'])) {
$this->setAPIResponse('error', 'Pihole URL is not defined', 422);
return false;
}
$failed = false;
$errors = '';
$list = $this->csvHomepageUrlToken($this->config['piholeURL'], $this->config['piholeToken']);
foreach ($list as $key => $value) {
$response = $this->getAuth($value['url'], $value['token']);
$errors = $response["errors"];
}
if ($errors != '') {
$this->setAPIResponse('error', $errors, 500);
return false;
} else {
$this->setAPIResponse('success', null, 200);
return true;
}
}
public function piholeHomepagePermissions($key = null)
{
$permissions = [
'main' => [
'enabled' => [
'homepagePiholeEnabled'
],
'auth' => [
'homepagePiholeAuth'
],
'not_empty' => [
'piholeURL'
]
]
];
return $this->homepageCheckKeyPermissions($key, $permissions);
}
public function homepageOrderPihole()
{
if ($this->homepageItemPermissions($this->piholeHomepagePermissions('main'))) {
return '
';
}
}
public function getAuth($base_url, $token)
{
$sid = null;
if ($token === '' || $token === null) {
$errors .= $base_url . ': Missing API Token';
$this->setAPIResponse('error', $errors, 500);
return $errors;
}
try {
$sid = $this->doRequest($base_url, "createAuth", [], ['password' => $token]);
$this->cleanSessions($base_url, $sid);
} catch (Requests_Exception $e) {
$errors .= $ip . ': ' . $e->getMessage();
$this->setLoggerChannel('PiHole')->error($e);
};
return ["errors" => $errors, "sid" => $sid];
}
public function cleanSessions($base_url, $sid)
{
$sessions = $this->doRequest($base_url, "getAuths", ["sid" => $sid]);
foreach ($sessions as $session) {
// Skip if not right user agent, skip if current session
if ($session['user_agent'] != 'Organizr' || $session['current_session'] == '1') {
continue;
}
$this->doRequest($base_url,"deleteAuth", ["sid" => $sid], $session['id']);
}
}
public function endpoints($endpoint)
{
return [
"createAuth" => [
"type" => "post",
"urlHandler" => function() {
return "auth";
},
"responseHandler" => function($payload) {
return $payload['session']['sid'];
},
"payloadHandler" => function($data) {
return json_encode($data);
}
],
"getAuths" => [
"type" => "get",
"urlHandler" => function() {
return "auth/sessions";
},
"responseHandler" => function($payload) {
return $payload['sessions'];
}
],
"deleteAuth" => [
"type" => "delete",
"urlHandler" => function($id) {
return "auth/session/$id";
},
],
"get24HourStatsSummary" => [
"type" => "get",
"urlHandler" => function() {
$nowUnixTimestamp = time();
$oneDayAgoUnixTimestamp = $nowUnixTimestamp - (24 * 60 * 60);
return "stats/database/summary?from=$oneDayAgoUnixTimestamp&until=$nowUnixTimestamp";
}
],
"get24HourBlockedDomains" => [
"type" => "get",
"urlHandler" => function() {
$nowUnixTimestamp = time();
$oneDayAgoUnixTimestamp = $nowUnixTimestamp - (24 * 60 * 60);
return "stats/database/top_domains?from=$oneDayAgoUnixTimestamp&until=$nowUnixTimestamp&blocked=true&count=1000";
},
"responseHandler" => function($payload) {
return array_map(
function($item) {
return $item['domain'];
}, $payload['domains']
);
}
],
][$endpoint];
}
public function doRequest($baseUrl, $endpoint, $headers = [], $data = null)
{
$endpointDictionary = $this->endpoints($endpoint);
$urlHandler = $endpointDictionary['urlHandler'];
$payloadHandler = $endpointDictionary['payloadHandler'] ?? function() {
return null;
};
$requestType = $endpointDictionary['type'];
$responseHandler = $endpointDictionary['responseHandler'] ?? function($payload) {
return $payload;
};
$url = $this->qualifyURL("$baseUrl/api/{$urlHandler($data)}");
$headers = $headers + ["User-Agent" => 'Organizr'];
try {
$response = Requests::$requestType($url, $headers, $payloadHandler($data));
if ($response->success) {
$processedResponse = $responseHandler($this->testAndFormatString($response->body)["data"]);
}
} catch (Requests_Exception $e) {
$this->setResponse(500, $e->getMessage());
$this->setLoggerChannel('PiHole')->error($e);
throw $e;
};
return $processedResponse ?? [];
}
public function getPiholeHomepageStats()
{
if (!$this->homepageItemPermissions($this->piholeHomepagePermissions('main'), true)) {
return false;
}
$api = [];
$list = $this->csvHomepageUrlToken($this->config['piholeURL'], $this->config['piholeToken']);
foreach ($list as $key => $value) {
$base_url = $value['url'];
$sid = $this->getAuth($base_url, $value['token'])["sid"];
$stats = $this->doRequest($base_url, "get24HourStatsSummary", ["sid" => $sid]);
$stats["domains_being_blocked"] = $this->doRequest($base_url, "get24HourBlockedDomains", ["sid" => $sid]);
$api['data'][$base_url] = $stats;
}
$api['options']['combine'] = $this->config['homepagePiholeCombine'];
$api['options']['title'] = $this->config['piholeHeaderToggle'];
$api = $api ?? null;
$this->setAPIResponse('success', null, 200, $api);
return $api;
}
}