Skip to content

Instantly share code, notes, and snippets.

@summersab
Last active April 13, 2021 23:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save summersab/363c753c4936f0bc563ea88a85de6241 to your computer and use it in GitHub Desktop.
Save summersab/363c753c4936f0bc563ea88a85de6241 to your computer and use it in GitHub Desktop.
Add app and category whitelisting and blacklisting to Nextcloud
<?php
/**
* @copyright Copyright (c) 2021, Platypus Innovations LLC
*
* @author Andrew Summers
*
* This snippet provides a way to implement app and category whitelists/
* blacklists on Nextcloud. This is accomplished by creating a dummy
* "appstore" on the local system:
* - Download the official listings from the Nextcloud servers
* - Filter out the apps/categories based on the provided configuration
* - Save the app/category files to the webroot
* - Modify `config.php` to point `appstoreurl` to localhost
*
* To use this script:
* 1. Save the file to the Nextcloud webroot
* 2. Make sure to set the proper permissions and ownership (usually by
* running `chown www-data:www-data appstore.php`)
* 3. From your browser, go to:
* https://your-Nextcloud-url.com/appstore.php?clearappcache
* This will automatically set up values in your `config.php`
* 4. Open up `config.php` and edit the whitelist/blacklist values as
* you see fit
* 5. Reload the page from step 3
*
* You will need to set up a cron job or other scheduled tast to call
* the script on a regular basis in order to refresh the listings on
* your server. Also, Nextcloud caches the app and category listings,
* so if you want to force your system to refresh the files, make sure
* to append the `?clearappcache` URL parameter.
*
* In addition to a whitelist/blacklist, this script provides a few
* other features:
* - If you need to get a list of all available apps and categories,
* include the URL parameter `applist` or `categorylist`, respectively
* - Add an "All Apps" category to the app manager page.
* - Hide untested apps. This checks `version` value in `config.php` to
* determine if apps are compatible or not. Note that it only checks
* the maximum version value of an app, not the minimum. Also, it
* only checks whole-number values, not dot-revisions (i.e. 20.0.6 or
* 15.3.8)
*/
<?php
<?php
require './lib/private/Config.php';
$config = new \OC\Config('./config/');
$config_keys = $config->getKeys();
if (isset($_GET['clearappcache'])) {
unlink($config->getValue('datadirectory') . '/appdata_' . $config->getValue('instanceid') . '/appstore/apps.json');
unlink($config->getValue('datadirectory') . '/appdata_' . $config->getValue('instanceid') . '/appstore/categories.json');
}
$app_whitelist = array();
$app_blacklist = array();
$category_whitelist = array();
$category_blacklist = array();
$hide_untested_apps = false;
$hide_invalid_urls = false;
$add_all_apps_category = false;
if (in_array('appwhitelist', $config_keys)) {
$app_whitelist = $config->getValue('appwhitelist');
}
if (in_array('appblacklist', $config_keys)) {
$app_blacklist = $config->getValue('appblacklist');
}
if (in_array('categorywhitelist', $config_keys)) {
$category_whitelist = $config->getValue('categorywhitelist');
}
if (in_array('categoryblacklist', $config_keys)) {
$category_blacklist = $config->getValue('categoryblacklist');
}
if (in_array('hideuntestedapps', $config_keys)) {
$hide_untested_apps = $config->getValue('hideuntestedapps');
}
if (in_array('hideinvalidurls', $config_keys)) {
$hide_invalid_urls = $config->getValue('hideinvalidurls');
}
if (in_array('addallappscategory', $config_keys)) {
$add_all_apps_category = $config->getValue('addallappscategory');
}
if (! in_array('appstoreenabled', $config_keys)) {
$config->setValue('appstoreenabled', true);
}
if (! in_array('appstoreurl', $config_keys)) {
$config->setValue('appstoreurl', $config->getValue('overwrite.cli.url'));
}
$apps = json_decode(file_get_contents('https://apps.nextcloud.com/api/v1/apps.json'),1);
$categories = json_decode(file_get_contents('https://apps.nextcloud.com/api/v1/categories.json'),1);
if (isset($_GET['applist']) && $_GET['applist'] != 'filtered') {
printAppList($apps);
}
if (isset($_GET['categorylist'])) {
printCategoryList($categories);
}
if (sizeof($app_whitelist) > 0) {
$apps = array_filter($apps, function($var) use ($app_whitelist) {
return in_array($var['id'], $app_whitelist);
});
}
if (sizeof($app_blacklist) > 0) {
$apps = array_filter($apps, function($var) use ($app_blacklist) {
return ! in_array($var['id'], $app_blacklist);
});
}
if (sizeof($category_whitelist) > 0) {
$categories = array_filter($categories, function($var) use ($category_whitelist) {
return in_array($var['id'], $category_whitelist);
});
}
if (sizeof($category_blacklist) > 0) {
$categories = array_filter($categories, function($var) use ($category_blacklist) {
return ! in_array($var['id'], $category_blacklist);
});
}
if ($add_all_apps_category) {
$all_apps_array = [
'id' => 'all',
'translations' => [
'en' => [
'description' => 'All available Nextcloud apps',
'name' => 'All Apps',
],
],
];
array_push($categories, $all_apps_array);
foreach ($apps as $key=>$app) {
array_push($apps[$key]['categories'], 'all');
}
}
if ($hide_untested_apps) {
foreach ($apps as $app_key=>$app) {
if (isset($app['releases']) || array_key_exists('releases', $app)) {
foreach ($app['releases'] as $release_key=>$release) {
$versions = explode(' ', $release['platformVersionSpec']);
if (sizeof($versions) != 2) {
$version_max = PHP_INT_MAX;
$versions[1] = '<' . PHP_INT_MAX;
}
$version_min = ltrim($versions[0], '=><');
$version_max = ltrim($versions[1], '=><');
$version_min_comp = explode($version_min, $versions[0])[0];
$version_max_comp = explode($version_max, $versions[1])[0];
if (
! version_compare($config->getValue('version'), $version_min, $version_min_comp) ||
! version_compare($config->getValue('version'), $version_max, $version_max_comp)
) {
unset($apps[$app_key]['releases'][$release_key]);
}
else {
$head = @get_headers($release['download']);
if ($head && is_array($head) && sizeof($head) > 0) {
$response_code = explode(' ', $head[0])[1];
if ($response_code > 399) {
unset($apps[$app_key]['releases'][$release_key]);
}
}
else {
unset($apps[$app_key]['releases'][$release_key]);
}
}
}
if (sizeof($apps[$app_key]['releases']) == 0) {
unset($apps[$app_key]);
}
else {
$apps[$app_key]['releases'] = array_values($apps[$app_key]['releases']);
}
}
}
$apps = array_values($apps);
}
if ($hide_invalid_urls) {
foreach ($apps as $app_key=>$app) {
if (isset($app['releases']) || array_key_exists('releases', $app)) {
foreach ($app['releases'] as $release_key=>$release) {
$head = @get_headers($release['download']);
if ($head && is_array($head) && sizeof($head) > 0) {
$response_code = explode(' ', $head[0])[1];
if ($response_code > 399) {
unset($apps[$app_key]['releases'][$release_key]);
}
}
else {
unset($apps[$app_key]['releases'][$release_key]);
}
}
if (sizeof($apps[$app_key]['releases']) == 0) {
unset($apps[$app_key]);
}
else {
$apps[$app_key]['releases'] = array_values($apps[$app_key]['releases']);
}
}
}
$apps = array_values($apps);
}
if (isset($_GET['applist']) && $_GET['applist'] == 'filtered') {
printAppList($apps);
}
file_put_contents('apps.json', json_encode($apps));
file_put_contents('categories.json', json_encode($categories));
function printAppList($apps) {
echo '<style>table,th,td{border:1px solid black; border-collapse:collapse;}</style>';
echo '<table>';
foreach ($apps as $app) {
if (sizeof($app['releases']) > 0) {
echo '<tr>';
echo '<td>' . $app['id'] . '</td>';
echo '<td>' . $app['translations']['en']['name'] . '</td>';
echo '</tr>';
}
}
echo '</table>';
}
function printCategoryList($categories) {
echo '<style>table,th,td{border:1px solid black; border-collapse:collapse;}</style>';
echo '<table>';
foreach ($categories as $category) {
echo '<tr>';
echo '<td>' . $category['id'] . '</td>';
echo '<td>' . $category['translations']['en']['name'] . '</td>';
echo '</tr>';
}
echo '</table>';
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment