Phase 06: License Service
Implement the central LicenseService that creates licenses, validates them via a 7-step algorithm, and provides status-transition helpers.
Files Written
Section titled “Files Written”src/Models/License.phpsrc/Services/LicenseService.php
License Model
Section titled “License Model”License::from_row(array $row): self maps a raw $wpdb row to a typed object.
$license->is_active() // status === 1$license->is_expired() // status === 3 or expires_at in past$license->is_revoked() // status === 5$license->is_terminated() // status === 6 (irreversible)$license->is_suspended() // status === 4$license->is_within_expiry() // active AND not past expiry$license->status_label() // "Active", "Expired", etc.$license->to_array(false) // safe array excluding plaintext keyStatus codes:
| Code | Meaning | Terminal? |
|---|---|---|
| 0 | Pending | No |
| 1 | Active | No |
| 2 | Inactive | No |
| 3 | Expired | No (can be renewed) |
| 4 | Suspended | No |
| 5 | Revoked | No |
| 6 | Terminated | Yes — cannot be reversed |
LicenseService
Section titled “LicenseService”Constructor takes 6 dependencies via DI:
public function __construct( LicenseRepository $license_repo, Signer $signer, KeyVault $vault, ActivationLogRepository $log_repo, BlacklistRepository $blacklist_repo, MachineRepository $machine_repo,)create()
Section titled “create()”- Generate raw key string (delegates to
GeneratorServiceor accepts a pre-generated key). - Compute
sha256($raw_key)— used as the lookup hash stored inlicense_key_hash. - Encrypt the raw key with
KeyVault::encrypt(). - Sign a claims payload with
Signer::sign()— token stored insigned_token. - Insert the record via
LicenseRepository::insert()withstatus = 2(Inactive) — keys are inactive until explicitly activated. - Fire
do_action('wplm_license_created', $license).
validate() — 7-step algorithm
Section titled “validate() — 7-step algorithm”1. Parse and base64url-decode the token.2. Verify Ed25519 signature — fail → INVALID_SIGNATURE.3. Verify `exp` claim — fail → TOKEN_EXPIRED.4. Look up the license record by key hash.5. Check license status — suspended/revoked/terminated → SUSPENDED / REVOKED / TERMINATED.6. Check blacklist (key hash and any device fingerprint provided) — hit → BLACKLISTED.7. Optionally verify machine fingerprint if device_id supplied.Return: ['valid' => bool, 'code' => string, 'license' => License|null]The code string is one of: VALID, INVALID_SIGNATURE, TOKEN_EXPIRED, NOT_FOUND, SUSPENDED, REVOKED, TERMINATED, BLACKLISTED, INACTIVE.
Wiring in Plugin.php
Section titled “Wiring in Plugin.php”$c->bind(LicenseService::class, fn($c) => new Services\LicenseService( $c->make(Repositories\LicenseRepository::class), $c->make(Crypto\Signer::class), $c->make(Crypto\KeyVault::class), $c->make(Repositories\ActivationLogRepository::class), $c->make(Repositories\BlacklistRepository::class), $c->make(Repositories\MachineRepository::class),));