Compare commits

..

61 Commits

Author SHA1 Message Date
KodeStar
1ccc0da2a7 Merge pull request #1476 from KodeStar/2.x
Load in configs values if class has been lost
2025-07-22 15:59:00 +01:00
Chris Hunt
41aa255b88 Add missing variable 2025-07-22 15:57:29 +01:00
Chris Hunt
a8e4ab448b Load in configs values if class has been lost 2025-07-22 15:50:51 +01:00
KodeStar
e42f78bd49 Merge pull request #1473 from KodeStar/2.x
Add misisng input type in the form builder
2025-07-21 10:12:27 +01:00
Chris Hunt
08b8ab6d4f Add misisng input type in the form builder 2025-07-21 10:10:13 +01:00
KodeStar
57e0a335b7 Merge pull request #1471 from KodeStar/2.x
Add cache table
2025-07-17 14:46:16 +01:00
Chris Hunt
0d90170385 Add cache table 2025-07-17 14:43:09 +01:00
KodeStar
abe08a7b04 Merge pull request #1470 from KodeStar/2.x
Fix importing apps and logging in
2025-07-17 14:23:09 +01:00
Chris Hunt
6075dcca2d Fix importing apps and logging in 2025-07-17 14:19:02 +01:00
KodeStar
4fa41d8114 Merge pull request #1469 from KodeStar/2.x
Add tests and fix user edit form
2025-07-15 17:10:49 +01:00
Chris Hunt
1e6b1f6de5 Add tests and fix user edit form 2025-07-15 17:04:47 +01:00
KodeStar
53fd6242db Merge pull request #1467 from KodeStar/2.x
Fixes to reduce the SSRF attack vector plus display image names
2025-07-14 11:15:13 +01:00
Chris Hunt
69bc8cb34e Fixes to reduce the SSRF attack vector. 2025-07-13 19:06:33 +01:00
KodeStar
0388ee939a Merge pull request #1466 from KodeStar/2.x
Fix uploads and displaying of malicious SVG files
2025-07-13 17:02:27 +01:00
Chris Hunt
2df58472a1 Fix uploads and displaying of malicious SVG files 2025-07-13 17:00:23 +01:00
KodeStar
abbc78ee8d Merge pull request #1464 from KodeStar/2.x
Update framework to laravel 11 and fix images with no extension causing error 500
2025-07-11 16:36:40 +01:00
Chris Hunt
d1801d1088 Update cache version 2025-07-11 16:33:05 +01:00
Chris Hunt
22f66d35e5 Throw error if image doesn't have an extension #1446 2025-07-11 16:19:34 +01:00
Chris Hunt
f197aeb013 Fix forms on enhanced apps 2025-07-11 16:18:13 +01:00
Chris Hunt
8fb6438254 Updates to vendors etc 2025-07-11 15:57:48 +01:00
KodeStar
d972cbcd0a Merge pull request #14 from KodeStar/shift-154026
Migrate to `spatie/laravel-html`
2025-07-10 20:20:26 +01:00
Shift
638d2fe4a4 Convert Form facade 2025-07-10 19:17:24 +00:00
Shift
e251f4f1bc Swap dependency 2025-07-10 19:17:23 +00:00
KodeStar
ecc54b6fbe Merge pull request #13 from KodeStar/shift-154023
Laravel 11.x Shift
2025-07-10 20:15:54 +01:00
Shift
f0ce9d633a Remove createApplication method 2025-07-10 18:54:07 +00:00
Shift
968a5823a1 Adopt Laravel type hints 2025-07-10 18:54:07 +00:00
Shift
53f28b5056 Adopt anonymous migrations 2025-07-10 18:54:05 +00:00
Shift
7bb0a7ceb4 Bump Composer dependencies 2025-07-10 18:54:04 +00:00
Shift
f5ddd93141 Re-register routes 2025-07-10 18:54:03 +00:00
Shift
8554861d0a Re-register service providers 2025-07-10 18:54:02 +00:00
Shift
9091d1d707 Consolidate service providers 2025-07-10 18:54:02 +00:00
Shift
42d29f0fdb Re-register HTTP middleware 2025-07-10 18:54:02 +00:00
Shift
474059eee8 Default new bootstrap/app.php 2025-07-10 18:54:01 +00:00
Shift
1fb6f75555 Set new ENV variables 2025-07-10 18:54:01 +00:00
Shift
48e16ebfc9 Streamline config files 2025-07-10 18:54:00 +00:00
Shift
7153a41e03 Shift core files 2025-07-10 18:53:55 +00:00
Shift
b9e75b9284 Remove default app files 2025-07-10 18:53:54 +00:00
Shift
b3cdc5779c Slim lang files 2025-07-10 18:53:48 +00:00
Shift
c1c3888673 Apply code style 2025-07-10 18:53:44 +00:00
KodeStar
11453e1018 Merge pull request #1453 from riv-gh/bugfix/userlist-wrap
fixing page "/userselect" if many users on this
2025-07-10 19:25:34 +01:00
KodeStar
749442ec6e Merge pull request #1454 from knom/2.x
Enable/Disable Items with authentification headers
2025-07-10 19:24:57 +01:00
knom
5950ca9076 renamed "controles" to "controls" 2025-05-05 11:49:42 +02:00
Tobias Kolzer
55d3766b39 added AUTH_ROLES_DELIMITER to example env file 2025-05-05 11:49:41 +02:00
Tobias Kolzer
c71479f266 fixed some typos 2025-05-05 11:49:41 +02:00
Tobias Kolzer
2e5d7453cf added ENV variable for the auth roles delimiter 2025-05-05 11:49:41 +02:00
Tobias Kolzer
3cbbf807ab corrected some spelling mistakes 2025-05-05 11:49:41 +02:00
Tobias Kolzer
65a6ad53bf small 2025-05-05 11:49:41 +02:00
Tobias Kolzer
dff3f90d00 Update readme.md 2025-05-05 11:49:41 +02:00
Tobias Kolzer
041ec4236b updated supportedapps 2025-05-05 11:49:41 +02:00
Tobias Kolzer
808c41acd6 disabled users, items, tags for non admin users and user and login forms for all users 2025-05-05 11:49:31 +02:00
Tobias Kolzer
c08b0bfe39 changed naming of property 2025-05-05 11:49:31 +02:00
Tobias Kolzer
f7de56b7a7 added missing variable to example env 2025-05-05 11:49:18 +02:00
Tobias Kolzer
921631bdcd fixed some rebase conflicts 2025-05-05 11:49:18 +02:00
Tobias Kolzer
d146fed320 hide switchuser when auth_role is used 2025-05-05 11:49:18 +02:00
Tobias Kolzer
c56ffe1d1e fixed some rebase conflicts 2025-05-05 11:49:18 +02:00
daenur
e9d561466b Add warp on userlist
fixing page "/userselect" if many users on this
2025-04-25 10:57:56 +03:00
KodeStar
b90b38eae9 Merge pull request #1392 from linuxserver/bugfix/allow_ico_images
Allow ico images
2024-11-05 11:23:43 +00:00
Chris Hunt
be59ac794e Allow ico images fixes #1357 2024-11-05 11:11:34 +00:00
KodeStar
f820c0b4f6 Merge pull request #1388 from dfernandezdaw/2.x
Update Spanish translations
2024-11-05 10:56:55 +00:00
KodeStar
2b43760dc8 Merge pull request #1391 from linuxserver/bugfix/two_dots
Fix 2 dots that are visible on light backgrounds
2024-11-05 10:50:21 +00:00
David
18609fb3c2 Update Spanish translations 2024-11-04 21:18:04 +01:00
8148 changed files with 274521 additions and 212585 deletions

View File

@@ -4,7 +4,15 @@ APP_KEY=
APP_DEBUG=false
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12
LOG_CHANNEL=daily
LOG_STACK=single
DB_CONNECTION=sqlite
DB_DATABASE=app.sqlite
@@ -16,11 +24,14 @@ DB_DATABASE=app.sqlite
#DB_USERNAME=<user>
#DB_PASSWORD=<password>
BROADCAST_DRIVER=log
CACHE_DRIVER=file
BROADCAST_CONNECTION=log
CACHE_STORE=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
QUEUE_DRIVER=sync
REDIS_HOST=127.0.0.1
@@ -48,3 +59,11 @@ PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
AUTH_ROLES_ENABLE=false
AUTH_ROLES_HEADER="remote-groups"
AUTH_ROLES_HTTP_HEADER="HTTP_REMOTE_GROUPS"
AUTH_ROLES_ADMIN="admin"
AUTH_ROLES_DELIMITER=","
ALLOW_INTERNAL_REQUESTS=false

View File

@@ -16,7 +16,7 @@ jobs:
extensions: mbstring, dom, fileinfo, mysql, libxml, xml, xmlwriter, dom, tokenizer, filter, json, phar, pcre, openssl, pdo, intl, curl
- name: Cache composer dependencies
uses: actions/cache@v1
uses: actions/cache@v4
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
@@ -32,7 +32,7 @@ jobs:
php artisan key:generate
- name: Cache yarn dependencies
uses: actions/cache@v1
uses: actions/cache@v4
with:
path: node_modules
key: yarn-${{ hashFiles('yarn.lock') }}

File diff suppressed because it is too large Load Diff

15
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003,
"pathMappings": {
"/var/www/html": "${workspaceFolder}"
}
}
]
}

16
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Docker Compose",
"type": "shell",
"command": "docker-compose up --build",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": []
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* Define the application's command schedule.
*/
protected function schedule(Schedule $schedule): void
{
// $schedule->command('inspire')
// ->hourly();
}
/**
* Register the commands for the application.
*/
protected function commands(): void
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@@ -1,30 +0,0 @@
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* The list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (Throwable $e) {
//
});
}
}

13
app/Facades/Form.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class Form extends Facade
{
protected static function getFacadeAccessor()
{
return 'custom-form';
}
}

View File

@@ -1,6 +1,7 @@
<?php
use Illuminate\Support\Str;
use enshrined\svgSanitize\Sanitizer;
/**
* @param $bytes
@@ -117,7 +118,7 @@ function className($name)
*/
function isImage(string $file, string $extension): bool
{
$allowedExtensions = ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'svg', 'webp'];
$allowedExtensions = ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'svg', 'webp', 'ico'];
if (!in_array($extension, $allowedExtensions)) {
return false;
@@ -129,7 +130,11 @@ function isImage(string $file, string $extension): bool
fwrite($handle, $file);
fclose($handle);
if ($extension == 'svg') {
if ($extension === 'svg') {
$sanitizer = new Sanitizer();
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($tempFileName));
file_put_contents($tempFileName, $sanitizedSvg);
return 'image/svg+xml' === mime_content_type($tempFileName);
}

View File

@@ -21,6 +21,8 @@ use Illuminate\Support\Facades\URL;
use Illuminate\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Illuminate\Http\Response;
use enshrined\svgSanitize\Sanitizer;
class ItemController extends Controller
{
@@ -33,34 +35,55 @@ class ItemController extends Controller
/**
* Display a listing of the resource on the dashboard.
*/
public function dash(): View
public function dash(Request $request): View
{
$treat_tags_as = \App\Setting::fetch('treat_tags_as');
$data["treat_tags_as"] = $treat_tags_as;
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
if (config('app.auth_roles_enable')) {
$roles = explode(config('app.auth_roles_delimiter'), $request->header(config('app.auth_roles_header')));
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function ($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
} else {
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->whereIn('role', $roles)->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->orderBy('order', 'asc')->get();
}
} else {
if ($treat_tags_as == 'categories') {
$data['categories'] = Item::whereHas('children')->with('children', function ($query) {
$query->pinned()->orderBy('order', 'asc');
})->pinned()->orderBy('order', 'asc')->get();
} elseif ($treat_tags_as == 'tags') {
$data['apps'] = Item::with('parents')->where('type', 0)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::where('type', 0)->orderBy('order', 'asc')->get();
$data['taglist'] = Item::where('id', 0)->orWhere(function ($query) {
$query->where('type', 1)->pinned();
})->orderBy('order', 'asc')->get();
} else {
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere('type', 1)->pinned()->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere(function ($query) {
$query->where('type', 1)->whereNot('id', 0);
})->orderBy('order', 'asc')->get();
$data['all_apps'] = Item::whereHas('parents', function ($query) {
$query->where('id', 0);
})->orWhere(function ($query) {
$query->where('type', 1)->whereNot('id', 0);
})->orderBy('order', 'asc')->get();
}
}
//$data['all_apps'] = Item::doesntHave('parents')->get();
@@ -171,6 +194,7 @@ class ItemController extends Controller
public function create(): View
{
//
$data['item'] = new \App\Item();
$data['tags'] = Item::ofType('tag')->orderBy('title', 'asc')->pluck('title', 'id');
$data['tags']->prepend(__('app.dashboard'), 0);
$data['current_tags'] = '0';
@@ -215,7 +239,23 @@ class ItemController extends Controller
]);
if ($request->hasFile('file')) {
$path = $request->file('file')->store('icons', 'public');
$image = $request->file('file');
$extension = $image->getClientOriginalExtension();
if ($extension === 'svg') {
$sanitizer = new Sanitizer();
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
// Verify that the sanitization removed malicious content
if (strpos($sanitizedSvg, '<script>') !== false) {
throw ValidationException::withMessages(['file' => 'SVG contains malicious content and cannot be uploaded.']);
}
// Save the sanitized SVG back to the file
file_put_contents($image->getRealPath(), $sanitizedSvg);
}
$path = $image->store('icons', 'public');
$request->merge([
'icon' => $path,
]);
@@ -229,10 +269,23 @@ class ItemController extends Controller
$file = $request->input('icon');
$path_parts = pathinfo($file);
if (!isset($path_parts['extension'])) {
throw ValidationException::withMessages(['file' => 'Icon URL must have a valid file extension.']);
}
$extension = $path_parts['extension'];
$contents = file_get_contents($request->input('icon'), false, stream_context_create($options));
if ($extension === 'svg') {
$sanitizer = new Sanitizer();
$contents = $sanitizer->sanitize($contents);
// Verify that the sanitization removed malicious content
if (strpos($contents, '<script>') !== false) {
throw ValidationException::withMessages(['file' => 'SVG contains malicious content and cannot be uploaded.']);
}
}
if (!isImage($contents, $extension)) {
throw ValidationException::withMessages(['file' => 'Icon must be an image.']);
}
@@ -270,7 +323,7 @@ class ItemController extends Controller
'user_id' => $current_user->getId(),
]);
if ($request->input('appid') === 'null') {
if ($request->input('appid') === 'null' || $request->input('appid') === null) {
$request->merge([
'class' => null,
]);
@@ -370,6 +423,7 @@ class ItemController extends Controller
{
$output = [];
$appid = $request->input('app');
$itemId = $request->input('item_id');
if ($appid === 'null') {
return null;
@@ -384,8 +438,10 @@ class ItemController extends Controller
$appdetails = Application::getApp($appid);
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;
// }
}
@@ -439,25 +495,48 @@ class ItemController extends Controller
*/
public function execute($url, array $attrs = [], $overridevars = false): ?ResponseInterface
{
$vars = ($overridevars !== false) ?
$overridevars : [
'http_errors' => false,
'timeout' => 15,
'connect_timeout' => 15,
'verify' => false,
];
// Default Guzzle client configuration
$clientOptions = [
'http_errors' => false,
'timeout' => 15,
'connect_timeout' => 15,
'verify' => false, // In production, set this to `true` and manage certs.
];
$client = new Client($vars);
// If the user provided overrides, use them.
if ($overridevars !== false) {
$clientOptions = $overridevars;
}
// Resolve the hostname to an IP address
$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);
// Check if the IP is private or reserved
$allowInternalIps = env('ALLOW_INTERNAL_REQUESTS', false);
if (!$allowInternalIps && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
Log::warning('Blocked access to private or reserved IPs.', ['ip' => $ip, 'host' => $host]);
abort(Response::HTTP_FORBIDDEN, 'Access to private or reserved IPs is not allowed.');
}
// Force Guzzle to use the resolved IP address
$clientOptions['curl'][CURLOPT_RESOLVE] = ["{$host}:80:{$ip}", "{$host}:443:{$ip}"];
$client = new Client($clientOptions);
$method = 'GET';
try {
return $client->request($method, $url, $attrs);
} catch (ConnectException $e) {
Log::error('Connection refused');
Log::debug($e->getMessage());
Log::warning('SSRF Attempt Blocked: Connection to a private IP was prevented.', [
'url' => $url,
'error' => $e->getMessage()
]);
return null;
} catch (ServerException $e) {
Log::debug($e->getMessage());
} catch (\Exception $e) {
Log::error('General error: ' . $e->getMessage());
}
return null;
@@ -469,10 +548,22 @@ class ItemController extends Controller
*/
public function websitelookup($url): StreamInterface
{
$url = base64_decode($url);
$data = $this->execute($url);
$decodedUrl = base64_decode($url);
return $data->getBody();
// Validate the URL format.
if (filter_var($decodedUrl, FILTER_VALIDATE_URL) === false) {
abort(Response::HTTP_BAD_REQUEST, 'Invalid URL format provided.');
}
$response = $this->execute($decodedUrl);
// If execute() returns null, it means the connection failed.
// This can happen for many reasons, including our SSRF protection kicking in.
if ($response === null) {
abort(Response::HTTP_FORBIDDEN, 'Access to the requested resource is not allowed or the resource is unavailable.');
}
return $response->getBody();
}
/**

View File

@@ -18,16 +18,23 @@ class SearchController extends Controller
$requestprovider = $request->input('provider');
$query = $request->input('q');
// 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 ($provider->type == 'standard') {
return redirect($provider->url.'?'.$provider->query.'='.urlencode($query));
} elseif ($provider->type == 'external') {
$class = new $provider->class;
//print_r($provider);
return $class->getResults($query, $provider);
}
//print_r($provider);
}
abort(404, 'Provider type not supported');}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Setting;
use App\SettingGroup;
use Exception;
use enshrined\svgSanitize\Sanitizer;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -68,16 +69,30 @@ class SettingsController extends Controller
if ($setting->type === 'image') {
$validatedData = $request->validate([
'value' => 'image'
'value' => 'image',
]);
if (!$request->hasFile('value')) {
throw new \Exception(
'file_too_big'
);
throw new \Exception('file_too_big');
}
$path = $request->file('value')->store('backgrounds', 'public');
$image = $request->file('value');
$extension = $image->getClientOriginalExtension();
if ($extension === 'svg') {
$sanitizer = new Sanitizer();
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
// Verify that the sanitization removed malicious content
if (strpos($sanitizedSvg, '<script>') !== false) {
throw new \Exception('SVG contains malicious content and cannot be uploaded.');
}
// Save the sanitized SVG back to the file
file_put_contents($image->getRealPath(), $sanitizedSvg);
}
$path = $image->store('backgrounds', 'public');
if ($path === null) {
throw new \Exception('file_not_stored');
@@ -99,7 +114,7 @@ class SettingsController extends Controller
} catch (Exception $e) {
return redirect($route)
->with([
'errors' => collect([__('app.alert.error.'.$e->getMessage())]),
'errors' => collect([__('app.alert.error.' . $e->getMessage())]),
]);
}
}

View File

@@ -88,11 +88,16 @@ class TagController extends Controller
*
* @param $slug
*/
public function show($slug): View
public function show($slug, Request $request): View
{
$item = Item::whereUrl($slug)->first();
//print_r($item);
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
if (config('app.auth_roles_enable')) {
$roles = explode(config('app.auth_roles_delimiter'), $request->header(config('app.auth_roles_header')));
$data['apps'] = $item->children()->whereIn('role', $roles)->pinned()->orderBy('order', 'asc')->get();
} else {
$data['apps'] = $item->children()->pinned()->orderBy('order', 'asc')->get();
}
$data['tag'] = $item->id;
$data['all_apps'] = $item->children;

View File

@@ -1,61 +0,0 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class.':60,1',
'bindings',
],
];
/**
* The application's middleware aliases.
*
* Aliases may be used to conveniently assign middleware to routes and groups.
*
* @var array
*/
protected $middlewareAliases = [
'allowed' => \App\Http\Middleware\CheckAllowed::class,
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}

View File

@@ -1,17 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array<int, string>
*/
protected $except = [
'current_password',
'password',
'password_confirmation',
];
}

View File

@@ -1,22 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Routing\Middleware\ValidateSignature as Middleware;
class ValidateSignature extends Middleware
{
/**
* The names of the query string parameters that should be ignored.
*
* @var array<int, string>
*/
protected $except = [
// 'fbclid',
// 'utm_campaign',
// 'utm_content',
// 'utm_medium',
// 'utm_source',
// 'utm_term',
];
}

View File

@@ -1,21 +0,0 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
'order',
'appload',
'test_config',
//'get_stats'
];
}

View File

@@ -33,6 +33,7 @@ use Symfony\Component\ClassLoader\ClassMapGenerator;
* @property string|null $class
* @property string|null $appid
* @property string|null $appdescription
* @property string|null $role
* @property-read \Illuminate\Database\Eloquent\Collection|Item[] $children
* @property-read int|null $children_count
* @property-read string $droppable
@@ -51,6 +52,7 @@ use Symfony\Component\ClassLoader\ClassMapGenerator;
* @method static Builder|Item pinned()
* @method static Builder|Item query()
* @method static Builder|Item whereAppdescription($value)
* @method static Builder|Item whereRole($value)
* @method static Builder|Item whereAppid($value)
* @method static Builder|Item whereClass($value)
* @method static Builder|Item whereColour($value)
@@ -105,6 +107,7 @@ class Item extends Model
'user_id',
'tag_id',
'appid',
'role',
];

View File

@@ -10,10 +10,13 @@ use App\User;
use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use App\Services\CustomFormBuilder;
use Spatie\Html\Html;
class AppServiceProvider extends ServiceProvider
{
@@ -88,6 +91,11 @@ class AppServiceProvider extends ServiceProvider
$view->with('trianglify_seed', $trianglify_seed);
$view->with('allusers', $allusers);
$view->with('current_user', $current_user);
if (config('app.auth_roles_enable')) {
$view->with('enable_auth_admin_controls', in_array(config('app.auth_roles_admin'), explode(config('app.auth_roles_delimiter'), $_SERVER[config('app.auth_roles_http_header')])));
} else {
$view->with('enable_auth_admin_controls', true);
}
});
$this->app['view']->addNamespace('SupportedApps', app_path('SupportedApps'));
@@ -122,6 +130,10 @@ class AppServiceProvider extends ServiceProvider
$this->app->register(IdeHelperServiceProvider::class);
}
$this->app->singleton('custom-form', function ($app) {
return new CustomFormBuilder($app->make(Html::class));
});
$this->app->singleton('settings', function () {
return new Setting();
});
@@ -139,6 +151,7 @@ class AppServiceProvider extends ServiceProvider
if ($db_type == 'sqlite') {
$db_file = database_path(env('DB_DATABASE', 'app.sqlite'));
Log::debug('SQLite Database Path: ' . $db_file);
if (! is_file($db_file)) {
touch($db_file);
}

View File

@@ -1,25 +0,0 @@
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*/
public function boot(): void
{
//
}
}

View File

@@ -1,19 +0,0 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Broadcast::routes();
require base_path('routes/channels.php');
}
}

View File

@@ -1,37 +0,0 @@
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\Event' => [
'App\Listeners\EventListener',
],
];
/**
* Register any events for your application.
*/
public function boot(): void
{
parent::boot();
//
}
/**
* Determine if events and listeners should be automatically discovered.
*/
public function shouldDiscoverEvents(): bool
{
return false;
}
}

View File

@@ -2,8 +2,6 @@
namespace App;
use Cache;
use Form;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Request as Input;
use Yaml;
@@ -123,15 +121,7 @@ abstract class Search
$output .= '<option value="'.$key.'"'.$selected.'>'.$searchprovider['name'].'</option>';
}
$output .= '</select>';
$output .= Form::text(
'q',
Input::get('q') ?? null,
[
'class' => 'homesearch',
'autofocus' => 'autofocus',
'placeholder' => __('app.settings.search').'...'
]
);
$output .= '<input type="text" name="q" value="'.(Input::get('q') ?? '').'" class="homesearch" autofocus placeholder="'.__('app.settings.search').'..." />';
$output .= '<button type="submit">'.ucwords(__('app.settings.search')).'</button>';
$output .= '</div>';
$output .= '</form>';

View File

@@ -0,0 +1,46 @@
<?php
namespace App\Services;
use Spatie\Html\Html;
use Illuminate\Support\HtmlString;
class CustomFormBuilder
{
protected Html $html;
public function __construct(Html $html)
{
$this->html = $html;
}
public function text($name, $value = null, $options = [])
{
return new HtmlString(
$this->html->input('text', $name, $value)->attributes($options)
);
}
public function select($name, $list = [], $selected = null, $options = [])
{
return new HtmlString(
$this->html->select($name)->options($list, $selected)->attributes($options)
);
}
public function textarea($name, $value = null, $options = [])
{
return new HtmlString(
$this->html->textarea($name, $value)->attributes($options)
);
}
public function input($type, $name, $value = null, $options = [])
{
return new HtmlString(
$this->html->input($type, $name, $value)->attributes($options)
);
}
// Add other methods as needed
}

View File

@@ -2,7 +2,6 @@
namespace App;
use Form;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -10,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Http\Request;
use Illuminate\Session\SessionManager;
use Illuminate\Session\Store;
use Illuminate\Support\Facades\Input;
use enshrined\svgSanitize\Sanitizer;
/**
* App\Setting
@@ -72,9 +71,23 @@ class Setting extends Model
public static function getInput(Request $request): object
{
$image = $request->file('value');
if ($image && $image->getClientOriginalExtension() === 'svg') {
$sanitizer = new Sanitizer();
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
// Verify that the sanitization removed malicious content
if (strpos($sanitizedSvg, '<script>') !== false) {
throw new \Exception('SVG contains malicious content and cannot be uploaded.');
}
// Save the sanitized SVG back to the file
file_put_contents($image->getRealPath(), $sanitizedSvg);
}
return (object) [
'value' => $request->input('value'),
'image' => $request->file('value'),
'image' => $image,
];
}
@@ -147,7 +160,7 @@ class Setting extends Model
$this->value).
'" /></a>';
}
$value .= Form::file('value', ['class' => 'form-control']);
$value .= '<input type="file" name="value" class="form-control" />';
if (isset($this->value) && ! empty($this->value)) {
$value .= '<a class="settinglink" href="'.
route('settings.clear', $this->id).
@@ -178,16 +191,17 @@ class Setting extends Model
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id');
}
$value = '<select name="value" class="form-control">';
foreach ($options as $key => $opt) {
$options->$key = __($opt);
$value .= '<option value="'.$key.'" '.(($this->value == $key) ? 'selected' : '').'>'.__($opt).'</option>';
}
$value = Form::select('value', $options, null, ['class' => 'form-control']);
$value .= '</select>';
break;
case 'textarea':
$value = Form::textarea('value', null, ['class' => 'form-control', 'cols' => '44', 'rows' => '15']);
$value = '<textarea name="value" class="form-control" cols="44" rows="15"></textarea>';
break;
default:
$value = Form::text('value', null, ['class' => 'form-control']);
$value = '<input type="text" name="value" class="form-control" />';
break;
}

50
artisan
View File

@@ -1,53 +1,15 @@
#!/usr/bin/env php
<?php
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
$app = require_once __DIR__.'/bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$status = $kernel->handle(
$input = new Symfony\Component\Console\Input\ArgvInput,
new Symfony\Component\Console\Output\ConsoleOutput
);
/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/
$kernel->terminate($input, $status);
// Bootstrap Laravel and handle the command...
$status = (require_once __DIR__.'/bootstrap/app.php')
->handleCommand(new ArgvInput);
exit($status);

View File

@@ -1,55 +1,43 @@
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
return Application::configure(basePath: dirname(__DIR__))
->withProviders([
\Spatie\Html\HtmlServiceProvider::class,
])
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
channels: __DIR__.'/../routes/channels.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->redirectGuestsTo(fn () => route('login'));
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/
$middleware->validateCsrfTokens(except: [
//
'order',
'appload',
'test_config',
//'get_stats'
]);
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$middleware->append(\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$middleware->throttleApi('60,1');
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
$middleware->replace(\Illuminate\Http\Middleware\TrustProxies::class, \App\Http\Middleware\TrustProxies::class);
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;
$middleware->alias([
'allowed' => \App\Http\Middleware\CheckAllowed::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

7
bootstrap/providers.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\FormMacroServiceProvider::class,
App\Providers\RouteServiceProvider::class,
];

View File

@@ -8,28 +8,29 @@
"license": "MIT",
"type": "project",
"require": {
"php": "^8.1",
"graham-campbell/github": "^12.0",
"guzzlehttp/guzzle": "^7.4",
"laravel/framework": "^10.44",
"laravel/tinker": "^2.8",
"laravel/ui": "^4.2",
"laravelcollective/html": "^6.4",
"nunomaduro/collision": "^6.3",
"symfony/yaml": "^6.2",
"ext-json": "*",
"php": "^8.2",
"ext-intl": "*",
"ext-json": "*",
"enshrined/svg-sanitize": "^0.21.0",
"graham-campbell/github": "^12.5",
"guzzlehttp/guzzle": "^7.8",
"laravel/framework": "^11.45",
"laravel/tinker": "^2.9",
"laravel/ui": "^4.4",
"league/flysystem-aws-s3-v3": "^3.0",
"spatie/laravel-ignition": "^2.0"
"nunomaduro/collision": "^8.0",
"spatie/laravel-html": "^3.11",
"spatie/laravel-ignition": "^2.4",
"symfony/yaml": "^7.0"
},
"require-dev": {
"barryvdh/laravel-ide-helper": "^2.13",
"barryvdh/laravel-ide-helper": "^3.0",
"filp/whoops": "^2.8",
"mockery/mockery": "^1.4.4",
"phpunit/phpunit": "^9.5.10",
"mockery/mockery": "^1.6",
"phpunit/phpunit": "^10.5",
"squizlabs/php_codesniffer": "3.*",
"symfony/thanks": "^1.2",
"fakerphp/faker": "^1.9.1"
"fakerphp/faker": "^1.23"
},
"autoload": {
"classmap": [

4145
composer.lock generated

File diff suppressed because it is too large Load Diff

0
config/.gitkeep Normal file
View File

View File

@@ -5,191 +5,28 @@ use Illuminate\Support\Facades\Facade;
return [
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
|
| This value is the name of your application. This value is used when the
| framework needs to place the application's name in a notification or
| any other location as required by the application or its packages.
|
*/
'version' => '2.7.2',
'name' => env('APP_NAME', 'Heimdall'),
'version' => '2.6.3',
/*
|--------------------------------------------------------------------------
| Application Environment
|--------------------------------------------------------------------------
|
| This value determines the "environment" your application is currently
| running in. This may determine how you prefer to configure various
| services your application utilizes. Set this in your ".env" file.
|
*/
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| your application so that it is used when running Artisan tasks.
|
*/
'url' => env('APP_URL', 'http://localhost'),
'asset_url' => env('ASSET_URL', null),
'appsource' => env('APP_SOURCE', 'https://appslist.heimdall.site/'),
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box.
|
*/
'timezone' => 'UTC',
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
'locale' => 'en',
/*
|--------------------------------------------------------------------------
| Application Fallback Locale
|--------------------------------------------------------------------------
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/
'fallback_locale' => 'en',
/*
|--------------------------------------------------------------------------
| Faker Locale
|--------------------------------------------------------------------------
|
| This locale will be used by the Faker PHP library when generating fake
| data for your database seeds. For example, this will be used to get
| localized telephone numbers, street address information and more.
|
*/
'faker_locale' => 'en_US',
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| This key is used by the Illuminate encrypter service and should be set
| to a random, 32 character string, otherwise these encrypted strings
| will not be safe. Please do this before deploying an application!
|
*/
'key' => env('APP_KEY', 'base64:I206O8ibx+GQyRE7BeOxDobn04Mfmyyc5Ptzns/C0mY='),
'cipher' => 'AES-256-CBC',
/*
|--------------------------------------------------------------------------
| Maintenance Mode Driver
|--------------------------------------------------------------------------
|
| These configuration options determine the driver used to determine and
| manage Laravel's "maintenance mode" status. The "cache" driver will
| allow maintenance mode to be controlled across multiple machines.
|
| Supported drivers: "file", "cache"
|
*/
'maintenance' => [
'driver' => 'file',
// 'store' => 'redis',
],
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
|--------------------------------------------------------------------------
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
'providers' => ServiceProvider::defaultProviders()->merge([
/*
* Package Service Providers...
*/
Collective\Html\HtmlServiceProvider::class,
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
])->toArray(),
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'allow_internal_requests' => env('ALLOW_INTERNAL_REQUESTS', false),
'aliases' => Facade::defaultAliases()->merge([
'EnhancedApps' => App\EnhancedApps::class,
'Form' => Collective\Html\FormFacade::class,
'Html' => Collective\Html\HtmlFacade::class,
'Form' => App\Facades\Form::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'SupportedApps' => App\SupportedApps::class,
'Yaml' => Symfony\Component\Yaml\Yaml::class,
])->toArray(),
'auth_roles_enable' => (bool) env('AUTH_ROLES_ENABLE', false),
'auth_roles_header' => env('AUTH_ROLES_HEADER', 'remote-groups'),
'auth_roles_http_header' => env('AUTH_ROLES_HTTP_HEADER', 'HTTP_REMOTE_GROUPS'),
'auth_roles_admin' => env('AUTH_ROLES_ADMIN', 'admin'),
'auth_roles_delimiter' => env('AUTH_ROLES_DELIMITER', ','),
];

View File

@@ -2,120 +2,18 @@
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
| The throttle setting is the number of seconds a user must wait before
| generating more password reset tokens. This prevents the user from
| quickly generating a very large amount of password reset tokens.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_reset_tokens',
'expire' => 60,
'throttle' => 60,
'model' => App\User::class, // Update this to the correct namespace
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];

View File

@@ -1,71 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
| Supported: "pusher", "ably", "redis", "log", "null"
|
*/
'default' => env('BROADCAST_DRIVER', 'null'),
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com',
'port' => env('PUSHER_PORT', 443),
'scheme' => env('PUSHER_SCHEME', 'https'),
'encrypted' => true,
'useTLS' => env('PUSHER_SCHEME', 'https') === 'https',
],
'client_options' => [
// Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
],
],
'ably' => [
'driver' => 'ably',
'key' => env('ABLY_KEY'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'log' => [
'driver' => 'log',
],
'null' => [
'driver' => 'null',
],
],
];

View File

@@ -1,111 +0,0 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
*/
'default' => env('CACHE_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
| Supported drivers: "apc", "array", "database", "file",
| "memcached", "redis", "dynamodb", "octane", "null"
|
*/
'stores' => [
'apc' => [
'driver' => 'apc',
],
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
'lock_connection' => null,
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
'lock_path' => storage_path('framework/cache/data'),
],
'memcached' => [
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'lock_connection' => 'default',
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
'octane' => [
'driver' => 'octane',
],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing the APC, database, memcached, Redis, or DynamoDB cache
| stores there might be other applications using the same cache. For
| that reason, you may prefix every cache key to avoid collisions.
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
];

View File

@@ -1,151 +1,22 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => env('DB_CONNECTION', 'mysql'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'default' => env('DB_CONNECTION', 'sqlite'), // Make sure the default connection is set
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DATABASE_URL'),
'database' => database_path(env('DB_DATABASE', 'database.sqlite')),
'database' => database_path(env('DB_DATABASE', 'app.sqlite')), // Make sure to use the correct path
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), // Enable foreign key constraints
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
'migrations' => [
'table' => 'migrations',
'update_date_on_publish' => false, // disable to preserve original behavior for existing applications
],
];

View File

@@ -2,77 +2,14 @@
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DISK', 'local'),
'cloud' => env('FILESYSTEM_CLOUD', 's3'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been set up for each driver as an example of the required values.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];

View File

@@ -1,54 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Hash Driver
|--------------------------------------------------------------------------
|
| This option controls the default hash driver that will be used to hash
| passwords for your application. By default, the bcrypt algorithm is
| used; however, you remain free to modify this option if you wish.
|
| Supported: "bcrypt", "argon", "argon2id"
|
*/
'driver' => 'bcrypt',
/*
|--------------------------------------------------------------------------
| Bcrypt Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Bcrypt algorithm. This will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'bcrypt' => [
'rounds' => env('BCRYPT_ROUNDS', 12),
'verify' => true,
],
/*
|--------------------------------------------------------------------------
| Argon Options
|--------------------------------------------------------------------------
|
| Here you may specify the configuration options that should be used when
| passwords are hashed using the Argon algorithm. These will allow you
| to control the amount of time it takes to hash the given password.
|
*/
'argon' => [
'memory' => 65536,
'threads' => 1,
'time' => 4,
'verify' => true,
],
];

View File

@@ -2,127 +2,15 @@
return [
/*
|--------------------------------------------------------------------------
| Default Mailer
|--------------------------------------------------------------------------
|
| This option controls the default mailer that is used to send any email
| messages sent by your application. Alternative mailers may be setup
| and used as needed; however, this mailer will be used by default.
|
*/
'default' => env('MAIL_MAILER', 'smtp'),
/*
|--------------------------------------------------------------------------
| Mailer Configurations
|--------------------------------------------------------------------------
|
| Here you may configure all of the mailers used by your application plus
| their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires.
|
| Laravel supports a variety of mail "transport" drivers to be used while
| sending an e-mail. You will specify which one you are using for your
| mailers below. You are free to add additional mailers as required.
|
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
| "postmark", "log", "array", "failover", "roundrobin"
|
*/
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'url' => env('MAIL_URL'),
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN'),
],
'ses' => [
'transport' => 'ses',
],
'postmark' => [
'transport' => 'postmark',
// 'message_stream_id' => null,
// 'client' => [
// 'timeout' => 5,
// ],
],
'mailgun' => [
'transport' => 'mailgun',
// 'client' => [
// 'timeout' => 5,
// ],
],
'sendmail' => [
'transport' => 'sendmail',
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
],
'log' => [
'transport' => 'log',
'channel' => env('MAIL_LOG_CHANNEL'),
],
'array' => [
'transport' => 'array',
],
'failover' => [
'transport' => 'failover',
'mailers' => [
'smtp',
'log',
],
],
'roundrobin' => [
'transport' => 'roundrobin',
'mailers' => [
'ses',
'postmark',
],
],
],
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all e-mails sent by your application to be sent from
| the same address. Here, you may specify a name and address that is
| used globally for all e-mails that are sent by your application.
|
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
/*
|--------------------------------------------------------------------------
| Markdown Mail Settings
|--------------------------------------------------------------------------
|
| If you are using Markdown based email rendering, you may configure your
| theme and component paths here, allowing you to customize the design
| of the emails. Or, you may simply stick with the Laravel defaults!
|
*/
'markdown' => [
'theme' => 'default',

View File

@@ -1,93 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same
| syntax for every one. Here you may define a default connection.
|
*/
'default' => env('QUEUE_CONNECTION', 'sync'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
'block_for' => 0,
'after_commit' => false,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => 90,
'block_for' => null,
'after_commit' => false,
],
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish.
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];

View File

@@ -2,18 +2,6 @@
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
@@ -21,14 +9,4 @@ return [
'scheme' => 'https',
],
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
];

View File

@@ -1,214 +0,0 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option controls the default session "driver" that will be used on
| requests. By default, we will use the lightweight native driver but
| you may specify any of the other wonderful drivers provided here.
|
| Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "dynamodb", "array"
|
*/
'driver' => env('SESSION_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option.
|
*/
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => false,
/*
|--------------------------------------------------------------------------
| Session Encryption
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
| should be encrypted before it is stored. All encryption will be run
| automatically by Laravel and you can use the Session like normal.
|
*/
'encrypt' => false,
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
| When using the native session driver, we need a location where session
| files may be stored. A default has been set for you but a different
| location may be specified. This is only needed for file sessions.
|
*/
'files' => storage_path('framework/sessions'),
/*
|--------------------------------------------------------------------------
| Session Database Connection
|--------------------------------------------------------------------------
|
| When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options.
|
*/
'connection' => env('SESSION_CONNECTION'),
/*
|--------------------------------------------------------------------------
| Session Database Table
|--------------------------------------------------------------------------
|
| When using the "database" session driver, you may specify the table we
| should use to manage the sessions. Of course, a sensible default is
| provided for you; however, you are free to change this as needed.
|
*/
'table' => 'sessions',
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
| While using one of the framework's cache driven session backends you may
| list a cache store that should be used for these sessions. This value
| must match with one of the application's configured cache "stores".
|
| Affects: "apc", "dynamodb", "memcached", "redis"
|
*/
'store' => env('SESSION_STORE'),
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery
|--------------------------------------------------------------------------
|
| Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100.
|
*/
'lottery' => [2, 100],
/*
|--------------------------------------------------------------------------
| Session Cookie Name
|--------------------------------------------------------------------------
|
| Here you may change the name of the cookie used to identify a session
| instance by ID. The name specified here will get used every time a
| new session cookie is created by the framework for every driver.
|
*/
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
/*
|--------------------------------------------------------------------------
| Session Cookie Path
|--------------------------------------------------------------------------
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
| your application but you are free to change this when necessary.
|
*/
'path' => '/',
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set.
|
*/
'domain' => env('SESSION_DOMAIN'),
/*
|--------------------------------------------------------------------------
| HTTPS Only Cookies
|--------------------------------------------------------------------------
|
| By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you when it can't be done securely.
|
*/
'secure' => env('SESSION_SECURE_COOKIE'),
/*
|--------------------------------------------------------------------------
| HTTP Access Only
|--------------------------------------------------------------------------
|
| Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through
| the HTTP protocol. You are free to modify this option if needed.
|
*/
'http_only' => true,
/*
|--------------------------------------------------------------------------
| Same-Site Cookies
|--------------------------------------------------------------------------
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" since this is a secure default value.
|
| Supported: "lax", "strict", "none", null
|
*/
'same_site' => null,
/*
|--------------------------------------------------------------------------
| Partitioned Cookies
|--------------------------------------------------------------------------
|
| Setting this value to true will tie the cookie to the top-level site for
| a cross-site context. Partitioned cookies are accepted by the browser
| when flagged "secure" and the Same-Site attribute is set to "none".
|
*/
'partitioned' => false,
];

0
database/.gitignore vendored Normal file → Executable file
View File

0
database/factories/ItemFactory.php Normal file → Executable file
View File

0
database/factories/ItemTagFactory.php Normal file → Executable file
View File

0
database/factories/UserFactory.php Normal file → Executable file
View File

View File

View File

View File

0
database/migrations/2018_02_16_193703_item_tag.php Normal file → Executable file
View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up(): void
{
Schema::table('items', function (Blueprint $table) {
$table->text('role')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down(): void
{
Schema::table('items', function (Blueprint $table) {
//
});
}
};

View File

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('cache');
Schema::dropIfExists('cache_locks');
}
};

0
database/seeders/DatabaseSeeder.php Normal file → Executable file
View File

1
database/seeders/SettingsSeeder.php Normal file → Executable file
View File

@@ -349,6 +349,5 @@ class SettingsSeeder extends Seeder
$setting->label = 'app.settings.treat_tags_as';
$setting->save();
}
}
}

1
database/seeders/UsersSeeder.php Normal file → Executable file
View File

@@ -18,6 +18,7 @@ class UsersSeeder extends Seeder
$user->username = 'admin';
$user->email = 'admin@test.com';
$user->password = null;
$user->public_front = 0; // Default value for public_front
$user->save();
$user_id = $user->id;

26
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,26 @@
version: "3"
services:
nginx:
build:
context: .
dockerfile: nginx/Dockerfile
ports:
- "8080:80"
networks:
- internal
volumes:
- ../:/var/www/html
php:
build:
context: .
dockerfile: php/Dockerfile
networks:
- internal
environment:
XDEBUG_MODE: debug
XDEBUG_CONFIG: client_host=host.docker.internal client_port=9003
volumes:
- ../:/var/www/html
networks:
internal:
driver: bridge

2
docker/nginx/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM nginx:alpine
COPY ./default.conf /etc/nginx/conf.d

19
docker/nginx/default.conf Normal file
View File

@@ -0,0 +1,19 @@
server {
listen 0.0.0.0:80;
root /var/www/html;
location / {
index index.php index.html;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
}
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
}

4
docker/php/Dockerfile Normal file
View File

@@ -0,0 +1,4 @@
FROM php:8.4-fpm
RUN pecl install xdebug \
&& docker-php-ext-enable xdebug

View File

@@ -105,4 +105,7 @@ return array (
'alert.success.user_restored' => 'Nutzer erfolgreich wiederhergestellt',
'dashboard.reorder' => 'Elemente neu anordnen und anheften',
'dashboard.settings' => 'Einstellungen',
'role' => 'Authentifizierungsrolle',
'unauthorized_for_form' => 'Sie haben keinen Zugriff auf diese Seite.',
'disabled_feature' => 'Diese Funktion ist deaktiviert.',
);

View File

@@ -114,4 +114,7 @@ return array (
'alert.success.user_restored' => 'User restored successfully',
'dashboard.reorder' => 'Reorder and pin items',
'dashboard.settings' => 'Settings',
'role' => 'Authentication role',
'unauthorized_for_form' => 'You are not authorized to view this form.',
'disabled_feature' => 'This feature is disabled.',
);

View File

@@ -1,6 +0,0 @@
<?php
return array (
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
);

View File

@@ -1,6 +0,0 @@
<?php
return array (
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
);

View File

@@ -4,6 +4,6 @@ return array (
'password' => 'Passwords must be at least six characters and match the confirmation.',
'reset' => 'Your password has been reset!',
'sent' => 'We have e-mailed your password reset link!',
'token' => 'This password reset token is invalid.',
'user' => 'We can\'t find a user with that e-mail address.',
);

View File

@@ -1,191 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute field must be accepted.',
'accepted_if' => 'The :attribute field must be accepted when :other is :value.',
'active_url' => 'The :attribute field must be a valid URL.',
'after' => 'The :attribute field must be a date after :date.',
'after_or_equal' => 'The :attribute field must be a date after or equal to :date.',
'alpha' => 'The :attribute field must only contain letters.',
'alpha_dash' => 'The :attribute field must only contain letters, numbers, dashes, and underscores.',
'alpha_num' => 'The :attribute field must only contain letters and numbers.',
'array' => 'The :attribute field must be an array.',
'ascii' => 'The :attribute field must only contain single-byte alphanumeric characters and symbols.',
'before' => 'The :attribute field must be a date before :date.',
'before_or_equal' => 'The :attribute field must be a date before or equal to :date.',
'between' => [
'array' => 'The :attribute field must have between :min and :max items.',
'file' => 'The :attribute field must be between :min and :max kilobytes.',
'numeric' => 'The :attribute field must be between :min and :max.',
'string' => 'The :attribute field must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'can' => 'The :attribute field contains an unauthorized value.',
'confirmed' => 'The :attribute field confirmation does not match.',
'current_password' => 'The password is incorrect.',
'date' => 'The :attribute field must be a valid date.',
'date_equals' => 'The :attribute field must be a date equal to :date.',
'date_format' => 'The :attribute field must match the format :format.',
'decimal' => 'The :attribute field must have :decimal decimal places.',
'declined' => 'The :attribute field must be declined.',
'declined_if' => 'The :attribute field must be declined when :other is :value.',
'different' => 'The :attribute field and :other must be different.',
'digits' => 'The :attribute field must be :digits digits.',
'digits_between' => 'The :attribute field must be between :min and :max digits.',
'dimensions' => 'The :attribute field has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_end_with' => 'The :attribute field must not end with one of the following: :values.',
'doesnt_start_with' => 'The :attribute field must not start with one of the following: :values.',
'email' => 'The :attribute field must be a valid email address.',
'ends_with' => 'The :attribute field must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'extensions' => 'The :attribute field must have one of the following extensions: :values.',
'file' => 'The :attribute field must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'array' => 'The :attribute field must have more than :value items.',
'file' => 'The :attribute field must be greater than :value kilobytes.',
'numeric' => 'The :attribute field must be greater than :value.',
'string' => 'The :attribute field must be greater than :value characters.',
],
'gte' => [
'array' => 'The :attribute field must have :value items or more.',
'file' => 'The :attribute field must be greater than or equal to :value kilobytes.',
'numeric' => 'The :attribute field must be greater than or equal to :value.',
'string' => 'The :attribute field must be greater than or equal to :value characters.',
],
'hex_color' => 'The :attribute field must be a valid hexadecimal color.',
'image' => 'The :attribute field must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field must exist in :other.',
'integer' => 'The :attribute field must be an integer.',
'ip' => 'The :attribute field must be a valid IP address.',
'ipv4' => 'The :attribute field must be a valid IPv4 address.',
'ipv6' => 'The :attribute field must be a valid IPv6 address.',
'json' => 'The :attribute field must be a valid JSON string.',
'lowercase' => 'The :attribute field must be lowercase.',
'lt' => [
'array' => 'The :attribute field must have less than :value items.',
'file' => 'The :attribute field must be less than :value kilobytes.',
'numeric' => 'The :attribute field must be less than :value.',
'string' => 'The :attribute field must be less than :value characters.',
],
'lte' => [
'array' => 'The :attribute field must not have more than :value items.',
'file' => 'The :attribute field must be less than or equal to :value kilobytes.',
'numeric' => 'The :attribute field must be less than or equal to :value.',
'string' => 'The :attribute field must be less than or equal to :value characters.',
],
'mac_address' => 'The :attribute field must be a valid MAC address.',
'max' => [
'array' => 'The :attribute field must not have more than :max items.',
'file' => 'The :attribute field must not be greater than :max kilobytes.',
'numeric' => 'The :attribute field must not be greater than :max.',
'string' => 'The :attribute field must not be greater than :max characters.',
],
'max_digits' => 'The :attribute field must not have more than :max digits.',
'mimes' => 'The :attribute field must be a file of type: :values.',
'mimetypes' => 'The :attribute field must be a file of type: :values.',
'min' => [
'array' => 'The :attribute field must have at least :min items.',
'file' => 'The :attribute field must be at least :min kilobytes.',
'numeric' => 'The :attribute field must be at least :min.',
'string' => 'The :attribute field must be at least :min characters.',
],
'min_digits' => 'The :attribute field must have at least :min digits.',
'missing' => 'The :attribute field must be missing.',
'missing_if' => 'The :attribute field must be missing when :other is :value.',
'missing_unless' => 'The :attribute field must be missing unless :other is :value.',
'missing_with' => 'The :attribute field must be missing when :values is present.',
'missing_with_all' => 'The :attribute field must be missing when :values are present.',
'multiple_of' => 'The :attribute field must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute field format is invalid.',
'numeric' => 'The :attribute field must be a number.',
'password' => [
'letters' => 'The :attribute field must contain at least one letter.',
'mixed' => 'The :attribute field must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute field must contain at least one number.',
'symbols' => 'The :attribute field must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'present_if' => 'The :attribute field must be present when :other is :value.',
'present_unless' => 'The :attribute field must be present unless :other is :value.',
'present_with' => 'The :attribute field must be present when :values is present.',
'present_with_all' => 'The :attribute field must be present when :values are present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute field format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute field must match :other.',
'size' => [
'array' => 'The :attribute field must contain :size items.',
'file' => 'The :attribute field must be :size kilobytes.',
'numeric' => 'The :attribute field must be :size.',
'string' => 'The :attribute field must be :size characters.',
],
'starts_with' => 'The :attribute field must start with one of the following: :values.',
'string' => 'The :attribute field must be a string.',
'timezone' => 'The :attribute field must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'uppercase' => 'The :attribute field must be uppercase.',
'url' => 'The :attribute field must be a valid URL.',
'ulid' => 'The :attribute field must be a valid ULID.',
'uuid' => 'The :attribute field must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

View File

@@ -4,23 +4,23 @@ return array (
'settings.system' => 'Sistema',
'settings.appearance' => 'Apariencia',
'settings.miscellaneous' => 'Miscelánea',
'settings.advanced' => 'Avanzada',
'settings.advanced' => 'Avanzado',
'settings.support' => 'Soporte',
'settings.donate' => 'Donar',
'settings.version' => 'Versión',
'settings.background_image' => 'Imagen de Fondo',
'settings.trianglify' => 'Trianglify',
'settings.trianglify_seed' => 'Trianglify Random Seed',
'settings.window_target' => 'Vínculo abre en',
'settings.window_target.current' => 'Abrir en ésta pestaña',
'settings.trianglify' => 'Patrón de triángulos',
'settings.trianglify_seed' => 'Semilla Aleatoria del Patrón de Triángulos',
'settings.window_target' => 'Abrir enlace en',
'settings.window_target.current' => 'Abrir en esta pestaña',
'settings.window_target.one' => 'Abrir en la misma pestaña',
'settings.window_target.new' => 'Abrir en una nueva pestaña',
'settings.homepage_search' => 'Página de Inicio de Búsqueda',
'settings.homepage_search' => 'Búsqueda en Página de Inicio',
'settings.search_provider' => 'Proveedor de búsqueda',
'settings.language' => 'Idioma',
'settings.reset' => 'Restablecer a predeterminado',
'settings.remove' => 'Quitar',
'settings.search' => 'búsqueda',
'settings.search' => 'buscar',
'settings.no_items' => 'No se encontraron elementos',
'settings.label' => 'Etiqueta',
'settings.value' => 'Valor',
@@ -28,6 +28,10 @@ return array (
'settings.view' => 'Ver',
'settings.custom_css' => 'CSS Personalizado',
'settings.custom_js' => 'JavaScript Personalizado',
'settings.treat_tags_as' => 'Tratar etiquetas como:',
'settings.folders' => 'Carpetas',
'settings.tags' => 'Etiquetas',
'settings.categories' => 'Categorías',
'options.none' => '- no establecido -',
'options.google' => 'Google',
'options.ddg' => 'DuckDuckGo',
@@ -42,38 +46,39 @@ return array (
'buttons.cancel' => 'Cancelar',
'buttons.add' => 'Añadir',
'buttons.upload' => 'Cargar un archivo',
'buttons.downloadapps' => 'Actualizar lista de Applicaciones',
'dash.pin_item' => 'Pin elemento al tablero',
'buttons.downloadapps' => 'Actualizar Lista de Aplicaciones',
'dash.pin_item' => 'Anclar elemento al tablero',
'dash.no_apps' => 'Actualmente no hay aplicaciones ancladas, :link1 o :link2',
'dash.link1' => 'Agregue una aplicación aquí',
'dash.link2' => 'Pin de un elemento en el tablero',
'dash.link2' => 'Anclar un elemento en el tablero',
'dash.pinned_items' => 'Elementos Anclados',
'apps.app_list' => 'Lista de aplicaciones',
'apps.app_list' => 'Listado de aplicaciones',
'apps.view_trash' => 'Vista de la papelera de reciclaje',
'apps.add_application' => 'Agregar aplicación',
'apps.application_name' => 'Nombre de la aplicación',
'apps.colour' => 'Color',
'apps.icon' => 'Icono',
'apps.pinned' => 'Fijado',
'apps.pinned' => 'Anclado',
'apps.title' => 'Título',
'apps.hex' => 'Código de color hexadecimal',
'apps.username' => 'Nombre de usuario',
'apps.password' => 'Contraseña',
'apps.config' => 'Config',
'apps.config' => 'Configuración',
'apps.apikey' => 'Clave de API',
'apps.enable' => 'Habilitar',
'apps.tag_list' => 'Lista de Etiquetas',
'apps.tag_list' => 'Listado de etiquetas',
'apps.add_tag' => 'Añadir Etiqueta',
'apps.tag_name' => 'Nombre de Etiqueta',
'apps.tags' => 'Etiquetas',
'apps.override' => 'Si es differente de la URL principal',
'apps.override' => 'Si es diferente de la URL principal',
'apps.preview' => 'Previsualizar',
'apps.apptype' => 'Tipo de Aplicación',
'apps.website' => 'Sitio Web',
'apps.description' => 'Descripción',
'apps.only_admin_account' => '¡Solo si tienes cuenta de administrador!',
'apps.autologin_url' => 'URL de auto inicio de sessión',
'apps.autologin_url' => 'URL de inicio de sesión automático',
'apps.show_deleted' => 'Mostrando Aplicaciones Eliminadas',
'apps.import' => 'Importar',
'dashboard' => 'Tablero Inicial',
'user.user_list' => 'Usuarios',
'user.add_user' => 'Añadir Usuario',
@@ -82,27 +87,31 @@ return array (
'user.email' => 'Correo Electrónico',
'user.password_confirm' => 'Confirmar Contraseña',
'user.secure_front' => 'Permitir acceso público a la interfaz - Forzado solo si una contraseña está definida.',
'user.autologin' => 'Permitir inicio de sesión desde una URL específica. Cualquiera con el vínculo puede iniciar sesión.',
'user.autologin' => 'Permitir inicio de sesión desde una URL específica. Cualquiera con el enlace puede iniciar sesión.',
'url' => 'Url',
'title' => 'Título',
'delete' => 'Borrar',
'optional' => 'Opcional',
'restore' => 'Restaurar',
'export' => 'Exportar',
'import' => 'Importar',
'alert.success.item_created' => 'Elemento creado con éxito',
'alert.success.item_updated' => 'Artículo actualizado con éxito',
'alert.success.item_updated' => 'Elemento actualizado con éxito',
'alert.success.item_deleted' => 'Elemento eliminado correctamente',
'alert.success.item_restored' => 'Elemento restaurado con éxito',
'alert.success.updating' => 'Actualizando lista de aplicaciones',
'alert.success.tag_created' => 'Etiqueta creada exitósamente',
'alert.success.tag_updated' => 'Etiqueta actualizada exitósamente',
'alert.success.tag_deleted' => 'Etiqueta eliminada exitósamente',
'alert.success.tag_restored' => 'Etiqueta restaurada exitósamente',
'alert.success.setting_updated' => 'Ha editado con éxito esta configuración',
'alert.success.tag_updated' => 'Etiqueta actualizada exitosamente',
'alert.success.tag_deleted' => 'Etiqueta eliminada exitosamente',
'alert.success.tag_restored' => 'Etiqueta restaurada exitosamente',
'alert.success.setting_updated' => 'Configuración editada con éxito',
'alert.error.not_exist' => 'Esta configuración no existe.',
'alert.success.user_created' => 'Usuario creado exitósamente',
'alert.success.user_updated' => 'Usuario actualizado exitósamente',
'alert.success.user_deleted' => 'Usuario eliminado exitósamente',
'alert.success.user_restored' => 'Usuario restaurado exitósamente',
'alert.error.file_too_big' => 'El fichero es demasiado grande.',
'alert.error.file_not_stored' => 'El fichero no se ha podido almacenar.',
'alert.success.user_created' => 'Usuario creado exitosamente',
'alert.success.user_updated' => 'Usuario actualizado exitosamente',
'alert.success.user_deleted' => 'Usuario eliminado exitosamente',
'alert.success.user_restored' => 'Usuario restaurado exitosamente',
'dashboard.reorder' => 'Reordenar y anclar elementos',
'dashboard.settings' => 'Ajustes',
);

6813
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,12 +2,12 @@
"private": true,
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"development": "npx mix",
"watch": "npx mix watch",
"watch-poll": "npx mix watch -- --watch-options-poll=1000",
"hot": "npx mix watch --hot",
"prod": "npm run production",
"production": "mix --production",
"production": "npx mix --production",
"lint": "eslint 'resources/assets/js/*'"
},
"devDependencies": {
@@ -21,7 +21,9 @@
"laravel-mix": "^6.0.49",
"prettier": "^2.8.1",
"sass": "^1.56.1",
"sass-loader": "13.*"
"sass-loader": "13.*",
"webpack": "^5.100.1",
"webpack-cli": "^6.0.1"
},
"dependencies": {
"select2": "^4.0.13",

View File

@@ -16,7 +16,7 @@
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="CACHE_STORE" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="MAIL_MAILER" value="array"/>

4
public/css/app.css vendored

File diff suppressed because one or more lines are too long

61
public/index.php generated
View File

@@ -1,60 +1,17 @@
<?php
/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/
$app = require_once __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
// Bootstrap Laravel and handle the request...
(require_once __DIR__.'/../bootstrap/app.php')
->handleRequest(Request::capture());

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

1
public/js/dummy.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,5 @@
{
"/css/app.css": "/css/app.css?id=e8db4d3d99fdd3f0c747bb894c843e8e",
"/js/app.js": "/js/app.js?id=3b306fb20ef1a3c96c09963a4f6ff712"
"/js/dummy.js": "/js/dummy.js?id=daec5f3b283a510837bec36ca3868a54",
"/css/app.css": "/css/app.css?id=8e5c9ae35dd160a37c9d33d663f996b9",
"/js/app.js": "/js/app.js?id=19052619246fec368cad13937c62d850"
}

View File

@@ -183,6 +183,35 @@ openssl.cafile = /config/heimdall.pem
Restart the container and the Enhanced apps should now be able to access your local HTTP websites. This configuration will survive updating or recreating the Heimdall container.
## Allow Internal IP Requests
By default, Heimdall blocks requests to private or reserved IP addresses to mitigate potential security risks such as Server-Side Request Forgery (SSRF). However, you can enable access to internal IPs by setting the `ALLOW_INTERNAL_REQUESTS` environment variable in your `.env` file.
### Steps to Enable Internal IP Requests
1. Open your `.env` file located in the root directory of your Heimdall installation.
2. Add the following line:
```env
ALLOW_INTERNAL_REQUESTS=true
```
Setting this to `true` allows Heimdall to make requests to internal IP addresses (e.g., `192.168.x.x`, `10.x.x.x`, `127.0.0.1`).
3. Save the file and clear the Laravel configuration cache:
```bash
php artisan config:clear
```
4. Restart your web server or development server:
```bash
php artisan serve
```
### Default Behavior
If the `ALLOW_INTERNAL_REQUESTS` variable is not set or is set to `false`, Heimdall will block requests to private or reserved IP addresses and return a `403 Forbidden` error.
### Important Notes
- Enabling internal IP requests may expose your application to SSRF risks if your Heimdall instance is accessible from the internet. Ensure your instance is properly secured and not publicly accessible.
- Use this feature only if you trust the internal network and understand the security implications.
## Running offline
The apps list is hosted on github, you have a couple of options if you want to run without a connection to the outside world:
1) Clone the repository and host it yourself, look at the .github actions file to see how to generate the apps list.

View File

@@ -238,6 +238,7 @@ body {
.userlist {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
.user {
@@ -787,12 +788,20 @@ div.create {
width: 160px;
height: 160px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
gap: 5px;
}
.icon-name {
font-size: 12px;
color: #666;
word-break: break-word;
text-align: center;
}
.selecticon {
max-width: 120px;
height: auto;

View File

@@ -1,6 +1,8 @@
@extends('layouts.app')
@section('content')
@if(!$app['config']->get('app.auth_roles_enable', false))
<?php
$user = \App\User::currentUser();
?>
@@ -21,5 +23,14 @@ $user = \App\User::currentUser();
</div>
</form>
@else
<section class="module-container">
<header>
<div class="section-title">
{{ __('app.disabled_feature') }}
</div>
</header>
</section>
@endif
@endsection

View File

@@ -2,9 +2,9 @@
@section('content')
{!! Form::open(array('route' => 'items.store', 'id' => 'itemform', 'files' => true, 'method'=>'POST')) !!}
{{ html()->form('POST', route('items.store'))->id('itemform')->acceptsFiles()->open() }}
@include('items.form')
{!! Form::close() !!}
{{ html()->form()->close() }}
@endsection
@section('scripts')

View File

@@ -2,9 +2,9 @@
@section('content')
{!! Form::model($item, ['data-item-id' =>$item->id, 'method' => 'PATCH', 'id' => 'itemform', 'files' => true, 'route' => ['items.update', $item->id]]) !!}
{{ html()->modelForm($item, 'PATCH', route('items.update', $item->id))->data('item-id', $item->id)->id('itemform')->acceptsFiles()->open() }}
@include('items.form')
{!! Form::close() !!}
{{ html()->closeModelForm() }}
@endsection
@section('scripts')

View File

@@ -1,6 +1,6 @@
<div class="toggleinput">
<label class="name">{{ __('app.apps.enable') }}</label>
{!! Form::hidden('config[enabled]', '0') !!}
{{ html()->hidden('config[enabled]', '0') }}
<label class="switch">
<?php
$checked = false;

View File

@@ -1,10 +1,12 @@
<section class="module-container">
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
{{ html()->hidden('app_id', $item->id) }}
<div class="section-title">{{ __('app.apps.preview') }}</div>
<div class="module-actions">
<div class="toggleinput">
<label class="name">{{ __('app.apps.pinned') }}</label>
{!! Form::hidden('pinned', '0') !!}
{{ html()->hidden('pinned', '0') }}
<label class="switch">
<?php
$checked = true;
@@ -29,7 +31,7 @@
<div><button id="optdetails-button" class="dark">{{ __('app.apps.apptype') }}</button></div>
<div class="optvalue">
<div class="input">
{!! Form::select('appid', App\Application::applist(), null, array('class' => 'form-control config-item', 'id' => 'apptype', 'data-config' => 'type')) !!}
{{ html()->select('appid', App\Application::applist())->class('form-control config-item')->id('apptype')->data('config', 'type') }}
</div>
</div>
</div>
@@ -37,7 +39,7 @@
<div><button class="dark">{{ __('app.apps.website') }}</button></div>
<div class="optvalue">
<div class="input">
{!! Form::text('website', $item->url ?? null, array('placeholder' => __('app.apps.website'), 'id' => 'website', 'class' => 'form-control')) !!}
{{ html()->text('website', $item->url ?? null)->placeholder(__('app.apps.website'))->id('website')->class('form-control') }}
<small class="help">Don't forget http(s)://</small>
</div>
<div><button class="btn">Go</button></div>
@@ -57,25 +59,32 @@
{!! csrf_field() !!}
<div class="input">
<label>{{ __('app.apps.application_name') }} *</label>
{!! Form::text('title', null, array('placeholder' => __('app.apps.title'), 'id' => 'appname', 'class' => 'form-control', 'required')) !!}
{{ html()->text('title')->placeholder(__('app.apps.title'))->id('appname')->class('form-control')->required() }}
</div>
<div class="input">
<label>{{ __('app.apps.colour') }}</label>
{!! Form::text('colour', $item->colour ?? '#161b1f', array('placeholder' => __('app.apps.hex'), 'id' => 'appcolour', 'class' => 'form-control color-picker set-bg-elem')) !!}
{{ html()->text('colour', $item->colour ?? '#161b1f')->placeholder(__('app.apps.hex'))->id('appcolour')->class('form-control color-picker set-bg-elem') }}
</div>
<div class="input">
<label>{{ strtoupper(__('app.url')) }} *</label>
{!! Form::text('url', $item->url ?? null, array('placeholder' => __('app.url'), 'id' => 'appurl', 'class' => 'form-control', 'required')) !!}
{{ html()->text('url', $item->url ?? null)->placeholder(__('app.url'))->id('appurl')->class('form-control')->required() }}
<small class="help">Don't forget http(s)://</small>
</div>
<div class="input">
<label>{{ __('app.apps.tags') }} ({{ __('app.optional') }})</label>
{!! Form::select('tags[]', $tags, $current_tags, ['class' => 'tags', 'multiple']) !!}
{{ html()->multiselect('tags[]', $tags, $current_tags)->class('tags') }}
</div>
@if($app['config']->get('app.auth_roles_enable', false))
<div class="input">
<label>{{ __('app.role') }}</label>
{{ html()->text('role', $item->role ?? null)->placeholder(__('app.role'))->id('role')->class('form-control') }}
</div>
@endif
<div class="input">
<div class="icon-container">
<div id="appimage">
@@ -85,7 +94,7 @@
else $icon = old('icon');
?>
<img src="{{ asset('storage/'.$icon) }}" />
{!! Form::hidden('icon', $icon, ['class' => 'form-control']) !!}
{{ html()->hidden('icon', $icon)->class('form-control') }}
@else
<img src="{{ asset('/img/heimdall-icon-small.png') }}" />
@endif
@@ -112,7 +121,7 @@
@if(isset($item) && $item->enhanced())
<div id="sapconfig" style="display: block;">
@if(isset($item))
@if(isset($item) && $item->class)
@include('SupportedApps::'.App\Item::nameFromClass($item->class).'.config')
@endif
</div>
@@ -137,6 +146,13 @@
<a href="{{ route('items.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -3,6 +3,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">{{ __('app.import') }}</div>
<div class="module-actions">
@@ -31,6 +32,13 @@
<a href="{{ route('settings.index', []) }}" class="button"><i class="fa fa-ban"></i><span>{{ __('app.buttons.cancel') }}</span></a>
</div>
</footer>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -2,6 +2,7 @@
@section('content')
<section class="module-container">
@if($enable_auth_admin_controls)
<header>
<div class="section-title">
{{ __('app.apps.app_list') }}
@@ -36,9 +37,9 @@
<td>{{ $app->getTagList() }}</td>
<td class="text-center"><a{{ $app->target }} href="{!! route('items.edit', [$app->id]) !!}" title="{{ __('app.settings.edit') }} {{ $app->title }}"><i class="fas fa-edit"></i></a></td>
<td class="text-center">
{!! Form::open(['method' => 'DELETE','route' => ['items.destroy', $app->id],'style'=>'display:inline']) !!}
{{ html()->form('DELETE', route('items.destroy', $app->id))->style('display:inline')->open() }}
<button class="link" type="submit"><i class="fa fa-trash-alt"></i></button>
{!! Form::close() !!}
{{ html()->form()->close() }}
</td>
</tr>
@endforeach
@@ -53,6 +54,13 @@
</tbody>
</table>
@else
<header>
<div class="section-title">
{{ __('app.unauthorized_for_form') }}
</div>
</header>
@endif
</section>

View File

@@ -153,7 +153,12 @@
$('#tile-preview .title').text($('#appname').val());
$('#websiteiconoptions').html('<div class="header"><span>Select Icon</span><span class="selectclose">Close</span></div><div class="results"></div>')
icons.forEach(icon => {
$('#websiteiconoptions .results').append('<div class="iconbutton"><img class="selecticon" src="' + icon + '" /></div>')
$('#websiteiconoptions .results').append(`
<div class="iconbutton">
<img class="selecticon" src="${icon}" />
<span class="icon-name">${icon.split('/').pop()}</span>
</div>
`);
})
console.log(websitedata)
})
@@ -166,13 +171,14 @@
})
function appload(appvalue) {
const itemId = $('input[name="item_id"]').val();
if(appvalue == 'null') {
$('#sapconfig').html('').hide();
$('#tile-preview .app-icon').attr('src', '/img/heimdall-icon-small.png');
$('#appimage').html("<img src='/img/heimdall-icon-small.png' />");
$('#sapconfig').html('').hide();
} else {
$.post('{{ route('appload') }}', { app: appvalue }, function(data) {
$.post('{{ route('appload') }}', { app: appvalue, item_id: itemId }, function(data) {
// Main details
$('#appimage').html("<img src='"+data.iconview+"' /><input type='hidden' name='icon' value='"+data.iconview+"' />");
$('input[name=colour]').val(data.colour);
@@ -189,6 +195,21 @@
if(data.custom != null) {
$.get(base+'view/'+data.custom, function(getdata) {
$('#sapconfig').html(getdata).show();
// Populate fields in the loaded form with description data
if (data.description) {
const description = JSON.parse(data.appvalue);
Object.keys(description).forEach(function(key) {
const value = description[key];
const field = $(`#sapconfig [name="config[${key}]"]`);
if (field.length) {
if (field.is(':checkbox')) {
field.prop('checked', value);
} else {
field.val(value);
}
}
});
}
});
} else {
$('#sapconfig').html('').hide();

View File

@@ -28,10 +28,10 @@
<td>{{ __('app.url') }}</td>
<td class="text-center"><a href="{!! route('items.restore', [$app->id]) !!}" title="{{ __('app.restore') }} {!! $app->title !!}"><i class="fas fa-undo"></i></a></td>
<td class="text-center">
{!! Form::open(['method' => 'DELETE','route' => ['items.destroy', $app->id],'style'=>'display:inline']) !!}
{{ html()->form('DELETE', route('items.destroy', $app->id))->style('display:inline')->open() }}
<input type="hidden" name="force" value="1" />
<button type="submit"><i class="fa fa-trash-alt"></i></button>
{!! Form::close() !!}
{{ html()->form()->close() }}
</td>
</tr>
@endforeach

Some files were not shown because too many files have changed in this diff Show More