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.
Files changed (184) hide show
  1. package/CapacitorNativeUpdate.podspec +18 -0
  2. package/LICENSE +21 -0
  3. package/Readme.md +451 -0
  4. package/android/build.gradle +92 -0
  5. package/android/gradle/wrapper/gradle-wrapper.properties +8 -0
  6. package/android/gradle.properties +17 -0
  7. package/android/proguard-rules.pro +29 -0
  8. package/android/settings.gradle +2 -0
  9. package/android/src/main/AndroidManifest.xml +34 -0
  10. package/android/src/main/java/com/aoneahsan/nativeupdate/AppReviewPlugin.kt +153 -0
  11. package/android/src/main/java/com/aoneahsan/nativeupdate/AppUpdatePlugin.kt +275 -0
  12. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundNotificationManager.kt +390 -0
  13. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateManager.kt +46 -0
  14. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdatePlugin.kt +333 -0
  15. package/android/src/main/java/com/aoneahsan/nativeupdate/BackgroundUpdateWorker.kt +251 -0
  16. package/android/src/main/java/com/aoneahsan/nativeupdate/CapacitorNativeUpdatePlugin.kt +265 -0
  17. package/android/src/main/java/com/aoneahsan/nativeupdate/LiveUpdatePlugin.kt +526 -0
  18. package/android/src/main/java/com/aoneahsan/nativeupdate/NotificationActionReceiver.kt +99 -0
  19. package/android/src/main/java/com/aoneahsan/nativeupdate/SecurityManager.kt +249 -0
  20. package/dist/esm/__tests__/bundle-manager.test.d.ts +1 -0
  21. package/dist/esm/__tests__/bundle-manager.test.js +123 -0
  22. package/dist/esm/__tests__/bundle-manager.test.js.map +1 -0
  23. package/dist/esm/__tests__/config.test.d.ts +1 -0
  24. package/dist/esm/__tests__/config.test.js +69 -0
  25. package/dist/esm/__tests__/config.test.js.map +1 -0
  26. package/dist/esm/__tests__/integration.test.d.ts +1 -0
  27. package/dist/esm/__tests__/integration.test.js +78 -0
  28. package/dist/esm/__tests__/integration.test.js.map +1 -0
  29. package/dist/esm/__tests__/security.test.d.ts +1 -0
  30. package/dist/esm/__tests__/security.test.js +54 -0
  31. package/dist/esm/__tests__/security.test.js.map +1 -0
  32. package/dist/esm/__tests__/version-manager.test.d.ts +1 -0
  33. package/dist/esm/__tests__/version-manager.test.js +45 -0
  34. package/dist/esm/__tests__/version-manager.test.js.map +1 -0
  35. package/dist/esm/app-review/app-review-manager.d.ts +24 -0
  36. package/dist/esm/app-review/app-review-manager.js +195 -0
  37. package/dist/esm/app-review/app-review-manager.js.map +1 -0
  38. package/dist/esm/app-review/index.d.ts +5 -0
  39. package/dist/esm/app-review/index.js +6 -0
  40. package/dist/esm/app-review/index.js.map +1 -0
  41. package/dist/esm/app-review/platform-review-handler.d.ts +20 -0
  42. package/dist/esm/app-review/platform-review-handler.js +138 -0
  43. package/dist/esm/app-review/platform-review-handler.js.map +1 -0
  44. package/dist/esm/app-review/review-conditions-checker.d.ts +22 -0
  45. package/dist/esm/app-review/review-conditions-checker.js +155 -0
  46. package/dist/esm/app-review/review-conditions-checker.js.map +1 -0
  47. package/dist/esm/app-review/review-rate-limiter.d.ts +23 -0
  48. package/dist/esm/app-review/review-rate-limiter.js +164 -0
  49. package/dist/esm/app-review/review-rate-limiter.js.map +1 -0
  50. package/dist/esm/app-review/types.d.ts +41 -0
  51. package/dist/esm/app-review/types.js +2 -0
  52. package/dist/esm/app-review/types.js.map +1 -0
  53. package/dist/esm/app-update/app-update-checker.d.ts +13 -0
  54. package/dist/esm/app-update/app-update-checker.js +104 -0
  55. package/dist/esm/app-update/app-update-checker.js.map +1 -0
  56. package/dist/esm/app-update/app-update-installer.d.ts +19 -0
  57. package/dist/esm/app-update/app-update-installer.js +123 -0
  58. package/dist/esm/app-update/app-update-installer.js.map +1 -0
  59. package/dist/esm/app-update/app-update-manager.d.ts +28 -0
  60. package/dist/esm/app-update/app-update-manager.js +199 -0
  61. package/dist/esm/app-update/app-update-manager.js.map +1 -0
  62. package/dist/esm/app-update/app-update-notifier.d.ts +14 -0
  63. package/dist/esm/app-update/app-update-notifier.js +100 -0
  64. package/dist/esm/app-update/app-update-notifier.js.map +1 -0
  65. package/dist/esm/app-update/index.d.ts +6 -0
  66. package/dist/esm/app-update/index.js +7 -0
  67. package/dist/esm/app-update/index.js.map +1 -0
  68. package/dist/esm/app-update/platform-app-update.d.ts +19 -0
  69. package/dist/esm/app-update/platform-app-update.js +129 -0
  70. package/dist/esm/app-update/platform-app-update.js.map +1 -0
  71. package/dist/esm/app-update/types.d.ts +58 -0
  72. package/dist/esm/app-update/types.js +12 -0
  73. package/dist/esm/app-update/types.js.map +1 -0
  74. package/dist/esm/background-update/background-scheduler.d.ts +17 -0
  75. package/dist/esm/background-update/background-scheduler.js +195 -0
  76. package/dist/esm/background-update/background-scheduler.js.map +1 -0
  77. package/dist/esm/background-update/index.d.ts +3 -0
  78. package/dist/esm/background-update/index.js +3 -0
  79. package/dist/esm/background-update/index.js.map +1 -0
  80. package/dist/esm/background-update/notification-manager.d.ts +29 -0
  81. package/dist/esm/background-update/notification-manager.js +89 -0
  82. package/dist/esm/background-update/notification-manager.js.map +1 -0
  83. package/dist/esm/core/analytics.d.ts +70 -0
  84. package/dist/esm/core/analytics.js +137 -0
  85. package/dist/esm/core/analytics.js.map +1 -0
  86. package/dist/esm/core/cache-manager.d.ts +72 -0
  87. package/dist/esm/core/cache-manager.js +275 -0
  88. package/dist/esm/core/cache-manager.js.map +1 -0
  89. package/dist/esm/core/config.d.ts +48 -0
  90. package/dist/esm/core/config.js +83 -0
  91. package/dist/esm/core/config.js.map +1 -0
  92. package/dist/esm/core/errors.d.ts +51 -0
  93. package/dist/esm/core/errors.js +80 -0
  94. package/dist/esm/core/errors.js.map +1 -0
  95. package/dist/esm/core/logger.d.ts +21 -0
  96. package/dist/esm/core/logger.js +109 -0
  97. package/dist/esm/core/logger.js.map +1 -0
  98. package/dist/esm/core/performance.d.ts +53 -0
  99. package/dist/esm/core/performance.js +140 -0
  100. package/dist/esm/core/performance.js.map +1 -0
  101. package/dist/esm/core/plugin-manager.d.ts +66 -0
  102. package/dist/esm/core/plugin-manager.js +148 -0
  103. package/dist/esm/core/plugin-manager.js.map +1 -0
  104. package/dist/esm/core/security.d.ts +93 -0
  105. package/dist/esm/core/security.js +315 -0
  106. package/dist/esm/core/security.js.map +1 -0
  107. package/dist/esm/definitions.d.ts +639 -0
  108. package/dist/esm/definitions.js +103 -0
  109. package/dist/esm/definitions.js.map +1 -0
  110. package/dist/esm/index.d.ts +12 -0
  111. package/dist/esm/index.js +16 -0
  112. package/dist/esm/index.js.map +1 -0
  113. package/dist/esm/live-update/bundle-manager.d.ts +94 -0
  114. package/dist/esm/live-update/bundle-manager.js +310 -0
  115. package/dist/esm/live-update/bundle-manager.js.map +1 -0
  116. package/dist/esm/live-update/certificate-pinning.d.ts +38 -0
  117. package/dist/esm/live-update/certificate-pinning.js +78 -0
  118. package/dist/esm/live-update/certificate-pinning.js.map +1 -0
  119. package/dist/esm/live-update/download-manager.d.ts +67 -0
  120. package/dist/esm/live-update/download-manager.js +319 -0
  121. package/dist/esm/live-update/download-manager.js.map +1 -0
  122. package/dist/esm/live-update/update-manager.d.ts +52 -0
  123. package/dist/esm/live-update/update-manager.js +294 -0
  124. package/dist/esm/live-update/update-manager.js.map +1 -0
  125. package/dist/esm/live-update/version-manager.d.ts +84 -0
  126. package/dist/esm/live-update/version-manager.js +335 -0
  127. package/dist/esm/live-update/version-manager.js.map +1 -0
  128. package/dist/esm/plugin.d.ts +6 -0
  129. package/dist/esm/plugin.js +283 -0
  130. package/dist/esm/plugin.js.map +1 -0
  131. package/dist/esm/security/crypto.d.ts +25 -0
  132. package/dist/esm/security/crypto.js +70 -0
  133. package/dist/esm/security/crypto.js.map +1 -0
  134. package/dist/esm/security/validator.d.ts +60 -0
  135. package/dist/esm/security/validator.js +143 -0
  136. package/dist/esm/security/validator.js.map +1 -0
  137. package/dist/esm/web.d.ts +74 -0
  138. package/dist/esm/web.js +595 -0
  139. package/dist/esm/web.js.map +1 -0
  140. package/dist/plugin.cjs.js +2 -0
  141. package/dist/plugin.cjs.js.map +1 -0
  142. package/dist/plugin.esm.js +2 -0
  143. package/dist/plugin.esm.js.map +1 -0
  144. package/dist/plugin.js +3 -0
  145. package/dist/plugin.js.map +1 -0
  146. package/docs/APP_REVIEW_GUIDE.md +768 -0
  147. package/docs/BUNDLE_SIGNING.md +264 -0
  148. package/docs/LIVE_UPDATES_GUIDE.md +650 -0
  149. package/docs/MIGRATION.md +192 -0
  150. package/docs/NATIVE_UPDATES_GUIDE.md +694 -0
  151. package/docs/QUICK_START.md +606 -0
  152. package/docs/README.md +111 -0
  153. package/docs/REMAINING_FEATURES.md +139 -0
  154. package/docs/api/app-review-api.md +259 -0
  155. package/docs/api/app-update-api.md +238 -0
  156. package/docs/api/events-api.md +451 -0
  157. package/docs/api/live-update-api.md +265 -0
  158. package/docs/background-updates.md +392 -0
  159. package/docs/examples/advanced-scenarios.md +410 -0
  160. package/docs/examples/basic-usage.md +185 -0
  161. package/docs/features/app-reviews.md +975 -0
  162. package/docs/features/app-updates.md +785 -0
  163. package/docs/features/live-updates.md +633 -0
  164. package/docs/getting-started/configuration.md +468 -0
  165. package/docs/getting-started/installation.md +209 -0
  166. package/docs/getting-started/quick-start.md +379 -0
  167. package/docs/guides/deployment-guide.md +333 -0
  168. package/docs/guides/migration-from-codepush.md +142 -0
  169. package/docs/guides/security-best-practices.md +1057 -0
  170. package/docs/guides/testing-guide.md +373 -0
  171. package/docs/production-readiness.md +478 -0
  172. package/docs/security/certificate-pinning.md +122 -0
  173. package/docs/server-requirements.md +147 -0
  174. package/ios/Plugin/AppReview/AppReviewPlugin.swift +158 -0
  175. package/ios/Plugin/AppUpdate/AppUpdatePlugin.swift +234 -0
  176. package/ios/Plugin/BackgroundUpdate/BackgroundNotificationManager.swift +329 -0
  177. package/ios/Plugin/BackgroundUpdate/BackgroundUpdatePlugin.swift +396 -0
  178. package/ios/Plugin/CapacitorNativeUpdatePlugin.m +45 -0
  179. package/ios/Plugin/CapacitorNativeUpdatePlugin.swift +190 -0
  180. package/ios/Plugin/Info.plist +43 -0
  181. package/ios/Plugin/LiveUpdate/LiveUpdatePlugin.swift +689 -0
  182. package/ios/Plugin/LiveUpdate/WebViewConfiguration.swift +45 -0
  183. package/ios/Plugin/Security/SecurityManager.swift +289 -0
  184. package/package.json +90 -0
@@ -0,0 +1,249 @@
1
+ package com.aoneahsan.nativeupdate
2
+
3
+ import android.content.Context
4
+ import android.util.Base64
5
+ import androidx.security.crypto.EncryptedSharedPreferences
6
+ import androidx.security.crypto.MasterKey
7
+ import com.getcapacitor.JSObject
8
+ import okhttp3.CertificatePinner
9
+ import java.io.File
10
+ import java.security.*
11
+ import java.security.spec.X509EncodedKeySpec
12
+ import javax.crypto.Cipher
13
+
14
+ class SecurityManager(private val context: Context) {
15
+ private var config: JSObject? = null
16
+ private val masterKey: MasterKey
17
+ private val securePrefs: android.content.SharedPreferences
18
+
19
+ init {
20
+ // Initialize master key for encryption
21
+ masterKey = MasterKey.Builder(context)
22
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
23
+ .build()
24
+
25
+ // Initialize encrypted shared preferences
26
+ securePrefs = EncryptedSharedPreferences.create(
27
+ context,
28
+ "native_update_secure",
29
+ masterKey,
30
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
31
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
32
+ )
33
+ }
34
+
35
+ fun configure(config: JSObject) {
36
+ this.config = config
37
+
38
+ // Validate security configuration
39
+ val enforceHttps = config.getBool("enforceHttps") ?: true
40
+ if (!enforceHttps) {
41
+ // Log warning about disabled HTTPS enforcement
42
+ android.util.Log.w("SecurityManager", "HTTPS enforcement is disabled. This is not recommended for production.")
43
+ }
44
+ }
45
+
46
+ fun getSecurityInfo(): JSObject {
47
+ val result = JSObject()
48
+
49
+ result.put("enforceHttps", config?.getBool("enforceHttps") ?: true)
50
+
51
+ val certificatePinning = JSObject()
52
+ val pinningConfig = config?.getJSObject("certificatePinning")
53
+ certificatePinning.put("enabled", pinningConfig?.getBool("enabled") ?: false)
54
+
55
+ // Convert pins to proper format
56
+ val pins = mutableListOf<JSObject>()
57
+ val pinsArray = pinningConfig?.getJSONArray("pins")
58
+ if (pinsArray != null) {
59
+ for (i in 0 until pinsArray.length()) {
60
+ val pin = pinsArray.getJSONObject(i)
61
+ val pinObject = JSObject()
62
+ pinObject.put("hostname", pin.getString("hostname"))
63
+ pinObject.put("sha256", pin.getJSONArray("sha256"))
64
+ pins.add(pinObject)
65
+ }
66
+ }
67
+ certificatePinning.put("pins", pins.toTypedArray())
68
+ result.put("certificatePinning", certificatePinning)
69
+
70
+ result.put("validateInputs", config?.getBool("validateInputs") ?: true)
71
+ result.put("secureStorage", config?.getBool("secureStorage") ?: true)
72
+
73
+ return result
74
+ }
75
+
76
+ fun validateUrl(url: String): Boolean {
77
+ if (!url.startsWith("https://") && isHttpsEnforced()) {
78
+ return false
79
+ }
80
+
81
+ // Check against allowed hosts if configured
82
+ val allowedHosts = getAllowedHosts()
83
+ if (allowedHosts.isNotEmpty()) {
84
+ val uri = android.net.Uri.parse(url)
85
+ val host = uri.host ?: return false
86
+ return allowedHosts.contains(host)
87
+ }
88
+
89
+ return true
90
+ }
91
+
92
+ fun getCertificatePinner(): CertificatePinner? {
93
+ val pinningConfig = config?.getJSObject("certificatePinning") ?: return null
94
+
95
+ if (pinningConfig.getBool("enabled") != true) {
96
+ return null
97
+ }
98
+
99
+ val pins = pinningConfig.getJSONArray("pins") ?: return null
100
+ if (pins.length() == 0) {
101
+ return null
102
+ }
103
+
104
+ val builder = CertificatePinner.Builder()
105
+
106
+ // Add certificate pins for each host
107
+ for (i in 0 until pins.length()) {
108
+ val pin = pins.getJSONObject(i)
109
+ val hostname = pin.getString("hostname") ?: continue
110
+ val sha256Pins = pin.getJSONArray("sha256") ?: continue
111
+
112
+ for (j in 0 until sha256Pins.length()) {
113
+ val sha256Pin = sha256Pins.getString(j)
114
+ builder.add(hostname, sha256Pin)
115
+ }
116
+ }
117
+
118
+ return builder.build()
119
+ }
120
+
121
+ fun verifySignature(data: ByteArray, signature: String, publicKeyString: String): Boolean {
122
+ return try {
123
+ // Handle PEM format or base64 encoded public key
124
+ val publicKeyBase64 = if (publicKeyString.contains("-----BEGIN PUBLIC KEY-----")) {
125
+ publicKeyString
126
+ .replace("-----BEGIN PUBLIC KEY-----", "")
127
+ .replace("-----END PUBLIC KEY-----", "")
128
+ .replace("\n", "")
129
+ .replace("\r", "")
130
+ .trim()
131
+ } else {
132
+ publicKeyString
133
+ }
134
+
135
+ val publicKeyBytes = Base64.decode(publicKeyBase64, Base64.DEFAULT)
136
+ val keySpec = X509EncodedKeySpec(publicKeyBytes)
137
+ val keyFactory = KeyFactory.getInstance("RSA")
138
+ val publicKey = keyFactory.generatePublic(keySpec)
139
+
140
+ // Use RSA-PSS to match web implementation
141
+ val sig = Signature.getInstance("SHA256withRSA/PSS")
142
+ sig.initVerify(publicKey)
143
+ sig.update(data)
144
+
145
+ val signatureBytes = Base64.decode(signature, Base64.DEFAULT)
146
+ sig.verify(signatureBytes)
147
+ } catch (e: Exception) {
148
+ android.util.Log.e("SecurityManager", "Signature verification failed", e)
149
+ false
150
+ }
151
+ }
152
+
153
+ fun calculateChecksum(file: File, algorithm: String = "SHA-256"): String {
154
+ val digest = MessageDigest.getInstance(algorithm)
155
+ file.inputStream().use { input ->
156
+ val buffer = ByteArray(8192)
157
+ var read: Int
158
+ while (input.read(buffer).also { read = it } != -1) {
159
+ digest.update(buffer, 0, read)
160
+ }
161
+ }
162
+ return digest.digest().joinToString("") { "%02x".format(it) }
163
+ }
164
+
165
+ fun saveSecureData(key: String, value: String) {
166
+ if (isSecureStorageEnabled()) {
167
+ securePrefs.edit().putString(key, value).apply()
168
+ } else {
169
+ // Fallback to regular preferences (not recommended)
170
+ val prefs = context.getSharedPreferences("native_update", Context.MODE_PRIVATE)
171
+ prefs.edit().putString(key, value).apply()
172
+ }
173
+ }
174
+
175
+ fun getSecureData(key: String): String? {
176
+ return if (isSecureStorageEnabled()) {
177
+ securePrefs.getString(key, null)
178
+ } else {
179
+ val prefs = context.getSharedPreferences("native_update", Context.MODE_PRIVATE)
180
+ prefs.getString(key, null)
181
+ }
182
+ }
183
+
184
+ fun validatePath(path: String): Boolean {
185
+ // Prevent directory traversal attacks
186
+ if (path.contains("..") || path.contains("//")) {
187
+ return false
188
+ }
189
+
190
+ // Ensure path is within app's private directory
191
+ val file = File(path)
192
+ val canonicalPath = file.canonicalPath
193
+ val appDir = context.filesDir.canonicalPath
194
+
195
+ return canonicalPath.startsWith(appDir)
196
+ }
197
+
198
+ fun sanitizeInput(input: String): String {
199
+ // Remove potentially dangerous characters
200
+ return input.replace(Regex("[^a-zA-Z0-9._-]"), "")
201
+ }
202
+
203
+ fun isHttpsEnforced(): Boolean {
204
+ return config?.getBool("enforceHttps") ?: true
205
+ }
206
+
207
+ fun isSecureStorageEnabled(): Boolean {
208
+ return config?.getBool("secureStorage") ?: true
209
+ }
210
+
211
+ fun isInputValidationEnabled(): Boolean {
212
+ return config?.getBool("validateInputs") ?: true
213
+ }
214
+
215
+ private fun getAllowedHosts(): List<String> {
216
+ val hosts = mutableListOf<String>()
217
+
218
+ // Add hosts from certificate pinning config
219
+ val pinningConfig = config?.getJSObject("certificatePinning")
220
+ if (pinningConfig != null) {
221
+ // In a real implementation, we'd extract hosts from the configuration
222
+ // For now, we'll use the server URL
223
+ val serverUrl = config?.getString("serverUrl")
224
+ if (serverUrl != null) {
225
+ val uri = android.net.Uri.parse(serverUrl)
226
+ uri.host?.let { hosts.add(it) }
227
+ }
228
+ }
229
+
230
+ // Add allowed hosts from live update config
231
+ val liveUpdateConfig = config?.getJSObject("liveUpdate")
232
+ val allowedHosts = liveUpdateConfig?.getJSONArray("allowedHosts")
233
+ if (allowedHosts != null) {
234
+ for (i in 0 until allowedHosts.length()) {
235
+ hosts.add(allowedHosts.getString(i))
236
+ }
237
+ }
238
+
239
+ return hosts.distinct()
240
+ }
241
+
242
+ fun logSecurityEvent(event: String, details: String? = null) {
243
+ if (config?.getBool("logSecurityEvents") == true) {
244
+ android.util.Log.i("SecurityManager", "Security Event: $event ${details ?: ""}")
245
+
246
+ // In production, you might want to send these to a security monitoring service
247
+ }
248
+ }
249
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,123 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { BundleManager } from '../live-update/bundle-manager';
3
+ // Mock dependencies
4
+ vi.mock('@capacitor/filesystem', () => ({
5
+ Filesystem: {
6
+ readFile: vi.fn(),
7
+ writeFile: vi.fn(),
8
+ deleteFile: vi.fn(),
9
+ mkdir: vi.fn(),
10
+ rmdir: vi.fn(),
11
+ readdir: vi.fn(),
12
+ stat: vi.fn(),
13
+ },
14
+ Directory: {
15
+ Data: 'DATA',
16
+ Cache: 'CACHE',
17
+ },
18
+ Encoding: {
19
+ UTF8: 'utf8',
20
+ },
21
+ }));
22
+ describe('BundleManager', () => {
23
+ let bundleManager;
24
+ beforeEach(async () => {
25
+ bundleManager = new BundleManager();
26
+ vi.clearAllMocks();
27
+ // Mock preferences
28
+ const mockPreferences = {
29
+ get: vi.fn().mockResolvedValue({ value: null }),
30
+ set: vi.fn().mockResolvedValue(undefined),
31
+ remove: vi.fn().mockResolvedValue(undefined),
32
+ clear: vi.fn().mockResolvedValue(undefined),
33
+ keys: vi.fn().mockResolvedValue({ keys: [] }),
34
+ };
35
+ // Initialize bundle manager with mocked preferences
36
+ const { ConfigManager } = await import('../core/config');
37
+ ConfigManager.getInstance().set('preferences', mockPreferences);
38
+ await bundleManager.initialize();
39
+ });
40
+ describe('validateBundleInfo', () => {
41
+ it('should validate bundle with correct info', async () => {
42
+ const bundle = {
43
+ bundleId: 'bundle-1.0.0',
44
+ version: '1.0.0',
45
+ path: '/bundles/bundle-1.0.0',
46
+ downloadTime: Date.now(),
47
+ size: 1024,
48
+ status: 'ready',
49
+ checksum: 'a'.repeat(64),
50
+ signature: 'signature',
51
+ verified: true,
52
+ };
53
+ await bundleManager.saveBundleInfo(bundle);
54
+ const savedBundle = await bundleManager.getBundle('bundle-1.0.0');
55
+ expect(savedBundle).toBeDefined();
56
+ expect(savedBundle === null || savedBundle === void 0 ? void 0 : savedBundle.version).toBe('1.0.0');
57
+ });
58
+ it('should reject bundle with invalid info', async () => {
59
+ const bundle = {
60
+ // Missing required fields
61
+ version: '1.0.0',
62
+ size: 1024,
63
+ };
64
+ await expect(bundleManager.saveBundleInfo(bundle)).rejects.toThrow();
65
+ });
66
+ });
67
+ describe('cleanupOldBundles', () => {
68
+ it('should keep only specified number of bundles', async () => {
69
+ const mockBundles = [
70
+ {
71
+ path: 'bundle-1.0.0',
72
+ modificationTime: new Date('2024-01-01').getTime(),
73
+ },
74
+ {
75
+ path: 'bundle-1.0.1',
76
+ modificationTime: new Date('2024-01-02').getTime(),
77
+ },
78
+ {
79
+ path: 'bundle-1.0.2',
80
+ modificationTime: new Date('2024-01-03').getTime(),
81
+ },
82
+ {
83
+ path: 'bundle-1.0.3',
84
+ modificationTime: new Date('2024-01-04').getTime(),
85
+ },
86
+ ];
87
+ const { Filesystem } = await import('@capacitor/filesystem');
88
+ vi.mocked(Filesystem.readdir).mockResolvedValue({
89
+ files: mockBundles.map((b) => ({
90
+ name: b.path,
91
+ type: 'directory',
92
+ size: 1024,
93
+ uri: b.path,
94
+ ctime: b.modificationTime,
95
+ mtime: b.modificationTime,
96
+ })),
97
+ });
98
+ await bundleManager['cleanupOldBundles'](2);
99
+ // Should delete the 2 oldest bundles
100
+ expect(Filesystem.rmdir).toHaveBeenCalledTimes(2);
101
+ });
102
+ });
103
+ describe('getBundle', () => {
104
+ it('should retrieve saved bundle', async () => {
105
+ const bundle = {
106
+ bundleId: 'bundle-1.2.3',
107
+ version: '1.2.3',
108
+ path: '/bundles/bundle-1.2.3',
109
+ downloadTime: Date.now(),
110
+ size: 2048,
111
+ status: 'ready',
112
+ checksum: 'b'.repeat(64),
113
+ signature: 'sig',
114
+ verified: true,
115
+ };
116
+ await bundleManager.saveBundleInfo(bundle);
117
+ const retrieved = await bundleManager.getBundle('bundle-1.2.3');
118
+ expect(retrieved).toBeDefined();
119
+ expect(retrieved === null || retrieved === void 0 ? void 0 : retrieved.path).toBe('/bundles/bundle-1.2.3');
120
+ });
121
+ });
122
+ });
123
+ //# sourceMappingURL=bundle-manager.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-manager.test.js","sourceRoot":"","sources":["../../../src/__tests__/bundle-manager.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { ConfigManager } from '../core/config';
3
+ describe('ConfigManager', () => {
4
+ let configManager;
5
+ beforeEach(() => {
6
+ // Reset singleton
7
+ ConfigManager['instance'] = undefined;
8
+ configManager = ConfigManager.getInstance();
9
+ });
10
+ describe('configure', () => {
11
+ it('should store and retrieve configuration', () => {
12
+ const config = {
13
+ baseUrl: 'https://updates.example.com',
14
+ publicKey: 'test-public-key',
15
+ enableLogging: true,
16
+ };
17
+ configManager.configure(config);
18
+ expect(configManager.get('baseUrl')).toBe('https://updates.example.com');
19
+ expect(configManager.get('publicKey')).toBe('test-public-key');
20
+ expect(configManager.get('enableLogging')).toBe(true);
21
+ });
22
+ it('should merge partial configurations', () => {
23
+ const initialConfig = {
24
+ baseUrl: 'https://updates.example.com',
25
+ retryAttempts: 3,
26
+ };
27
+ const updateConfig = {
28
+ retryAttempts: 5,
29
+ enableLogging: false,
30
+ };
31
+ configManager.configure(initialConfig);
32
+ configManager.configure(updateConfig);
33
+ expect(configManager.get('baseUrl')).toBe('https://updates.example.com');
34
+ expect(configManager.get('retryAttempts')).toBe(5);
35
+ expect(configManager.get('enableLogging')).toBe(false);
36
+ });
37
+ });
38
+ describe('validation', () => {
39
+ it('should validate base URL is HTTPS', () => {
40
+ const config = {
41
+ baseUrl: 'http://updates.example.com', // HTTP should fail
42
+ };
43
+ expect(() => configManager.configure(config)).toThrow();
44
+ });
45
+ it('should validate retry attempts', () => {
46
+ const config = {
47
+ baseUrl: 'https://updates.example.com',
48
+ retryAttempts: -1, // Negative should fail
49
+ };
50
+ expect(() => configManager.configure(config)).toThrow();
51
+ });
52
+ });
53
+ describe('getAll', () => {
54
+ it('should return all configuration values', () => {
55
+ const config = {
56
+ baseUrl: 'https://updates.example.com',
57
+ retryAttempts: 3,
58
+ enableLogging: true,
59
+ };
60
+ configManager.configure(config);
61
+ const allConfig = configManager.getAll();
62
+ expect(allConfig).toMatchObject(config);
63
+ expect(allConfig).toHaveProperty('baseUrl', 'https://updates.example.com');
64
+ expect(allConfig).toHaveProperty('retryAttempts', 3);
65
+ expect(allConfig).toHaveProperty('enableLogging', true);
66
+ });
67
+ });
68
+ });
69
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../../../src/__tests__/config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG/C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAI,aAA4B,CAAC;IAEjC,UAAU,CAAC,GAAG,EAAE;QACd,kBAAkB;QAClB,aAAa,CAAC,UAAU,CAAC,GAAG,SAAgB,CAAC;QAC7C,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,MAAM,GAAiB;gBAC3B,OAAO,EAAE,6BAA6B;gBACtC,SAAS,EAAE,iBAAiB;gBAC5B,aAAa,EAAE,IAAI;aACpB,CAAC;YAEF,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAEhC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YACzE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC/D,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,aAAa,GAAiB;gBAClC,OAAO,EAAE,6BAA6B;gBACtC,aAAa,EAAE,CAAC;aACjB,CAAC;YAEF,MAAM,YAAY,GAA0B;gBAC1C,aAAa,EAAE,CAAC;gBAChB,aAAa,EAAE,KAAK;aACrB,CAAC;YAEF,aAAa,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACvC,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YAEtC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YACzE,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACnD,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,MAAM,GAAiB;gBAC3B,OAAO,EAAE,4BAA4B,EAAE,mBAAmB;aAC3D,CAAC;YAEF,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAiB;gBAC3B,OAAO,EAAE,6BAA6B;gBACtC,aAAa,EAAE,CAAC,CAAC,EAAE,uBAAuB;aAC3C,CAAC;YAEF,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,MAAM,GAAiB;gBAC3B,OAAO,EAAE,6BAA6B;gBACtC,aAAa,EAAE,CAAC;gBAChB,aAAa,EAAE,IAAI;aACpB,CAAC;YAEF,aAAa,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAChC,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC;YAEzC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,CAAC,SAAS,CAAC,CAAC,cAAc,CAC9B,SAAS,EACT,6BAA6B,CAC9B,CAAC;YACF,MAAM,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;YACrD,MAAM,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { NativeUpdateWeb } from '../web';
3
+ describe('Integration Tests', () => {
4
+ let plugin;
5
+ beforeEach(() => {
6
+ plugin = new NativeUpdateWeb();
7
+ });
8
+ describe('Plugin Lifecycle', () => {
9
+ it('should configure and check for updates', async () => {
10
+ const config = {
11
+ baseUrl: 'https://updates.example.com',
12
+ enableLogging: true,
13
+ };
14
+ // Configure plugin
15
+ await plugin.configure({ config });
16
+ // Sync for updates (will fail without server)
17
+ try {
18
+ const result = await plugin.sync();
19
+ expect(result).toBeDefined();
20
+ }
21
+ catch (error) {
22
+ expect(error).toBeDefined();
23
+ }
24
+ });
25
+ it('should handle app review requests', async () => {
26
+ const result = await plugin.requestReview();
27
+ expect(result).toBeDefined();
28
+ expect(result.displayed).toBe(false); // Web platform
29
+ });
30
+ it('should check native app updates', async () => {
31
+ const result = await plugin.getAppUpdateInfo();
32
+ expect(result).toBeDefined();
33
+ expect(result.updateAvailable).toBe(false); // Web platform
34
+ });
35
+ });
36
+ describe('Error Handling', () => {
37
+ it('should validate configuration', async () => {
38
+ const invalidConfig = {
39
+ baseUrl: 'http://insecure.com', // Should fail - not HTTPS
40
+ };
41
+ await expect(plugin.configure({ config: invalidConfig }))
42
+ .rejects.toThrow();
43
+ });
44
+ it('should handle missing configuration', async () => {
45
+ // Try to sync without configuration
46
+ await expect(plugin.sync())
47
+ .rejects.toThrow();
48
+ });
49
+ });
50
+ describe('Security', () => {
51
+ it('should validate URLs are HTTPS', async () => {
52
+ const { SecurityValidator } = await import('../core/security');
53
+ expect(SecurityValidator.validateUrl('https://example.com')).toBe(true);
54
+ expect(SecurityValidator.validateUrl('http://example.com')).toBe(false);
55
+ });
56
+ it('should validate checksums', async () => {
57
+ const { SecurityValidator } = await import('../core/security');
58
+ const validChecksum = 'a'.repeat(64);
59
+ const invalidChecksum = 'invalid';
60
+ expect(SecurityValidator.validateChecksum(validChecksum)).toBe(true);
61
+ expect(SecurityValidator.validateChecksum(invalidChecksum)).toBe(false);
62
+ });
63
+ });
64
+ describe('Version Management', () => {
65
+ it('should compare versions correctly', async () => {
66
+ const { VersionManager } = await import('../live-update/version-manager');
67
+ expect(VersionManager.compareVersions('1.0.0', '1.0.1')).toBe(-1);
68
+ expect(VersionManager.compareVersions('2.0.0', '1.9.9')).toBe(1);
69
+ expect(VersionManager.compareVersions('1.0.0', '1.0.0')).toBe(0);
70
+ });
71
+ it('should determine if update is needed', async () => {
72
+ const { VersionManager } = await import('../live-update/version-manager');
73
+ expect(VersionManager.shouldUpdate('1.0.0', '1.0.1')).toBe(true);
74
+ expect(VersionManager.shouldUpdate('1.0.1', '1.0.0')).toBe(false);
75
+ });
76
+ });
77
+ });
78
+ //# sourceMappingURL=integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration.test.js","sourceRoot":"","sources":["../../../src/__tests__/integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { SecurityValidator } from '../core/security';
3
+ describe('SecurityValidator', () => {
4
+ describe('validateUrl', () => {
5
+ it('should accept HTTPS URLs', () => {
6
+ expect(SecurityValidator.validateUrl('https://example.com')).toBe(true);
7
+ expect(SecurityValidator.validateUrl('https://sub.example.com/path')).toBe(true);
8
+ expect(SecurityValidator.validateUrl('https://example.com:8443')).toBe(true);
9
+ });
10
+ it('should reject HTTP URLs', () => {
11
+ expect(SecurityValidator.validateUrl('http://example.com')).toBe(false);
12
+ expect(SecurityValidator.validateUrl('http://localhost')).toBe(false);
13
+ });
14
+ it('should reject invalid URLs', () => {
15
+ expect(SecurityValidator.validateUrl('not-a-url')).toBe(false);
16
+ expect(SecurityValidator.validateUrl('')).toBe(false);
17
+ expect(SecurityValidator.validateUrl('javascript:alert(1)')).toBe(false);
18
+ });
19
+ });
20
+ describe('validateChecksum', () => {
21
+ it('should validate SHA-256 checksums', () => {
22
+ const validChecksum = 'a'.repeat(64);
23
+ expect(SecurityValidator.validateChecksum(validChecksum)).toBe(true);
24
+ });
25
+ it('should reject invalid checksums', () => {
26
+ expect(SecurityValidator.validateChecksum('too-short')).toBe(false);
27
+ expect(SecurityValidator.validateChecksum('invalid@chars')).toBe(false);
28
+ expect(SecurityValidator.validateChecksum('')).toBe(false);
29
+ });
30
+ });
31
+ describe('sanitizeInput', () => {
32
+ it('should sanitize dangerous input', () => {
33
+ expect(SecurityValidator.sanitizeInput('<script>alert(1)</script>')).toBe('alert1');
34
+ expect(SecurityValidator.sanitizeInput('normal text')).toBe('normal text');
35
+ expect(SecurityValidator.sanitizeInput('path/to/file')).toBe('path/to/file');
36
+ });
37
+ it('should handle null and undefined', () => {
38
+ expect(SecurityValidator.sanitizeInput(null)).toBe('');
39
+ expect(SecurityValidator.sanitizeInput(undefined)).toBe('');
40
+ });
41
+ });
42
+ describe('validateBundleSize', () => {
43
+ it('should accept reasonable bundle sizes', () => {
44
+ expect(SecurityValidator.validateBundleSize(1024 * 1024)).toBe(true); // 1MB
45
+ expect(SecurityValidator.validateBundleSize(50 * 1024 * 1024)).toBe(true); // 50MB
46
+ });
47
+ it('should reject excessive sizes', () => {
48
+ expect(SecurityValidator.validateBundleSize(200 * 1024 * 1024)).toBe(false); // 200MB
49
+ expect(SecurityValidator.validateBundleSize(-1)).toBe(false);
50
+ expect(SecurityValidator.validateBundleSize(0)).toBe(false);
51
+ });
52
+ });
53
+ });
54
+ //# sourceMappingURL=security.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.test.js","sourceRoot":"","sources":["../../../src/__tests__/security.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};