native-update 1.2.0 → 1.3.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 +36 -22
- package/docs/CHANGELOG.md +168 -0
- package/docs/EXAMPLE_APPS_SIMPLIFICATION_PLAN.md +384 -0
- package/docs/EXAMPLE_APPS_SIMPLIFICATION_TRACKER.md +390 -0
- package/docs/MARKETING_WEBSITE_PLAN.md +659 -0
- package/docs/MARKETING_WEBSITE_TRACKER.md +661 -0
- package/docs/ROADMAP.md +143 -0
- package/docs/SECURITY.md +356 -0
- package/docs/api/API.md +557 -0
- package/docs/api/FEATURES.md +414 -0
- package/docs/guides/key-management.md +1 -1
- package/docs/plans/PLANNING_COMPLETE_SUMMARY.md +361 -0
- package/docs/plans/TASK_1_ANDROID_EXAMPLE_APP.md +401 -0
- package/docs/plans/TASK_2_API_ENDPOINTS.md +856 -0
- package/docs/plans/TASK_2_DASHBOARD_UI_UX.md +820 -0
- package/docs/plans/TASK_2_DATABASE_SCHEMA.md +704 -0
- package/docs/plans/TASK_2_GOOGLE_DRIVE_INTEGRATION.md +646 -0
- package/docs/plans/TASK_2_SAAS_ARCHITECTURE.md +587 -0
- package/docs/plans/TASK_2_USER_AUTHENTICATION.md +600 -0
- package/docs/reports/AUDIT_SUMMARY_2025-12-26.md +203 -0
- package/docs/reports/COMPLETE_VERIFICATION.md +106 -0
- package/docs/reports/EVENT_FLOW_VERIFICATION.md +80 -0
- package/docs/reports/EXAMPLE_APPS_SIMPLIFICATION_COMPLETE.md +369 -0
- package/docs/reports/FINAL_STATUS.md +122 -0
- package/docs/reports/FINAL_VERIFICATION_CHECKLIST.md +425 -0
- package/docs/reports/MARKETING_WEBSITE_COMPLETE.md +466 -0
- package/docs/reports/PACKAGE_COMPLETENESS_REPORT.md +130 -0
- package/docs/reports/PRODUCTION_STATUS.md +115 -0
- package/docs/reports/PROJECT_RESTRUCTURE_2025-12-27.md +287 -0
- package/docs/reports/PROJECT_RESTRUCTURE_FINAL_SUMMARY.md +464 -0
- package/docs/reports/PUBLISHING_VERIFICATION.md +144 -0
- package/docs/reports/RELEASE_READY_SUMMARY.md +99 -0
- package/docs/tracking/IMPLEMENTATION_TRACKER.md +303 -0
- package/package.json +2 -3
- package/backend-template/README.md +0 -56
- package/backend-template/package.json +0 -20
- package/backend-template/server.js +0 -121
package/docs/api/API.md
ADDED
|
@@ -0,0 +1,557 @@
|
|
|
1
|
+
# Native Update - API Reference
|
|
2
|
+
|
|
3
|
+
This document provides a complete API reference for the Native Update plugin.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Configuration](#configuration)
|
|
8
|
+
- [Live Update API](#live-update-api)
|
|
9
|
+
- [App Update API](#app-update-api)
|
|
10
|
+
- [App Review API](#app-review-api)
|
|
11
|
+
- [Security API](#security-api)
|
|
12
|
+
- [Types and Interfaces](#types-and-interfaces)
|
|
13
|
+
- [Error Codes](#error-codes)
|
|
14
|
+
- [Security Best Practices](#security-best-practices)
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
### configure(config: UpdateConfig): Promise<void>
|
|
19
|
+
|
|
20
|
+
Configure the plugin with your settings.
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
await NativeUpdate.configure({
|
|
24
|
+
liveUpdate: {
|
|
25
|
+
appId: 'your-app-id',
|
|
26
|
+
serverUrl: 'https://your-update-server.com', // HTTPS required
|
|
27
|
+
channel: 'production',
|
|
28
|
+
autoUpdate: true,
|
|
29
|
+
publicKey: 'your-public-key', // For signature verification
|
|
30
|
+
requireSignature: true, // Enforce signature verification
|
|
31
|
+
maxBundleSize: 50 * 1024 * 1024, // 50MB limit
|
|
32
|
+
checksumAlgorithm: 'SHA-256', // Required checksum validation
|
|
33
|
+
},
|
|
34
|
+
appUpdate: {
|
|
35
|
+
minimumVersion: '1.0.0',
|
|
36
|
+
updatePriority: 3,
|
|
37
|
+
allowDowngrade: false, // Prevent version downgrade attacks
|
|
38
|
+
},
|
|
39
|
+
appReview: {
|
|
40
|
+
minimumDaysSinceInstall: 7,
|
|
41
|
+
minimumLaunchCount: 3,
|
|
42
|
+
},
|
|
43
|
+
security: {
|
|
44
|
+
enforceHttps: true,
|
|
45
|
+
certificatePinning: {
|
|
46
|
+
enabled: true,
|
|
47
|
+
certificates: ['sha256/...'], // Pin update server certificates
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Live Update API
|
|
54
|
+
|
|
55
|
+
### sync(options?: SyncOptions): Promise<SyncResult>
|
|
56
|
+
|
|
57
|
+
Synchronize with the update server and apply updates if available.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const result = await NativeUpdate.sync({
|
|
61
|
+
channel: 'production',
|
|
62
|
+
updateMode: 'background',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
console.log(result.status); // 'UP_TO_DATE' | 'UPDATE_AVAILABLE' | 'UPDATE_INSTALLED' | 'ERROR'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### download(options: DownloadOptions): Promise<BundleInfo>
|
|
69
|
+
|
|
70
|
+
Download a specific bundle version.
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const bundle = await NativeUpdate.download({
|
|
74
|
+
url: 'https://updates.example.com/bundle-v2.0.0.zip', // HTTPS enforced
|
|
75
|
+
version: '2.0.0',
|
|
76
|
+
checksum: 'sha256:...', // Required for integrity verification
|
|
77
|
+
signature: 'base64...', // Required if signature verification enabled
|
|
78
|
+
maxRetries: 3,
|
|
79
|
+
timeout: 30000, // 30 second timeout
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### set(bundle: BundleInfo): Promise<void>
|
|
84
|
+
|
|
85
|
+
Set the active bundle to a specific downloaded version.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
await NativeUpdate.set({
|
|
89
|
+
bundleId: 'bundle-123',
|
|
90
|
+
version: '2.0.0',
|
|
91
|
+
path: '/path/to/bundle',
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### reload(): Promise<void>
|
|
96
|
+
|
|
97
|
+
Reload the app with the currently active bundle.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
await NativeUpdate.reload();
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### reset(): Promise<void>
|
|
104
|
+
|
|
105
|
+
Reset to the original bundle shipped with the app.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
await NativeUpdate.reset();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### current(): Promise<BundleInfo>
|
|
112
|
+
|
|
113
|
+
Get information about the currently active bundle.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const currentBundle = await NativeUpdate.current();
|
|
117
|
+
console.log(currentBundle.version);
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### list(): Promise<BundleInfo[]>
|
|
121
|
+
|
|
122
|
+
List all downloaded bundles.
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const bundles = await NativeUpdate.list();
|
|
126
|
+
bundles.forEach((bundle) => {
|
|
127
|
+
console.log(`${bundle.version} - ${bundle.downloadTime}`);
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### delete(options: DeleteOptions): Promise<void>
|
|
132
|
+
|
|
133
|
+
Delete a specific bundle or clean up old bundles.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Delete specific bundle
|
|
137
|
+
await NativeUpdate.delete({ bundleId: 'bundle-123' });
|
|
138
|
+
|
|
139
|
+
// Clean up old bundles
|
|
140
|
+
await NativeUpdate.delete({
|
|
141
|
+
keepVersions: 2,
|
|
142
|
+
olderThan: Date.now() - 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### notifyAppReady(): Promise<void>
|
|
147
|
+
|
|
148
|
+
Notify that the app has successfully started with the new bundle.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// Call this after your app has successfully initialized
|
|
152
|
+
await NativeUpdate.notifyAppReady();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### getLatest(): Promise<LatestVersion>
|
|
156
|
+
|
|
157
|
+
Check for the latest available version without downloading.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
const latest = await NativeUpdate.getLatest();
|
|
161
|
+
if (latest.available) {
|
|
162
|
+
console.log(`New version ${latest.version} available`);
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### setChannel(channel: string): Promise<void>
|
|
167
|
+
|
|
168
|
+
Switch to a different update channel.
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
await NativeUpdate.setChannel('beta');
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### setUpdateUrl(url: string): Promise<void>
|
|
175
|
+
|
|
176
|
+
Change the update server URL.
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
await NativeUpdate.setUpdateUrl('https://new-server.com/updates');
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## App Update API
|
|
183
|
+
|
|
184
|
+
### getAppUpdateInfo(): Promise<AppUpdateInfo>
|
|
185
|
+
|
|
186
|
+
Check for native app updates in the app store.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const updateInfo = await NativeUpdate.getAppUpdateInfo();
|
|
190
|
+
if (updateInfo.updateAvailable) {
|
|
191
|
+
console.log(`Version ${updateInfo.availableVersion} is available`);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### performImmediateUpdate(): Promise<void>
|
|
196
|
+
|
|
197
|
+
Start an immediate (blocking) update from the app store.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
try {
|
|
201
|
+
await NativeUpdate.performImmediateUpdate();
|
|
202
|
+
// App will restart after update
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (error.code === 'UPDATE_CANCELLED') {
|
|
205
|
+
// User cancelled the update
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### startFlexibleUpdate(): Promise<void>
|
|
211
|
+
|
|
212
|
+
Start a flexible (background) update from the app store.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
await NativeUpdate.startFlexibleUpdate();
|
|
216
|
+
// Update downloads in background
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### completeFlexibleUpdate(): Promise<void>
|
|
220
|
+
|
|
221
|
+
Complete a flexible update that has finished downloading.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
await NativeUpdate.completeFlexibleUpdate();
|
|
225
|
+
// App will restart
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### openAppStore(options?: OpenAppStoreOptions): Promise<void>
|
|
229
|
+
|
|
230
|
+
Open the app store page for the app.
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
await NativeUpdate.openAppStore({
|
|
234
|
+
appId: 'com.example.app', // Optional, uses current app ID if not provided
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## App Review API
|
|
239
|
+
|
|
240
|
+
### requestReview(): Promise<ReviewResult>
|
|
241
|
+
|
|
242
|
+
Request an in-app review from the user.
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const result = await NativeUpdate.requestReview();
|
|
246
|
+
if (result.shown) {
|
|
247
|
+
console.log('Review dialog was shown');
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### canRequestReview(): Promise<CanRequestReviewResult>
|
|
252
|
+
|
|
253
|
+
Check if it's appropriate to request a review.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
const canRequest = await NativeUpdate.canRequestReview();
|
|
257
|
+
if (canRequest.allowed) {
|
|
258
|
+
await NativeUpdate.requestReview();
|
|
259
|
+
} else {
|
|
260
|
+
console.log(`Cannot request: ${canRequest.reason}`);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Types and Interfaces
|
|
265
|
+
|
|
266
|
+
### UpdateConfig
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
interface UpdateConfig {
|
|
270
|
+
liveUpdate?: LiveUpdateConfig;
|
|
271
|
+
appUpdate?: AppUpdateConfig;
|
|
272
|
+
appReview?: AppReviewConfig;
|
|
273
|
+
security?: SecurityConfig;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
interface LiveUpdateConfig {
|
|
277
|
+
appId: string;
|
|
278
|
+
serverUrl: string; // Must be HTTPS
|
|
279
|
+
channel?: string;
|
|
280
|
+
autoUpdate?: boolean;
|
|
281
|
+
updateStrategy?: 'immediate' | 'background' | 'manual';
|
|
282
|
+
publicKey?: string; // Base64 encoded public key for signature verification
|
|
283
|
+
requireSignature?: boolean; // Default: true
|
|
284
|
+
checksumAlgorithm?: 'SHA-256' | 'SHA-512'; // Default: 'SHA-256'
|
|
285
|
+
checkInterval?: number;
|
|
286
|
+
allowEmulator?: boolean; // Default: false for production
|
|
287
|
+
mandatoryInstallMode?: InstallMode;
|
|
288
|
+
optionalInstallMode?: InstallMode;
|
|
289
|
+
maxBundleSize?: number; // Maximum allowed bundle size in bytes
|
|
290
|
+
allowedHosts?: string[]; // Whitelist of allowed update servers
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
interface AppUpdateConfig {
|
|
294
|
+
minimumVersion?: string;
|
|
295
|
+
updatePriority?: number;
|
|
296
|
+
storeUrl?: {
|
|
297
|
+
android?: string;
|
|
298
|
+
ios?: string;
|
|
299
|
+
};
|
|
300
|
+
checkOnAppStart?: boolean;
|
|
301
|
+
allowDowngrade?: boolean; // Default: false
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
interface AppReviewConfig {
|
|
305
|
+
minimumDaysSinceInstall?: number;
|
|
306
|
+
minimumDaysSinceLastPrompt?: number;
|
|
307
|
+
minimumLaunchCount?: number;
|
|
308
|
+
customTriggers?: string[];
|
|
309
|
+
|
|
310
|
+
interface SecurityConfig {
|
|
311
|
+
enforceHttps?: boolean; // Default: true
|
|
312
|
+
certificatePinning?: {
|
|
313
|
+
enabled: boolean;
|
|
314
|
+
certificates: string[]; // SHA256 fingerprints
|
|
315
|
+
includeSubdomains?: boolean;
|
|
316
|
+
maxAge?: number; // Pin duration in seconds
|
|
317
|
+
};
|
|
318
|
+
validateInputs?: boolean; // Default: true
|
|
319
|
+
secureStorage?: boolean; // Default: true
|
|
320
|
+
logSecurityEvents?: boolean; // Default: true in debug
|
|
321
|
+
}
|
|
322
|
+
debugMode?: boolean;
|
|
323
|
+
}
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### SyncResult
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
interface SyncResult {
|
|
330
|
+
status: 'UP_TO_DATE' | 'UPDATE_AVAILABLE' | 'UPDATE_INSTALLED' | 'ERROR';
|
|
331
|
+
version?: string;
|
|
332
|
+
description?: string;
|
|
333
|
+
mandatory?: boolean;
|
|
334
|
+
error?: UpdateError;
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### BundleInfo
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
interface BundleInfo {
|
|
342
|
+
bundleId: string;
|
|
343
|
+
version: string;
|
|
344
|
+
path: string; // Sanitized path within app sandbox
|
|
345
|
+
downloadTime: number;
|
|
346
|
+
size: number;
|
|
347
|
+
status: 'PENDING' | 'DOWNLOADING' | 'READY' | 'ACTIVE' | 'FAILED';
|
|
348
|
+
checksum: string; // SHA-256 checksum of the bundle
|
|
349
|
+
signature?: string; // Digital signature if available
|
|
350
|
+
verified: boolean; // Indicates if bundle passed all security checks
|
|
351
|
+
metadata?: Record<string, any>;
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### AppUpdateInfo
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
interface AppUpdateInfo {
|
|
359
|
+
updateAvailable: boolean;
|
|
360
|
+
currentVersion: string;
|
|
361
|
+
availableVersion?: string;
|
|
362
|
+
updatePriority?: number;
|
|
363
|
+
immediateUpdateAllowed?: boolean;
|
|
364
|
+
flexibleUpdateAllowed?: boolean;
|
|
365
|
+
clientVersionStalenessDays?: number;
|
|
366
|
+
installStatus?: InstallStatus;
|
|
367
|
+
bytesDownloaded?: number;
|
|
368
|
+
totalBytesToDownload?: number;
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### ReviewResult
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
interface ReviewResult {
|
|
376
|
+
shown: boolean;
|
|
377
|
+
error?: string;
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Error Codes
|
|
382
|
+
|
|
383
|
+
The plugin uses standard error codes for different failure scenarios:
|
|
384
|
+
|
|
385
|
+
### Live Update Errors
|
|
386
|
+
|
|
387
|
+
- `NETWORK_ERROR` - Network connection failed
|
|
388
|
+
- `SERVER_ERROR` - Update server returned an error
|
|
389
|
+
- `DOWNLOAD_ERROR` - Bundle download failed
|
|
390
|
+
- `VERIFICATION_ERROR` - Bundle signature verification failed
|
|
391
|
+
- `CHECKSUM_ERROR` - Bundle checksum validation failed
|
|
392
|
+
- `STORAGE_ERROR` - Insufficient storage or write error
|
|
393
|
+
- `INSTALL_ERROR` - Bundle installation failed
|
|
394
|
+
- `ROLLBACK_ERROR` - Rollback operation failed
|
|
395
|
+
- `INSECURE_URL` - Attempted to use non-HTTPS URL
|
|
396
|
+
- `INVALID_CERTIFICATE` - Certificate pinning validation failed
|
|
397
|
+
- `SIZE_LIMIT_EXCEEDED` - Bundle exceeds maximum allowed size
|
|
398
|
+
- `PERMISSION_DENIED` - Required permission not granted
|
|
399
|
+
- `PATH_TRAVERSAL` - Attempted directory traversal detected
|
|
400
|
+
|
|
401
|
+
### App Update Errors
|
|
402
|
+
|
|
403
|
+
- `UPDATE_NOT_AVAILABLE` - No update available in app store
|
|
404
|
+
- `UPDATE_IN_PROGRESS` - Another update is already in progress
|
|
405
|
+
- `UPDATE_CANCELLED` - User cancelled the update
|
|
406
|
+
- `PLATFORM_NOT_SUPPORTED` - Feature not supported on this platform
|
|
407
|
+
|
|
408
|
+
### App Review Errors
|
|
409
|
+
|
|
410
|
+
- `REVIEW_NOT_SUPPORTED` - In-app reviews not supported
|
|
411
|
+
- `QUOTA_EXCEEDED` - Review request quota exceeded
|
|
412
|
+
- `CONDITIONS_NOT_MET` - Review conditions not satisfied
|
|
413
|
+
|
|
414
|
+
## Events
|
|
415
|
+
|
|
416
|
+
The plugin emits events for update progress and state changes:
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
// Listen for download progress
|
|
420
|
+
NativeUpdate.addListener('downloadProgress', (progress) => {
|
|
421
|
+
console.log(`Downloaded ${progress.percent}%`);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Listen for update state changes
|
|
425
|
+
NativeUpdate.addListener('updateStateChanged', (state) => {
|
|
426
|
+
console.log(`Update state: ${state.status}`);
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// Remove listeners when done
|
|
430
|
+
NativeUpdate.removeAllListeners();
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## Security API
|
|
434
|
+
|
|
435
|
+
### validateUpdate(options: ValidateOptions): Promise<ValidationResult>
|
|
436
|
+
|
|
437
|
+
Validate an update bundle before installation.
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
const validation = await NativeUpdate.validateUpdate({
|
|
441
|
+
bundlePath: '/path/to/bundle',
|
|
442
|
+
checksum: 'sha256:...',
|
|
443
|
+
signature: 'base64...',
|
|
444
|
+
maxSize: 50 * 1024 * 1024,
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
if (!validation.isValid) {
|
|
448
|
+
console.error(`Validation failed: ${validation.error}`);
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### getSecurityInfo(): Promise<SecurityInfo>
|
|
453
|
+
|
|
454
|
+
Get current security configuration and status.
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
const security = await NativeUpdate.getSecurityInfo();
|
|
458
|
+
console.log(`HTTPS enforced: ${security.enforceHttps}`);
|
|
459
|
+
console.log(`Certificate pinning: ${security.certificatePinning.enabled}`);
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
## Platform-Specific Notes
|
|
463
|
+
|
|
464
|
+
### iOS
|
|
465
|
+
|
|
466
|
+
- App updates require manual version checking against iTunes API
|
|
467
|
+
- In-app reviews use StoreKit framework
|
|
468
|
+
- Maximum 3 review requests per year per user
|
|
469
|
+
- Uses Keychain Services for secure storage
|
|
470
|
+
- File operations validated within app sandbox
|
|
471
|
+
|
|
472
|
+
### Android
|
|
473
|
+
|
|
474
|
+
- App updates use Google Play Core Library
|
|
475
|
+
- Requires Play Store app to be installed
|
|
476
|
+
- In-app reviews use Play Core Review API
|
|
477
|
+
- Uses Android Keystore for secure storage
|
|
478
|
+
- Runtime permissions required for storage access
|
|
479
|
+
|
|
480
|
+
### Web
|
|
481
|
+
|
|
482
|
+
- Live updates work through service worker updates
|
|
483
|
+
- App updates and reviews show fallback UI
|
|
484
|
+
- Limited functionality compared to native platforms
|
|
485
|
+
- Uses Web Crypto API for security features
|
|
486
|
+
|
|
487
|
+
## Security Best Practices
|
|
488
|
+
|
|
489
|
+
### Secure Configuration Example
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
// Recommended security configuration
|
|
493
|
+
await NativeUpdate.configure({
|
|
494
|
+
liveUpdate: {
|
|
495
|
+
appId: 'your-app-id',
|
|
496
|
+
serverUrl: 'https://updates.example.com', // Always use HTTPS
|
|
497
|
+
publicKey: process.env.UPDATE_PUBLIC_KEY, // Never hardcode keys
|
|
498
|
+
requireSignature: true,
|
|
499
|
+
checksumAlgorithm: 'SHA-256',
|
|
500
|
+
maxBundleSize: 50 * 1024 * 1024,
|
|
501
|
+
allowedHosts: ['updates.example.com'], // Whitelist update servers
|
|
502
|
+
allowEmulator: false, // Disable in production
|
|
503
|
+
},
|
|
504
|
+
security: {
|
|
505
|
+
enforceHttps: true,
|
|
506
|
+
certificatePinning: {
|
|
507
|
+
enabled: true,
|
|
508
|
+
certificates: [process.env.UPDATE_CERT_PIN],
|
|
509
|
+
},
|
|
510
|
+
validateInputs: true,
|
|
511
|
+
secureStorage: true,
|
|
512
|
+
},
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Input Validation
|
|
517
|
+
|
|
518
|
+
Always validate user inputs and options:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
// Good: Validate before use
|
|
522
|
+
try {
|
|
523
|
+
if (!isValidUrl(updateUrl) || !updateUrl.startsWith('https://')) {
|
|
524
|
+
throw new Error('Invalid update URL');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
await NativeUpdate.download({
|
|
528
|
+
url: updateUrl,
|
|
529
|
+
checksum: checksum,
|
|
530
|
+
signature: signature,
|
|
531
|
+
});
|
|
532
|
+
} catch (error) {
|
|
533
|
+
// Handle validation error
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Error Handling
|
|
538
|
+
|
|
539
|
+
Handle errors without exposing sensitive information:
|
|
540
|
+
|
|
541
|
+
````typescript
|
|
542
|
+
try {
|
|
543
|
+
await NativeUpdate.sync();
|
|
544
|
+
} catch (error) {
|
|
545
|
+
// Don't expose internal paths or server details
|
|
546
|
+
if (error.code === 'VERIFICATION_ERROR') {
|
|
547
|
+
console.error('Update verification failed');
|
|
548
|
+
// Log detailed error internally, show generic message to user
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
```## Support
|
|
552
|
+
|
|
553
|
+
For questions, issues, or contributions:
|
|
554
|
+
- Email: aoneahsan@gmail.com
|
|
555
|
+
- GitHub Issues: [https://github.com/aoneahsan/native-update/issues](https://github.com/aoneahsan/native-update/issues)
|
|
556
|
+
- Author: Ahsan Mahmood ([Portfolio](https://aoneahsan.com))
|
|
557
|
+
````
|