@kawanua/license-sdk 1.0.0 → 1.1.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/LICENSE +15 -0
- package/README.md +83 -0
- package/index.js +16 -44
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, [Kawanua Indo Digital]
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @kawanua/license-sdk
|
|
2
|
+
|
|
3
|
+
SDK resmi untuk klien yang menggunakan sistem lisensi Kawanua. SDK ini menyediakan metode verifikasi lisensi berbasis JWT (RS256) di sisi klien dengan fitur auto-branding dan kontrol akses fitur yang dinamis.
|
|
4
|
+
|
|
5
|
+
## Fitur Utama
|
|
6
|
+
|
|
7
|
+
- **Verifikasi Aman:** Memverifikasi token JWT lisensi menggunakan RS256.
|
|
8
|
+
- **Dukungan Multi-Environment:** Mendukung browser (via `<script>`), CommonJS, dan ESM.
|
|
9
|
+
- **Kontrol Fitur:** Mendukung limitasi fitur berdasarkan plan (Starter, Professional, Enterprise).
|
|
10
|
+
- **Auto-Branding:** Secara otomatis menyuntikkan atau menyembunyikan elemen "Powered by Kawanua" sesuai ketentuan lisensi.
|
|
11
|
+
- **Auto-Refresh:** Mekanisme pembaruan token otomatis sebelum masa berlaku habis.
|
|
12
|
+
|
|
13
|
+
## Instalasi
|
|
14
|
+
|
|
15
|
+
### via CDN (Browser)
|
|
16
|
+
|
|
17
|
+
Tambahkan script berikut sebelum tag `</body>`:
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<script src="https://cdn.kawanua.id/sdk/license.min.js"></script>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### via NPM
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @kawanua/license-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Penggunaan
|
|
30
|
+
|
|
31
|
+
### Inisialisasi
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
import { KawanuaLicense } from '@kawanua/license-sdk';
|
|
35
|
+
|
|
36
|
+
KawanuaLicense.init({
|
|
37
|
+
token: 'YOUR_JWT_TOKEN',
|
|
38
|
+
onRefresh: async () => {
|
|
39
|
+
// Implementasi untuk fetch token baru dari server kamu
|
|
40
|
+
const res = await fetch('/api/license/refresh');
|
|
41
|
+
const { token } = await res.json();
|
|
42
|
+
return token;
|
|
43
|
+
},
|
|
44
|
+
onReady: (state) => {
|
|
45
|
+
console.log('Lisensi aktif, plan:', state.plan);
|
|
46
|
+
},
|
|
47
|
+
onError: (err) => {
|
|
48
|
+
console.error('Inisialisasi gagal:', err.message);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Mengecek Akses Fitur
|
|
54
|
+
|
|
55
|
+
Setelah inisialisasi berhasil, kamu bisa mengecek apakah sebuah fitur diperbolehkan:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// Mengecek boolean
|
|
59
|
+
if (KawanuaLicense.can('api_access')) {
|
|
60
|
+
// Tampilkan fitur API
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Mendapatkan nilai (misal: limit jumlah user)
|
|
64
|
+
const maxUsers = KawanuaLicense.get('max_users');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Referensi Plan
|
|
68
|
+
|
|
69
|
+
SDK secara otomatis mengatur batasan fitur berdasarkan plan:
|
|
70
|
+
|
|
71
|
+
| Fitur | Starter | Professional | Enterprise |
|
|
72
|
+
| :--- | :---: | :---: | :---: |
|
|
73
|
+
| **Remove Branding** | ❌ | ✅ | ✅ |
|
|
74
|
+
| **Custom Domain** | ❌ | ❌ | ✅ |
|
|
75
|
+
| **API Access** | ❌ | ✅ | ✅ |
|
|
76
|
+
| **Max Users** | 5 | 50 | ∞ |
|
|
77
|
+
|
|
78
|
+
## Lisensi
|
|
79
|
+
|
|
80
|
+
ISC
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
*Dibuat oleh [Kawanua Indo Digital](https://labs.kawanua.co)*
|
package/index.js
CHANGED
|
@@ -29,22 +29,10 @@
|
|
|
29
29
|
|
|
30
30
|
// ─── Konstanta ──────────────────────────────────────────────────
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
*/
|
|
37
|
-
const KAWANUA_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
38
|
-
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a2rwplBQLzHPZe5TNJF
|
|
39
|
-
... (ganti dengan public key RS256 aktual dari server kamu) ...
|
|
40
|
-
-----END PUBLIC KEY-----`;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* URL endpoint JWKS publik — alternatif lebih dinamis dari hardcode PEM.
|
|
44
|
-
* SDK akan fetch public key dari sini jika PEM tidak di-set.
|
|
45
|
-
* Endpoint ini harus tersedia di server Kawanua.
|
|
46
|
-
*/
|
|
47
|
-
const JWKS_URL = "https://lisensi.kawanua.workers.dev/.well-known/jwks.json";
|
|
32
|
+
// Public key RS256 dari server lisensi Kawanua (Base64-encoded PEM).
|
|
33
|
+
// Klien hanya bisa VERIFY — tidak bisa forge token baru.
|
|
34
|
+
const KAWANUA_PUBLIC_KEY_B64 =
|
|
35
|
+
"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzTFgrbDdKbS9VQ25nZ1VmcVhXMAoxazN2M2FYR0RRdEF3Z2NyeVFad1lUY2x5SzdQdFdxMG10ejArUDRyTW0veFBhdmlaQlRaYUt4aVdScWVTQUhUCk4wVDdVSFRSbnJjaElwY1JaeExiTXlzWHJ6eS9NcjZ3cTF1aW5FUjJ1TGNjRE9Hc2swR0Q4QU1TWU54Q1NsZ24KcFREN200R0g0TE1DTzNPU2dXYm9Ua0VWdkp2TXN5ckZ2TTlTT2N1UG9NTmJyTGk2SDVnOTR2OU9UWkRvTzhZeQo0RXUwQjRaM3luVS9iRzY2TFZmWGNTYlNBaGU4TWZ6NDZ2UUxzMXJJNUpqZElhajAxWDdsamw1cWdWcklCRHhkCjhneXUxK1FZcXZjYTdzaTRUVkZzOTlYV0xlUVpBWWh2UC9kT3gvdWxvNE1CL1doQU9NRWNwai9kaGVHYk5ieTcKZ3dJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg=="; // <- isi dengan base64(PUBLIC_KEY_PEM)
|
|
48
36
|
|
|
49
37
|
/** Feature map per plan — single source of truth */
|
|
50
38
|
const PLAN_FEATURES = {
|
|
@@ -112,15 +100,17 @@ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a2rwplBQLzHPZe5TNJF
|
|
|
112
100
|
}
|
|
113
101
|
|
|
114
102
|
/**
|
|
115
|
-
* Import public key RS256 dari PEM
|
|
116
|
-
* Menggunakan Web Crypto API (tersedia di semua browser modern).
|
|
103
|
+
* Import public key RS256 dari base64-encoded PEM ke CryptoKey.
|
|
117
104
|
*/
|
|
118
|
-
async function _importPublicKey(
|
|
105
|
+
async function _importPublicKey(b64) {
|
|
106
|
+
const pem = atob(b64);
|
|
119
107
|
const pemBody = pem
|
|
120
108
|
.replace(/-----BEGIN PUBLIC KEY-----/, "")
|
|
121
109
|
.replace(/-----END PUBLIC KEY-----/, "")
|
|
122
110
|
.replace(/\s+/g, "");
|
|
111
|
+
|
|
123
112
|
const der = Uint8Array.from(atob(pemBody), (c) => c.charCodeAt(0));
|
|
113
|
+
|
|
124
114
|
return crypto.subtle.importKey(
|
|
125
115
|
"spki",
|
|
126
116
|
der.buffer,
|
|
@@ -130,24 +120,6 @@ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a2rwplBQLzHPZe5TNJF
|
|
|
130
120
|
);
|
|
131
121
|
}
|
|
132
122
|
|
|
133
|
-
/**
|
|
134
|
-
* Fetch public key dari JWKS endpoint.
|
|
135
|
-
* Fallback jika PEM belum di-hardcode (mode dinamis).
|
|
136
|
-
*/
|
|
137
|
-
async function _fetchPublicKeyFromJWKS(kid) {
|
|
138
|
-
const res = await fetch(JWKS_URL, { cache: "force-cache" });
|
|
139
|
-
const jwks = await res.json();
|
|
140
|
-
const jwk = kid ? jwks.keys.find((k) => k.kid === kid) : jwks.keys[0];
|
|
141
|
-
if (!jwk) throw new Error("No matching key found in JWKS");
|
|
142
|
-
return crypto.subtle.importKey(
|
|
143
|
-
"jwk",
|
|
144
|
-
jwk,
|
|
145
|
-
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
146
|
-
false,
|
|
147
|
-
["verify"],
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
123
|
/**
|
|
152
124
|
* Verifikasi signature JWT dengan RS256.
|
|
153
125
|
* Returns true jika valid, false jika tidak.
|
|
@@ -197,14 +169,14 @@ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a2rwplBQLzHPZe5TNJF
|
|
|
197
169
|
);
|
|
198
170
|
}
|
|
199
171
|
|
|
200
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
publicKey = await _fetchPublicKeyFromJWKS(header.kid);
|
|
172
|
+
// Fail-fast jika public key belum dikonfigurasi.
|
|
173
|
+
if (!KAWANUA_PUBLIC_KEY_B64) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
"[KawanuaLicense] KAWANUA_PUBLIC_KEY_B64 belum dikonfigurasi. " +
|
|
176
|
+
"Hubungi Kawanua untuk mendapatkan public key SDK kamu.",
|
|
177
|
+
);
|
|
207
178
|
}
|
|
179
|
+
const publicKey = await _importPublicKey(KAWANUA_PUBLIC_KEY_B64);
|
|
208
180
|
|
|
209
181
|
// Verify signature
|
|
210
182
|
const isValid = await _verifySignature(token, publicKey);
|