Lizenzierung einbauen
Kompakter Auftrag für neue Anwendungen – so bekommt eigene Software Lizenzen von Cyrellian. Zum Einfügen in den Prompt.
Diese Seite ist ein Auftrag zum Kopieren: Wer eine neue Anwendung baut (oder einen Coding-Agenten damit beauftragt), fügt sie komplett in den Prompt ein. Sie fasst zusammen, was die Software tun muss, um Lizenzen von Cyrellian zu bekommen und zu prüfen. Die Details stehen in der Lizenzschlüssel-API und der Lizenz-API.
1. Art wählen
| Art (Konsole) | Wann | Wie kommt die Lizenz in die Software? |
|---|---|---|
| Nur Lizenz (Standard) | Desktop-Apps, CLIs, Plugins, selbst gehostete Werkzeuge ohne Kundenkonto | Kunde tippt einen Lizenzschlüssel ein, die Software aktiviert ihn auf dem Gerät |
| Plattform | Selbst gehostete Produkte mit Konto-Verknüpfung, Tarifen, Updates und Add-ons (wie Plazello, Docsello) | Installation wird im Browser mit einem Cyrellian-Konto verknüpft |
Im Zweifel: Nur Lizenz. Der Rest dieser Seite beschreibt diese Art; Plattform-Anwendungen siehe Abschnitt 7.
2. Einrichtung in der Konsole (Operator)
- Konsole → Anwendungen → Neue Anwendung: ID (z. B.
mein-tool, 2–40 Zeichen, Kleinbuchstaben, Ziffern, Bindestriche), Name, Art Nur Lizenz, Features (JSON) – die Funktionen, die Tarife freischalten, mit ihrem Standardwert, z. B.{"pro": false, "maxProjects": 3, "export": ["pdf"]}(null= unbegrenzt). Optional: „Verwaltungscode zu jedem Schlüssel“. - Cyrellian legt dabei den Ed25519-Signaturschlüssel und einen Tarif
standardan. Weitere Tarife mit ihren Feature-Werten unter Tarife. - Die Übersichtsseite der Anwendung zeigt die Basis-URL und den öffentlichen Schlüssel – beides kommt fest in die Software.
- Lizenzschlüssel → Schlüssel ausstellen: Tarif, Anzahl Geräte (leer = unbegrenzt), Ablauf (leer = nie), Kunde.
3. Was die Software als Konfiguration bekommt
| Wert | Beispiel | Hinweis |
|---|---|---|
| Basis-URL | https://updates.cyrellian.com/mein-tool/license/v1 |
Dev: http://updates.localhost:3200/mein-tool/license/v1 |
| Öffentliche Schlüssel | ["MCowBQYDK2VwAyEA…"] |
Base64, SPKI DER. Liste, damit ein Schlüsselwechsel möglich ist. In den Build einbauen, nicht zur Laufzeit holen |
| Anwendungs-ID | mein-tool |
steht im Token als app |
Nie in die Software: private Schlüssel, Konsolen-Zugänge, Operator-Tokens. Die Software braucht nur die öffentlichen Daten oben.
4. Umsetzen – Checkliste
Client: Für JavaScript/TypeScript (Node 20+, Electron, Bun, Deno, Browser) die Datei
packages/license-client/src/index.ts aus dem Cyrellian-Repository ins Projekt kopieren (keine Abhängigkeiten,
Klasse LicenseClient). Andere Sprachen setzen Abschnitt 6 um.
- Geräte-ID (
machineId): stabil über Neustarts und Updates, 4–200 Zeichen ausA–Z a–z 0–9 . _ : -. Nicht roh den Rechnernamen nehmen, sondern einen Hash, z. B.sha256(<OS-Maschinen-ID> + ":" + <App-ID>)als Hex. Bei Server-Software: eine beim ersten Start erzeugte und gespeicherte UUID. - Token speichern: Datei im App-Datenordner, Schlüsselbund oder
localStorage(storage.get/storage.set). Gespeichert wird nur das Token, nicht der Lizenzschlüssel –validateunddeactivatefunktionieren mit dem Token. - Aktivieren: Eingabefeld für den Schlüssel (
XXXXX-XXXXX-XXXXX-XXXXX-XXXXX, Groß-/Kleinschreibung, Leerzeichen und Bindestriche egal) und optional ein Gerätename →activate(key, { name }). - Prüfen:
check()beim Start und etwa einmal am Tag (nicht öfter als stündlich). Es fragt den Server und fällt offline auf das gespeicherte Token zurück. - Freischalten: Funktionen ausschließlich aus
state.featuresableiten (Werte wie im Feature-Template der Konsole). Ohne gültige Lizenz gelten die Standardwerte des Templates bzw. der freie Umfang – nie ein lokales „ist Pro“-Flag, das ohne Token wahr sein kann. - Anzeigen: Tarif (
planName), Ablauf der Lizenz (licenseExpiresAt,null= unbefristet), „offline geprüft“ wennsource === "offline", und – falls vorhanden – einen Link „Lizenz verwalten“ aufmanageUrl. - Abmelden: Knopf „Lizenz von diesem Gerät entfernen“ →
deactivate()(gibt den Geräteplatz frei). Auch beim Deinstallieren, wenn möglich. - Fehler übersetzen (Tabelle unten) – nie den rohen Code anzeigen.
import { LicenseClient, LicenseError } from "./license-client";
const license = new LicenseClient({
baseUrl: LICENSE_API_URL,
publicKeys: LICENSE_PUBLIC_KEYS,
machineId: await machineId(),
storage: { get: () => readTokenFile(), set: (t) => writeTokenFile(t) },
version: APP_VERSION,
});
// Start und täglich
const state = await license.check();
const pro = state.valid && state.features.pro === true;
// Aktivieren aus dem Dialog
try {
await license.activate(input, { name: os.hostname() });
} catch (e) {
if (e instanceof LicenseError) showError(e.code);
}5. Verhalten, das stimmen muss
| Situation | Verhalten |
|---|---|
Server sagt invalid_key, expired, suspended, revoked, not_activated |
Token löschen, Lizenz ist auf diesem Gerät weg (macht check() selbst) |
Kein Netz, Timeout, rate_limited, 5xx |
Gespeichertes Token entscheidet – kein Fehlerdialog |
| Token abgelaufen (7 Tage ohne erfolgreiche Prüfung) | Freier Umfang, Hinweis „Bitte online gehen, um die Lizenz zu prüfen“. Nie Daten löschen oder sperren |
Lizenz endet (licenseExpiresAt) |
Token läuft spätestens dann ab; vorher (z. B. 14 Tage) auf Verlängerung hinweisen |
Fehlertexte für die Oberfläche:
| Code | Meldung (Sinn) |
|---|---|
invalid_request |
Der Schlüssel hat nicht das richtige Format. |
invalid_key |
Diesen Schlüssel gibt es nicht. |
expired / suspended / revoked |
Die Lizenz ist abgelaufen / gesperrt / widerrufen. |
limit_reached |
Der Schlüssel ist schon auf allen erlaubten Geräten aktiv – erst ein Gerät abmelden. |
not_activated |
Dieses Gerät ist für den Schlüssel nicht mehr aktiviert – bitte neu aktivieren. |
rate_limited |
Zu viele Versuche – bitte kurz warten. |
network |
Keine Verbindung zum Lizenzserver. |
not_configured, not_found |
Fehler auf unserer Seite (falsche Basis-URL oder Anwendung nicht eingerichtet). |
Limits des Servers: 120 Anfragen pro Minute und IP, höchstens 20 unbekannte Schlüssel pro IP in 10 Minuten.
6. Ohne Client-Paket (andere Sprachen)
Alle Aufrufe sind JSON, ohne Cookies, CORS ist offen:
| Aufruf | Body | Antwort |
|---|---|---|
POST <basis>/activate |
{key, machineId, name?, version?} |
{status: "active", token, license} |
POST <basis>/validate |
{token, machineId, version?} (oder key statt token) |
{status: "active", token, license} – immer das neue Token speichern |
POST <basis>/deactivate |
{token, machineId} |
{ok: true} |
GET <basis>/public-key |
– | {algorithm: "Ed25519", keys: [{publicKey, active}]} |
Fehler: HTTP 4xx/5xx mit {error: "<code>"}. license = {plan, planName, features, expiresAt, tokenExpiresAt, maxActivations, manageUrl?}.
Token offline prüfen – das Token ist <inhalt>.<signatur>, beides base64url:
- Am ersten
.trennen. - Signatur (base64url → 64 Bytes) mit Ed25519 über die ASCII-Bytes des Inhalt-Teils (nicht über das dekodierte JSON) prüfen – gegen jeden der öffentlichen Schlüssel, einer muss passen. Der öffentliche Schlüssel ist Base64 SPKI DER; der rohe 32-Byte-Schlüssel sind die letzten 32 Bytes.
- Inhalt dekodieren (base64url → JSON) und prüfen:
typ === "license_key",status === "active",sub === machineId,app === <App-ID>,exp(Unix-Sekunden) in der Zukunft. features,plan,planName,licenseExpiresAtverwenden.
7. Plattform-Anwendungen
Für Anwendungen der Art Plattform gibt es keine Lizenzschlüssel; die Installation wird mit einem Konto verknüpft (Details: Lizenz-API, Updates: Update-API).
- Beim ersten Start eine
instanceId(UUID) erzeugen und speichern. - „Mit Konto verknüpfen“: 32 zufällige Bytes als
secreterzeugen (nur lokal), dannPOST https://account.cyrellian.com/<app>/api/license/link/startmit{instanceId, name, url, version, secretHash: sha256hex(secret)}→{code, approveUrl, expiresAt}. codeundapproveUrlanzeigen; der Besitzer meldet sich dort an und wählt einen Tarif. Code gilt 30 Minuten.- Alle paar Sekunden
POST …/api/license/link/pollmit{instanceId, code, secret}bisstatusapproved(dannlicensespeichern),expiredoderunknown. - Täglich
POST …/api/license/refreshmitAuthorization: Bearer <lizenz>und{version}– neues Token speichern;{status: "unlinked"}→ Lizenz löschen, freier Umfang. - Token offline prüfen wie in Abschnitt 6, aber
sub === instanceId, ohnetyp/app. Gültig 30 Tage, danach 14 Tage Kulanz mit Hinweis, dann freier Umfang. Die öffentlichen Schlüssel liefertGET https://updates.cyrellian.com/<app>/license/v1/public-key(beim Verknüpfen holen und speichern). - „Trennen“:
POST …/api/license/unlinkmit Bearer-Token, dann Lizenz lokal löschen. - Updates:
GET https://updates.cyrellian.com/<app>/v1/check?channel=stable&version=<v>&instance=<instanceId>mit Bearer-Token; vor dem Installieren SHA-256 und Signatur prüfen.
8. Fertig, wenn …
- ein in der lokalen Konsole ausgestellter Testschlüssel aktiviert, die Pro-Funktion freigeschaltet und nach
deactivatewieder gesperrt ist, - die Software ohne Netz mit gespeichertem Token weiterläuft und nach Ablauf des Tokens auf den freien Umfang fällt,
- ein in der Konsole gesperrter Schlüssel beim nächsten
check()die Freischaltung entfernt, - ein Token mit verändertem Inhalt oder fremder
machineIdabgelehnt wird, limit_reachedundinvalid_keyverständliche Meldungen zeigen.