This commit is contained in:
Kekskurse 2020-11-08 03:07:10 +01:00
parent 327aa77e08
commit 5e949d93f8
46 changed files with 1705 additions and 68 deletions

2
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml

6
.idea/misc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/vpn.keks.cloud.iml" filepath="$PROJECT_DIR$/.idea/vpn.keks.cloud.iml" />
</modules>
</component>
</project>

118
.idea/php.xml Normal file
View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit" />
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/vendor/ralouphie/getallheaders" />
<path value="$PROJECT_DIR$/vendor/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/vendor/fakerphp/faker" />
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/vendor/hamcrest/hamcrest-php" />
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-iconv" />
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/vendor/tijsverkoyen/css-to-inline-styles" />
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php72" />
<path value="$PROJECT_DIR$/vendor/dragonmantank/cron-expression" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/vendor/symfony/process" />
<path value="$PROJECT_DIR$/vendor/symfony/string" />
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/vendor/facade/flare-client-php" />
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/vendor/facade/ignition-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/console" />
<path value="$PROJECT_DIR$/vendor/facade/ignition" />
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php73" />
<path value="$PROJECT_DIR$/vendor/vlucas/phpdotenv" />
<path value="$PROJECT_DIR$/vendor/voku/portable-ascii" />
<path value="$PROJECT_DIR$/vendor/league/flysystem" />
<path value="$PROJECT_DIR$/vendor/league/mime-type-detection" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/vendor/opis/closure" />
<path value="$PROJECT_DIR$/vendor/nunomaduro/collision" />
<path value="$PROJECT_DIR$/vendor/brick/math" />
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/vendor/psr/http-client" />
<path value="$PROJECT_DIR$/vendor/psr/log" />
<path value="$PROJECT_DIR$/vendor/asm89/stack-cors" />
<path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
<path value="$PROJECT_DIR$/vendor/dnoegel/php-xdg-base-dir" />
<path value="$PROJECT_DIR$/vendor/psr/container" />
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/vendor/league/commonmark" />
<path value="$PROJECT_DIR$/vendor/egulias/email-validator" />
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/vendor/nesbot/carbon" />
<path value="$PROJECT_DIR$/vendor/filp/whoops" />
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/vendor/swiftmailer/swiftmailer" />
<path value="$PROJECT_DIR$/vendor/ramsey/collection" />
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/vendor/ramsey/uuid" />
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
<path value="$PROJECT_DIR$/vendor/psy/psysh" />
<path value="$PROJECT_DIR$/vendor/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/vendor/laravel/framework" />
<path value="$PROJECT_DIR$/vendor/composer" />
<path value="$PROJECT_DIR$/vendor/fideloper/proxy" />
<path value="$PROJECT_DIR$/vendor/fruitcake/laravel-cors" />
<path value="$PROJECT_DIR$/vendor/laravel/tinker" />
<path value="$PROJECT_DIR$/vendor/mockery/mockery" />
<path value="$PROJECT_DIR$/vendor/phpoption/phpoption" />
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/vendor/s1lentium/iptools" />
</include_path>
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/phpunit.xml" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" use_configuration_file="true" />
</phpunit_settings>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

120
.idea/vpn.keks.cloud.iml Normal file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/database/seeders" isTestSource="false" packagePrefix="Database\Seeders\" />
<sourceFolder url="file://$MODULE_DIR$/app" isTestSource="false" packagePrefix="App\" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="Tests\" />
<sourceFolder url="file://$MODULE_DIR$/database/factories" isTestSource="false" packagePrefix="Database\Factories\" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/vendor/asm89/stack-cors" />
<excludeFolder url="file://$MODULE_DIR$/vendor/brick/math" />
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/dnoegel/php-xdg-base-dir" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/inflector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/lexer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/dragonmantank/cron-expression" />
<excludeFolder url="file://$MODULE_DIR$/vendor/egulias/email-validator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/facade/flare-client-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/facade/ignition" />
<excludeFolder url="file://$MODULE_DIR$/vendor/facade/ignition-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/fakerphp/faker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/fideloper/proxy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/filp/whoops" />
<excludeFolder url="file://$MODULE_DIR$/vendor/fruitcake/laravel-cors" />
<excludeFolder url="file://$MODULE_DIR$/vendor/graham-campbell/result-type" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/guzzle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/promises" />
<excludeFolder url="file://$MODULE_DIR$/vendor/guzzlehttp/psr7" />
<excludeFolder url="file://$MODULE_DIR$/vendor/hamcrest/hamcrest-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/framework" />
<excludeFolder url="file://$MODULE_DIR$/vendor/laravel/tinker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/league/commonmark" />
<excludeFolder url="file://$MODULE_DIR$/vendor/league/flysystem" />
<excludeFolder url="file://$MODULE_DIR$/vendor/league/mime-type-detection" />
<excludeFolder url="file://$MODULE_DIR$/vendor/mockery/mockery" />
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nesbot/carbon" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/nunomaduro/collision" />
<excludeFolder url="file://$MODULE_DIR$/vendor/opis/closure" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoption/phpoption" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/prophecy" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-message" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/log" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/simple-cache" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psy/psysh" />
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/collection" />
<excludeFolder url="file://$MODULE_DIR$/vendor/ramsey/uuid" />
<excludeFolder url="file://$MODULE_DIR$/vendor/s1lentium/iptools" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/resource-operations" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" />
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
<excludeFolder url="file://$MODULE_DIR$/vendor/swiftmailer/swiftmailer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/console" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/css-selector" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/error-handler" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/event-dispatcher-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/finder" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-client-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-foundation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/http-kernel" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/mime" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-ctype" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-iconv" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-grapheme" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-idn" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-intl-normalizer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-mbstring" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php72" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php73" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php80" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/process" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/routing" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/service-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/string" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/translation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/var-dumper" />
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
<excludeFolder url="file://$MODULE_DIR$/vendor/tijsverkoyen/css-to-inline-styles" />
<excludeFolder url="file://$MODULE_DIR$/vendor/vlucas/phpdotenv" />
<excludeFolder url="file://$MODULE_DIR$/vendor/voku/portable-ascii" />
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

0
Dockerfile Normal file
View File

View File

@ -1,61 +1,5 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400"></a></p>
# vpn.keks.cloud
<p align="center">
<a href="https://travis-ci.org/laravel/framework"><img src="https://travis-ci.org/laravel/framework.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
GUI to config VPN
## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains over 1500 video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the Laravel [Patreon page](https://patreon.com/taylorotwell).
### Premium Partners
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Cubet Techno Labs](https://cubettech.com)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[Many](https://www.many.co.uk)**
- **[Webdock, Fast VPS Hosting](https://www.webdock.io/en)**
- **[DevSquad](https://devsquad.com)**
- **[OP.GG](https://op.gg)**
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
Used https://github.com/suquant/wgrest

View File

@ -0,0 +1,78 @@
<?php
namespace App\Console\Commands;
use App\Models\User;
use App\Models\VPN;
use App\Models\VPNAccess;
use App\Services\WGRest;
use Illuminate\Console\Command;
class ImportDevices extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'wgrest:import-devices';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get All Devices from WGREST server and add to db';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @param WGRest $wgrest
* @return int
*/
public function handle(WGRest $wgrest)
{
$res = $wgrest->listDevices();
foreach($res as $network) {
$setAdmins = false;
$this->info("Update Device: ".$network["name"]);
$vpn = VPN::query()->where("name", "=", $network["name"])->first();
if(is_null($vpn)) {
$this->info("Create New Device: ".$network["name"]);
$vpn = new VPN();
$vpn->displayName = $network["name"];
$setAdmins = true;
}
$vpn->name = $network["name"];
$vpn->listen_port = $network["listen_port"];
$vpn->network = $network["network"];
$vpn->private_key = $network["private_key"];
$vpn->public_key = $network["public_key"];
$vpn->saveOrFail();
if($setAdmins) {
$admins = User::findAdmins();
foreach($admins as $admin) {
$access = new VPNAccess();
$access->user_id = $admin->id;
$access->vpn_id = $vpn->id;
$access->status = "Admin";
$access->saveOrFail();
}
}
}
return 0;
}
}

View File

@ -0,0 +1,84 @@
<?php
namespace App\Console\Commands;
use App\Models\Peer;
use App\Models\User;
use App\Models\VPN;
use App\Models\VPNAccess;
use App\Services\WGRest;
use Illuminate\Console\Command;
use IPTools\Network;
class ImportPeers extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'wgrest:import-peers';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Get All Peers for all Devices';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @param WGRest $wgrest
* @return int
*/
public function handle(WGRest $wgrest)
{
$vpns = VPN::query()->get();
foreach ($vpns as $vpn) {
$internalPeers = Peer::query()->where("vpn_id", "=", $vpn->id)->get();
$this->info("Import for ".$vpn->name);
$knownpeers=[];
foreach ($internalPeers as $p) {
$knownpeers[] = $p->public_key;
}
$peers = $wgrest->getPeers($vpn->name);
foreach ($peers as $peer) {
if(!in_array($peer["public_key"], $knownpeers)) {
$this->info("Import ".$peer["public_key"]);
$peerToSave = new Peer();
$peerToSave->name = "import";
$peerToSave->public_key = $peer["public_key"];
$peerToSave->allowed_ips = implode(",", $peer["allowed_ips"]);
if(isset($peer["preshared_key"])) {
$peerToSave->preshared_key = $peer["preshared_key"];
}
if(count($peer["allowed_ips"]) == 1) {
$n = Network::parse($peer["allowed_ips"][0]);
if((string)$n->getNetmask()=="255.255.255.255") {
$peerToSave->ip = (string)$n->getIP();
$peerToSave->allowed_ips = null;
}
}
$peerToSave->imported = true;
$peerToSave->vpn_id = $vpn->id;
$peerToSave->saveOrFail();
}
}
}
}
}

View File

@ -2,6 +2,8 @@
namespace App\Console;
use App\Console\Commands\ImportDevices;
use App\Console\Commands\ImportPeers;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@ -13,7 +15,8 @@ class Kernel extends ConsoleKernel
* @var array
*/
protected $commands = [
//
ImportDevices::class,
ImportPeers::class
];
/**

17
app/Helper/WGKey.php Normal file
View File

@ -0,0 +1,17 @@
<?php
namespace App\Helper;
class WGKey
{
static public function generatePrivateKeyForPeer() {
$folder = sys_get_temp_dir()."/".uniqid("wg-");
mkdir($folder);
exec("cd ".$folder."; wg genkey > privkey; cat privkey | wg pubkey > pubkey; wg genpsk > presharedkey");
$keys = [];
$keys["public"] = trim(file_get_contents($folder."/pubkey"));
$keys["privkey"] = trim(file_get_contents($folder."/privkey"));
$keys["presharedkey"] = trim(file_get_contents($folder."/presharedkey"));
return $keys;
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class DashboardController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function dashboardView() {
return view("dashboard.dashboard");
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace App\Http\Controllers;
use App\Helper\WGKey;
use App\Models\Peer;
use App\Models\VPN;
use App\Services\WGRest;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Auth;
use IPTools\IP;
use IPTools\Network;
class PeerController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function overview() {
$user = Auth::user();
$vpn_id = session()->get("current_vpn");
$peers1 = Peer::query()->where("vpn_id", "=", $vpn_id)->where("user_id", "!=", $user->id)->get();
$peers2 = Peer::query()->where("vpn_id", "=", $vpn_id)->whereNull("user_id")->get();
$peers = [];
foreach ($peers1 as $p){
$peers[] = $p;
}
foreach ($peers2 as $p) {
$peers[] = $p;
}
$mypeers = Peer::query()->where("vpn_id", "=", $vpn_id)->where("user_id", "=", $user->id)->get();
return view("peer.overview",["peers" => $peers, "mypeers" => $mypeers]);
}
public function newView() {
return view("peer.new");
}
public function new(Request $request) {
$vpn_id = session()->get("current_vpn");
$vpn = VPN::query()->where("id", "=", $vpn_id)->firstOrFail();
$peer = new Peer();
$peer->name = $request->input("name");
$peer->user_id = Auth::user()->id;
$peer->vpn_id = $vpn_id;
//Calculate IP
$nework = Network::parse($vpn->network);
$peers = Peer::query()->where("vpn_id", "=", $vpn->id)->get();
$usedIPs = [];
foreach ($peers as $p) {
$usedIPs[] = $p->ip;
}
$first = true;
foreach ($nework as $ip) {
if($first) {
$first = false;
continue;
}
if(in_array($ip, $usedIPs)) {
continue;
}
$peer->ip = (string)$ip;
break;
}
//Generate Key
if($request->input("genKeys")) {
$keys = WGKey::generatePrivateKeyForPeer();
$peer->public_key = $keys["privkey"];
$peer->preshared_key = $keys["presharedkey"];
} else {
$peer->public_key = $request->input("public_key");
$peer->preshared_key = $request->input("preshared_key");
}
$peer->saveOrFail();
if($request->input("genKeys")) {
return view("peer.install", ["keys" => $keys, "peer" => $peer]);
}
}
public function syncPeers(WGRest $WGRest) {
$vpn_id = session()->get("current_vpn");
$this->syncPeersNow($vpn_id, $WGRest);
return redirect("/vpn?id=".$vpn_id);
}
private function syncPeersNow($vpnId, WGRest $WGRest) {
$vpn = VPN::query()->where("id", "=", $vpnId)->firstOrFail();
$peers = Peer::query()->where("vpn_id", "=", $vpn->id)->get();
$validePublicKeys = [];
foreach ($peers as $peer) {
$WGRest->createPeer($vpn->name, $peer->public_key, $peer->preshared_key, [$peer->ip."/32"]);
$validePublicKeys[] = $peer->public_key;
}
$wgPeers = $WGRest->getPeers($vpn->name);
foreach ($wgPeers as $peer) {
if(!in_array($peer["public_key"], $validePublicKeys)) {
$WGRest->deletePeer($vpn->name, $peer["peer_id"]);
}
}
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Http\Controllers;
use App\Models\Privilege;
use App\Models\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class PublicController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function loginView() {
if(Auth::check()) {
return redirect("/dashboard");
}
return view("public.login");
}
public function registerView(Request $request) {
return view("public.register");
}
public function register(Request $request) {
$validatedData = $request->validate([
'email' => ['required', 'email:rfc,dns'],
'password' => ['required'],
'password2' => ['required', 'same:password']
]);
//How Many user already exists, check to make the first user admin
$userCount = User::query()->count('id');
$user = new User();
$user->email = $validatedData["email"];
$user->password = Hash::make($validatedData["password"]);
$user->saveOrFail();
$privilege = new Privilege();
$privilege->user_id = $user->id;
if($userCount == 0) {
$privilege->admin = true;
$privilege->createVPN = true;
}
$privilege->saveOrFail();
return redirect("/login");
}
public function login(Request $request) {
$validatedData = $request->validate([
'email' => ['required', 'email:rfc'],
'password' => ['required']
]);
if(Auth::attempt($validatedData)) {
return redirect("/dashboard");
}
return view("public.login", ["msg"=> "Login failed"]);
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Http\Controllers;
use App\Models\Privilege;
use App\Models\User;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Auth;
class UsersController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function overview() {
$user = Auth::user();
if(!$user->hasPrivilege("admin")) {
return response('Unauthenticated.', 401);
}
$users = User::query()->get();
return view("users.overview", ["users" => $users]);
}
public function updateUser(Request $request) {
$user = Auth::user();
if(!$user->hasPrivilege("admin")) {
return response('Unauthenticated.', 401);
}
$validatedData = $request->validate([
'id' => ['required', 'integer'],
'createVPN' => ['boolean'],
'admin' => ['boolean']
]);
$p = Privilege::query()->where("user_id", "=", $validatedData["id"])->first();
if(isset($validatedData["createVPN"]) && $validatedData["createVPN"]) {
$p->createVPN = true;
} else {
$p->createVPN = false;
}
if(isset($validatedData["admin"]) && $validatedData["admin"]) {
$p->admin = true;
} else {
$p->admin = false;
}
$p->saveOrFail();
return redirect("/users");
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers;
use App\Models\Peer;
use App\Models\User;
use App\Models\VPN;
use App\Services\WGRest;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\View;
use IPTools\Network;
class VPNController extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function overview(Request $request) {
$id = $request->input("id");
$vpn = VPN::query()->where("id", "=", $id)->first();
session()->put("current_vpn", $vpn->id);
View::share("currentVPNName", $vpn->name);
//Calculate Free IPS
$network = Network::parse($vpn->network);
$usedIPs = Peer::query()->where("vpn_id", "=", $vpn->id)->count();
$percent = (100 / $network->count()) * $usedIPs ;
return view("vpn.overview", ["currentVPN"=>$vpn, "percent" => $percent ]);
}
public function accessView() {
$vpn_id = session()->get("current_vpn");
$users = User::query()->get();
return view("vpn.access", ["users" => $users, "vpn_id" => $vpn_id]);
}
public function setAccess(Request $request) {
$vpn_id = session()->get("current_vpn");
$user = User::query()->where("id", "=", $request->input("id"))->firstOrFail();
$user->setVPNRole($vpn_id, $request->input("access"));
return redirect("/vpn/access");
}
public function newView() {
return view("vpn.new");
}
public function new(Request $request) {
$vpn = new VPN();
$vpn->name = $request->input("name");
$vpn->displayName = $request->input("display_name");
$vpn->listen_port = $request->input("port");
$vpn->network = $request->input("network");
$privateKey = $request->input("private_key");
if(empty($privateKey)) {
$privateKey = exec('wg genkey');
}
$vpn->private_key = $privateKey;
$vpn->public_key = null;
$vpn->saveOrFail();
}
public function sendToRest(WGRest $WGRest) {
$vpn_id = session()->get("current_vpn");
$vpn = VPN::query()->where("id", "=", $vpn_id)->firstOrFail();
$WGRest->createDevice($vpn->name, $vpn->listen_port, $vpn->private_key, $vpn->network);
return redirect("/vpn?id=".$vpn->id);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class AuthMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if(Auth::check()) {
return $next($request);
}
return redirect("/login?url=".$request->url());
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Http\Middleware;
use App\Models\VPN;
use Closure;
use Illuminate\Support\Facades\Auth;
use \Illuminate\Support\Facades\View;
class GUIMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
//Get Curretn user
$user = Auth::user();
View::share("user", $user);
//Get ALL VPNS
$vpn = VPN::findForUser($user->id);
View::share("vpn", $vpn);
//Get Selectet VPN
$currentVPNId = session()->get("current_vpn");
if($currentVPNId === null && count($vpn)==1) {
session()->put("current_vpn", $vpn[0]->id);
$currentVPNId = $vpn[0]->id;
}
$currentVPN = VPN::query()->where("id", "=", $currentVPNId)->first();
if($currentVPN != null) {
View::share("currentVPNName", $currentVPN->name);
}
return $next($request);
}
}

31
app/Models/Peer.php Normal file
View File

@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Peer extends Authenticatable
{
use HasFactory, Notifiable;
protected $table = "peers";
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'public_key',
'allowed_ips',
'preshared_key',
'user_id',
'vpn_id',
'ip',
];
}

25
app/Models/Privilege.php Normal file
View File

@ -0,0 +1,25 @@
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Privilege extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'user_id',
'admin',
'createVPN'
];
}

View File

@ -40,4 +40,40 @@ class User extends Authenticatable
protected $casts = [
'email_verified_at' => 'datetime',
];
public function hasPrivilege($name) {
$p = Privilege::query()->where("user_id", "=", $this->id)->first();
if($p->$name) {
return true;
}
return false;
}
public function setVPNRole(int $vpnID, string $accessName) {
$access = VPNAccess::query()->where("user_id", "=", $this->id)->where("vpn_id", "=", $vpnID)->first();
if($access === null) {
$access = new VPNAccess();
$access->user_id = $this->id;
$access->vpn_id = $vpnID;
}
$access->status = $accessName;
$access->saveOrFail();
}
public function getVPNRole(int $vpnId) {
$access = VPNAccess::query()->where("user_id", "=", $this->id)->where("vpn_id", "=", $vpnId)->first();
if($access === null) {
return "None";
}
return $access->status;
}
static public function findAdmins() {
$admins = Privilege::query()->where("admin", "=", true)->get();
$users = [];
foreach($admins as $admin) {
$users[] = User::query()->where("id", "=", $admin->user_id)->firstOrFail();
}
return $users;
}
}

41
app/Models/VPN.php Normal file
View File

@ -0,0 +1,41 @@
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class VPN extends Authenticatable
{
use HasFactory, Notifiable;
protected $table = "vpns";
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name',
'displayName',
'listen_port',
'network',
'private_key',
'public_key'
];
static public function findForUser(int $user_id) {
$access = VPNAccess::query()->where("user_id", "=", $user_id)->get();
$vpns = [];
foreach ($access as $a) {
if($a->status != "None") {
$vpns[] = VPN::query()->where("id", "=", $a->vpn_id)->firstOrFail();
}
}
return $vpns;
}
}

27
app/Models/VPNAccess.php Normal file
View File

@ -0,0 +1,27 @@
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class VPNAccess extends Authenticatable
{
use HasFactory, Notifiable;
protected $table = "vpn_access";
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'user_id',
'vpn_id',
'status'
];
}

View File

@ -2,6 +2,8 @@
namespace App\Providers;
use App\Services\WGRest;
use GuzzleHttp\Client;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@ -13,7 +15,12 @@ class AppServiceProvider extends ServiceProvider
*/
public function register()
{
//
$this->app->singleton(WGRest::class, function ($app) {
$client = new Client(["base_uri"=>"http://home.kekskurse.de:8000/"]);
$wgrest = new WGRest($client, "secret");
return $wgrest;
});
}
/**
@ -23,6 +30,6 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
//
}
}

56
app/Services/WGRest.php Normal file
View File

@ -0,0 +1,56 @@
<?php
namespace App\Services;
use GuzzleHttp\Client;
class WGRest
{
/* @var \GuzzleHttp\Client $client */
private $client;
private $token;
public function __construct(Client $client, string $token)
{
$this->client = $client;
$this->token = $token;
}
public function createDevice(string $name, int $listen_port, string $private_key, string $network) {
$data = [];
$data["name"] = $name;
$data["listen_port"] = $listen_port;
$data["private_key"] = $private_key;
$data["network"] = $network;
$res = $this->client->request("POST", "/devices/", ["json" => $data, "headers" => ["Token" => $this->token]]);
}
public function listDevices() {
$res = $this->client->request("GET", "/devices/", ["headers" => ["Token" => $this->token]]);
return json_decode($res->getBody(), true);
}
public function createPeer(string $vpn_name, string $public_key, string $preshared_key, array $allowed_ips) {
$data = [];
$data["public_key"] = $public_key;
$data["allowed_ips"] = $allowed_ips;
$data["preshared_key"] = $preshared_key;
$res = $this->client->request("POST", "/devices/".$vpn_name."/peers", ["json" => $data, "headers" => ["Token" => $this->token]]);
}
public function getPeers(string $vpn_name) {
$res = $this->client->request("GET", "/devices/".$vpn_name."/peers", ["headers" => ["Token" => $this->token]]);
return json_decode($res->getBody(), true);
}
public function deletePeer(string $vpn_name, string $peer_id) {
$res = $this->client->request("DELETE", "/devices/".$vpn_name."/peers/".$peer_id, ["headers" => ["Token" => $this->token]]);
}
}

View File

@ -11,9 +11,10 @@
"php": "^7.3|^8.0",
"fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^8.12",
"laravel/tinker": "^2.5"
"laravel/tinker": "^2.5",
"s1lentium/iptools": "^1.1"
},
"require-dev": {
"facade/ignition": "^2.5",

53
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fac753ae2702317b354e7eb283f28cbc",
"content-hash": "fc90d2119cc669b7ff0da2f60d113e6e",
"packages": [
{
"name": "asm89/stack-cors",
@ -2210,6 +2210,57 @@
],
"time": "2020-08-18T17:17:46+00:00"
},
{
"name": "s1lentium/iptools",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/S1lentium/IPTools.git",
"reference": "f6f8ab6132ca7443bd7cced1681f5066d725fd5f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/S1lentium/IPTools/zipball/f6f8ab6132ca7443bd7cced1681f5066d725fd5f",
"reference": "f6f8ab6132ca7443bd7cced1681f5066d725fd5f",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
"satooshi/php-coveralls": "~1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"IPTools\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Safarov Alisher",
"email": "alisher.safarov@outlook.com",
"homepage": "https://github.com/S1lentium"
}
],
"description": "PHP Library for manipulating network addresses (IPv4 and IPv6)",
"keywords": [
"IP",
"IP-Tools",
"cidr",
"ipv4",
"ipv6",
"network",
"subnet"
],
"time": "2018-09-19T06:15:53+00:00"
},
{
"name": "swiftmailer/swiftmailer",
"version": "v6.2.3",

View File

@ -15,13 +15,22 @@ class CreateUsersTable extends Migration
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create("privileges", function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger("user_id");
$table->boolean("admin")->default(false);
$table->boolean("createVPN")->default(false);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
}
/**

View File

@ -0,0 +1,49 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Vpn extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('vpns', function (Blueprint $table) {
$table->id();
$table->string("name")->comment("Device Name");
$table->string("displayName");
$table->string("listen_port");
$table->string("network");
$table->string("private_key");
$table->string("public_key")->nullable();
$table->timestamps();
});
Schema::create("vpn_access", function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger("user_id");
$table->unsignedBigInteger("vpn_id");
$table->enum("status", ["None", "User", "Admin"]);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('vpn_id')->references('id')->on('vpns');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('vpns');
Schema::dropIfExists('vpn_access');
}
}

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class Peers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('peers', function (Blueprint $table) {
$table->id();
$table->string("name");
$table->string("public_key");
$table->string("ip")->nullable();
$table->string("allowed_ips")->nullable();
$table->string("preshared_key")->nullable();
$table->boolean("imported")->default(false);
$table->unsignedBigInteger("user_id")->nullable();
$table->unsignedBigInteger("vpn_id");
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('vpn_id')->references('id')->on('vpns');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('peers');
}
}

1
public/css Symbolic link
View File

@ -0,0 +1 @@
../resources/css

12
resources/css/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>Dashboard</h1>
{{ $user->email }}
</div>
</div>
@endsection

View File

@ -0,0 +1,73 @@
<!-- Stored in resources/views/layouts/app.blade.php -->
<html>
<head>
<title>@yield('title')</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-lg navbar-dark bg-primary" style="margin-top: 20px;">
<a class="navbar-brand" href="/dashboard">VPN</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarColor01">
<ul class="navbar-nav mr-auto">
@if($user->hasPrivilege("createVPN") || count($vpn) > 1)
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
@if(isset($currentVPNName))
{{ $currentVPNName }}
@else
VPN
@endif
</a>
<div class="dropdown-menu">
@foreach($vpn as $v)
<a class="dropdown-item" href="/vpn?id={{ $v->id }}">{{ $v->name }}</a>
@endforeach
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="/vpn/new">New</a>
</div>
</li>
@endif
@if(isset($currentVPNName))
<li class="nav-item">
<a class="nav-link" href="/vpn/peer">Peers</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">API-Key</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/vpn/access">Access</a>
</li>
@endif
</ul>
</div>
<div class="navbar-collapse">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/users">Users</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Logout</a>
</li>
</ul>
</div>
</nav>
<div class="row" style="min-height: 30px;"></div>
@yield('content')
</div>
</body>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
@yield('script')
</html>

View File

@ -0,0 +1,14 @@
<!-- Stored in resources/views/layouts/app.blade.php -->
<html>
<head>
<title>@yield('title')</title>
<link rel="stylesheet" href="/css/bootstrap.min.css">
</head>
<body>
<div class="container">
@yield('content')
</div>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>Keys</h1>
<p>This is your private key, save it somewhere without this key you can't connect to the VPN. You can't get this Key a secound time from this Wepage.</p>
<input disabled class="form-control" value="{{ $keys["privkey"] }}">
<br>
<table class="table">
<tr>
<th>IP</th>
<td>{{ $peer->ip }}</td>
</tr>
</table>
</div>
</div>
@endsection

View File

@ -0,0 +1,44 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>New Peer</h1>
<form method="post">
@csrf
<label>Name</label>
<input name="name" class="form-control">
<span id="keys">
<label>Public Key</label>
<input name="public_key" id="public_key" class="form-control">
<label>Preshared Key</label>
<input name="preshared_key" id="preshared_key" class="form-control">
</span>
<input style="margin-top: 15px;" type="checkbox" id="genKeys" name="genKeys"> Generate Keys at the Server <b>Very Insecure!</b>
<br>
<input style="margin-top: 15px;" type="submit" value="Create Peer" class="btn btn-success">
</form>
</div>
</div>
@endsection
@section('script')
<script>
$("#genKeys").change(function() {
if($("#genKeys").prop("checked")) {
alert("Generate the Key on the Server is not secure!")
$("#keys").hide();
$("#public_key").val("");
$("#preshared_key").val("");
} else {
$("#keys").show();
}
});
</script>
@endsection

View File

@ -0,0 +1,46 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>My Peers</h1>
<table class="table">
<tr>
<th>Name</th>
<th>PublicKey</th>
<th>IPs</th>
<th>Actions</th>
</tr>
@foreach($mypeers as $peer)
<tr>
<td>{{ $peer->name }}</td>
<td>{{$peer->public_key}}</td>
<td>{{$peer->ip}}@if($peer->allowed_ips && $peer->ip), @endif{{$peer->allowed_ips}}</td>
<td>-</td>
</tr>
@endforeach
</table>
<h1>Peers</h1>
<table class="table">
<tr>
<th>Name</th>
<th>PublicKey</th>
<th>IPs</th>
<th>Actions</th>
</tr>
@foreach($peers as $peer)
<tr>
<td>{{ $peer->name }}</td>
<td>{{$peer->public_key}}</td>
<td>{{$peer->ip}}@if($peer->allowed_ips && $peer->ip), @endif{{$peer->allowed_ips}}</td>
<td>-</td>
</tr>
@endforeach
</table>
</div>
</div>
@endsection

View File

@ -0,0 +1,24 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.public')
@section('title', 'Login')
@section('content')
<div class="row" style="margin-top: 20%;">
<div class="col-md-3"></div>
<div class="col-md-6">
<h1>Login</h1>
<form method="post" style="margin-top: 30px;">
@csrf
<label>E-Mail</label>
<input type="email" name="email" placeholder="E-Mail" class="form-control">
<label style="margin-top: 8px;">Password</label>
<input type="password" name="password" placeholder="Password" class="form-control">
<input type="submit" class="btn btn-success" style="margin-top: 15px;" value="Login">
<a href="/register" class="btn" style="margin-top: 15px;float: right;">Register new Account</a>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,36 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.public')
@section('title', 'Register')
@section('content')
<div class="row" style="margin-top: 20%;">
<div class="col-md-3"></div>
<div class="col-md-6">
<h1>Register</h1>
@if ($errors->all())
<div class="alert alert-warning" role="alert">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" style="margin-top: 30px;">
@csrf
<label>E-Mail</label>
<input type="email" name="email" placeholder="E-Mail" class="form-control">
<label style="margin-top: 8px;">Password</label>
<input type="password" name="password" placeholder="Password" class="form-control">
<label style="margin-top: 8px;">Password Again</label>
<input type="password" name="password2" placeholder="Password" class="form-control">
<input type="submit" class="btn btn-success" style="margin-top: 15px;" value="Register">
<a href="/login" class="btn" style="margin-top: 15px;float: right;">Login</a>
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,41 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>Users</h1>
@if ($errors->all())
<div class="alert alert-warning" role="alert">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<table class="table">
<tr>
<th>E-Mail</th>
<th>Create VPN</th>
<th>Admin</th>
<th class="text-right">Save</th>
</tr>
@foreach($users as $u)
<tr>
<form method="post">
@csrf
<td>{{ $u->email }}<input name="id" style="display: none" value="{{ $u->id }}"> </td>
<td><input type="checkbox" value="1" name="createVPN" @if($u->hasPrivilege("createVPN")) checked @endif> </td>
<td><input type="checkbox" value="1" name="admin" @if($u->hasPrivilege("admin")) checked @endif> </td>
<td><input type="submit" class="btn btn-primary btn-sm float-right" value="Save"> </td>
</form>
</tr>
@endforeach
</table>
</div>
</div>
@endsection

View File

@ -0,0 +1,36 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>VPN Access</h1>
<table class="table">
<tr>
<th>Mail</th>
<th>Access</th>
<th class="text-right">Save</th>
</tr>
@foreach($users as $u)
<tr>
<form method="post">
@csrf
<td>{{$u->email}}<input style="display: none" name="id" value="{{$u->id}}"> </td>
<td>
<select name="access" class="form-control">
<option @if ($u->getVPNRole($vpn_id)=="None") selected="selected" @endif >None</option>
<option @if ($u->getVPNRole($vpn_id)=="User") selected="selected" @endif >User</option>
<option @if ($u->getVPNRole($vpn_id)=="Admin") selected="selected" @endif >Admin</option>
</select>
</td>
<td class="text-right"><input type="submit" class="btn btn-primary" value="Save"></td>
</form>
</tr>
@endforeach
</table>
</div>
</div>
@endsection

View File

@ -0,0 +1,28 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>New VPN</h1>
<form method="post">
@csrf
<label>Device Name</label>
<input name="name" class="form-control" placeholder="wg0">
<label>Display Name</label>
<input name="display_name" class="form-control">
<label>Listening Port</label>
<input name="port" class="form-control" placeholder="51820">
<label>Private Key</label>
<input name="private_key" class="form-control" placeholder="Create new if empty">
<label>Network</label>
<input name="network" class="form-control" placeholder="10.0.1.1/24">
<br><br>
<input type="submit" class="btn btn-success" value="Create">
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,56 @@
<!-- Stored in resources/views/child.blade.php -->
@extends('layout.app')
@section('title', 'VPN')
@section('content')
<div class="row"">
<div class="col-md-12">
<h1>VPN: {{ $currentVPN->displayName }}</h1>
<h3>Usage</h3>
Based on the Subnet there are only a limited numbers of ip which can used in this VPN.
<div class="progress">
<div class="progress-bar" role="progressbar" style="width: {{$percent}}%;" aria-valuenow="{{$percent}}" aria-valuemin="0" aria-valuemax="100">{{$percent}}%</div>
</div>
<h3 style="margin-top: 20px;">Config</h3>
<table class="table">
<tr>
<th>Name/Device Name</th>
<td><input disabled class="form-control" value="{{ $currentVPN->name }}"> </td>
</tr>
<tr>
<th>Display Name</th>
<td><input disabled class="form-control" value="{{ $currentVPN->displayName }}"> </td>
</tr>
<tr>
<th>Public Key</th>
<td><input disabled class="form-control" value="{{ $currentVPN->public_key }}"> </td>
</tr>
<tr>
<th>Private Key</th>
<td><input disabled class="form-control" value="{{ $currentVPN->private_key }}"> </td>
</tr>
<tr>
<th>Network</th>
<td><input disabled class="form-control" value="{{ $currentVPN->network }}"> </td>
</tr>
</table>
<h3>Actions</h3>
<table class="table">
<tr>
<th>Sync Peers</th>
<td></td>
<td><a href="/vpn/syncPeers" class="btn btn-primary btn-sm float-right">Run</a> </td>
</tr>
<tr>
<th>Create Device on Server</th>
<td>Only needed if Wireguard Server is new</td>
<td><a href="/vpn/sendToServer" class="btn btn-danger btn-sm float-right">Run</a> </td>
</tr>
</table>
</div>
</div>
@endsection

View File

@ -14,5 +14,28 @@ use Illuminate\Support\Facades\Route;
*/
Route::get('/', function () {
return view('welcome');
return redirect("/login");
});
Route::get("/login", [\App\Http\Controllers\PublicController::class, "loginView"]);
Route::post("/login", [\App\Http\Controllers\PublicController::class, "login"]);
Route::get("/register", [\App\Http\Controllers\PublicController::class, "registerView"]);
Route::post("/register", [\App\Http\Controllers\PublicController::class, "register"]);
Route::middleware([\App\Http\Middleware\AuthMiddleware::class, \App\Http\Middleware\GUIMiddleware::class])->group(function () {
Route::get('/dashboard', [\App\Http\Controllers\DashboardController::class, "dashboardView"]);
Route::get("/vpn", [\App\Http\Controllers\VPNController::class, "overview"]);
Route::get("/vpn/access", [\App\Http\Controllers\VPNController::class, "accessView"]);
Route::post("/vpn/access", [\App\Http\Controllers\VPNController::class, "setAccess"]);
Route::get("/vpn/new", [\App\Http\Controllers\VPNController::class, "newView"]);
Route::post("/vpn/new", [\App\Http\Controllers\VPNController::class, "new"]);
Route::get("/vpn/sendToServer", [\App\Http\Controllers\VPNController::class, "sendToRest"]);
Route::get("/vpn/peer", [\App\Http\Controllers\PeerController::class, "overview"]);
Route::get("/vpn/peer/new", [\App\Http\Controllers\PeerController::class, "newView"]);
Route::post("/vpn/peer/new", [\App\Http\Controllers\PeerController::class, "new"]);
Route::get("/vpn/syncPeers", [\App\Http\Controllers\PeerController::class, "syncPeers"]);
Route::get("/users", [\App\Http\Controllers\UsersController::class, "overview"]);
Route::post("/users", [\App\Http\Controllers\UsersController::class, "updateUser"]);
});