This commit is contained in:
Andras Bacsai
2023-07-14 11:27:08 +02:00
parent cac59e4873
commit cbefbb7927
29 changed files with 447 additions and 141 deletions

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Actions\License;
use App\Models\InstanceSettings;
use Illuminate\Support\Facades\Http;
use Visus\Cuid2\Cuid2;
class CheckResaleLicense
{
public function __invoke()
{
try {
$settings = InstanceSettings::get();
$instance_id = config('app.id');
if (!$settings->resale_license) {
return;
}
ray('Checking license key');
$data = Http::withHeaders([
'Accept' => 'application/json',
])->post('https://api.lemonsqueezy.com/v1/licenses/validate', [
'license_key' => $settings->resale_license,
'instance_name' => $instance_id,
])->throw()->json();
$product_id = data_get($data, 'meta.product_id');
if (isDev()) {
$valid_product_id = 93221;
} else {
$valid_product_id = 93222;
}
if ($product_id !== $valid_product_id) {
throw new \Exception('Invalid product id');
}
ray('Valid Product Id');
['valid' => $valid, 'license_key' => $license_key] = $data;
if ($valid) {
if (data_get($license_key, 'status') === 'inactive') {
Http::withHeaders([
'Accept' => 'application/json',
])->post('https://api.lemonsqueezy.com/v1/licenses/activate', [
'license_key' => $settings->resale_license,
'instance_name' => $instance_id,
])->throw()->json();
}
$settings->update([
'is_resale_license_active' => true,
]);
return;
}
throw new \Exception('Invalid license key');
} catch (\Throwable $th) {
ray($th);
$settings->update([
'resale_license' => null,
'is_resale_license_active' => false,
]);
throw $th;
}
}
}

View File

@@ -2,9 +2,11 @@
namespace App\Console;
use App\Jobs\CheckResaleLicenseJob;
use App\Jobs\InstanceAutoUpdateJob;
use App\Jobs\ProxyCheckJob;
use App\Jobs\DockerCleanupJob;
use App\Jobs\CheckResaleLicenseKeys;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
@@ -14,6 +16,7 @@ class Kernel extends ConsoleKernel
{
if (isDev()) {
$schedule->command('horizon:snapshot')->everyMinute();
$schedule->job(new CheckResaleLicenseJob)->everyMinute();
$schedule->job(new DockerCleanupJob)->everyOddHour();
// $schedule->job(new InstanceAutoUpdateJob(true))->everyMinute();
} else {
@@ -29,4 +32,4 @@ class Kernel extends ConsoleKernel
require base_path('routes/console.php');
}
}
}

View File

@@ -17,9 +17,11 @@ class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
public function license()
public function subscription()
{
return view('license');
return view('subscription', [
'settings' => InstanceSettings::get()
]);
}
public function dashboard()
{

View File

@@ -21,7 +21,6 @@ class Kernel extends HttpKernel
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\LicenseValid::class,
];

View File

@@ -0,0 +1,42 @@
<?php
namespace App\Http\Livewire;
use App\Actions\License\CheckResaleLicense;
use App\Models\InstanceSettings;
use Livewire\Component;
class CheckLicense extends Component
{
public InstanceSettings|null $settings = null;
public string|null $instance_id = null;
protected $rules = [
'settings.resale_license' => 'nullable',
'settings.is_resale_license_active' => 'nullable',
];
protected $validationAttributes = [
'settings.resale_license' => 'License',
'instance_id' => 'Instance Id (Do not change this)',
'settings.is_resale_license_active' => 'Is License Active',
];
public function mount()
{
$this->instance_id = config('app.id');
$this->settings = InstanceSettings::get();
}
public function submit()
{
$this->validate();
$this->settings->save();
if ($this->settings->resale_license) {
try {
resolve(CheckResaleLicense::class)();
$this->emit('reloadWindow');
} catch (\Throwable $th) {
session()->flash('error', 'License is not valid. Please contact support.');
ray($th->getMessage());
return redirect()->to('/subscription');
}
}
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http\Livewire\Settings;
use App\Jobs\ProxyCheckJob;
use App\Models\InstanceSettings as ModelsInstanceSettings;
use App\Models\Server;
use Illuminate\Support\Facades\Http;
use Livewire\Component;
use Spatie\Url\Url;
use Symfony\Component\Yaml\Yaml;
@@ -21,11 +22,13 @@ class Configuration extends Component
protected $rules = [
'settings.fqdn' => 'nullable',
'settings.resale_license' => 'nullable',
'settings.public_port_min' => 'required',
'settings.public_port_max' => 'required',
];
protected $validationAttributes = [
'settings.fqdn' => 'FQDN',
'settings.resale_license' => 'Resale License',
'settings.public_port_min' => 'Public port min',
'settings.public_port_max' => 'Public port max',
];

View File

@@ -16,15 +16,21 @@ class LicenseValid
*/
public function handle(Request $request, Closure $next): Response
{
if (isCloud() && !isDev()) {
if (isCloud()) {
$value = Cache::get('license_key');
if (isDev()) {
$value = true;
}
if (!$value) {
ray($request->path());
if ($request->path() !== 'license' && $request->path() !== 'livewire/message/license') {
return redirect('license');
}
} else {
if ($request->path() === 'license' || $request->path() === 'livewire/message/license') {
return redirect('home');
}
}
}
return $next($request);
}
}
}

View File

@@ -4,33 +4,34 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\HttpFoundation\Response;
class SubscriptionValid
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$allowed_paths = [
'team',
'livewire/message/team',
'subscription',
'login',
'register',
'livewire/message/switch-team',
'logout',
'livewire/message/check-license',
'livewire/message/switch-team',
];
if (isCloud()) {
if (!$request->user()?->currentTeam()?->subscription && $request->user()?->currentTeam()->subscription?->lemon_status !== 'active') {
if (isCloud() && !isSubscribed()) {
ray('SubscriptionValid Middleware');
if (!in_array($request->path(), $allowed_paths)) {
return redirect('team');
return redirect('subscription');
} else {
return $next($request);
}
} else {
if ($request->path() === 'subscription') {
return redirect('/');
} else {
return $next($request);
}
}
return $next($request);
}
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Jobs;
use App\Actions\License\CheckResaleLicense;
use App\Models\InstanceSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Http;
use Visus\Cuid2\Cuid2;
class CheckResaleLicenseJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct()
{
}
public function handle(): void
{
try {
resolve(CheckResaleLicense::class)();
} catch (\Throwable $th) {
ray($th);
}
}
}

View File

@@ -12,6 +12,7 @@ use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
class InstanceSettings extends Model implements SendsEmail
{
use Notifiable, SchemalessAttributesTrait;
protected $guarded = [];
protected $schemalessAttributes = [
'smtp',
];

View File

@@ -61,7 +61,8 @@ class User extends Authenticatable implements SendsEmail
{
return $this->email;
}
public function isAdmin() {
public function isAdmin()
{
return $this->pivot->role === 'admin' || $this->pivot->role === 'owner';
}
public function isAdminFromSession()
@@ -91,7 +92,8 @@ class User extends Authenticatable implements SendsEmail
});
return $found_root_team->count() > 0;
}
public function personalTeam() {
public function personalTeam()
{
return $this->teams()->where('personal_team', true)->first();
}
public function teams()