native-update 1.0.9 → 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/Readme.md +35 -17
- package/cli/cap-update.js +45 -0
- package/cli/commands/backend-create.js +582 -0
- package/cli/commands/bundle-create.js +113 -0
- package/cli/commands/bundle-sign.js +58 -0
- package/cli/commands/bundle-verify.js +55 -0
- package/cli/commands/init.js +146 -0
- package/cli/commands/keys-generate.js +92 -0
- package/cli/commands/monitor.js +68 -0
- package/cli/commands/server-start.js +96 -0
- package/cli/index.js +269 -0
- package/cli/package.json +12 -0
- package/docs/BUNDLE_SIGNING.md +16 -9
- package/docs/LIVE_UPDATES_GUIDE.md +1 -1
- package/docs/README.md +1 -0
- package/docs/cli-reference.md +321 -0
- package/docs/getting-started/configuration.md +3 -2
- package/docs/getting-started/quick-start.md +53 -1
- package/docs/guides/deployment-guide.md +9 -7
- package/docs/guides/key-management.md +284 -0
- package/docs/guides/migration-from-codepush.md +9 -5
- package/docs/guides/testing-guide.md +4 -4
- package/package.json +15 -2
|
@@ -345,14 +345,66 @@ async function safeUpdateCheck() {
|
|
|
345
345
|
});
|
|
346
346
|
```
|
|
347
347
|
|
|
348
|
+
## Setting Up Backend & Creating Updates
|
|
349
|
+
|
|
350
|
+
### Quick Backend Setup
|
|
351
|
+
|
|
352
|
+
Use our CLI to quickly set up a backend:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
# Create an Express.js backend with admin dashboard
|
|
356
|
+
npx native-update backend create express --with-admin
|
|
357
|
+
|
|
358
|
+
# Or create a Firebase Functions backend
|
|
359
|
+
npx native-update backend create firebase --with-monitoring
|
|
360
|
+
|
|
361
|
+
# Start the development server
|
|
362
|
+
cd native-update-backend
|
|
363
|
+
npm install
|
|
364
|
+
npm run dev
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Creating and Deploying Updates
|
|
368
|
+
|
|
369
|
+
1. **Generate signing keys** (see [Key Management Guide](../guides/key-management.md) for details):
|
|
370
|
+
```bash
|
|
371
|
+
npx native-update keys generate --type rsa --size 4096
|
|
372
|
+
```
|
|
373
|
+
This creates a private key (keep secret) and public key (add to app config)
|
|
374
|
+
|
|
375
|
+
2. **Build and create update bundle**:
|
|
376
|
+
```bash
|
|
377
|
+
npm run build
|
|
378
|
+
npx native-update bundle create ./www --version 1.0.1
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
3. **Sign the bundle**:
|
|
382
|
+
```bash
|
|
383
|
+
npx native-update bundle sign ./update-bundles/bundle-*.zip --key ./keys/private-*.pem
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
4. **Upload via admin dashboard or API**
|
|
387
|
+
|
|
388
|
+
### Development Server
|
|
389
|
+
|
|
390
|
+
For local testing:
|
|
391
|
+
```bash
|
|
392
|
+
# Start a local update server
|
|
393
|
+
npx native-update server start --port 3000
|
|
394
|
+
|
|
395
|
+
# Monitor updates in real-time
|
|
396
|
+
npx native-update monitor --server http://localhost:3000
|
|
397
|
+
```
|
|
398
|
+
|
|
348
399
|
## Next Steps
|
|
349
400
|
|
|
350
401
|
Now that you have the basics working:
|
|
351
402
|
|
|
352
|
-
1.
|
|
403
|
+
1. Deploy your backend to production
|
|
353
404
|
2. Implement [Security Best Practices](../guides/security-best-practices.md)
|
|
354
405
|
3. Configure [Advanced Options](./configuration.md)
|
|
355
406
|
4. Explore [API Reference](../api/live-update-api.md) for all available methods
|
|
407
|
+
5. See [CLI Reference](../cli-reference.md) for all available commands
|
|
356
408
|
|
|
357
409
|
## Quick Reference
|
|
358
410
|
|
|
@@ -90,11 +90,13 @@ pm2 startup
|
|
|
90
90
|
|
|
91
91
|
### 1. Production Keys
|
|
92
92
|
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
```bash
|
|
94
|
+
# Generate RSA keys for production
|
|
95
|
+
npx native-update keys generate --type rsa --size 4096
|
|
96
|
+
|
|
97
|
+
# This creates:
|
|
98
|
+
# - private-[timestamp].pem (keep secure on CI/CD server)
|
|
99
|
+
# - public-[timestamp].pem (embed in app)
|
|
98
100
|
```
|
|
99
101
|
|
|
100
102
|
### 2. Configure Plugin
|
|
@@ -181,10 +183,10 @@ ServerDown:
|
|
|
181
183
|
npm run build
|
|
182
184
|
|
|
183
185
|
# Create bundle
|
|
184
|
-
|
|
186
|
+
npx native-update bundle create ./www
|
|
185
187
|
|
|
186
188
|
# Sign bundle
|
|
187
|
-
|
|
189
|
+
npx native-update bundle sign bundle.zip --key private-key.pem
|
|
188
190
|
```
|
|
189
191
|
|
|
190
192
|
### 2. Upload to Server
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Key Management Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to generate, manage, and use cryptographic keys for bundle signing in the Native Update plugin.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Native Update plugin uses public key cryptography to ensure the security and integrity of update bundles. This system prevents tampering and ensures updates come from trusted sources.
|
|
8
|
+
|
|
9
|
+
### Why Use Cryptographic Signing?
|
|
10
|
+
|
|
11
|
+
1. **Integrity**: Ensures bundles haven't been modified during transmission
|
|
12
|
+
2. **Authenticity**: Verifies bundles come from your trusted server
|
|
13
|
+
3. **Non-repudiation**: Proves the origin of updates
|
|
14
|
+
4. **Security**: Prevents man-in-the-middle attacks and bundle injection
|
|
15
|
+
|
|
16
|
+
## Key Generation
|
|
17
|
+
|
|
18
|
+
### Using the CLI Tool (Recommended)
|
|
19
|
+
|
|
20
|
+
The easiest way to generate keys is using our CLI tool:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Generate RSA 4096-bit keys (recommended for production)
|
|
24
|
+
npx native-update keys generate --type rsa --size 4096
|
|
25
|
+
|
|
26
|
+
# Generate RSA 2048-bit keys (faster, still secure)
|
|
27
|
+
npx native-update keys generate --type rsa --size 2048
|
|
28
|
+
|
|
29
|
+
# Generate EC keys (smaller signatures, modern)
|
|
30
|
+
npx native-update keys generate --type ec --size 256
|
|
31
|
+
|
|
32
|
+
# Specify output directory
|
|
33
|
+
npx native-update keys generate --output ./my-keys
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This will create:
|
|
37
|
+
- `private-{timestamp}.pem` - Keep this SECRET on your server
|
|
38
|
+
- `public-{timestamp}.pem` - Include this in your app
|
|
39
|
+
|
|
40
|
+
### Manual Key Generation
|
|
41
|
+
|
|
42
|
+
If you prefer to generate keys manually, you can use OpenSSL:
|
|
43
|
+
|
|
44
|
+
#### RSA Keys
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Generate 4096-bit RSA private key
|
|
48
|
+
openssl genrsa -out private.pem 4096
|
|
49
|
+
|
|
50
|
+
# Extract public key from private key
|
|
51
|
+
openssl rsa -in private.pem -pubout -out public.pem
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Elliptic Curve Keys
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Generate EC private key (P-256 curve)
|
|
58
|
+
openssl ecparam -genkey -name prime256v1 -out private-ec.pem
|
|
59
|
+
|
|
60
|
+
# Extract public key
|
|
61
|
+
openssl ec -in private-ec.pem -pubout -out public-ec.pem
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Key Usage
|
|
65
|
+
|
|
66
|
+
### 1. Store Private Key Securely
|
|
67
|
+
|
|
68
|
+
The private key must be kept secure on your server:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Set restrictive permissions
|
|
72
|
+
chmod 600 private-*.pem
|
|
73
|
+
|
|
74
|
+
# Store in secure location
|
|
75
|
+
sudo mv private-*.pem /secure/keys/
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Security Tips:**
|
|
79
|
+
- Never commit private keys to version control
|
|
80
|
+
- Use environment variables or key management services
|
|
81
|
+
- Rotate keys periodically
|
|
82
|
+
- Keep backup copies in secure storage
|
|
83
|
+
|
|
84
|
+
### 2. Configure Public Key in App
|
|
85
|
+
|
|
86
|
+
Add the public key to your Capacitor configuration:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// capacitor.config.ts
|
|
90
|
+
import { CapacitorConfig } from '@capacitor/cli';
|
|
91
|
+
|
|
92
|
+
const config: CapacitorConfig = {
|
|
93
|
+
plugins: {
|
|
94
|
+
NativeUpdate: {
|
|
95
|
+
publicKey: 'YOUR_BASE64_PUBLIC_KEY_HERE',
|
|
96
|
+
// ... other config
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export default config;
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
To get the base64 version of your public key:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Convert public key to base64
|
|
108
|
+
cat public-*.pem | base64 -w 0 > public-key.b64
|
|
109
|
+
|
|
110
|
+
# On macOS
|
|
111
|
+
cat public-*.pem | base64 > public-key.b64
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Sign Bundles
|
|
115
|
+
|
|
116
|
+
Use the private key to sign update bundles:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Sign a bundle
|
|
120
|
+
npx native-update bundle sign ./bundle.zip --key /secure/keys/private.pem
|
|
121
|
+
|
|
122
|
+
# This creates a signature file alongside the bundle
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4. Verify Signatures
|
|
126
|
+
|
|
127
|
+
The plugin automatically verifies signatures using the configured public key. You can manually verify:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# Verify a signed bundle
|
|
131
|
+
npx native-update bundle verify ./bundle.zip --key ./public.pem
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Security Best Practices
|
|
135
|
+
|
|
136
|
+
### Key Storage
|
|
137
|
+
|
|
138
|
+
1. **Server Side (Private Key)**:
|
|
139
|
+
- Store in hardware security module (HSM) if possible
|
|
140
|
+
- Use encrypted storage
|
|
141
|
+
- Implement access controls
|
|
142
|
+
- Never expose via API or logs
|
|
143
|
+
|
|
144
|
+
2. **Client Side (Public Key)**:
|
|
145
|
+
- Embed in app configuration
|
|
146
|
+
- Can be safely distributed
|
|
147
|
+
- Consider certificate pinning for extra security
|
|
148
|
+
|
|
149
|
+
### Key Rotation
|
|
150
|
+
|
|
151
|
+
Implement a key rotation strategy:
|
|
152
|
+
|
|
153
|
+
1. Generate new key pair
|
|
154
|
+
2. Start signing new bundles with new key
|
|
155
|
+
3. Update app with both old and new public keys
|
|
156
|
+
4. Phase out old key after all users update
|
|
157
|
+
5. Remove old public key in future release
|
|
158
|
+
|
|
159
|
+
### Environment-Specific Keys
|
|
160
|
+
|
|
161
|
+
Use different keys for different environments:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
const config: CapacitorConfig = {
|
|
165
|
+
plugins: {
|
|
166
|
+
NativeUpdate: {
|
|
167
|
+
publicKey: process.env.NODE_ENV === 'production'
|
|
168
|
+
? 'PRODUCTION_PUBLIC_KEY_BASE64'
|
|
169
|
+
: 'STAGING_PUBLIC_KEY_BASE64',
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Implementation Details
|
|
176
|
+
|
|
177
|
+
### How Signing Works
|
|
178
|
+
|
|
179
|
+
1. **Bundle Creation**: Your web assets are packaged into a ZIP file
|
|
180
|
+
2. **Hash Generation**: SHA-256 hash of the bundle is calculated
|
|
181
|
+
3. **Signing**: Hash is signed with your private key using RSA-SHA256
|
|
182
|
+
4. **Distribution**: Bundle + signature are uploaded to your server
|
|
183
|
+
|
|
184
|
+
### How Verification Works
|
|
185
|
+
|
|
186
|
+
1. **Download**: App downloads bundle and signature
|
|
187
|
+
2. **Hash Calculation**: App calculates SHA-256 hash of downloaded bundle
|
|
188
|
+
3. **Signature Verification**: App uses public key to verify signature matches hash
|
|
189
|
+
4. **Installation**: Bundle is only installed if verification succeeds
|
|
190
|
+
|
|
191
|
+
### Signature Format
|
|
192
|
+
|
|
193
|
+
Signatures are base64-encoded for transport:
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"bundle": "bundle-1.0.1.zip",
|
|
198
|
+
"signature": "MEUCIQDp3...base64...==",
|
|
199
|
+
"algorithm": "RSA-SHA256",
|
|
200
|
+
"timestamp": "2024-01-20T10:30:00Z"
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Troubleshooting
|
|
205
|
+
|
|
206
|
+
### Common Issues
|
|
207
|
+
|
|
208
|
+
1. **"Signature verification failed"**
|
|
209
|
+
- Ensure public key in app matches private key used for signing
|
|
210
|
+
- Check bundle hasn't been modified after signing
|
|
211
|
+
- Verify base64 encoding is correct
|
|
212
|
+
|
|
213
|
+
2. **"Invalid key format"**
|
|
214
|
+
- Keys must be in PEM format
|
|
215
|
+
- Check for proper headers/footers in key files
|
|
216
|
+
- Ensure no extra whitespace or characters
|
|
217
|
+
|
|
218
|
+
3. **"Permission denied" when accessing keys**
|
|
219
|
+
- Set proper file permissions: `chmod 600 private-*.pem`
|
|
220
|
+
- Store in accessible location for your server process
|
|
221
|
+
|
|
222
|
+
### Testing Key Pairs
|
|
223
|
+
|
|
224
|
+
Test your keys are properly paired:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Create test message
|
|
228
|
+
echo "test message" > test.txt
|
|
229
|
+
|
|
230
|
+
# Sign with private key
|
|
231
|
+
openssl dgst -sha256 -sign private.pem -out test.sig test.txt
|
|
232
|
+
|
|
233
|
+
# Verify with public key
|
|
234
|
+
openssl dgst -sha256 -verify public.pem -signature test.sig test.txt
|
|
235
|
+
# Should output: "Verified OK"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Advanced Topics
|
|
239
|
+
|
|
240
|
+
### Hardware Security Modules (HSM)
|
|
241
|
+
|
|
242
|
+
For maximum security, use HSM for key storage:
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
// Example using AWS KMS
|
|
246
|
+
const AWS = require('aws-sdk');
|
|
247
|
+
const kms = new AWS.KMS();
|
|
248
|
+
|
|
249
|
+
async function signWithHSM(data) {
|
|
250
|
+
const params = {
|
|
251
|
+
KeyId: 'arn:aws:kms:...',
|
|
252
|
+
Message: data,
|
|
253
|
+
SigningAlgorithm: 'RSASSA_PKCS1_V1_5_SHA_256'
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
const result = await kms.sign(params).promise();
|
|
257
|
+
return result.Signature;
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Certificate Chains
|
|
262
|
+
|
|
263
|
+
For enterprise deployments, use certificate chains:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Create certificate chain
|
|
267
|
+
cat intermediate.crt root.crt > chain.pem
|
|
268
|
+
|
|
269
|
+
# Configure in app
|
|
270
|
+
{
|
|
271
|
+
"certificateChain": "base64_encoded_chain",
|
|
272
|
+
"publicKey": "base64_encoded_public_key"
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Next Steps
|
|
277
|
+
|
|
278
|
+
- Review [Security Best Practices](./security-best-practices.md)
|
|
279
|
+
- Implement [Bundle Signing](../BUNDLE_SIGNING.md)
|
|
280
|
+
- Set up [CI/CD Integration](../ci-cd-integration.md)
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
Made with ❤️ by Ahsan Mahmood
|
|
@@ -23,10 +23,14 @@ This guide helps you migrate from Microsoft CodePush to Capacitor Native Update.
|
|
|
23
23
|
First, you need to set up your own update server:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
#
|
|
27
|
-
|
|
26
|
+
# Create a backend using our templates
|
|
27
|
+
npx native-update backend create express --with-admin
|
|
28
|
+
# or for Firebase
|
|
29
|
+
npx native-update backend create firebase --with-monitoring
|
|
30
|
+
|
|
31
|
+
cd native-update-backend
|
|
28
32
|
npm install
|
|
29
|
-
npm
|
|
33
|
+
npm run dev
|
|
30
34
|
```
|
|
31
35
|
|
|
32
36
|
### 2. Update Your App Code
|
|
@@ -88,8 +92,8 @@ Replace release process:
|
|
|
88
92
|
code-push release-react MyApp ios -d Production
|
|
89
93
|
|
|
90
94
|
# New (Capacitor Native Update)
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
npx native-update bundle create ./www
|
|
96
|
+
npx native-update bundle sign bundle.zip --key private-key.pem
|
|
93
97
|
# Upload to your server
|
|
94
98
|
```
|
|
95
99
|
|
|
@@ -120,7 +120,7 @@ try {
|
|
|
120
120
|
#### Signature Verification
|
|
121
121
|
```bash
|
|
122
122
|
# Create signed bundle
|
|
123
|
-
|
|
123
|
+
npx native-update bundle sign test-bundle.zip --key private-key.pem
|
|
124
124
|
|
|
125
125
|
# Verify in app
|
|
126
126
|
const isValid = await NativeUpdate.validateUpdate({
|
|
@@ -153,10 +153,10 @@ NativeUpdate.addListener('downloadProgress', (progress) => {
|
|
|
153
153
|
1. **Prepare Test Bundle**
|
|
154
154
|
```bash
|
|
155
155
|
# Create bundle
|
|
156
|
-
|
|
156
|
+
npx native-update bundle create ./www
|
|
157
157
|
|
|
158
158
|
# Sign bundle
|
|
159
|
-
|
|
159
|
+
npx native-update bundle sign bundle.zip --key private-key.pem
|
|
160
160
|
|
|
161
161
|
# Upload to server
|
|
162
162
|
curl -X POST http://localhost:3000/api/updates/upload/update-id \
|
|
@@ -299,7 +299,7 @@ jobs:
|
|
|
299
299
|
### Bundle Testing
|
|
300
300
|
```bash
|
|
301
301
|
# Create test bundle
|
|
302
|
-
|
|
302
|
+
npx native-update bundle create ./test-www
|
|
303
303
|
|
|
304
304
|
# Verify bundle
|
|
305
305
|
unzip -t test-bundle.zip
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "native-update",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Foundation package for building a comprehensive update system for Capacitor apps. Provides architecture and interfaces but requires backend implementation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|
|
7
7
|
"module": "dist/esm/index.js",
|
|
8
8
|
"types": "dist/esm/index.d.ts",
|
|
9
9
|
"unpkg": "dist/plugin.js",
|
|
10
|
+
"bin": {
|
|
11
|
+
"native-update": "./cli/index.js"
|
|
12
|
+
},
|
|
10
13
|
"files": [
|
|
11
14
|
"android/src/main/",
|
|
12
15
|
"android/build.gradle",
|
|
@@ -18,7 +21,9 @@
|
|
|
18
21
|
"dist/",
|
|
19
22
|
"ios/Plugin/",
|
|
20
23
|
"NativeUpdate.podspec",
|
|
21
|
-
"docs/"
|
|
24
|
+
"docs/",
|
|
25
|
+
"cli/",
|
|
26
|
+
"templates/"
|
|
22
27
|
],
|
|
23
28
|
"author": {
|
|
24
29
|
"name": "Ahsan Mahmood",
|
|
@@ -55,6 +60,14 @@
|
|
|
55
60
|
"test:ui": "vitest --ui",
|
|
56
61
|
"test:coverage": "vitest --coverage"
|
|
57
62
|
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"archiver": "^7.0.1",
|
|
65
|
+
"chalk": "^5.6.0",
|
|
66
|
+
"commander": "^14.0.0",
|
|
67
|
+
"express": "^5.1.0",
|
|
68
|
+
"ora": "^8.2.0",
|
|
69
|
+
"prompts": "^2.4.2"
|
|
70
|
+
},
|
|
58
71
|
"devDependencies": {
|
|
59
72
|
"@capacitor/android": "^7.4.2",
|
|
60
73
|
"@capacitor/core": "^7.4.2",
|