@notur/sdk 1.1.2 → 1.1.4

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 CHANGED
@@ -5,11 +5,11 @@ Notur Extension Developer SDK. This package provides the runtime helpers and Rea
5
5
  ## Install
6
6
 
7
7
  ```bash
8
+ # Using npm, yarn, pnpm, or bun
8
9
  npm install @notur/sdk
9
- ```
10
-
11
- ```bash
12
- bun add @notur/sdk
10
+ # or: yarn add @notur/sdk
11
+ # or: pnpm add @notur/sdk
12
+ # or: bun add @notur/sdk
13
13
  ```
14
14
 
15
15
  Peer dependencies:
@@ -70,12 +70,9 @@ All hooks are exported from `@notur/sdk`.
70
70
  The SDK includes a CLI tool to package your extension into a `.notur` archive that can be uploaded to the Pterodactyl admin panel.
71
71
 
72
72
  ```bash
73
- # From your extension directory
73
+ # From your extension directory (using npx, yarn dlx, pnpm dlx, or bunx)
74
74
  npx notur-pack
75
75
 
76
- # Or with bun
77
- bunx notur-pack
78
-
79
76
  # Specify a different path
80
77
  npx notur-pack /path/to/my-extension
81
78
 
@@ -89,13 +86,41 @@ This creates a `.notur` file (tar.gz archive) containing:
89
86
 
90
87
  Upload the resulting `.notur` file to your Pterodactyl admin panel at `/admin/notur/extensions`.
91
88
 
92
- ## Build
89
+ ## Signing Extensions
90
+
91
+ The SDK provides tools for Ed25519 signing of extension archives, compatible with the PHP `notur:keygen` and `notur:export --sign` commands.
92
+
93
+ ### Generating a Keypair
93
94
 
94
95
  ```bash
95
- bun run build
96
+ npx notur-keygen
96
97
  ```
97
98
 
99
+ This generates a new Ed25519 keypair and outputs:
100
+ - **Public Key** (64 hex characters) -- Share with panel administrators
101
+ - **Secret Key** (128 hex characters) -- Keep private, used for signing
102
+
103
+ ### Signing an Archive
104
+
105
+ ```bash
106
+ # Using environment variable
107
+ NOTUR_SECRET_KEY=your_secret_key npx notur-pack --sign
108
+
109
+ # Or with --secret-key flag
110
+ npx notur-pack --sign --secret-key your_secret_key
111
+ ```
112
+
113
+ This produces three files:
114
+ - `vendor-name-1.0.0.notur` -- The extension archive
115
+ - `vendor-name-1.0.0.notur.sha256` -- SHA-256 checksum
116
+ - `vendor-name-1.0.0.notur.sig` -- Ed25519 signature (hex-encoded)
117
+
118
+ The `.sig` file format is compatible with PHP's `SignatureVerifier::verify()` and panels with `require_signatures` enabled.
119
+
120
+ ## Build
121
+
98
122
  ```bash
123
+ # Using npm, yarn, pnpm, or bun
99
124
  npm run build
100
125
  ```
101
126
 
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * notur-keygen - Generate Ed25519 keypair for signing Notur extensions
5
+ *
6
+ * Usage:
7
+ * npx notur-keygen
8
+ * bunx notur-keygen
9
+ *
10
+ * Generates a new Ed25519 keypair and outputs both keys in hex format.
11
+ * The output format matches the PHP `php artisan notur:keygen` command.
12
+ */
13
+
14
+ const sodium = require('libsodium-wrappers');
15
+
16
+ async function main() {
17
+ await sodium.ready;
18
+
19
+ const keypair = sodium.crypto_sign_keypair();
20
+
21
+ const publicKeyHex = sodium.to_hex(keypair.publicKey);
22
+ const secretKeyHex = sodium.to_hex(keypair.privateKey);
23
+
24
+ console.log('Ed25519 keypair generated successfully.');
25
+ console.log('');
26
+ console.log('Public Key:');
27
+ console.log(publicKeyHex);
28
+ console.log('');
29
+ console.log('Secret Key:');
30
+ console.log(secretKeyHex);
31
+ console.log('');
32
+ console.log('Store the secret key securely. It is used to sign extension archives.');
33
+ console.log('Add the public key to your panel configuration:');
34
+ console.log('');
35
+ console.log(` NOTUR_PUBLIC_KEY=${publicKeyHex}`);
36
+ console.log('');
37
+ console.log('To sign an archive, set the secret key as an environment variable:');
38
+ console.log('');
39
+ console.log(` NOTUR_SECRET_KEY=${secretKeyHex}`);
40
+ console.log(' npx notur-pack --sign');
41
+ }
42
+
43
+ main().catch(err => {
44
+ console.error('Error:', err.message);
45
+ process.exit(1);
46
+ });
package/bin/notur-pack.js CHANGED
@@ -6,6 +6,8 @@
6
6
  * Usage:
7
7
  * npx notur-pack [path] # Pack extension at path (default: current dir)
8
8
  * npx notur-pack --output foo.notur
9
+ * npx notur-pack --sign # Sign using NOTUR_SECRET_KEY env var
10
+ * npx notur-pack --sign --secret-key xxx
9
11
  * bunx notur-pack
10
12
  *
11
13
  * A .notur file is a tar.gz archive containing:
@@ -34,11 +36,17 @@ function parseArgs() {
34
36
  const options = {
35
37
  path: '.',
36
38
  output: null,
39
+ sign: false,
40
+ secretKey: null,
37
41
  };
38
42
 
39
43
  for (let i = 0; i < args.length; i++) {
40
44
  if (args[i] === '--output' || args[i] === '-o') {
41
45
  options.output = args[++i];
46
+ } else if (args[i] === '--sign' || args[i] === '-s') {
47
+ options.sign = true;
48
+ } else if (args[i] === '--secret-key') {
49
+ options.secretKey = args[++i];
42
50
  } else if (!args[i].startsWith('-')) {
43
51
  options.path = args[i];
44
52
  }
@@ -123,7 +131,45 @@ function computeChecksums(dir, files) {
123
131
  return checksums;
124
132
  }
125
133
 
126
- function pack(sourceDir, outputPath) {
134
+ async function signArchive(archivePath, secretKeyHex) {
135
+ const sodium = require('libsodium-wrappers');
136
+ await sodium.ready;
137
+
138
+ const content = fs.readFileSync(archivePath);
139
+ const secretKey = sodium.from_hex(secretKeyHex);
140
+ const signature = sodium.crypto_sign_detached(content, secretKey);
141
+
142
+ return sodium.to_hex(signature);
143
+ }
144
+
145
+ function getSecretKey(options) {
146
+ // Check --secret-key argument first, then environment variable
147
+ const secretKey = options.secretKey || process.env.NOTUR_SECRET_KEY;
148
+
149
+ if (!secretKey) {
150
+ console.error('Error: --sign requires a secret key.');
151
+ console.error('');
152
+ console.error('Provide it via:');
153
+ console.error(' NOTUR_SECRET_KEY=xxx npx notur-pack --sign');
154
+ console.error(' npx notur-pack --sign --secret-key xxx');
155
+ console.error('');
156
+ console.error('Generate a keypair with: npx notur-keygen');
157
+ process.exit(1);
158
+ }
159
+
160
+ // Validate format: Ed25519 secret keys are 64 bytes = 128 hex chars
161
+ if (!/^[0-9a-fA-F]{128}$/.test(secretKey)) {
162
+ console.error('Error: Invalid secret key format.');
163
+ console.error('Expected 128 hexadecimal characters (64 bytes).');
164
+ console.error('');
165
+ console.error('Generate a valid keypair with: npx notur-keygen');
166
+ process.exit(1);
167
+ }
168
+
169
+ return secretKey;
170
+ }
171
+
172
+ async function pack(sourceDir, outputPath, options = {}) {
127
173
  const resolvedDir = path.resolve(sourceDir);
128
174
 
129
175
  if (!fs.existsSync(resolvedDir)) {
@@ -174,6 +220,16 @@ function pack(sourceDir, outputPath) {
174
220
 
175
221
  console.log(`\nCreated: ${outputFullPath}`);
176
222
  console.log(`Checksum: ${archiveChecksum}`);
223
+
224
+ // Sign the archive if requested
225
+ if (options.sign) {
226
+ const secretKey = getSecretKey(options);
227
+ const signature = await signArchive(outputFullPath, secretKey);
228
+ const sigPath = outputFullPath + '.sig';
229
+ fs.writeFileSync(sigPath, signature + '\n');
230
+ console.log(`Signature: ${sigPath}`);
231
+ }
232
+
177
233
  console.log(`\nUpload this file to your Pterodactyl admin panel at /admin/notur/extensions`);
178
234
 
179
235
  } finally {
@@ -186,4 +242,7 @@ function pack(sourceDir, outputPath) {
186
242
 
187
243
  // Main
188
244
  const options = parseArgs();
189
- pack(options.path, options.output);
245
+ pack(options.path, options.output, options).catch(err => {
246
+ console.error('Error:', err.message);
247
+ process.exit(1);
248
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notur/sdk",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "Notur Extension Developer SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -15,7 +15,8 @@
15
15
  "access": "public"
16
16
  },
17
17
  "bin": {
18
- "notur-pack": "./bin/notur-pack.js"
18
+ "notur-pack": "./bin/notur-pack.js",
19
+ "notur-keygen": "./bin/notur-keygen.js"
19
20
  },
20
21
  "keywords": [
21
22
  "notur",
@@ -40,6 +41,7 @@
40
41
  "react-dom": "^16.14.0"
41
42
  },
42
43
  "dependencies": {
44
+ "libsodium-wrappers": "^0.7.13",
43
45
  "yaml": "^2.3.0"
44
46
  },
45
47
  "devDependencies": {