@richhtmleditor/enterprise 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -0
- package/dist/browser.d.ts +4 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +4 -0
- package/dist/browser.js.map +1 -0
- package/dist/gate-shared.d.ts +27 -0
- package/dist/gate-shared.d.ts.map +1 -0
- package/dist/gate-shared.js +47 -0
- package/dist/gate-shared.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/online.d.ts +22 -0
- package/dist/online.d.ts.map +1 -0
- package/dist/online.js +57 -0
- package/dist/online.js.map +1 -0
- package/dist/predefined-licenses.json +21 -0
- package/dist/token.d.ts +21 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +56 -0
- package/dist/token.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @richhtmleditor/enterprise
|
|
2
|
+
|
|
3
|
+
Licence verification and feature gating for self-hosted Rich HTML Editor deployments. Resolves signed `DE1.*` tokens and predefined demo keys into [`@richhtmleditor/core`](https://www.npmjs.com/package/@richhtmleditor/core) `EditorFeatureFlags` for AI, comments, workflows, and the full toolbar preset.
|
|
4
|
+
|
|
5
|
+
**Current release: 1.0.0** — Depends on `@richhtmleditor/core` **^1.0.0**.
|
|
6
|
+
|
|
7
|
+
**Repository:** [github.com/rajkishorsahu89/richhtmleditor](https://github.com/rajkishorsahu89/richhtmleditor)
|
|
8
|
+
|
|
9
|
+
**Demo:** [richhtmleditor.vercel.app](https://richhtmleditor.vercel.app/) — [demo](https://richhtmleditor.vercel.app/demo) · [guide](https://richhtmleditor.vercel.app/guide) · [API](https://richhtmleditor.vercel.app/api). Doc Preview joint demo: [doc-preview-app.vercel.app/demo/enterprise](https://doc-preview-app.vercel.app/demo/enterprise)
|
|
10
|
+
|
|
11
|
+
### What's in 1.0.0
|
|
12
|
+
|
|
13
|
+
- **`resolveEnterpriseFeatures`** — verify signed tokens or predefined demo keys; returns `EditorFeatureFlags`
|
|
14
|
+
- **Predefined demo keys** — `RHE-ENT-DEMO-2026-FULL`, `RHE-ENT-DEMO-2026-COMMENTS` (see `predefined-licenses.json`)
|
|
15
|
+
- **Signed tokens** — `DE1.<base64url(payload)>.<hmac-sha256>` minted with `createEnterpriseLicenceToken`
|
|
16
|
+
- **`@richhtmleditor/enterprise/browser`** — browser-safe entry (predefined keys only, no `process.env`)
|
|
17
|
+
- **Online verification** — `resolveEnterpriseFeaturesOnline` for remote licence checks
|
|
18
|
+
|
|
19
|
+
> Use the main export on your server (Node) with `DE_LICENCE_SECRET`. Use `/browser` in client bundles for demo keys only.
|
|
20
|
+
|
|
21
|
+
**Keywords:** `richhtmleditor` `enterprise` `licence` `feature-flags` `licensing`
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @richhtmleditor/enterprise
|
|
27
|
+
# Requires @richhtmleditor/core (pulled in by framework wrappers).
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage — server-side verification
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createEditor } from "@richhtmleditor/core";
|
|
34
|
+
import { resolveEnterpriseFeatures } from "@richhtmleditor/enterprise";
|
|
35
|
+
|
|
36
|
+
const gate = resolveEnterpriseFeatures(
|
|
37
|
+
{ token: process.env.DE_LICENCE! },
|
|
38
|
+
{ secret: process.env.DE_LICENCE_SECRET! }
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const editor = createEditor({
|
|
42
|
+
element: host,
|
|
43
|
+
features: gate.features,
|
|
44
|
+
toolbar: gate.features.toolbarFull ? { preset: "full" } : { preset: "standard" }
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage — browser (demo keys)
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { resolveEnterpriseFeatures } from "@richhtmleditor/enterprise/browser";
|
|
52
|
+
|
|
53
|
+
const gate = resolveEnterpriseFeatures({ token: "RHE-ENT-DEMO-2026-FULL" });
|
|
54
|
+
// gate.valid === true
|
|
55
|
+
// gate.features — { ai: true, comments: true, workflows: true, toolbarFull: true, … }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Usage — mint signed tokens
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { createEnterpriseLicenceToken } from "@richhtmleditor/enterprise";
|
|
62
|
+
|
|
63
|
+
const token = createEnterpriseLicenceToken(
|
|
64
|
+
{
|
|
65
|
+
sub: "acme-corp",
|
|
66
|
+
exp: Math.floor(Date.now() / 1000) + 86400,
|
|
67
|
+
features: { ai: true, comments: true, workflows: true, toolbarFull: true }
|
|
68
|
+
},
|
|
69
|
+
process.env.DE_LICENCE_SECRET!
|
|
70
|
+
);
|
|
71
|
+
// Returns "DE1.<payload>.<signature>"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Set `DE_LICENCE_SECRET` in your deployment environment. Payload `exp` is a Unix timestamp (seconds).
|
|
75
|
+
|
|
76
|
+
## Token formats
|
|
77
|
+
|
|
78
|
+
| Format | Example | Where verified |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| Predefined demo key | `RHE-ENT-DEMO-2026-FULL` | Server or `/browser` |
|
|
81
|
+
| Signed token | `DE1.eyJ…}.a1b2c3…` | Server with `DE_LICENCE_SECRET` |
|
|
82
|
+
|
|
83
|
+
### Demo keys (documentation only)
|
|
84
|
+
|
|
85
|
+
| Key | Features |
|
|
86
|
+
| --- | --- |
|
|
87
|
+
| `RHE-ENT-DEMO-2026-FULL` | AI, comments, workflows, `toolbarFull` |
|
|
88
|
+
| `RHE-ENT-DEMO-2026-COMMENTS` | Comments only |
|
|
89
|
+
|
|
90
|
+
## API
|
|
91
|
+
|
|
92
|
+
| Export | Description |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| `resolveEnterpriseFeatures(licence?, options?)` | Verify token; merge into `EditorFeatureFlags`. |
|
|
95
|
+
| `createEnterpriseLicenceToken(payload, secret)` | Mint a signed `DE1.*` token (server-side). |
|
|
96
|
+
| `verifySignedLicenceToken(token, secret, now?)` | Low-level token verification. |
|
|
97
|
+
| `DEFAULT_ENTERPRISE_FEATURES` | Base flags when no licence is valid. |
|
|
98
|
+
| `PREDEFINED_ENTERPRISE_LICENSES` | Built-in demo key catalogue. |
|
|
99
|
+
| `mergeEnterpriseFeatures(base, overrides?)` | Merge partial feature overrides. |
|
|
100
|
+
| `resolveEnterpriseFeaturesOnline(options)` | Remote licence verification. |
|
|
101
|
+
|
|
102
|
+
### `EnterpriseGateResult`
|
|
103
|
+
|
|
104
|
+
| Field | Type | Description |
|
|
105
|
+
| --- | --- | --- |
|
|
106
|
+
| `valid` | `boolean` | Whether the licence was accepted. |
|
|
107
|
+
| `features` | `EditorFeatureFlags` | Resolved feature flags for `createEditor`. |
|
|
108
|
+
| `message` | `string?` | Human-readable status. |
|
|
109
|
+
| `subject` | `string?` | Licence subject / owner. |
|
|
110
|
+
|
|
111
|
+
### Default feature flags
|
|
112
|
+
|
|
113
|
+
| Flag | Default (no licence) |
|
|
114
|
+
| --- | --- |
|
|
115
|
+
| `tables` | `true` |
|
|
116
|
+
| `media` | `true` |
|
|
117
|
+
| `collapsible` | `true` |
|
|
118
|
+
| `comments` | `false` |
|
|
119
|
+
| `ai` | `false` |
|
|
120
|
+
| `workflows` | `false` |
|
|
121
|
+
| `toolbarFull` | `false` |
|
|
122
|
+
|
|
123
|
+
## Related packages
|
|
124
|
+
|
|
125
|
+
- [`@richhtmleditor/core`](https://www.npmjs.com/package/@richhtmleditor/core) — consumes `EditorFeatureFlags`.
|
|
126
|
+
- [`@richhtmleditor/ai`](https://www.npmjs.com/package/@richhtmleditor/ai) — requires `features.ai`.
|
|
127
|
+
- [`@richhtmleditor/comments`](https://www.npmjs.com/package/@richhtmleditor/comments) — requires `features.comments`.
|
|
128
|
+
- [`@richhtmleditor/workflows`](https://www.npmjs.com/package/@richhtmleditor/workflows) — requires `features.workflows`.
|
|
129
|
+
- [`@richhtmleditor/angular`](https://www.npmjs.com/package/@richhtmleditor/angular) — Angular wrapper.
|
|
130
|
+
- [`@richhtmleditor/react`](https://www.npmjs.com/package/@richhtmleditor/react) — React wrapper.
|
|
131
|
+
|
|
132
|
+
## License
|
|
133
|
+
|
|
134
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DEFAULT_ENTERPRISE_FEATURES, PREDEFINED_ENTERPRISE_LICENSES, findPredefinedEnterpriseLicense, isPredefinedLicenseNotExpired, mergeEnterpriseFeatures, resolvePredefinedEnterpriseFeatures, type EnterpriseGateResult, type EnterpriseLicence, type PredefinedEnterpriseLicense } from "./gate-shared.js";
|
|
2
|
+
export { resolvePredefinedEnterpriseFeatures as resolveEnterpriseFeatures } from "./gate-shared.js";
|
|
3
|
+
export { resolveEnterpriseFeaturesOnline, type OnlineLicenceVerifyOptions, type OnlineLicenceVerifyResponse } from "./online.js";
|
|
4
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,+BAA+B,EAC/B,6BAA6B,EAC7B,uBAAuB,EACvB,mCAAmC,EACnC,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mCAAmC,IAAI,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAEpG,OAAO,EACL,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DEFAULT_ENTERPRISE_FEATURES, PREDEFINED_ENTERPRISE_LICENSES, findPredefinedEnterpriseLicense, isPredefinedLicenseNotExpired, mergeEnterpriseFeatures, resolvePredefinedEnterpriseFeatures } from "./gate-shared.js";
|
|
2
|
+
export { resolvePredefinedEnterpriseFeatures as resolveEnterpriseFeatures } from "./gate-shared.js";
|
|
3
|
+
export { resolveEnterpriseFeaturesOnline } from "./online.js";
|
|
4
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,+BAA+B,EAC/B,6BAA6B,EAC7B,uBAAuB,EACvB,mCAAmC,EAIpC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mCAAmC,IAAI,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAEpG,OAAO,EACL,+BAA+B,EAGhC,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { EditorFeatureFlags } from "@richhtmleditor/core";
|
|
2
|
+
export type EnterpriseLicence = {
|
|
3
|
+
/** Signed licence token (`DE1.<payload>.<sig>`) or predefined demo key. */
|
|
4
|
+
token: string;
|
|
5
|
+
/** Feature overrides applied when the licence is valid (unsigned preview only). */
|
|
6
|
+
features?: Partial<EditorFeatureFlags>;
|
|
7
|
+
};
|
|
8
|
+
export type EnterpriseGateResult = {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
features: EditorFeatureFlags;
|
|
11
|
+
message?: string;
|
|
12
|
+
subject?: string;
|
|
13
|
+
};
|
|
14
|
+
export type PredefinedEnterpriseLicense = {
|
|
15
|
+
key: string;
|
|
16
|
+
owner?: string;
|
|
17
|
+
expiresAt?: string;
|
|
18
|
+
features?: Partial<EditorFeatureFlags>;
|
|
19
|
+
};
|
|
20
|
+
export declare const DEFAULT_ENTERPRISE_FEATURES: EditorFeatureFlags;
|
|
21
|
+
export declare const PREDEFINED_ENTERPRISE_LICENSES: readonly PredefinedEnterpriseLicense[];
|
|
22
|
+
export declare function findPredefinedEnterpriseLicense(key: string): PredefinedEnterpriseLicense | null;
|
|
23
|
+
export declare function isPredefinedLicenseNotExpired(license: PredefinedEnterpriseLicense, now?: Date): boolean;
|
|
24
|
+
export declare function mergeEnterpriseFeatures(base: EditorFeatureFlags, overrides?: Partial<EditorFeatureFlags>): EditorFeatureFlags;
|
|
25
|
+
/** Resolve predefined demo keys only — safe for browser bundles. */
|
|
26
|
+
export declare function resolvePredefinedEnterpriseFeatures(licence?: EnterpriseLicence | null, now?: Date): EnterpriseGateResult;
|
|
27
|
+
//# sourceMappingURL=gate-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-shared.d.ts","sourceRoot":"","sources":["../src/gate-shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG/D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,mFAAmF;IACnF,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GAAG;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC,CAAC;AAEF,eAAO,MAAM,2BAA2B,EAAE,kBAQzC,CAAC;AAIF,eAAO,MAAM,8BAA8B,EAAE,SAAS,2BAA2B,EAAuB,CAAC;AAEzG,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,MAAM,GAAG,2BAA2B,GAAG,IAAI,CAG/F;AAED,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,2BAA2B,EAAE,GAAG,OAAa,GAAG,OAAO,CAM7G;AAED,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,kBAAkB,EACxB,SAAS,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACtC,kBAAkB,CAEpB;AAED,oEAAoE;AACpE,wBAAgB,mCAAmC,CACjD,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAClC,GAAG,OAAa,GACf,oBAAoB,CAoBtB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import predefinedLicensesJson from "./predefined-licenses.json" with { type: "json" };
|
|
2
|
+
export const DEFAULT_ENTERPRISE_FEATURES = {
|
|
3
|
+
tables: true,
|
|
4
|
+
media: true,
|
|
5
|
+
comments: false,
|
|
6
|
+
ai: false,
|
|
7
|
+
collapsible: true,
|
|
8
|
+
workflows: false,
|
|
9
|
+
toolbarFull: false
|
|
10
|
+
};
|
|
11
|
+
const predefinedLicenses = predefinedLicensesJson;
|
|
12
|
+
export const PREDEFINED_ENTERPRISE_LICENSES = predefinedLicenses;
|
|
13
|
+
export function findPredefinedEnterpriseLicense(key) {
|
|
14
|
+
const found = predefinedLicenses.find((entry) => entry.key === key.trim());
|
|
15
|
+
return found ? { ...found } : null;
|
|
16
|
+
}
|
|
17
|
+
export function isPredefinedLicenseNotExpired(license, now = new Date()) {
|
|
18
|
+
if (!license.expiresAt?.trim()) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const end = new Date(license.expiresAt);
|
|
22
|
+
return !Number.isNaN(end.getTime()) && now.getTime() <= end.getTime();
|
|
23
|
+
}
|
|
24
|
+
export function mergeEnterpriseFeatures(base, overrides) {
|
|
25
|
+
return { ...base, ...overrides };
|
|
26
|
+
}
|
|
27
|
+
/** Resolve predefined demo keys only — safe for browser bundles. */
|
|
28
|
+
export function resolvePredefinedEnterpriseFeatures(licence, now = new Date()) {
|
|
29
|
+
const token = licence?.token?.trim();
|
|
30
|
+
if (!token) {
|
|
31
|
+
return { valid: false, features: DEFAULT_ENTERPRISE_FEATURES, message: "No enterprise licence" };
|
|
32
|
+
}
|
|
33
|
+
const license = findPredefinedEnterpriseLicense(token);
|
|
34
|
+
if (!license) {
|
|
35
|
+
return { valid: false, features: DEFAULT_ENTERPRISE_FEATURES, message: "Licence secret not configured" };
|
|
36
|
+
}
|
|
37
|
+
if (!isPredefinedLicenseNotExpired(license, now)) {
|
|
38
|
+
return { valid: false, features: DEFAULT_ENTERPRISE_FEATURES, message: "Predefined licence expired" };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
valid: true,
|
|
42
|
+
features: mergeEnterpriseFeatures(DEFAULT_ENTERPRISE_FEATURES, { ...license.features, ...licence?.features }),
|
|
43
|
+
message: "Predefined enterprise licence accepted",
|
|
44
|
+
subject: license.owner ?? license.key
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=gate-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate-shared.js","sourceRoot":"","sources":["../src/gate-shared.ts"],"names":[],"mappings":"AACA,OAAO,sBAAsB,MAAM,4BAA4B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAuBtF,MAAM,CAAC,MAAM,2BAA2B,GAAuB;IAC7D,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,KAAK;IACf,EAAE,EAAE,KAAK;IACT,WAAW,EAAE,IAAI;IACjB,SAAS,EAAE,KAAK;IAChB,WAAW,EAAE,KAAK;CACnB,CAAC;AAEF,MAAM,kBAAkB,GAAG,sBAAuD,CAAC;AAEnF,MAAM,CAAC,MAAM,8BAA8B,GAA2C,kBAAkB,CAAC;AAEzG,MAAM,UAAU,+BAA+B,CAAC,GAAW;IACzD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,OAAoC,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;IAClG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,IAAwB,EACxB,SAAuC;IAEvC,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,EAAE,CAAC;AACnC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,mCAAmC,CACjD,OAAkC,EAClC,GAAG,GAAG,IAAI,IAAI,EAAE;IAEhB,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,2BAA2B,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnG,CAAC;IAED,MAAM,OAAO,GAAG,+BAA+B,CAAC,KAAK,CAAC,CAAC;IACvD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,2BAA2B,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;IAC3G,CAAC;IACD,IAAI,CAAC,6BAA6B,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,2BAA2B,EAAE,OAAO,EAAE,4BAA4B,EAAE,CAAC;IACxG,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,uBAAuB,CAAC,2BAA2B,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC;QAC7G,OAAO,EAAE,wCAAwC;QACjD,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG;KACtC,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type EnterpriseGateResult, type EnterpriseLicence, type PredefinedEnterpriseLicense } from "./gate-shared.js";
|
|
2
|
+
import { type LicencePayload } from "./token.js";
|
|
3
|
+
export type { EnterpriseLicence, EnterpriseGateResult, PredefinedEnterpriseLicense };
|
|
4
|
+
export type { LicencePayload };
|
|
5
|
+
export { signLicencePayload, verifySignedLicenceToken } from "./token.js";
|
|
6
|
+
export { DEFAULT_ENTERPRISE_FEATURES, PREDEFINED_ENTERPRISE_LICENSES, findPredefinedEnterpriseLicense, isPredefinedLicenseNotExpired, mergeEnterpriseFeatures } from "./gate-shared.js";
|
|
7
|
+
/**
|
|
8
|
+
* Verify a signed `DE1.*` token or predefined demo key.
|
|
9
|
+
* Pass `secret` from your server env (e.g. `DE_LICENCE_SECRET`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveEnterpriseFeatures(licence?: EnterpriseLicence | null, options?: {
|
|
12
|
+
secret?: string;
|
|
13
|
+
now?: Date;
|
|
14
|
+
}): EnterpriseGateResult;
|
|
15
|
+
/** Server-side helper to mint signed licence tokens. */
|
|
16
|
+
export declare function createEnterpriseLicenceToken(payload: LicencePayload, secret: string): string;
|
|
17
|
+
export { resolveEnterpriseFeaturesOnline, type OnlineLicenceVerifyOptions, type OnlineLicenceVerifyResponse } from "./online.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,KAAK,2BAA2B,EACjC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAgD,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/F,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,2BAA2B,EAAE,CAAC;AACrF,YAAY,EAAE,cAAc,EAAE,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,+BAA+B,EAC/B,6BAA6B,EAC7B,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAE1B;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAClC,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,IAAI,CAAA;CAAE,GACxC,oBAAoB,CA2BtB;AAED,wDAAwD;AACxD,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5F;AAED,OAAO,EACL,+BAA+B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EACjC,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { DEFAULT_ENTERPRISE_FEATURES, mergeEnterpriseFeatures, resolvePredefinedEnterpriseFeatures } from "./gate-shared.js";
|
|
2
|
+
import { signLicencePayload, verifySignedLicenceToken } from "./token.js";
|
|
3
|
+
export { signLicencePayload, verifySignedLicenceToken } from "./token.js";
|
|
4
|
+
export { DEFAULT_ENTERPRISE_FEATURES, PREDEFINED_ENTERPRISE_LICENSES, findPredefinedEnterpriseLicense, isPredefinedLicenseNotExpired, mergeEnterpriseFeatures } from "./gate-shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* Verify a signed `DE1.*` token or predefined demo key.
|
|
7
|
+
* Pass `secret` from your server env (e.g. `DE_LICENCE_SECRET`).
|
|
8
|
+
*/
|
|
9
|
+
export function resolveEnterpriseFeatures(licence, options) {
|
|
10
|
+
const predefined = resolvePredefinedEnterpriseFeatures(licence, options?.now);
|
|
11
|
+
if (predefined.valid) {
|
|
12
|
+
return predefined;
|
|
13
|
+
}
|
|
14
|
+
const token = licence?.token?.trim();
|
|
15
|
+
if (!token) {
|
|
16
|
+
return predefined;
|
|
17
|
+
}
|
|
18
|
+
const secret = options?.secret?.trim() || process.env.DE_LICENCE_SECRET?.trim();
|
|
19
|
+
if (!secret) {
|
|
20
|
+
return predefined;
|
|
21
|
+
}
|
|
22
|
+
const verified = verifySignedLicenceToken(token, secret, options?.now?.getTime());
|
|
23
|
+
if (!verified.valid || !verified.payload) {
|
|
24
|
+
return { valid: false, features: DEFAULT_ENTERPRISE_FEATURES, message: verified.message ?? "Invalid licence" };
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
valid: true,
|
|
28
|
+
features: mergeEnterpriseFeatures(DEFAULT_ENTERPRISE_FEATURES, { ...verified.payload.features, ...licence?.features }),
|
|
29
|
+
message: "Signed licence accepted",
|
|
30
|
+
subject: verified.payload.sub
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Server-side helper to mint signed licence tokens. */
|
|
34
|
+
export function createEnterpriseLicenceToken(payload, secret) {
|
|
35
|
+
return signLicencePayload(payload, secret);
|
|
36
|
+
}
|
|
37
|
+
export { resolveEnterpriseFeaturesOnline } from "./online.js";
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,mCAAmC,EAIpC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAuB,MAAM,YAAY,CAAC;AAI/F,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE1E,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,+BAA+B,EAC/B,6BAA6B,EAC7B,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAE1B;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAkC,EAClC,OAAyC;IAEzC,MAAM,UAAU,GAAG,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAC9E,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAChF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAClF,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QACzC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,2BAA2B,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,IAAI,iBAAiB,EAAE,CAAC;IACjH,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,uBAAuB,CAAC,2BAA2B,EAAE,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC;QACtH,OAAO,EAAE,yBAAyB;QAClC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG;KAC9B,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,4BAA4B,CAAC,OAAuB,EAAE,MAAc;IAClF,OAAO,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED,OAAO,EACL,+BAA+B,EAGhC,MAAM,aAAa,CAAC"}
|
package/dist/online.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { EditorFeatureFlags } from "@richhtmleditor/core";
|
|
2
|
+
import { type EnterpriseGateResult, type EnterpriseLicence } from "./gate-shared.js";
|
|
3
|
+
export type OnlineLicenceVerifyResponse = {
|
|
4
|
+
valid: boolean;
|
|
5
|
+
features?: Partial<EditorFeatureFlags>;
|
|
6
|
+
subject?: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
};
|
|
9
|
+
export type OnlineLicenceVerifyOptions = {
|
|
10
|
+
/** POST endpoint that accepts `{ token }` and returns feature flags. */
|
|
11
|
+
endpoint?: string;
|
|
12
|
+
fetch?: typeof fetch;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
secret?: string;
|
|
15
|
+
now?: Date;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Verify a licence offline first (predefined keys), then fall back to an
|
|
19
|
+
* online server for signed tokens when no local secret is available (browser / edge runtimes).
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveEnterpriseFeaturesOnline(licence?: EnterpriseLicence | null, options?: OnlineLicenceVerifyOptions): Promise<EnterpriseGateResult>;
|
|
22
|
+
//# sourceMappingURL=online.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"online.d.ts","sourceRoot":"","sources":["../src/online.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,2BAA2B,GAAG;IACxC,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,CAAC;AAIF;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,OAAO,CAAC,EAAE,iBAAiB,GAAG,IAAI,EAClC,OAAO,CAAC,EAAE,0BAA0B,GACnC,OAAO,CAAC,oBAAoB,CAAC,CAuD/B"}
|
package/dist/online.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { DEFAULT_ENTERPRISE_FEATURES, mergeEnterpriseFeatures, resolvePredefinedEnterpriseFeatures } from "./gate-shared.js";
|
|
2
|
+
const DEFAULT_VERIFY_URL = "https://licence.richhtmleditor.dev/api/verify";
|
|
3
|
+
/**
|
|
4
|
+
* Verify a licence offline first (predefined keys), then fall back to an
|
|
5
|
+
* online server for signed tokens when no local secret is available (browser / edge runtimes).
|
|
6
|
+
*/
|
|
7
|
+
export async function resolveEnterpriseFeaturesOnline(licence, options) {
|
|
8
|
+
const offline = resolvePredefinedEnterpriseFeatures(licence, options?.now);
|
|
9
|
+
if (offline.valid) {
|
|
10
|
+
return offline;
|
|
11
|
+
}
|
|
12
|
+
const token = licence?.token?.trim();
|
|
13
|
+
if (!token?.startsWith("DE1.")) {
|
|
14
|
+
return offline;
|
|
15
|
+
}
|
|
16
|
+
const endpoint = options?.endpoint?.trim() ||
|
|
17
|
+
(typeof process !== "undefined" ? process.env.DE_LICENCE_VERIFY_URL?.trim() : undefined) ||
|
|
18
|
+
DEFAULT_VERIFY_URL;
|
|
19
|
+
const fetchFn = options?.fetch ?? globalThis.fetch;
|
|
20
|
+
if (!fetchFn) {
|
|
21
|
+
return { ...offline, message: offline.message ?? "Fetch unavailable for online licence verify" };
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetchFn(endpoint, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
27
|
+
body: JSON.stringify({ token }),
|
|
28
|
+
signal: options?.signal
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
return {
|
|
32
|
+
valid: false,
|
|
33
|
+
features: offline.features,
|
|
34
|
+
message: `Online licence verify failed (${response.status})`
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const data = (await response.json());
|
|
38
|
+
if (!data.valid) {
|
|
39
|
+
return {
|
|
40
|
+
valid: false,
|
|
41
|
+
features: offline.features,
|
|
42
|
+
message: data.message ?? offline.message ?? "Invalid licence"
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
valid: true,
|
|
47
|
+
features: mergeEnterpriseFeatures(DEFAULT_ENTERPRISE_FEATURES, { ...data.features, ...licence?.features }),
|
|
48
|
+
message: "Online licence accepted",
|
|
49
|
+
subject: data.subject
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const message = error instanceof Error ? error.message : "Online licence verify unavailable";
|
|
54
|
+
return { valid: false, features: offline.features, message };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=online.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"online.js","sourceRoot":"","sources":["../src/online.ts"],"names":[],"mappings":"AACA,OAAO,EACL,2BAA2B,EAC3B,uBAAuB,EACvB,mCAAmC,EAGpC,MAAM,kBAAkB,CAAC;AAkB1B,MAAM,kBAAkB,GAAG,+CAA+C,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,OAAkC,EAClC,OAAoC;IAEpC,MAAM,OAAO,GAAG,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,QAAQ,GACZ,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE;QACzB,CAAC,OAAO,OAAO,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QACxF,kBAAkB,CAAC;IACrB,MAAM,OAAO,GAAG,OAAO,EAAE,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,6CAA6C,EAAE,CAAC;IACnG,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE;YACvC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;YAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;YAC/B,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,OAAO,EAAE,iCAAiC,QAAQ,CAAC,MAAM,GAAG;aAC7D,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAgC,CAAC;QACpE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI,iBAAiB;aAC9D,CAAC;QACJ,CAAC;QAED,OAAO;YACL,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,uBAAuB,CAAC,2BAA2B,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC;YAC1G,OAAO,EAAE,yBAAyB;YAClC,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC;QAC7F,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;IAC/D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"key": "RHE-ENT-DEMO-2026-FULL",
|
|
4
|
+
"owner": "richhtmleditor Demo",
|
|
5
|
+
"expiresAt": "2027-12-31",
|
|
6
|
+
"features": {
|
|
7
|
+
"ai": true,
|
|
8
|
+
"comments": true,
|
|
9
|
+
"workflows": true,
|
|
10
|
+
"toolbarFull": true
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"key": "RHE-ENT-DEMO-2026-COMMENTS",
|
|
15
|
+
"owner": "richhtmleditor Demo",
|
|
16
|
+
"expiresAt": "2027-12-31",
|
|
17
|
+
"features": {
|
|
18
|
+
"comments": true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
]
|
package/dist/token.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EditorFeatureFlags } from "@richhtmleditor/core";
|
|
2
|
+
export declare const LICENCE_TOKEN_PREFIX = "DE1";
|
|
3
|
+
export type LicencePayload = {
|
|
4
|
+
sub: string;
|
|
5
|
+
exp?: number;
|
|
6
|
+
features?: Partial<EditorFeatureFlags>;
|
|
7
|
+
};
|
|
8
|
+
export type SignedLicenceParts = {
|
|
9
|
+
prefix: string;
|
|
10
|
+
payloadPart: string;
|
|
11
|
+
signaturePart: string;
|
|
12
|
+
payload: LicencePayload;
|
|
13
|
+
};
|
|
14
|
+
export declare function parseSignedLicenceToken(token: string): SignedLicenceParts | null;
|
|
15
|
+
export declare function signLicencePayload(payload: LicencePayload, secret: string): string;
|
|
16
|
+
export declare function verifySignedLicenceToken(token: string, secret: string, nowMs?: number): {
|
|
17
|
+
valid: boolean;
|
|
18
|
+
payload?: LicencePayload;
|
|
19
|
+
message?: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAE1C,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;CACzB,CAAC;AAeF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAmBhF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,KAAK,SAAa,GACjB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,cAAc,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAehE"}
|
package/dist/token.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
export const LICENCE_TOKEN_PREFIX = "DE1";
|
|
3
|
+
function base64UrlEncode(value) {
|
|
4
|
+
return Buffer.from(value)
|
|
5
|
+
.toString("base64")
|
|
6
|
+
.replace(/\+/g, "-")
|
|
7
|
+
.replace(/\//g, "_")
|
|
8
|
+
.replace(/=+$/g, "");
|
|
9
|
+
}
|
|
10
|
+
function base64UrlDecode(value) {
|
|
11
|
+
const padded = value.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - (value.length % 4)) % 4);
|
|
12
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
13
|
+
}
|
|
14
|
+
export function parseSignedLicenceToken(token) {
|
|
15
|
+
const parts = token.trim().split(".");
|
|
16
|
+
if (parts.length !== 3 || parts[0] !== LICENCE_TOKEN_PREFIX) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const payload = JSON.parse(base64UrlDecode(parts[1]));
|
|
21
|
+
if (!payload?.sub?.trim()) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
prefix: parts[0],
|
|
26
|
+
payloadPart: parts[1],
|
|
27
|
+
signaturePart: parts[2],
|
|
28
|
+
payload
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function signLicencePayload(payload, secret) {
|
|
36
|
+
const body = base64UrlEncode(JSON.stringify(payload));
|
|
37
|
+
const signature = base64UrlEncode(createHmac("sha256", secret).update(body).digest());
|
|
38
|
+
return `${LICENCE_TOKEN_PREFIX}.${body}.${signature}`;
|
|
39
|
+
}
|
|
40
|
+
export function verifySignedLicenceToken(token, secret, nowMs = Date.now()) {
|
|
41
|
+
const parsed = parseSignedLicenceToken(token);
|
|
42
|
+
if (!parsed) {
|
|
43
|
+
return { valid: false, message: "Invalid licence token format" };
|
|
44
|
+
}
|
|
45
|
+
const expected = base64UrlEncode(createHmac("sha256", secret).update(parsed.payloadPart).digest());
|
|
46
|
+
const a = Buffer.from(expected);
|
|
47
|
+
const b = Buffer.from(parsed.signaturePart);
|
|
48
|
+
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
49
|
+
return { valid: false, message: "Licence signature mismatch" };
|
|
50
|
+
}
|
|
51
|
+
if (parsed.payload.exp !== undefined && nowMs > parsed.payload.exp * 1000) {
|
|
52
|
+
return { valid: false, message: "Licence expired" };
|
|
53
|
+
}
|
|
54
|
+
return { valid: true, payload: parsed.payload };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@richhtmleditor/enterprise",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Licence and feature-gate helpers for Rich HTML Editor enterprise deployments.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./browser": {
|
|
15
|
+
"types": "./dist/browser.d.ts",
|
|
16
|
+
"import": "./dist/browser.js",
|
|
17
|
+
"default": "./dist/browser.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.json && node -e \"import('node:fs').then(fs=>fs.copyFileSync('src/predefined-licenses.json','dist/predefined-licenses.json'))\"",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"prepack": "node ../../scripts/assert-pack-ready.mjs"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@richhtmleditor/core": "^1.0.0"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"richhtmleditor",
|
|
34
|
+
"enterprise",
|
|
35
|
+
"licence",
|
|
36
|
+
"feature-flags"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^22.0.0",
|
|
47
|
+
"vitest": "^2.1.0"
|
|
48
|
+
}
|
|
49
|
+
}
|