Files

53 lines
2.6 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class LicenseService
{
public function issue(int $userId, int $purchaseId): void
{
if (DB::table('licenses')->where('purchase_id', $purchaseId)->exists()) {
return;
}
$key = 'TNX-'.Str::upper(bin2hex(random_bytes(20)));
DB::table('licenses')->insert(['user_id' => $userId, 'purchase_id' => $purchaseId, 'key_hash' => hash('sha256', $key), 'key_encrypted' => Crypt::encryptString($key), 'status' => 'active', 'device_limit' => 2, 'created_at' => now(), 'updated_at' => now()]);
}
public function activate(string $key, string $device): array
{
return DB::transaction(function () use ($key, $device) {
$license = DB::table('licenses')->where('key_hash', hash('sha256', $key))->lockForUpdate()->first();
abort_unless($license && $license->status === 'active', 403, 'Invalid or revoked license.');
$deviceHash = hash('sha256', $device);
$existing = DB::table('activations')->where('license_id', $license->id)->where('device_hash', $deviceHash)->first();
abort_if(! $existing && DB::table('activations')->where('license_id', $license->id)->count() >= $license->device_limit, 409, 'Device limit reached.');
$token = bin2hex(random_bytes(32));
DB::table('activations')->updateOrInsert(['license_id' => $license->id, 'device_hash' => $deviceHash], ['token_hash' => hash('sha256', $token), 'last_seen_at' => now(), 'created_at' => now(), 'updated_at' => now()]);
return ['activation_token' => $token, 'valid' => true, 'check_again_in' => 86400];
}, 3);
}
public function check(string $token, bool $deactivate = false): array
{
return DB::transaction(function () use ($token, $deactivate) {
$activation = DB::table('activations')->where('token_hash', hash('sha256', $token))->first();
abort_unless($activation, 403, 'Invalid activation.');
$license = DB::table('licenses')->where('id', $activation->license_id)->lockForUpdate()->first();
if ($deactivate) {
DB::table('activations')->where('id', $activation->id)->delete();
return ['deactivated' => true];
}
abort_unless($license->status === 'active', 403, 'License revoked.');
DB::table('activations')->where('id', $activation->id)->update(['last_seen_at' => now()]);
return ['valid' => true, 'check_again_in' => 86400];
}, 3);
}
}