mirror of
https://github.com/linuxserver/Heimdall.git
synced 2026-03-01 07:53:35 +09:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32bf1d034f | ||
|
|
6d12c547e7 | ||
|
|
ae4ce92dab | ||
|
|
966279b252 | ||
|
|
54cf2b88ca | ||
|
|
31f1ba8192 | ||
|
|
eadd9d1dd8 | ||
|
|
c9ea2cdeb3 | ||
|
|
517f51ba90 | ||
|
|
825f67a4a4 | ||
|
|
05a552ffcf | ||
|
|
ad4584e548 | ||
|
|
7d93099f2c | ||
|
|
31ca05f74f | ||
|
|
cd95fc3b92 | ||
|
|
63e777b338 | ||
|
|
fd926e983d | ||
|
|
dce37c1412 | ||
|
|
31db31d0f7 |
14
SECURITY.md
14
SECURITY.md
@@ -1,14 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 2.3.x | :white_check_mark: |
|
||||
| < 2.3 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
You can report any vulnerabilities on our discord server by DM-ing a team member, or asking a team member to DM you.
|
||||
|
||||
https://discord.com/invite/YWrKVTn
|
||||
@@ -27,6 +27,17 @@ function format_bytes($bytes, bool $is_drive_size = true, string $beforeunit = '
|
||||
}
|
||||
}
|
||||
|
||||
function parse_size($size) {
|
||||
$unit = strtolower(substr($size, -1));
|
||||
$bytes = (int)$size;
|
||||
switch($unit) {
|
||||
case 'g': $bytes *= 1024 * 1024 * 1024; break;
|
||||
case 'm': $bytes *= 1024 * 1024; break;
|
||||
case 'k': $bytes *= 1024; break;
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $title
|
||||
* @param string $separator
|
||||
|
||||
@@ -267,9 +267,16 @@ class ItemController extends Controller
|
||||
],
|
||||
];
|
||||
|
||||
// Proxy management
|
||||
$httpsProxy = getenv('HTTPS_PROXY');
|
||||
$httpsProxyLower = getenv('https_proxy');
|
||||
if ($httpsProxy !== false || $httpsProxyLower !== false) {
|
||||
$options['proxy']['http'] = $httpsProxy ?: $httpsProxyLower;
|
||||
}
|
||||
|
||||
$file = $request->input('icon');
|
||||
$path_parts = pathinfo($file);
|
||||
if (!isset($path_parts['extension'])) {
|
||||
if (!array_key_exists('extension', $path_parts)) {
|
||||
throw ValidationException::withMessages(['file' => 'Icon URL must have a valid file extension.']);
|
||||
}
|
||||
$extension = $path_parts['extension'];
|
||||
@@ -312,7 +319,11 @@ class ItemController extends Controller
|
||||
$storedConfigObject = json_decode($storedItem->getAttribute('description'));
|
||||
|
||||
$configObject = json_decode($config);
|
||||
$configObject->password = $storedConfigObject->password;
|
||||
if ($storedConfigObject && property_exists($storedConfigObject, 'password')) {
|
||||
$configObject->password = $storedConfigObject->password;
|
||||
} else {
|
||||
$configObject->password = null;
|
||||
}
|
||||
|
||||
$config = json_encode($configObject);
|
||||
}
|
||||
@@ -429,20 +440,31 @@ class ItemController extends Controller
|
||||
return null;
|
||||
}
|
||||
|
||||
$output['config'] = null;
|
||||
$output['custom'] = null;
|
||||
|
||||
$app = Application::single($appid);
|
||||
|
||||
if (!$app) {
|
||||
return response()->json(['error' => 'Application not found.'], 404);
|
||||
}
|
||||
|
||||
$output = (array)$app;
|
||||
|
||||
$appdetails = Application::getApp($appid);
|
||||
|
||||
if (!$appdetails) {
|
||||
return response()->json(['error' => 'Application details not found.'], 404);
|
||||
}
|
||||
|
||||
if ((bool)$app->enhanced === true) {
|
||||
$item = $itemId ? Item::find($itemId) : Item::where('appid', $appid)->first();
|
||||
// if(!isset($app->config)) { // class based config
|
||||
$output['custom'] = className($appdetails->name) . '.config';
|
||||
$output['appvalue'] = $item->description;
|
||||
// }
|
||||
|
||||
if ($item) {
|
||||
$output['custom'] = className($appdetails->name) . '.config';
|
||||
$output['appvalue'] = $item->description;
|
||||
} else {
|
||||
// Ensure the app is installed if not found
|
||||
$output['custom'] = className($appdetails->name) . '.config';
|
||||
$output['appvalue'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
$output['colour'] = ($app->tile_background == 'light') ? '#fafbfc' : '#161b1f';
|
||||
@@ -450,14 +472,12 @@ class ItemController extends Controller
|
||||
if (strpos($app->icon, '://') !== false) {
|
||||
$output['iconview'] = $app->icon;
|
||||
} elseif (strpos($app->icon, 'icons/') !== false) {
|
||||
// Private apps have the icon locally
|
||||
$output['iconview'] = URL::to('/') . '/storage/' . $app->icon;
|
||||
$output['icon'] = str_replace('icons/', '', $output['icon']);
|
||||
} else {
|
||||
$output['iconview'] = config('app.appsource') . 'icons/' . $app->icon;
|
||||
}
|
||||
|
||||
|
||||
return json_encode($output);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,17 +21,17 @@ class SearchController extends Controller
|
||||
// Sanitize the query to prevent XSS
|
||||
$query = htmlspecialchars($query, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// Validate the presence and non-emptiness of the query parameter
|
||||
if (!$query || trim($query) === '') {
|
||||
abort(400, 'Missing or empty query parameter');
|
||||
}
|
||||
|
||||
$provider = Search::providerDetails($requestprovider);
|
||||
|
||||
if (!$provider || !isset($provider->type)) {
|
||||
abort(404, 'Invalid provider');
|
||||
}
|
||||
|
||||
// If the query is empty, redirect to the provider's base URL
|
||||
if (!$query || trim($query) === '') {
|
||||
return redirect($provider->url);
|
||||
}
|
||||
|
||||
if ($provider->type == 'standard') {
|
||||
return redirect($provider->url.'?'.$provider->query.'='.urlencode($query));
|
||||
} elseif ($provider->type == 'external') {
|
||||
@@ -39,5 +39,6 @@ class SearchController extends Controller
|
||||
return $class->getResults($query, $provider);
|
||||
}
|
||||
|
||||
abort(404, 'Provider type not supported');}
|
||||
abort(404, 'Provider type not supported');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,27 @@ class CustomFormBuilder
|
||||
);
|
||||
}
|
||||
|
||||
public function password($name, $options = [])
|
||||
{
|
||||
return new HtmlString(
|
||||
$this->html->input('password', $name)->attributes($options)
|
||||
);
|
||||
}
|
||||
|
||||
public function hidden($name, $value = null, $options = [])
|
||||
{
|
||||
return new HtmlString(
|
||||
$this->html->input('hidden', $name, $value)->attributes($options)
|
||||
);
|
||||
}
|
||||
|
||||
public function checkbox($name, $value = null, $checked = false, $options = [])
|
||||
{
|
||||
return new HtmlString(
|
||||
$this->html->checkbox($name, $value, $checked)->attributes($options)
|
||||
);
|
||||
}
|
||||
|
||||
public function select($name, $list = [], $selected = null, $options = [])
|
||||
{
|
||||
return new HtmlString(
|
||||
|
||||
@@ -5,7 +5,7 @@ use Illuminate\Support\Facades\Facade;
|
||||
|
||||
return [
|
||||
|
||||
'version' => '2.7.3',
|
||||
'version' => '2.7.6',
|
||||
|
||||
'appsource' => env('APP_SOURCE', 'https://appslist.heimdall.site/'),
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ return array (
|
||||
'settings.language' => 'Sprache',
|
||||
'settings.reset' => 'Zurücksetzen auf Standard',
|
||||
'settings.remove' => 'Entfernen',
|
||||
'settings.search' => 'suche',
|
||||
'settings.search' => 'Suche',
|
||||
'settings.no_items' => 'Keine Elemente gefunden',
|
||||
'settings.label' => 'Bezeichnung',
|
||||
'settings.value' => 'Wert',
|
||||
@@ -33,7 +33,7 @@ return array (
|
||||
'options.ddg' => 'DuckDuckGo',
|
||||
'options.bing' => 'Bing',
|
||||
'options.qwant' => 'Qwant',
|
||||
'options.startpage' => 'StartSeite',
|
||||
'options.startpage' => 'Startseite',
|
||||
'options.yes' => 'Ja',
|
||||
'options.no' => 'Nein',
|
||||
'options.nzbhydra' => 'NZBHydra',
|
||||
@@ -46,7 +46,7 @@ return array (
|
||||
'dash.pin_item' => 'Element auf dem Dashboard anheften',
|
||||
'dash.no_apps' => 'Derzeit gibt es keine angeheftete Anwendungen. :link1 oder :link2',
|
||||
'dash.link1' => 'Anwendung neu hinzufügen',
|
||||
'dash.link2' => 'anheften',
|
||||
'dash.link2' => 'Anheften',
|
||||
'dash.pinned_items' => 'Angeheftete Elemente',
|
||||
'apps.app_list' => 'Anwendungsliste',
|
||||
'apps.view_trash' => 'Ansicht Papierkorb',
|
||||
@@ -66,7 +66,7 @@ return array (
|
||||
'apps.add_tag' => 'Tag hinzufügen',
|
||||
'apps.tag_name' => 'Tag Name',
|
||||
'apps.tags' => 'Tags',
|
||||
'apps.override' => 'Fals anders zur Haupt-URL',
|
||||
'apps.override' => 'Falls anders zur Haupt-URL',
|
||||
'apps.preview' => 'Vorschau',
|
||||
'apps.apptype' => 'Anwendungstyp',
|
||||
'apps.website' => 'Webseite',
|
||||
@@ -81,7 +81,7 @@ return array (
|
||||
'user.avatar' => 'Avatar',
|
||||
'user.email' => 'Email',
|
||||
'user.password_confirm' => 'Passwort bestätigen',
|
||||
'user.secure_front' => 'Öffentlichen Zugang erlauben - Tritt nur bei gesetztem Passwort in kraft.',
|
||||
'user.secure_front' => 'Öffentlichen Zugang erlauben - Tritt nur bei gesetztem Passwort in Kraft.',
|
||||
'user.autologin' => 'Anmelden von spezieller URL erlauben. Jeder mit diesem Link kann sich anmelden.',
|
||||
'url' => 'URL',
|
||||
'title' => 'Titel',
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
<section class="module-container">
|
||||
@if($enable_auth_admin_controls)
|
||||
|
||||
<header>
|
||||
<div class="section-title">{{ __($setting->label) }}</div>
|
||||
<div class="section-title">
|
||||
{{ __($setting->label) }}
|
||||
@if($setting->type === 'image')
|
||||
@php
|
||||
$max_upload = ini_get('upload_max_filesize');
|
||||
$max_upload_bytes = parse_size($max_upload);
|
||||
@endphp
|
||||
<a class="settinglink" target="_blank" rel="nofollow noreferer" href="https://github.com/linuxserver/Heimdall?tab=readme-ov-file#new-background-image-not-being-set">({{ format_bytes($max_upload_bytes, false) }})</a>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
<div class="module-actions">
|
||||
<button type="submit"class="button"><i class="fa fa-save"></i><span>{{ __('app.buttons.save') }}</span></button>
|
||||
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
|
||||
|
||||
@@ -32,22 +32,4 @@ class SearchTest extends TestCase
|
||||
$response->assertStatus(404); // Assert that the response status is 404
|
||||
}
|
||||
|
||||
public function test_search_page_without_query_parameter(): void
|
||||
{
|
||||
$provider = 'google'; // Example provider
|
||||
|
||||
$response = $this->get(route('search', ['provider' => $provider]));
|
||||
|
||||
$response->assertStatus(400); // Assert that the response status is 400 (Bad Request)
|
||||
}
|
||||
|
||||
public function test_search_page_with_empty_query(): void
|
||||
{
|
||||
$provider = 'google'; // Example provider
|
||||
$query = ''; // Empty search term
|
||||
|
||||
$response = $this->get(route('search', ['provider' => $provider, 'q' => $query]));
|
||||
|
||||
$response->assertStatus(400); // Assert that the response status is 400 (Bad Request)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user