You've already forked wc-licensed-product-client
Initialize composer project for WooCommerce Licensed Product Client
- Set up composer.json with package metadata and PSR-4 autoloading - Add symfony/http-client ^7.0 as HTTP client dependency - Create project structure (src/, tests/, tmp/) - Add README.md with project overview - Add CHANGELOG.md to track version history - Add .gitignore for vendor and cache files - Include OpenAPI specification in tmp/openapi.json Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
indent_size = 2
|
||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/vendor/
|
||||
.phpunit.result.cache
|
||||
.php-cs-fixer.cache
|
||||
*.log
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
18
CHANGELOG.md
Normal file
18
CHANGELOG.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.0.1] - 2026-01-22
|
||||
|
||||
### Added
|
||||
|
||||
- Initial composer project setup
|
||||
- Package configuration with PSR-4 autoloading
|
||||
- Symfony HttpClient dependency (^7.0)
|
||||
- Project documentation (README.md, CHANGELOG.md)
|
||||
- OpenAPI specification reference in tmp/openapi.json
|
||||
91
CLAUDE.md
Normal file
91
CLAUDE.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# License-Client for WooCommerce Licensed Product Plugin
|
||||
|
||||
**Author:** Marco Graetsch
|
||||
**Author URL:** <https://src.bundespruefstelle.ch/magdev>
|
||||
**Author Email:** <magdev3.0@gmail.com>
|
||||
**Repository URL:** <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client>
|
||||
**Issues URL:** <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues>
|
||||
**Package-Name:** `magdev/wc-licensed-product-client`
|
||||
|
||||
## Project Overview
|
||||
|
||||
This composer package implements a Client for the WooCommerce Licensed Product Plugin. It uses the REST API as described in `tmp/openapi.json` to activate, validate and check the status of licenses.
|
||||
|
||||
## Features
|
||||
|
||||
- Easy integration in licensed software packages
|
||||
- Defines a PHP constant if a licensed is valid or not
|
||||
- Obfuscate the security critical code parts using plain PHP tools as best as possible
|
||||
|
||||
### Key Fact: 100% AI-Generated
|
||||
|
||||
This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance.
|
||||
|
||||
## Temporary Roadmap
|
||||
|
||||
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file.
|
||||
|
||||
### Known Bugs
|
||||
|
||||
No known bugs at the moment
|
||||
|
||||
### Version 0.0.1
|
||||
|
||||
- Initialize composer project of type `library` with the known details
|
||||
- Install dependencies
|
||||
|
||||
## Technical Stack
|
||||
|
||||
- **Language:** PHP 8.3.x
|
||||
- **Coding-Style:** Symfony
|
||||
- **HTTP-Client-Library:** symfony/http-client
|
||||
- **Dependency Management:** Composer
|
||||
- **OpenAPI Description:** `tmp/openapi.json`
|
||||
|
||||
---
|
||||
|
||||
**For AI Assistants:**
|
||||
|
||||
When starting a new session on this project:
|
||||
|
||||
1. Read this CLAUDE.md file first
|
||||
2. Semantic versioning follows the `MAJOR.MINOR.BUGFIX` pattern
|
||||
3. Check git log for recent changes
|
||||
4. Verify you're on the `dev` branch before making changes
|
||||
5. Run `composer install` if vendor/ is missing
|
||||
6. Test changes before committing
|
||||
7. Follow commit message format with Claude Code attribution
|
||||
8. Update this session history section with learnings
|
||||
9. Always update the `README.md` on related changes
|
||||
10. Keep changes in a single `CHANGELOG.md`
|
||||
11. Follow markdown linting rules (see below)
|
||||
|
||||
Always refer to this document when starting work on this project.
|
||||
|
||||
### Markdown Linting Rules
|
||||
|
||||
When editing CLAUDE.md or other markdown files, follow these rules to avoid linting errors:
|
||||
|
||||
1. **MD031 - Blank lines around fenced code blocks**: Always add a blank line before and after fenced code blocks, even when they follow list items. Example of correct format:
|
||||
|
||||
- **Item label**:
|
||||
|
||||
(blank line here)
|
||||
\`\`\`php
|
||||
code example
|
||||
\`\`\`
|
||||
(blank line here)
|
||||
|
||||
2. **MD056 - Table column count**: Table separators must have matching column counts and proper spacing. Use consistent dash lengths that match column header widths.
|
||||
|
||||
3. **MD009 - No trailing spaces**: Remove trailing whitespace from lines
|
||||
|
||||
4. **MD012 - No multiple consecutive blank lines**: Use only single blank lines between sections
|
||||
|
||||
5. **MD040 - Fenced code blocks should have a language specified**: Always add a language identifier to code blocks (e.g., `txt`, `bash`, `php`). For shortcode examples, use `txt`.
|
||||
|
||||
6. **MD032 - Lists should be surrounded by blank lines**: Add a blank line before AND after list blocks, including after bold labels like `**Attributes:**`.
|
||||
|
||||
7. **MD034 - Bare URLs**: Wrap URLs in angle brackets (e.g., `<https://example.com>`) or use markdown link syntax `[text](url)`.
|
||||
|
||||
8. **Author section formatting**: Use a heading (`### Name`) instead of bold (`**Name**`) for the author name to maintain consistent document structure.
|
||||
49
README.md
Normal file
49
README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# WooCommerce Licensed Product Client
|
||||
|
||||
A PHP client library for the WooCommerce Licensed Product Plugin REST API. Activate, validate, and check the status of software licenses.
|
||||
|
||||
## Requirements
|
||||
|
||||
- PHP 8.3 or higher
|
||||
- Composer
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
composer require magdev/wc-licensed-product-client
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Easy integration in licensed software packages
|
||||
- License validation against domains
|
||||
- License activation on domains
|
||||
- License status checking
|
||||
- Built on Symfony HttpClient
|
||||
|
||||
## API Endpoints
|
||||
|
||||
This client interacts with the following WooCommerce Licensed Product API endpoints:
|
||||
|
||||
- **POST /validate** - Validate a license key for a specific domain
|
||||
- **POST /status** - Get detailed license status information
|
||||
- **POST /activate** - Activate a license on a domain
|
||||
|
||||
## Usage
|
||||
|
||||
Coming soon in future versions.
|
||||
|
||||
## License
|
||||
|
||||
GPL-2.0-or-later
|
||||
|
||||
## Author
|
||||
|
||||
Marco Graetsch
|
||||
|
||||
- Website: <https://src.bundespruefstelle.ch/magdev>
|
||||
- Email: <magdev3.0@gmail.com>
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and pull requests are welcome at <https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues>
|
||||
36
composer.json
Normal file
36
composer.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "magdev/wc-licensed-product-client",
|
||||
"description": "Client library for WooCommerce Licensed Product Plugin - Activate, validate and check the status of licenses via REST API",
|
||||
"type": "library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Graetsch",
|
||||
"email": "magdev3.0@gmail.com",
|
||||
"homepage": "https://src.bundespruefstelle.ch/magdev"
|
||||
}
|
||||
],
|
||||
"homepage": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client",
|
||||
"support": {
|
||||
"issues": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client/issues",
|
||||
"source": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"symfony/http-client": "^7.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Magdev\\WcLicensedProductClient\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Magdev\\WcLicensedProductClient\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"minimum-stability": "stable"
|
||||
}
|
||||
537
composer.lock
generated
Normal file
537
composer.lock
generated
Normal file
@@ -0,0 +1,537 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "dabb6ce648c8b638dc4b20b8999dea1d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "psr/container",
|
||||
"version": "2.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/container.git",
|
||||
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||
"reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Container\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common Container Interface (PHP FIG PSR-11)",
|
||||
"homepage": "https://github.com/php-fig/container",
|
||||
"keywords": [
|
||||
"PSR-11",
|
||||
"container",
|
||||
"container-interface",
|
||||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/php-fig/container/issues",
|
||||
"source": "https://github.com/php-fig/container/tree/2.0.2"
|
||||
},
|
||||
"time": "2021-11-05T16:47:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/log",
|
||||
"version": "3.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/log/tree/3.0.2"
|
||||
},
|
||||
"time": "2024-09-11T13:17:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/contracts",
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"function.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/d01dfac1e0dc99f18da48b18101c23ce57929616",
|
||||
"reference": "d01dfac1e0dc99f18da48b18101c23ce57929616",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
|
||||
"symfony/polyfill-php83": "^1.29",
|
||||
"symfony/service-contracts": "^2.5|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"amphp/amp": "<2.5",
|
||||
"amphp/socket": "<1.1",
|
||||
"php-http/discovery": "<1.15",
|
||||
"symfony/http-foundation": "<6.4"
|
||||
},
|
||||
"provide": {
|
||||
"php-http/async-client-implementation": "*",
|
||||
"php-http/client-implementation": "*",
|
||||
"psr/http-client-implementation": "1.0",
|
||||
"symfony/http-client-implementation": "3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/http-client": "^4.2.1|^5.0",
|
||||
"amphp/http-tunnel": "^1.0|^2.0",
|
||||
"guzzlehttp/promises": "^1.4|^2.0",
|
||||
"nyholm/psr7": "^1.0",
|
||||
"php-http/httplug": "^1.0|^2.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"symfony/amphp-http-client-meta": "^1.0|^2.0",
|
||||
"symfony/cache": "^6.4|^7.0|^8.0",
|
||||
"symfony/dependency-injection": "^6.4|^7.0|^8.0",
|
||||
"symfony/http-kernel": "^6.4|^7.0|^8.0",
|
||||
"symfony/messenger": "^6.4|^7.0|^8.0",
|
||||
"symfony/process": "^6.4|^7.0|^8.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0|^8.0",
|
||||
"symfony/stopwatch": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\HttpClient\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-23T14:50:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
"version": "v3.6.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client-contracts.git",
|
||||
"reference": "75d7043853a42837e68111812f4d964b01e5101c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
|
||||
"reference": "75d7043853a42837e68111812f4d964b01e5101c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/contracts",
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Contracts\\HttpClient\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Test/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Generic abstractions related to HTTP clients",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"abstractions",
|
||||
"contracts",
|
||||
"decoupling",
|
||||
"interfaces",
|
||||
"interoperability",
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-29T11:18:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php83",
|
||||
"version": "v1.33.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php83.git",
|
||||
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
|
||||
"reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php83\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-08T02:45:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.6.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"psr/container": "^1.1|^2.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3"
|
||||
},
|
||||
"conflict": {
|
||||
"ext-psr": "<1.1|>=2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/contracts",
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Contracts\\Service\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Test/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Generic abstractions related to writing services",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"abstractions",
|
||||
"contracts",
|
||||
"decoupling",
|
||||
"interfaces",
|
||||
"interoperability",
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T11:30:57+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.3"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
538
tmp/openapi.json
Normal file
538
tmp/openapi.json
Normal file
@@ -0,0 +1,538 @@
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "WooCommerce Licensed Product API",
|
||||
"description": "REST API for validating and managing software licenses bound to domains. This API allows external applications to validate license keys, check license status, and activate licenses on specific domains.",
|
||||
"version": "0.0.7",
|
||||
"contact": {
|
||||
"name": "Marco Graetsch",
|
||||
"url": "https://src.bundespruefstelle.ch/magdev",
|
||||
"email": "magdev3.0@gmail.com"
|
||||
},
|
||||
"license": {
|
||||
"name": "GPL-2.0-or-later",
|
||||
"url": "https://www.gnu.org/licenses/gpl-2.0.html"
|
||||
}
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "{baseUrl}/wp-json/wc-licensed-product/v1",
|
||||
"description": "WordPress REST API endpoint",
|
||||
"variables": {
|
||||
"baseUrl": {
|
||||
"default": "https://example.com",
|
||||
"description": "The base URL of your WordPress installation"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/validate": {
|
||||
"post": {
|
||||
"operationId": "validateLicense",
|
||||
"summary": "Validate a license key for a domain",
|
||||
"description": "Validates whether a license key is valid for a specific domain. Checks license status, expiration, and domain binding. This is the primary endpoint for software to verify license validity.",
|
||||
"tags": ["License Validation"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateRequest"
|
||||
},
|
||||
"example": {
|
||||
"license_key": "ABCD-1234-EFGH-5678",
|
||||
"domain": "example.com"
|
||||
}
|
||||
},
|
||||
"application/x-www-form-urlencoded": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "License is valid for the specified domain",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSuccessResponse"
|
||||
},
|
||||
"example": {
|
||||
"valid": true,
|
||||
"license": {
|
||||
"product_id": 123,
|
||||
"expires_at": "2027-01-21",
|
||||
"version_id": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "License validation failed",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateErrorResponse"
|
||||
},
|
||||
"examples": {
|
||||
"license_not_found": {
|
||||
"summary": "License key not found",
|
||||
"value": {
|
||||
"valid": false,
|
||||
"error": "license_not_found",
|
||||
"message": "License key not found."
|
||||
}
|
||||
},
|
||||
"license_revoked": {
|
||||
"summary": "License has been revoked",
|
||||
"value": {
|
||||
"valid": false,
|
||||
"error": "license_revoked",
|
||||
"message": "This license has been revoked."
|
||||
}
|
||||
},
|
||||
"license_expired": {
|
||||
"summary": "License has expired",
|
||||
"value": {
|
||||
"valid": false,
|
||||
"error": "license_expired",
|
||||
"message": "This license has expired."
|
||||
}
|
||||
},
|
||||
"license_inactive": {
|
||||
"summary": "License is inactive",
|
||||
"value": {
|
||||
"valid": false,
|
||||
"error": "license_inactive",
|
||||
"message": "This license is inactive."
|
||||
}
|
||||
},
|
||||
"domain_mismatch": {
|
||||
"summary": "License not valid for this domain",
|
||||
"value": {
|
||||
"valid": false,
|
||||
"error": "domain_mismatch",
|
||||
"message": "This license is not valid for this domain."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/RateLimitExceeded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/status": {
|
||||
"post": {
|
||||
"operationId": "checkStatus",
|
||||
"summary": "Get license status information",
|
||||
"description": "Retrieves detailed status information for a license key, including validity, domain binding, expiration date, and activation counts.",
|
||||
"tags": ["License Status"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/StatusRequest"
|
||||
},
|
||||
"example": {
|
||||
"license_key": "ABCD-1234-EFGH-5678"
|
||||
}
|
||||
},
|
||||
"application/x-www-form-urlencoded": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/StatusRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "License status retrieved successfully",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/StatusResponse"
|
||||
},
|
||||
"example": {
|
||||
"valid": true,
|
||||
"status": "active",
|
||||
"domain": "example.com",
|
||||
"expires_at": "2027-01-21",
|
||||
"activations_count": 1,
|
||||
"max_activations": 3
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "License key not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
},
|
||||
"example": {
|
||||
"valid": false,
|
||||
"error": "license_not_found",
|
||||
"message": "License key not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/RateLimitExceeded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/activate": {
|
||||
"post": {
|
||||
"operationId": "activateLicense",
|
||||
"summary": "Activate a license on a domain",
|
||||
"description": "Activates a license key on a specific domain. If the license is already activated on the same domain, returns success. If activating on a new domain, the old domain binding is replaced (single-domain licenses).",
|
||||
"tags": ["License Activation"],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ActivateRequest"
|
||||
},
|
||||
"example": {
|
||||
"license_key": "ABCD-1234-EFGH-5678",
|
||||
"domain": "newdomain.com"
|
||||
}
|
||||
},
|
||||
"application/x-www-form-urlencoded": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ActivateRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "License activated successfully or already activated",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ActivateSuccessResponse"
|
||||
},
|
||||
"examples": {
|
||||
"activated": {
|
||||
"summary": "License activated on new domain",
|
||||
"value": {
|
||||
"success": true,
|
||||
"message": "License activated successfully."
|
||||
}
|
||||
},
|
||||
"already_activated": {
|
||||
"summary": "License already activated on this domain",
|
||||
"value": {
|
||||
"success": true,
|
||||
"message": "License is already activated for this domain."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "Activation failed due to license restrictions",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
},
|
||||
"examples": {
|
||||
"license_invalid": {
|
||||
"summary": "License is not valid",
|
||||
"value": {
|
||||
"success": false,
|
||||
"error": "license_invalid",
|
||||
"message": "This license is not valid."
|
||||
}
|
||||
},
|
||||
"max_activations_reached": {
|
||||
"summary": "Maximum activations reached",
|
||||
"value": {
|
||||
"success": false,
|
||||
"error": "max_activations_reached",
|
||||
"message": "Maximum number of activations reached."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "License key not found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
},
|
||||
"example": {
|
||||
"success": false,
|
||||
"error": "license_not_found",
|
||||
"message": "License key not found."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"429": {
|
||||
"$ref": "#/components/responses/RateLimitExceeded"
|
||||
},
|
||||
"500": {
|
||||
"description": "Server error during activation",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
},
|
||||
"example": {
|
||||
"success": false,
|
||||
"error": "activation_failed",
|
||||
"message": "Failed to activate license."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ValidateRequest": {
|
||||
"type": "object",
|
||||
"required": ["license_key", "domain"],
|
||||
"properties": {
|
||||
"license_key": {
|
||||
"type": "string",
|
||||
"description": "The license key to validate (format: XXXX-XXXX-XXXX-XXXX)",
|
||||
"maxLength": 64,
|
||||
"example": "ABCD-1234-EFGH-5678"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string",
|
||||
"description": "The domain to validate the license against",
|
||||
"maxLength": 255,
|
||||
"example": "example.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidateSuccessResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"valid": {
|
||||
"type": "boolean",
|
||||
"const": true,
|
||||
"description": "Indicates the license is valid"
|
||||
},
|
||||
"license": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"product_id": {
|
||||
"type": "integer",
|
||||
"description": "WooCommerce product ID associated with the license"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": ["string", "null"],
|
||||
"format": "date",
|
||||
"description": "Expiration date (null for lifetime licenses)"
|
||||
},
|
||||
"version_id": {
|
||||
"type": ["integer", "null"],
|
||||
"description": "Product version ID if license is bound to a version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidateErrorResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"valid": {
|
||||
"type": "boolean",
|
||||
"const": false,
|
||||
"description": "Indicates validation failed"
|
||||
},
|
||||
"error": {
|
||||
"type": "string",
|
||||
"enum": ["license_not_found", "license_revoked", "license_expired", "license_inactive", "domain_mismatch"],
|
||||
"description": "Error code for programmatic handling"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable error message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StatusRequest": {
|
||||
"type": "object",
|
||||
"required": ["license_key"],
|
||||
"properties": {
|
||||
"license_key": {
|
||||
"type": "string",
|
||||
"description": "The license key to check",
|
||||
"example": "ABCD-1234-EFGH-5678"
|
||||
}
|
||||
}
|
||||
},
|
||||
"StatusResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"valid": {
|
||||
"type": "boolean",
|
||||
"description": "Whether the license is currently valid"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["active", "inactive", "expired", "revoked"],
|
||||
"description": "Current license status"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string",
|
||||
"description": "Domain the license is bound to"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": ["string", "null"],
|
||||
"format": "date",
|
||||
"description": "Expiration date (null for lifetime licenses)"
|
||||
},
|
||||
"activations_count": {
|
||||
"type": "integer",
|
||||
"description": "Current number of activations"
|
||||
},
|
||||
"max_activations": {
|
||||
"type": "integer",
|
||||
"description": "Maximum allowed activations"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ActivateRequest": {
|
||||
"type": "object",
|
||||
"required": ["license_key", "domain"],
|
||||
"properties": {
|
||||
"license_key": {
|
||||
"type": "string",
|
||||
"description": "The license key to activate",
|
||||
"example": "ABCD-1234-EFGH-5678"
|
||||
},
|
||||
"domain": {
|
||||
"type": "string",
|
||||
"description": "The domain to activate the license on",
|
||||
"example": "newdomain.com"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ActivateSuccessResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"const": true,
|
||||
"description": "Indicates activation was successful"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable success message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ErrorResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"const": false,
|
||||
"description": "Indicates the operation failed"
|
||||
},
|
||||
"valid": {
|
||||
"type": "boolean",
|
||||
"const": false,
|
||||
"description": "Indicates validation failed (for validation endpoints)"
|
||||
},
|
||||
"error": {
|
||||
"type": "string",
|
||||
"description": "Error code for programmatic handling"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"description": "Human-readable error message"
|
||||
}
|
||||
}
|
||||
},
|
||||
"RateLimitResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"const": false
|
||||
},
|
||||
"error": {
|
||||
"type": "string",
|
||||
"const": "rate_limit_exceeded"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"example": "Too many requests. Please try again later."
|
||||
},
|
||||
"retry_after": {
|
||||
"type": "integer",
|
||||
"description": "Seconds until rate limit resets"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"RateLimitExceeded": {
|
||||
"description": "Rate limit exceeded (30 requests per minute per IP)",
|
||||
"headers": {
|
||||
"Retry-After": {
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
},
|
||||
"description": "Seconds until the rate limit resets"
|
||||
}
|
||||
},
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/RateLimitResponse"
|
||||
},
|
||||
"example": {
|
||||
"success": false,
|
||||
"error": "rate_limit_exceeded",
|
||||
"message": "Too many requests. Please try again later.",
|
||||
"retry_after": 45
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
{
|
||||
"name": "License Validation",
|
||||
"description": "Validate license keys against domains"
|
||||
},
|
||||
{
|
||||
"name": "License Status",
|
||||
"description": "Check license status and details"
|
||||
},
|
||||
{
|
||||
"name": "License Activation",
|
||||
"description": "Activate licenses on domains"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user