native-update 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/CapacitorNativeUpdate.podspec +18 -0
- package/LICENSE +21 -0
- package/Readme.md +451 -0
- package/android/build.gradle +92 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
- package/android/gradle.properties +17 -0
- package/android/proguard-rules.pro +29 -0
- package/android/settings.gradle +2 -0
- package/android/src/main/AndroidManifest.xml +34 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
- package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
- package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/bundle-manager.test.js +123 -0
- package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
- package/dist/esm/__tests__/config.test.d.ts +1 -0
- package/dist/esm/__tests__/config.test.js +69 -0
- package/dist/esm/__tests__/config.test.js.map +1 -0
- package/dist/esm/__tests__/integration.test.d.ts +1 -0
- package/dist/esm/__tests__/integration.test.js +78 -0
- package/dist/esm/__tests__/integration.test.js.map +1 -0
- package/dist/esm/__tests__/security.test.d.ts +1 -0
- package/dist/esm/__tests__/security.test.js +54 -0
- package/dist/esm/__tests__/security.test.js.map +1 -0
- package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
- package/dist/esm/__tests__/version-manager.test.js +45 -0
- package/dist/esm/__tests__/version-manager.test.js.map +1 -0
- package/dist/esm/app-review/app-review-manager.d.ts +24 -0
- package/dist/esm/app-review/app-review-manager.js +195 -0
- package/dist/esm/app-review/app-review-manager.js.map +1 -0
- package/dist/esm/app-review/index.d.ts +5 -0
- package/dist/esm/app-review/index.js +6 -0
- package/dist/esm/app-review/index.js.map +1 -0
- package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
- package/dist/esm/app-review/platform-review-handler.js +138 -0
- package/dist/esm/app-review/platform-review-handler.js.map +1 -0
- package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
- package/dist/esm/app-review/review-conditions-checker.js +155 -0
- package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
- package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
- package/dist/esm/app-review/review-rate-limiter.js +164 -0
- package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
- package/dist/esm/app-review/types.d.ts +41 -0
- package/dist/esm/app-review/types.js +2 -0
- package/dist/esm/app-review/types.js.map +1 -0
- package/dist/esm/app-update/app-update-checker.d.ts +13 -0
- package/dist/esm/app-update/app-update-checker.js +104 -0
- package/dist/esm/app-update/app-update-checker.js.map +1 -0
- package/dist/esm/app-update/app-update-installer.d.ts +19 -0
- package/dist/esm/app-update/app-update-installer.js +123 -0
- package/dist/esm/app-update/app-update-installer.js.map +1 -0
- package/dist/esm/app-update/app-update-manager.d.ts +28 -0
- package/dist/esm/app-update/app-update-manager.js +199 -0
- package/dist/esm/app-update/app-update-manager.js.map +1 -0
- package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
- package/dist/esm/app-update/app-update-notifier.js +100 -0
- package/dist/esm/app-update/app-update-notifier.js.map +1 -0
- package/dist/esm/app-update/index.d.ts +6 -0
- package/dist/esm/app-update/index.js +7 -0
- package/dist/esm/app-update/index.js.map +1 -0
- package/dist/esm/app-update/platform-app-update.d.ts +19 -0
- package/dist/esm/app-update/platform-app-update.js +129 -0
- package/dist/esm/app-update/platform-app-update.js.map +1 -0
- package/dist/esm/app-update/types.d.ts +58 -0
- package/dist/esm/app-update/types.js +12 -0
- package/dist/esm/app-update/types.js.map +1 -0
- package/dist/esm/background-update/background-scheduler.d.ts +17 -0
- package/dist/esm/background-update/background-scheduler.js +195 -0
- package/dist/esm/background-update/background-scheduler.js.map +1 -0
- package/dist/esm/background-update/index.d.ts +3 -0
- package/dist/esm/background-update/index.js +3 -0
- package/dist/esm/background-update/index.js.map +1 -0
- package/dist/esm/background-update/notification-manager.d.ts +29 -0
- package/dist/esm/background-update/notification-manager.js +89 -0
- package/dist/esm/background-update/notification-manager.js.map +1 -0
- package/dist/esm/core/analytics.d.ts +70 -0
- package/dist/esm/core/analytics.js +137 -0
- package/dist/esm/core/analytics.js.map +1 -0
- package/dist/esm/core/cache-manager.d.ts +72 -0
- package/dist/esm/core/cache-manager.js +275 -0
- package/dist/esm/core/cache-manager.js.map +1 -0
- package/dist/esm/core/config.d.ts +48 -0
- package/dist/esm/core/config.js +83 -0
- package/dist/esm/core/config.js.map +1 -0
- package/dist/esm/core/errors.d.ts +51 -0
- package/dist/esm/core/errors.js +80 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/logger.d.ts +21 -0
- package/dist/esm/core/logger.js +109 -0
- package/dist/esm/core/logger.js.map +1 -0
- package/dist/esm/core/performance.d.ts +53 -0
- package/dist/esm/core/performance.js +140 -0
- package/dist/esm/core/performance.js.map +1 -0
- package/dist/esm/core/plugin-manager.d.ts +66 -0
- package/dist/esm/core/plugin-manager.js +148 -0
- package/dist/esm/core/plugin-manager.js.map +1 -0
- package/dist/esm/core/security.d.ts +93 -0
- package/dist/esm/core/security.js +315 -0
- package/dist/esm/core/security.js.map +1 -0
- package/dist/esm/definitions.d.ts +639 -0
- package/dist/esm/definitions.js +103 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +12 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/live-update/bundle-manager.d.ts +94 -0
- package/dist/esm/live-update/bundle-manager.js +310 -0
- package/dist/esm/live-update/bundle-manager.js.map +1 -0
- package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
- package/dist/esm/live-update/certificate-pinning.js +78 -0
- package/dist/esm/live-update/certificate-pinning.js.map +1 -0
- package/dist/esm/live-update/download-manager.d.ts +67 -0
- package/dist/esm/live-update/download-manager.js +319 -0
- package/dist/esm/live-update/download-manager.js.map +1 -0
- package/dist/esm/live-update/update-manager.d.ts +52 -0
- package/dist/esm/live-update/update-manager.js +294 -0
- package/dist/esm/live-update/update-manager.js.map +1 -0
- package/dist/esm/live-update/version-manager.d.ts +84 -0
- package/dist/esm/live-update/version-manager.js +335 -0
- package/dist/esm/live-update/version-manager.js.map +1 -0
- package/dist/esm/plugin.d.ts +6 -0
- package/dist/esm/plugin.js +283 -0
- package/dist/esm/plugin.js.map +1 -0
- package/dist/esm/security/crypto.d.ts +25 -0
- package/dist/esm/security/crypto.js +70 -0
- package/dist/esm/security/crypto.js.map +1 -0
- package/dist/esm/security/validator.d.ts +60 -0
- package/dist/esm/security/validator.js +143 -0
- package/dist/esm/security/validator.js.map +1 -0
- package/dist/esm/web.d.ts +74 -0
- package/dist/esm/web.js +595 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +2 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.esm.js +2 -0
- package/dist/plugin.esm.js.map +1 -0
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -0
- package/docs/APP_REVIEW_GUIDE.md +768 -0
- package/docs/BUNDLE_SIGNING.md +264 -0
- package/docs/LIVE_UPDATES_GUIDE.md +650 -0
- package/docs/MIGRATION.md +192 -0
- package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
- package/docs/QUICK_START.md +606 -0
- package/docs/README.md +111 -0
- package/docs/REMAINING_FEATURES.md +139 -0
- package/docs/api/app-review-api.md +259 -0
- package/docs/api/app-update-api.md +238 -0
- package/docs/api/events-api.md +451 -0
- package/docs/api/live-update-api.md +265 -0
- package/docs/background-updates.md +392 -0
- package/docs/examples/advanced-scenarios.md +410 -0
- package/docs/examples/basic-usage.md +185 -0
- package/docs/features/app-reviews.md +975 -0
- package/docs/features/app-updates.md +785 -0
- package/docs/features/live-updates.md +633 -0
- package/docs/getting-started/configuration.md +468 -0
- package/docs/getting-started/installation.md +209 -0
- package/docs/getting-started/quick-start.md +379 -0
- package/docs/guides/deployment-guide.md +333 -0
- package/docs/guides/migration-from-codepush.md +142 -0
- package/docs/guides/security-best-practices.md +1057 -0
- package/docs/guides/testing-guide.md +373 -0
- package/docs/production-readiness.md +478 -0
- package/docs/security/certificate-pinning.md +122 -0
- package/docs/server-requirements.md +147 -0
- package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
- package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
- package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
- package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
- package/ios/Plugin/Info.plist +43 -0
- package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
- package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
- package/ios/Plugin/Security/SecurityManager.swift +289 -0
- package/package.json +90 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Certificate pinning utilities
|
|
3
|
+
*/
|
|
4
|
+
export class CertificatePinning {
|
|
5
|
+
/**
|
|
6
|
+
* Generate SHA-256 fingerprint from certificate
|
|
7
|
+
* Note: This is a utility for generating pins, not for runtime validation
|
|
8
|
+
*/
|
|
9
|
+
static async generateFingerprint(certificatePem) {
|
|
10
|
+
// Remove PEM headers and convert to binary
|
|
11
|
+
const base64 = certificatePem
|
|
12
|
+
.replace(/-----BEGIN CERTIFICATE-----/g, '')
|
|
13
|
+
.replace(/-----END CERTIFICATE-----/g, '')
|
|
14
|
+
.replace(/\s/g, '');
|
|
15
|
+
const binaryString = atob(base64);
|
|
16
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
17
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
18
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
19
|
+
}
|
|
20
|
+
// Calculate SHA-256
|
|
21
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes);
|
|
22
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
23
|
+
const hashBase64 = btoa(String.fromCharCode(...hashArray));
|
|
24
|
+
return `sha256/${hashBase64}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Validate certificate pinning configuration
|
|
28
|
+
*/
|
|
29
|
+
static validateConfig(config) {
|
|
30
|
+
if (!config || typeof config !== 'object') {
|
|
31
|
+
throw new Error('Certificate pinning config must be an object');
|
|
32
|
+
}
|
|
33
|
+
if (typeof config.enabled !== 'boolean') {
|
|
34
|
+
throw new Error('Certificate pinning enabled must be a boolean');
|
|
35
|
+
}
|
|
36
|
+
if (!config.enabled) {
|
|
37
|
+
return; // No need to validate pins if disabled
|
|
38
|
+
}
|
|
39
|
+
if (!Array.isArray(config.pins)) {
|
|
40
|
+
throw new Error('Certificate pins must be an array');
|
|
41
|
+
}
|
|
42
|
+
for (const pin of config.pins) {
|
|
43
|
+
if (!pin.hostname || typeof pin.hostname !== 'string') {
|
|
44
|
+
throw new Error('Certificate pin hostname must be a non-empty string');
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(pin.sha256) || pin.sha256.length === 0) {
|
|
47
|
+
throw new Error('Certificate pin sha256 must be a non-empty array');
|
|
48
|
+
}
|
|
49
|
+
for (const hash of pin.sha256) {
|
|
50
|
+
if (!hash || typeof hash !== 'string' || !hash.startsWith('sha256/')) {
|
|
51
|
+
throw new Error('Certificate pin hash must be in format "sha256/base64hash"');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Example configuration
|
|
58
|
+
*/
|
|
59
|
+
static example() {
|
|
60
|
+
return {
|
|
61
|
+
enabled: true,
|
|
62
|
+
pins: [
|
|
63
|
+
{
|
|
64
|
+
hostname: 'api.example.com',
|
|
65
|
+
sha256: [
|
|
66
|
+
'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
|
|
67
|
+
'sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=', // Backup pin
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
hostname: 'cdn.example.com',
|
|
72
|
+
sha256: ['sha256/CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC='],
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=certificate-pinning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"certificate-pinning.js","sourceRoot":"","sources":["../../../src/live-update/certificate-pinning.ts"],"names":[],"mappings":"AAwBA;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAC7B;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,cAAsB;QACrD,2CAA2C;QAC3C,MAAM,MAAM,GAAG,cAAc;aAC1B,OAAO,CAAC,8BAA8B,EAAE,EAAE,CAAC;aAC3C,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC;aACzC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAEtB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7C,KAAK,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC;QAED,oBAAoB;QACpB,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAChE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;QAE3D,OAAO,UAAU,UAAU,EAAE,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAgC;QACpD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,uCAAuC;QACjD,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACtD,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACzE,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;YACtE,CAAC;YAED,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;gBAC9B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;oBACrE,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE;gBACJ;oBACE,QAAQ,EAAE,iBAAiB;oBAC3B,MAAM,EAAE;wBACN,qDAAqD;wBACrD,qDAAqD,EAAE,aAAa;qBACrE;iBACF;gBACD;oBACE,QAAQ,EAAE,iBAAiB;oBAC3B,MAAM,EAAE,CAAC,qDAAqD,CAAC;iBAChE;aACF;SACF,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { DownloadProgressEvent } from '../definitions';
|
|
2
|
+
/**
|
|
3
|
+
* Manages file downloads with progress tracking and resume capability
|
|
4
|
+
*/
|
|
5
|
+
export declare class DownloadManager {
|
|
6
|
+
private activeDownloads;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
private readonly configManager;
|
|
9
|
+
private filesystem;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Initialize the download manager
|
|
13
|
+
*/
|
|
14
|
+
initialize(): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Validate URL against allowed hosts
|
|
17
|
+
*/
|
|
18
|
+
private validateUrl;
|
|
19
|
+
/**
|
|
20
|
+
* Download a file with progress tracking
|
|
21
|
+
*/
|
|
22
|
+
download(url: string, bundleId: string, onProgress?: (event: DownloadProgressEvent) => void): Promise<Blob>;
|
|
23
|
+
/**
|
|
24
|
+
* Validate content type
|
|
25
|
+
*/
|
|
26
|
+
private isValidContentType;
|
|
27
|
+
/**
|
|
28
|
+
* Validate blob size
|
|
29
|
+
*/
|
|
30
|
+
private validateBlobSize;
|
|
31
|
+
/**
|
|
32
|
+
* Cancel a download
|
|
33
|
+
*/
|
|
34
|
+
cancelDownload(bundleId: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Cancel all active downloads
|
|
37
|
+
*/
|
|
38
|
+
cancelAllDownloads(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Check if a download is active
|
|
41
|
+
*/
|
|
42
|
+
isDownloading(bundleId: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Get active download count
|
|
45
|
+
*/
|
|
46
|
+
getActiveDownloadCount(): number;
|
|
47
|
+
/**
|
|
48
|
+
* Download with retry logic
|
|
49
|
+
*/
|
|
50
|
+
downloadWithRetry(url: string, bundleId: string, onProgress?: (event: DownloadProgressEvent) => void): Promise<Blob>;
|
|
51
|
+
/**
|
|
52
|
+
* Convert blob to ArrayBuffer
|
|
53
|
+
*/
|
|
54
|
+
blobToArrayBuffer(blob: Blob): Promise<ArrayBuffer>;
|
|
55
|
+
/**
|
|
56
|
+
* Save blob to filesystem
|
|
57
|
+
*/
|
|
58
|
+
saveBlob(bundleId: string, blob: Blob): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* Load blob from filesystem
|
|
61
|
+
*/
|
|
62
|
+
loadBlob(bundleId: string): Promise<Blob | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Delete blob from filesystem
|
|
65
|
+
*/
|
|
66
|
+
deleteBlob(bundleId: string): Promise<void>;
|
|
67
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { ConfigManager } from '../core/config';
|
|
2
|
+
import { Logger } from '../core/logger';
|
|
3
|
+
import { DownloadError, ErrorCode, ValidationError } from '../core/errors';
|
|
4
|
+
import { Directory } from '@capacitor/filesystem';
|
|
5
|
+
/**
|
|
6
|
+
* Manages file downloads with progress tracking and resume capability
|
|
7
|
+
*/
|
|
8
|
+
export class DownloadManager {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.activeDownloads = new Map();
|
|
11
|
+
this.filesystem = null;
|
|
12
|
+
this.logger = Logger.getInstance();
|
|
13
|
+
this.configManager = ConfigManager.getInstance();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the download manager
|
|
17
|
+
*/
|
|
18
|
+
async initialize() {
|
|
19
|
+
this.filesystem = this.configManager.get('filesystem');
|
|
20
|
+
if (!this.filesystem) {
|
|
21
|
+
throw new DownloadError(ErrorCode.MISSING_DEPENDENCY, 'Filesystem not configured. Please configure the plugin first.');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validate URL against allowed hosts
|
|
26
|
+
*/
|
|
27
|
+
validateUrl(url) {
|
|
28
|
+
try {
|
|
29
|
+
const parsedUrl = new URL(url);
|
|
30
|
+
// Ensure HTTPS
|
|
31
|
+
if (parsedUrl.protocol !== 'https:') {
|
|
32
|
+
throw new ValidationError(ErrorCode.INVALID_URL, 'Only HTTPS URLs are allowed for security reasons');
|
|
33
|
+
}
|
|
34
|
+
// Check against allowed hosts if configured
|
|
35
|
+
const allowedHosts = this.configManager.get('allowedHosts');
|
|
36
|
+
if (allowedHosts.length > 0 &&
|
|
37
|
+
!allowedHosts.includes(parsedUrl.hostname)) {
|
|
38
|
+
throw new ValidationError(ErrorCode.UNAUTHORIZED_HOST, `Host ${parsedUrl.hostname} is not in the allowed hosts list`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error instanceof ValidationError)
|
|
43
|
+
throw error;
|
|
44
|
+
throw new ValidationError(ErrorCode.INVALID_URL, 'Invalid URL format');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Download a file with progress tracking
|
|
49
|
+
*/
|
|
50
|
+
async download(url, bundleId, onProgress) {
|
|
51
|
+
// Validate inputs
|
|
52
|
+
this.validateUrl(url);
|
|
53
|
+
if (!bundleId) {
|
|
54
|
+
throw new ValidationError(ErrorCode.INVALID_BUNDLE_FORMAT, 'Bundle ID is required');
|
|
55
|
+
}
|
|
56
|
+
// Check if already downloading
|
|
57
|
+
if (this.activeDownloads.has(bundleId)) {
|
|
58
|
+
throw new DownloadError(ErrorCode.DOWNLOAD_FAILED, `Download already in progress for bundle ${bundleId}`);
|
|
59
|
+
}
|
|
60
|
+
// Create abort controller for this download
|
|
61
|
+
const abortController = new AbortController();
|
|
62
|
+
const downloadState = {
|
|
63
|
+
controller: abortController,
|
|
64
|
+
startTime: Date.now(),
|
|
65
|
+
};
|
|
66
|
+
this.activeDownloads.set(bundleId, downloadState);
|
|
67
|
+
try {
|
|
68
|
+
const timeout = this.configManager.get('downloadTimeout');
|
|
69
|
+
const timeoutId = setTimeout(() => abortController.abort(), timeout);
|
|
70
|
+
const response = await fetch(url, {
|
|
71
|
+
signal: abortController.signal,
|
|
72
|
+
headers: {
|
|
73
|
+
'Cache-Control': 'no-cache',
|
|
74
|
+
Accept: 'application/octet-stream, application/zip',
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
clearTimeout(timeoutId);
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new DownloadError(ErrorCode.DOWNLOAD_FAILED, `Download failed: ${response.status} ${response.statusText}`, { status: response.status, statusText: response.statusText });
|
|
80
|
+
}
|
|
81
|
+
// Validate content type
|
|
82
|
+
const contentType = response.headers.get('content-type');
|
|
83
|
+
if (contentType && !this.isValidContentType(contentType)) {
|
|
84
|
+
throw new ValidationError(ErrorCode.INVALID_BUNDLE_FORMAT, `Invalid content type: ${contentType}`);
|
|
85
|
+
}
|
|
86
|
+
// Get total size from headers
|
|
87
|
+
const contentLength = response.headers.get('content-length');
|
|
88
|
+
const totalBytes = contentLength ? parseInt(contentLength, 10) : 0;
|
|
89
|
+
// Check size limit
|
|
90
|
+
if (totalBytes > this.configManager.get('maxBundleSize')) {
|
|
91
|
+
throw new ValidationError(ErrorCode.BUNDLE_TOO_LARGE, `Bundle size ${totalBytes} exceeds maximum allowed size`);
|
|
92
|
+
}
|
|
93
|
+
// If no content length, fall back to simple download
|
|
94
|
+
if (!totalBytes || !response.body) {
|
|
95
|
+
const blob = await response.blob();
|
|
96
|
+
this.validateBlobSize(blob);
|
|
97
|
+
return blob;
|
|
98
|
+
}
|
|
99
|
+
// Stream the response with progress tracking
|
|
100
|
+
const reader = response.body.getReader();
|
|
101
|
+
const chunks = [];
|
|
102
|
+
let receivedBytes = 0;
|
|
103
|
+
while (true) {
|
|
104
|
+
const { done, value } = await reader.read();
|
|
105
|
+
if (done)
|
|
106
|
+
break;
|
|
107
|
+
chunks.push(value);
|
|
108
|
+
receivedBytes += value.length;
|
|
109
|
+
// Check if size exceeds limit during download
|
|
110
|
+
if (receivedBytes > this.configManager.get('maxBundleSize')) {
|
|
111
|
+
throw new ValidationError(ErrorCode.BUNDLE_TOO_LARGE, `Download size exceeds maximum allowed size`);
|
|
112
|
+
}
|
|
113
|
+
// Report progress
|
|
114
|
+
if (onProgress) {
|
|
115
|
+
const percent = Math.round((receivedBytes / totalBytes) * 100);
|
|
116
|
+
onProgress({
|
|
117
|
+
percent,
|
|
118
|
+
bytesDownloaded: receivedBytes,
|
|
119
|
+
totalBytes,
|
|
120
|
+
bundleId,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Combine chunks into a single blob
|
|
125
|
+
const blob = new Blob(chunks);
|
|
126
|
+
this.validateBlobSize(blob);
|
|
127
|
+
this.logger.info('Download completed', {
|
|
128
|
+
bundleId,
|
|
129
|
+
size: blob.size,
|
|
130
|
+
duration: Date.now() - downloadState.startTime,
|
|
131
|
+
});
|
|
132
|
+
return blob;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
136
|
+
const isTimeout = Date.now() - downloadState.startTime >=
|
|
137
|
+
this.configManager.get('downloadTimeout');
|
|
138
|
+
throw new DownloadError(isTimeout ? ErrorCode.DOWNLOAD_TIMEOUT : ErrorCode.DOWNLOAD_FAILED, isTimeout ? 'Download timed out' : 'Download cancelled', undefined, error);
|
|
139
|
+
}
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
// Clean up
|
|
144
|
+
this.activeDownloads.delete(bundleId);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Validate content type
|
|
149
|
+
*/
|
|
150
|
+
isValidContentType(contentType) {
|
|
151
|
+
const validTypes = [
|
|
152
|
+
'application/octet-stream',
|
|
153
|
+
'application/zip',
|
|
154
|
+
'application/x-zip-compressed',
|
|
155
|
+
'application/x-zip',
|
|
156
|
+
];
|
|
157
|
+
return validTypes.some((type) => contentType.includes(type));
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Validate blob size
|
|
161
|
+
*/
|
|
162
|
+
validateBlobSize(blob) {
|
|
163
|
+
if (blob.size === 0) {
|
|
164
|
+
throw new ValidationError(ErrorCode.INVALID_BUNDLE_FORMAT, 'Downloaded file is empty');
|
|
165
|
+
}
|
|
166
|
+
if (blob.size > this.configManager.get('maxBundleSize')) {
|
|
167
|
+
throw new ValidationError(ErrorCode.BUNDLE_TOO_LARGE, `File size ${blob.size} exceeds maximum allowed size`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Cancel a download
|
|
172
|
+
*/
|
|
173
|
+
cancelDownload(bundleId) {
|
|
174
|
+
const state = this.activeDownloads.get(bundleId);
|
|
175
|
+
if (state) {
|
|
176
|
+
state.controller.abort();
|
|
177
|
+
this.activeDownloads.delete(bundleId);
|
|
178
|
+
this.logger.info('Download cancelled', { bundleId });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Cancel all active downloads
|
|
183
|
+
*/
|
|
184
|
+
cancelAllDownloads() {
|
|
185
|
+
for (const state of this.activeDownloads.values()) {
|
|
186
|
+
state.controller.abort();
|
|
187
|
+
}
|
|
188
|
+
const count = this.activeDownloads.size;
|
|
189
|
+
this.activeDownloads.clear();
|
|
190
|
+
if (count > 0) {
|
|
191
|
+
this.logger.info('All downloads cancelled', { count });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Check if a download is active
|
|
196
|
+
*/
|
|
197
|
+
isDownloading(bundleId) {
|
|
198
|
+
return this.activeDownloads.has(bundleId);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get active download count
|
|
202
|
+
*/
|
|
203
|
+
getActiveDownloadCount() {
|
|
204
|
+
return this.activeDownloads.size;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Download with retry logic
|
|
208
|
+
*/
|
|
209
|
+
async downloadWithRetry(url, bundleId, onProgress) {
|
|
210
|
+
const maxRetries = this.configManager.get('retryAttempts');
|
|
211
|
+
const retryDelay = this.configManager.get('retryDelay');
|
|
212
|
+
let lastError = null;
|
|
213
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
214
|
+
try {
|
|
215
|
+
// Add delay between retries (exponential backoff)
|
|
216
|
+
if (attempt > 0) {
|
|
217
|
+
const delay = Math.min(retryDelay * Math.pow(2, attempt - 1), 30000);
|
|
218
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
219
|
+
this.logger.debug('Retrying download', { bundleId, attempt, delay });
|
|
220
|
+
}
|
|
221
|
+
return await this.download(url, bundleId, onProgress);
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
lastError = error;
|
|
225
|
+
// Don't retry if cancelled or validation error
|
|
226
|
+
if (error instanceof ValidationError ||
|
|
227
|
+
(error instanceof Error && error.name === 'AbortError')) {
|
|
228
|
+
throw error;
|
|
229
|
+
}
|
|
230
|
+
this.logger.warn(`Download attempt ${attempt + 1} failed`, {
|
|
231
|
+
bundleId,
|
|
232
|
+
error,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
throw new DownloadError(ErrorCode.DOWNLOAD_FAILED, 'Download failed after all retries', { attempts: maxRetries }, lastError || undefined);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Convert blob to ArrayBuffer
|
|
240
|
+
*/
|
|
241
|
+
async blobToArrayBuffer(blob) {
|
|
242
|
+
return blob.arrayBuffer();
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Save blob to filesystem
|
|
246
|
+
*/
|
|
247
|
+
async saveBlob(bundleId, blob) {
|
|
248
|
+
if (!this.filesystem) {
|
|
249
|
+
throw new DownloadError(ErrorCode.MISSING_DEPENDENCY, 'Filesystem not initialized');
|
|
250
|
+
}
|
|
251
|
+
const arrayBuffer = await this.blobToArrayBuffer(blob);
|
|
252
|
+
const base64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
|
|
253
|
+
const path = `bundles/${bundleId}/bundle.zip`;
|
|
254
|
+
await this.filesystem.writeFile({
|
|
255
|
+
path,
|
|
256
|
+
data: base64,
|
|
257
|
+
directory: Directory.Data,
|
|
258
|
+
recursive: true,
|
|
259
|
+
});
|
|
260
|
+
this.logger.debug('Bundle saved to filesystem', {
|
|
261
|
+
bundleId,
|
|
262
|
+
path,
|
|
263
|
+
size: blob.size,
|
|
264
|
+
});
|
|
265
|
+
return path;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Load blob from filesystem
|
|
269
|
+
*/
|
|
270
|
+
async loadBlob(bundleId) {
|
|
271
|
+
if (!this.filesystem) {
|
|
272
|
+
throw new DownloadError(ErrorCode.MISSING_DEPENDENCY, 'Filesystem not initialized');
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
const path = `bundles/${bundleId}/bundle.zip`;
|
|
276
|
+
const result = await this.filesystem.readFile({
|
|
277
|
+
path,
|
|
278
|
+
directory: Directory.Data,
|
|
279
|
+
});
|
|
280
|
+
const binaryString = atob(result.data);
|
|
281
|
+
const bytes = new Uint8Array(binaryString.length);
|
|
282
|
+
for (let i = 0; i < binaryString.length; i++) {
|
|
283
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
284
|
+
}
|
|
285
|
+
return new Blob([bytes], { type: 'application/zip' });
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
this.logger.debug('Failed to load bundle from filesystem', {
|
|
289
|
+
bundleId,
|
|
290
|
+
error,
|
|
291
|
+
});
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Delete blob from filesystem
|
|
297
|
+
*/
|
|
298
|
+
async deleteBlob(bundleId) {
|
|
299
|
+
if (!this.filesystem) {
|
|
300
|
+
throw new DownloadError(ErrorCode.MISSING_DEPENDENCY, 'Filesystem not initialized');
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const path = `bundles/${bundleId}`;
|
|
304
|
+
await this.filesystem.rmdir({
|
|
305
|
+
path,
|
|
306
|
+
directory: Directory.Data,
|
|
307
|
+
recursive: true,
|
|
308
|
+
});
|
|
309
|
+
this.logger.debug('Bundle deleted from filesystem', { bundleId });
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
this.logger.warn('Failed to delete bundle from filesystem', {
|
|
313
|
+
bundleId,
|
|
314
|
+
error,
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=download-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"download-manager.js","sourceRoot":"","sources":["../../../src/live-update/download-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { UpdateOptions } from '../definitions';
|
|
2
|
+
/**
|
|
3
|
+
* Manages atomic bundle installation with rollback capability
|
|
4
|
+
*/
|
|
5
|
+
export declare class UpdateManager {
|
|
6
|
+
private readonly pluginManager;
|
|
7
|
+
private readonly securityValidator;
|
|
8
|
+
private filesystem;
|
|
9
|
+
private updateInProgress;
|
|
10
|
+
private currentState;
|
|
11
|
+
constructor();
|
|
12
|
+
/**
|
|
13
|
+
* Initialize update manager
|
|
14
|
+
*/
|
|
15
|
+
initialize(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Apply bundle update atomically
|
|
18
|
+
*/
|
|
19
|
+
applyUpdate(bundleId: string, options?: UpdateOptions): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Validate update before applying
|
|
22
|
+
*/
|
|
23
|
+
private validateUpdate;
|
|
24
|
+
/**
|
|
25
|
+
* Create backup of current bundle
|
|
26
|
+
*/
|
|
27
|
+
private createBackup;
|
|
28
|
+
/**
|
|
29
|
+
* Perform the actual update
|
|
30
|
+
*/
|
|
31
|
+
private performUpdate;
|
|
32
|
+
/**
|
|
33
|
+
* Verify update was successful
|
|
34
|
+
*/
|
|
35
|
+
private verifyUpdate;
|
|
36
|
+
/**
|
|
37
|
+
* Rollback to previous state
|
|
38
|
+
*/
|
|
39
|
+
rollback(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Get current update progress
|
|
42
|
+
*/
|
|
43
|
+
getUpdateProgress(): {
|
|
44
|
+
inProgress: boolean;
|
|
45
|
+
bundleId?: string;
|
|
46
|
+
startTime?: number;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Cancel current update (if possible)
|
|
50
|
+
*/
|
|
51
|
+
cancelUpdate(): Promise<void>;
|
|
52
|
+
}
|