10 KiB
Siti Plugin Repo
Deze repository bevat een Vite/React frontend en een Express backend die samen een centrale licentie- en pluginbeheeromgeving vormen. Je beheert hier WordPress-plugins, gekoppelde licenties en gebruikers (inclusief admin-rollen), en biedt een HTTP API waar je eigen plugins tegenaan kunnen praten voor licentievalidatie en update-informatie.
Inhoud
- Architectuuroverzicht
- Installatie & configuratie
- Gebruikers & rollen
- API-overzicht
- Integratie met je WordPress-plugin
- Handige tips
Architectuuroverzicht
| Component | Omschrijving |
|---|---|
server/ |
Express-app die licenties, gebruikers en plugin metadata serveert. Praat met MariaDB en Git providers. |
src/ |
React frontend voor licentiebeheer, inclusief admin flows en in-app authenticatie. |
| MariaDB | Externe database met tabellen users, licenses, license_hostnames. Licentiegegevens staan niet meer in JSON-bestanden. |
| Git providers | Manifest-/release-/commitdata wordt opgehaald bij GitHub of Gitea, afhankelijk van entries in server/repos.json. |
Belangrijke eigenschappen:
- Vanaf de eerste run wordt het schema automatisch gecreëerd in MariaDB.
- De allereerste gebruiker die zich registreert wordt automatisch admin.
- Admins kunnen gebruikers aanmaken en licenties namens andere gebruikers genereren.
- Een licentie hoort bij de eerste hostname die zich meldt; elke volgende hostname wordt geweigerd.
Installatie & configuratie
Vereisten
- Node.js 18+
- MariaDB 10.6+ (extern of lokaal)
- Optioneel Docker (voor containerized deployment)
Stap 1 – .env
Gebruik .env.example als startpunt en zet hem om naar .env:
cp .env.example .env
Stel daarna minimaal de volgende variabelen in:
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=sitiapp
DB_PASSWORD=supergeheim
DB_NAME=siti_plugin_repo
JWT_SECRET=een-lang-en-random-geheim
JWT_EXPIRES_IN=7d
Let op: geef de backend toegang tot een bestaande database. Het schema wordt automatisch ingericht, maar de database zelf moet bestaan.
Stap 2 – Dependencies installeren
npm install
Stap 3 – Ontwikkelservers starten
# Backend API + licentiebeheer UI
npm run dev:server
# Frontend (Vite dev server)
npm run dev
Vite proxy’t /api/* naar localhost:3001, dus beide processen moeten draaien.
Docker Compose
Wil je alles containerizen, gebruik dan docker-compose.yml. De Compose configuratie bevat alleen de applicatiecontainer; MariaDB blijft een externe service. Voorbeeld:
DB_HOST=database.internal
DB_PORT=3306
DB_USER=sitiapp
DB_PASSWORD=my-secret
DB_NAME=siti_plugin_repo
JWT_SECRET=prod-secret
docker compose up --build
Gebruikers & rollen
- Eerste gebruiker → admin (
is_admin = 1). - Admins kunnen:
- Overzicht van alle gebruikers downloaden (
GET /api/admin/users). - Nieuwe gebruikers aanmaken (
POST /api/admin/users). - Licenties koppelen aan andere gebruikers door
userIdmee te geven aanPOST /api/licenses.
- Overzicht van alle gebruikers downloaden (
- Niet-admins:
- Kunnen alleen hun eigen licenties zien en aanmaken.
- Kunnen geen andere gebruikers zien of licenties voor anderen beheren.
Authenticatie:
- JWT’s worden uitgegeven door
/api/auth/loginof/api/auth/register. - Het frontend bewaart de token in
localStorageen stuurtAuthorization: Bearer …. requireAdminmiddleware blokkeert niet-admin gebruikers automatisch voor admin-routes.
API-overzicht
| Methode & pad | Rol | Beschrijving |
|---|---|---|
POST /api/auth/register |
Publiek | Maakt gebruiker aan (eerste gebruiker wordt admin). |
POST /api/auth/login |
Publiek | Verstrekt JWT. |
GET /api/auth/me |
Auth | Retourneert huidige gebruiker. |
GET /api/admin/users |
Admin | Geeft lijst met alle gebruikers. |
POST /api/admin/users |
Admin | Maakt gebruiker aan (met optionele admin-flag). |
GET /api/plugins |
Publiek | Lijst met plugins uit server/repos.json. |
GET /api/plugins/:owner/:repo |
Publiek | Details van één plugin. |
GET /api/licenses |
Auth | Licenties van ingelogde gebruiker. Admins kunnen ?userId=… meegeven. |
POST /api/licenses |
Auth | Licentie aanmaken. Admins: userId om een andere eigenaar te kiezen. |
POST /api/licenses/verify |
Publiek | Valideert licentiekey + hostname en geeft huidige versie terug. |
POST /api/licenses/download |
Publiek (met geldige licentie) | Verifieert licentie + hostname en streamt een ZIP (versie of latest). |
POST /api/licenses/verify is het belangrijkste eindpunt voor WordPress-plugins. Request body:
{
"key": "SITI-XXXX-XXXX",
"hostname": "example.com"
}
Response (succes):
{
"valid": true,
"hostname": "example.com",
"boundNow": false,
"license": {
"pluginName": "Mijn Plugin",
"pluginVersion": "1.2.3",
"primaryHostname": "example.com",
"key": "SITI-XXXX-XXXX",
"hostnames": [
{ "hostname": "example.com", "hits": 12, "lastSeenAt": "2026-02-01T11:22:33.000Z" }
]
}
}
Als de hostname nog niet eerder gekoppeld was, wordt boundNow: true. Als een andere site al gekoppeld is, krijg je HTTP 403 met de melding Licentie hoort bij ….
Integratie met je WordPress-plugin
1. Bewaar licentie en API-basis-URL
Maak in je plugin een settingspagina waar de klant:
- De licentiecode invult (bijv.
SITI-ABCD-1234). - De URL van je licentie-API configureert (
https://repo.jouwdomein.nl).
Sla dit op in wp_options, bijvoorbeeld:
update_option( 'siti_license_key', sanitize_text_field( $_POST['siti_license_key'] ) );
update_option( 'siti_license_api', esc_url_raw( $_POST['siti_license_api'] ) );
2. License check helper
function siti_verify_license() {
$license = get_option( 'siti_license_key' );
$api = untrailingslashit( get_option( 'siti_license_api' ) );
if ( empty( $license ) || empty( $api ) ) {
return new WP_Error( 'missing', 'Geen licentie ingesteld.' );
}
$hostname = parse_url( home_url(), PHP_URL_HOST );
$response = wp_remote_post( "{$api}/api/licenses/verify", array(
'headers' => array( 'Content-Type' => 'application/json' ),
'body' => wp_json_encode( array(
'key' => $license,
'hostname' => $hostname,
) ),
'timeout' => 15,
) );
if ( is_wp_error( $response ) ) {
return $response;
}
$code = wp_remote_retrieve_response_code( $response );
$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( 200 !== $code || empty( $body['valid'] ) ) {
return new WP_Error( 'invalid', $body['error'] ?? 'Licentie ongeldig.' );
}
update_option( 'siti_license_last_check', current_time( 'mysql' ) );
update_option( 'siti_license_version', $body['license']['pluginVersion'] ?? null );
return $body['license'];
}
Gebruik deze helper in:
admin_init(om bij het openen van de plugin-instellingen te valideren).- Een WP-Cron job (bijv. dagelijks) om de licentie actief te houden.
3. Updates / downloads doorgeven aan WordPress
Omdat je backend bij verify de pluginVersion retourneert, kun je dat gebruiken om WP te vertellen dat er een update is. Een simpele aanpak:
add_filter( 'pre_set_site_transient_update_plugins', function ( $transient ) {
$license = siti_verify_license();
if ( is_wp_error( $license ) ) {
return $transient;
}
$current_version = '1.2.0'; // huidige pluginversie
$remote_version = $license['pluginVersion'];
if ( version_compare( $remote_version, $current_version, '>' ) ) {
$transient->response['jouw-plugin/jouw-plugin.php'] = (object) array(
'slug' => 'jouw-plugin',
'new_version' => $remote_version,
'package' => 'https://jouw-download-url/zip', // eigen distributie
'tested' => get_bloginfo( 'version' ),
'url' => 'https://jouwwebsite.nl/plugin',
);
}
return $transient;
});
De API levert geen ZIP-bestand; je blijft zelf verantwoordelijk voor het aanbieden van downloads (bijv. via GitHub releases of Gitea). Gebruik
packagehierboven om naar de daadwerkelijke download te verwijzen.
Download endpoint gebruiken
Wanneer je liever via jouw eigen endpoint distribueert, roep dan POST /api/licenses/download aan vanaf je plugin of update-server. Body:
{
"key": "SITI-XXXX-XXXX",
"hostname": "example.com",
"version": "v1.2.3" // of "latest"
}
Bij succes streamt de API direct een ZIP-bestand. Tip:
- Laat WordPress jouw eigen mini-proxy aanspreken (omdat WP_UPgrader meestal een URL verwacht). Je proxy kan de POST doen, headers controleren en de stream doorgeven.
- Of gebruik
download_url()in WordPress metwp_remote_posten sla de response body tijdelijk op in upload-dir. - Versie
latestpakt de nieuwste release (via GitHub/Gitea). Specifieke tags vallen terug oprefs/tags/{tag}. Als een tag ontbreekt, wordt de branch/commitnaam gebruikt.
4. Fouten tonen
Laat admins weten wanneer een licentie ongeldig is:
add_action( 'admin_notices', function () {
$license = siti_verify_license();
if ( is_wp_error( $license ) ) {
printf(
'<div class="notice notice-error"><p>%s</p></div>',
esc_html( $license->get_error_message() )
);
}
} );
Handige tips
- Houd
server/repos.jsonup-to-date met alle Git repositories waarvan je manifest wilt tonen. - Wanneer je licenties migreert vanuit
server/licenses.json, schrijf een kleine scriptje dat records in de nieuwe MariaDB-tabellen importeert. - Gebruik HTTPS op productie; licentiekeys en hostnames gaan over het netwerk.
- Voor staging of development kun je
JWT_SECRETkort houden, maar in productie moet het lang en random zijn. - Log server-output (
server.log) in een centralized logging stack om snel te zien wanneer licenties worden geweigerd.
Veel succes met het integreren! Mocht je verdere automatisering willen (bijvoorbeeld automatische updateserver voor ZIP’s), breid dit project dan uit met een downloadendpoint dat controleert of een licentie geldig is voordat hij een ZIP serveert.