capacitor-secure-storage-plugin 0.11.0 → 0.13.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/CapacitorSecureStoragePlugin.podspec +2 -2
- package/Package.swift +30 -0
- package/README.md +17 -1
- package/android/build.gradle +9 -9
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js.map +1 -1
- package/ios/{Plugin/SecureStoragePluginPlugin.swift → Sources/SecureStoragePlugin/SecureStoragePlugin.swift} +11 -1
- package/ios/Tests/SecureStoragePluginTests/SecureStoragePluginTests.swift +247 -0
- package/package.json +17 -15
- package/ios/Plugin/Info.plist +0 -24
- package/ios/Plugin/SecureStoragePluginPlugin.h +0 -10
- package/ios/Plugin/SecureStoragePluginPlugin.m +0 -13
|
@@ -10,8 +10,8 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.homepage = package['repository']['url']
|
|
11
11
|
s.author = package['author']
|
|
12
12
|
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
-
s.source_files = 'ios/
|
|
14
|
-
s.ios.deployment_target = '
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '15.0'
|
|
15
15
|
s.dependency 'Capacitor'
|
|
16
16
|
s.dependency 'SwiftKeychainWrapper'
|
|
17
17
|
s.swift_version = '5.1'
|
package/Package.swift
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapacitorSecureStoragePlugin",
|
|
6
|
+
platforms: [.iOS(.v15)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "CapacitorSecureStoragePlugin",
|
|
10
|
+
targets: ["SecureStoragePlugin"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
|
|
14
|
+
.package(url: "https://github.com/jrendel/SwiftKeychainWrapper.git", from: "4.0.0")
|
|
15
|
+
],
|
|
16
|
+
targets: [
|
|
17
|
+
.target(
|
|
18
|
+
name: "SecureStoragePlugin",
|
|
19
|
+
dependencies: [
|
|
20
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
21
|
+
.product(name: "Cordova", package: "capacitor-swift-pm"),
|
|
22
|
+
.product(name: "SwiftKeychainWrapper", package: "SwiftKeychainWrapper")
|
|
23
|
+
],
|
|
24
|
+
path: "ios/Sources/SecureStoragePlugin"),
|
|
25
|
+
.testTarget(
|
|
26
|
+
name: "SecureStoragePluginTests",
|
|
27
|
+
dependencies: ["SecureStoragePlugin"],
|
|
28
|
+
path: "ios/Tests/SecureStoragePluginTests")
|
|
29
|
+
]
|
|
30
|
+
)
|
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://badge.fury.io/js/capacitor-secure-storage-plugin)
|
|
2
|
+
|
|
1
3
|
# capacitor-secure-storage-plugin
|
|
2
4
|
|
|
3
5
|
Capacitor plugin for storing string values securly on iOS and Android.
|
|
@@ -182,6 +184,20 @@ async getUsername(key: string) {
|
|
|
182
184
|
|
|
183
185
|
This plugin uses SwiftKeychainWrapper under the hood for iOS.
|
|
184
186
|
|
|
187
|
+
After reinstalling an app, the data stored in the keychain are not deleted automatically. To clear the data the following code has to be added to AppDelegate.swift. This is just an example, there are multiple ways how it can be achieved.
|
|
188
|
+
|
|
189
|
+
```swift
|
|
190
|
+
import SwiftKeychainWrapper
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
if !UserDefaults.standard.bool(forKey: "firstTimeLaunchOccurred") {
|
|
194
|
+
let keychainWrapper = KeychainWrapper(serviceName: "cap_sec")
|
|
195
|
+
keychainWrapper.removeAllKeys()
|
|
196
|
+
|
|
197
|
+
UserDefaults.standard.set(true, forKey: "firstTimeLaunchOccurred")
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
185
201
|
> **Warning**
|
|
186
202
|
> Up to version v0.4.0 there was standard keychain used. Since v0.5.0 there is separate keychain wrapper, so keys() method returns only keys set in v0.5.0 or higher version.
|
|
187
203
|
|
|
@@ -194,4 +210,4 @@ On Android it is implemented by AndroidKeyStore and SharedPreferences. Source: [
|
|
|
194
210
|
|
|
195
211
|
### Web
|
|
196
212
|
|
|
197
|
-
There is no secure storage in browser (not because it is not implemented by this plugin, but it does not exist at all). Values are stored in LocalStorage, but they are at least base64 encoded. Plugin adds '
|
|
213
|
+
There is no secure storage in browser (not because it is not implemented by this plugin, but it does not exist at all). Values are stored in LocalStorage, but they are at least base64 encoded. Plugin adds 'cap_sec' prefix to keys to avoid conflicts with other data stored in LocalStorage.
|
package/android/build.gradle
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
ext {
|
|
2
2
|
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
-
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.
|
|
4
|
-
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.
|
|
5
|
-
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
buildscript {
|
|
@@ -11,18 +11,18 @@ buildscript {
|
|
|
11
11
|
mavenCentral()
|
|
12
12
|
}
|
|
13
13
|
dependencies {
|
|
14
|
-
classpath 'com.android.tools.build:gradle:8.
|
|
14
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
apply plugin: 'com.android.library'
|
|
19
19
|
|
|
20
20
|
android {
|
|
21
|
-
namespace "com.whitestein.securestorage"
|
|
22
|
-
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion :
|
|
21
|
+
namespace = "com.whitestein.securestorage"
|
|
22
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
23
23
|
defaultConfig {
|
|
24
|
-
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion :
|
|
25
|
-
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion :
|
|
24
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
|
25
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
26
26
|
versionCode 1
|
|
27
27
|
versionName "1.0"
|
|
28
28
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
@@ -34,7 +34,7 @@ android {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
lintOptions {
|
|
37
|
-
abortOnError false
|
|
37
|
+
abortOnError = false
|
|
38
38
|
}
|
|
39
39
|
compileOptions {
|
|
40
40
|
sourceCompatibility JavaVersion.VERSION_21
|
package/dist/esm/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,sBACX,SAAQ,SAAS;IADnB;;QAGE,WAAM,GAAG,UAAU,CAAC;QAyCZ,cAAS,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAC/C,iBAAY,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAzCC,GAAG,CAAC,OAAwB;QAC1B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,KAAK,IAAI;YACnB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;gBACd,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;aACnB,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC,CAAC;IAC3D,CAAC;IACD,GAAG,CAAC,OAAuC;QACzC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACvE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,CAAC,OAAwB;QAC7B,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,MAAM,OAAO,sBACX,SAAQ,SAAS;IADnB;;QAGE,WAAM,GAAG,UAAU,CAAC;QAyCZ,cAAS,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;QAC/C,iBAAY,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;IAzCC,GAAG,CAAC,OAAwB;QAC1B,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,OAAO,KAAK,KAAK,IAAI;YACnB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;gBACd,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;aACnB,CAAC;YACJ,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC,CAAC;IAC3D,CAAC;IACD,GAAG,CAAC,OAAuC;QACzC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QACvE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,CAAC,OAAwB;QAC7B,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACtD,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YACrD,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,OAAO,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IACD,KAAK;QACH,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI;QACF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;aACnC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;aACzC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,WAAW;QACT,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;CAIF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\nimport type { SecureStoragePluginPlugin } from './definitions';\n\nexport class SecureStoragePluginWeb\n extends WebPlugin\n implements SecureStoragePluginPlugin {\n PREFIX = 'cap_sec_';\n\n get(options: { key: string }): Promise<{ value: string }> {\n const value = localStorage.getItem(this.addPrefix(options.key));\n return value !== null\n ? Promise.resolve({\n value: atob(value),\n })\n : Promise.reject('Item with given key does not exist');\n }\n set(options: { key: string; value: string }): Promise<{ value: boolean }> {\n localStorage.setItem(this.addPrefix(options.key), btoa(options.value));\n return Promise.resolve({ value: true });\n }\n remove(options: { key: string }): Promise<{ value: boolean }> {\n if (localStorage.getItem(this.addPrefix(options.key))) {\n localStorage.removeItem(this.addPrefix(options.key));\n return Promise.resolve({ value: true });\n } else {\n return Promise.reject('Item with given key does not exist');\n }\n }\n clear(): Promise<{ value: boolean }> {\n for (const key in localStorage) {\n if (key.indexOf(this.PREFIX) === 0) {\n localStorage.removeItem(key);\n }\n }\n return Promise.resolve({ value: true });\n }\n keys(): Promise<{ value: string[] }> {\n const keys = Object.keys(localStorage)\n .filter(k => k.indexOf(this.PREFIX) === 0)\n .map(this.removePrefix);\n return Promise.resolve({ value: keys });\n }\n\n getPlatform(): Promise<{ value: string }> {\n return Promise.resolve({ value: 'web' });\n }\n\n private addPrefix = (key: string) => this.PREFIX + key;\n private removePrefix = (key: string) => key.replace(this.PREFIX, '');\n}\n"]}
|
package/dist/plugin.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SecureStoragePlugin = registerPlugin('SecureStoragePlugin', {\n web: () => import('./web').then(m => new m.SecureStoragePluginWeb()),\n});\nexport * from './definitions';\nexport { SecureStoragePlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SecureStoragePluginWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.PREFIX = 'cap_sec_';\n this.addPrefix = (key) => this.PREFIX + key;\n this.removePrefix = (key) => key.replace(this.PREFIX, '');\n }\n get(options) {\n const value = localStorage.getItem(this.addPrefix(options.key));\n return value !== null\n ? Promise.resolve({\n value: atob(value),\n })\n : Promise.reject('Item with given key does not exist');\n }\n set(options) {\n localStorage.setItem(this.addPrefix(options.key), btoa(options.value));\n return Promise.resolve({ value: true });\n }\n remove(options) {\n if (localStorage.getItem(this.addPrefix(options.key))) {\n localStorage.removeItem(this.addPrefix(options.key));\n return Promise.resolve({ value: true });\n }\n else {\n return Promise.reject('Item with given key does not exist');\n }\n }\n clear() {\n for (const key in localStorage) {\n if (key.indexOf(this.PREFIX) === 0) {\n localStorage.removeItem(key);\n }\n }\n return Promise.resolve({ value: true });\n }\n keys() {\n const keys = Object.keys(localStorage)\n .filter(k => k.indexOf(this.PREFIX) === 0)\n .map(this.removePrefix);\n return Promise.resolve({ value: keys });\n }\n getPlatform() {\n return Promise.resolve({ value: 'web' });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,mBAAmB,GAAGA,mBAAc,CAAC,qBAAqB,EAAE;AAClE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,sBAAsB,EAAE,CAAC;AACxE,CAAC;;ACFM,MAAM,sBAAsB,SAASC,cAAS,CAAC;AACtD,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;AAC3B,QAAQ,IAAI,CAAC,MAAM,GAAG,UAAU;AAChC,QAAQ,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG;AACnD,QAAQ,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACjE;
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SecureStoragePlugin = registerPlugin('SecureStoragePlugin', {\n web: () => import('./web').then(m => new m.SecureStoragePluginWeb()),\n});\nexport * from './definitions';\nexport { SecureStoragePlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SecureStoragePluginWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.PREFIX = 'cap_sec_';\n this.addPrefix = (key) => this.PREFIX + key;\n this.removePrefix = (key) => key.replace(this.PREFIX, '');\n }\n get(options) {\n const value = localStorage.getItem(this.addPrefix(options.key));\n return value !== null\n ? Promise.resolve({\n value: atob(value),\n })\n : Promise.reject('Item with given key does not exist');\n }\n set(options) {\n localStorage.setItem(this.addPrefix(options.key), btoa(options.value));\n return Promise.resolve({ value: true });\n }\n remove(options) {\n if (localStorage.getItem(this.addPrefix(options.key))) {\n localStorage.removeItem(this.addPrefix(options.key));\n return Promise.resolve({ value: true });\n }\n else {\n return Promise.reject('Item with given key does not exist');\n }\n }\n clear() {\n for (const key in localStorage) {\n if (key.indexOf(this.PREFIX) === 0) {\n localStorage.removeItem(key);\n }\n }\n return Promise.resolve({ value: true });\n }\n keys() {\n const keys = Object.keys(localStorage)\n .filter(k => k.indexOf(this.PREFIX) === 0)\n .map(this.removePrefix);\n return Promise.resolve({ value: keys });\n }\n getPlatform() {\n return Promise.resolve({ value: 'web' });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,mBAAmB,GAAGA,mBAAc,CAAC,qBAAqB,EAAE;AAClE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,sBAAsB,EAAE,CAAC;AACxE,CAAC;;ACFM,MAAM,sBAAsB,SAASC,cAAS,CAAC;AACtD,IAAI,WAAW,GAAG;AAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;AAC3B,QAAQ,IAAI,CAAC,MAAM,GAAG,UAAU;AAChC,QAAQ,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG;AACnD,QAAQ,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AACjE,IAAI;AACJ,IAAI,GAAG,CAAC,OAAO,EAAE;AACjB,QAAQ,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACvE,QAAQ,OAAO,KAAK,KAAK;AACzB,cAAc,OAAO,CAAC,OAAO,CAAC;AAC9B,gBAAgB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;AAClC,aAAa;AACb,cAAc,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC;AAClE,IAAI;AACJ,IAAI,GAAG,CAAC,OAAO,EAAE;AACjB,QAAQ,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC/C,IAAI;AACJ,IAAI,MAAM,CAAC,OAAO,EAAE;AACpB,QAAQ,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE;AAC/D,YAAY,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAChE,YAAY,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACnD,QAAQ;AACR,aAAa;AACb,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC;AACvE,QAAQ;AACR,IAAI;AACJ,IAAI,KAAK,GAAG;AACZ,QAAQ,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;AACxC,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;AAChD,gBAAgB,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;AAC5C,YAAY;AACZ,QAAQ;AACR,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC/C,IAAI;AACJ,IAAI,IAAI,GAAG;AACX,QAAQ,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY;AAC7C,aAAa,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACrD,aAAa,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;AACnC,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC/C,IAAI;AACJ,IAAI,WAAW,GAAG;AAClB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAChD,IAAI;AACJ;;;;;;;;;"}
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SecureStoragePlugin = registerPlugin('SecureStoragePlugin', {\n web: () => import('./web').then(m => new m.SecureStoragePluginWeb()),\n});\nexport * from './definitions';\nexport { SecureStoragePlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SecureStoragePluginWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.PREFIX = 'cap_sec_';\n this.addPrefix = (key) => this.PREFIX + key;\n this.removePrefix = (key) => key.replace(this.PREFIX, '');\n }\n get(options) {\n const value = localStorage.getItem(this.addPrefix(options.key));\n return value !== null\n ? Promise.resolve({\n value: atob(value),\n })\n : Promise.reject('Item with given key does not exist');\n }\n set(options) {\n localStorage.setItem(this.addPrefix(options.key), btoa(options.value));\n return Promise.resolve({ value: true });\n }\n remove(options) {\n if (localStorage.getItem(this.addPrefix(options.key))) {\n localStorage.removeItem(this.addPrefix(options.key));\n return Promise.resolve({ value: true });\n }\n else {\n return Promise.reject('Item with given key does not exist');\n }\n }\n clear() {\n for (const key in localStorage) {\n if (key.indexOf(this.PREFIX) === 0) {\n localStorage.removeItem(key);\n }\n }\n return Promise.resolve({ value: true });\n }\n keys() {\n const keys = Object.keys(localStorage)\n .filter(k => k.indexOf(this.PREFIX) === 0)\n .map(this.removePrefix);\n return Promise.resolve({ value: keys });\n }\n getPlatform() {\n return Promise.resolve({ value: 'web' });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,mBAAmB,GAAGA,mBAAc,CAAC,qBAAqB,EAAE;IAClE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,sBAAsB,EAAE,CAAC;IACxE,CAAC;;ICFM,MAAM,sBAAsB,SAASC,cAAS,CAAC;IACtD,IAAI,WAAW,GAAG;IAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3B,QAAQ,IAAI,CAAC,MAAM,GAAG,UAAU;IAChC,QAAQ,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG;IACnD,QAAQ,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACjE;
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SecureStoragePlugin = registerPlugin('SecureStoragePlugin', {\n web: () => import('./web').then(m => new m.SecureStoragePluginWeb()),\n});\nexport * from './definitions';\nexport { SecureStoragePlugin };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SecureStoragePluginWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.PREFIX = 'cap_sec_';\n this.addPrefix = (key) => this.PREFIX + key;\n this.removePrefix = (key) => key.replace(this.PREFIX, '');\n }\n get(options) {\n const value = localStorage.getItem(this.addPrefix(options.key));\n return value !== null\n ? Promise.resolve({\n value: atob(value),\n })\n : Promise.reject('Item with given key does not exist');\n }\n set(options) {\n localStorage.setItem(this.addPrefix(options.key), btoa(options.value));\n return Promise.resolve({ value: true });\n }\n remove(options) {\n if (localStorage.getItem(this.addPrefix(options.key))) {\n localStorage.removeItem(this.addPrefix(options.key));\n return Promise.resolve({ value: true });\n }\n else {\n return Promise.reject('Item with given key does not exist');\n }\n }\n clear() {\n for (const key in localStorage) {\n if (key.indexOf(this.PREFIX) === 0) {\n localStorage.removeItem(key);\n }\n }\n return Promise.resolve({ value: true });\n }\n keys() {\n const keys = Object.keys(localStorage)\n .filter(k => k.indexOf(this.PREFIX) === 0)\n .map(this.removePrefix);\n return Promise.resolve({ value: keys });\n }\n getPlatform() {\n return Promise.resolve({ value: 'web' });\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,mBAAmB,GAAGA,mBAAc,CAAC,qBAAqB,EAAE;IAClE,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,sBAAsB,EAAE,CAAC;IACxE,CAAC;;ICFM,MAAM,sBAAsB,SAASC,cAAS,CAAC;IACtD,IAAI,WAAW,GAAG;IAClB,QAAQ,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3B,QAAQ,IAAI,CAAC,MAAM,GAAG,UAAU;IAChC,QAAQ,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,GAAG,GAAG;IACnD,QAAQ,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IACjE,IAAI;IACJ,IAAI,GAAG,CAAC,OAAO,EAAE;IACjB,QAAQ,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvE,QAAQ,OAAO,KAAK,KAAK;IACzB,cAAc,OAAO,CAAC,OAAO,CAAC;IAC9B,gBAAgB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;IAClC,aAAa;IACb,cAAc,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC;IAClE,IAAI;IACJ,IAAI,GAAG,CAAC,OAAO,EAAE;IACjB,QAAQ,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9E,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI;IACJ,IAAI,MAAM,CAAC,OAAO,EAAE;IACpB,QAAQ,IAAI,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE;IAC/D,YAAY,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChE,YAAY,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACnD,QAAQ;IACR,aAAa;IACb,YAAY,OAAO,OAAO,CAAC,MAAM,CAAC,oCAAoC,CAAC;IACvE,QAAQ;IACR,IAAI;IACJ,IAAI,KAAK,GAAG;IACZ,QAAQ,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE;IACxC,YAAY,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;IAChD,gBAAgB,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;IAC5C,YAAY;IACZ,QAAQ;IACR,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI;IACJ,IAAI,IAAI,GAAG;IACX,QAAQ,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY;IAC7C,aAAa,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IACrD,aAAa,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC;IACnC,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI;IACJ,IAAI,WAAW,GAAG;IAClB,QAAQ,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAChD,IAAI;IACJ;;;;;;;;;;;;;;;"}
|
|
@@ -7,7 +7,17 @@ import SwiftKeychainWrapper
|
|
|
7
7
|
* here: https://capacitor.ionicframework.com/docs/plugins/ios
|
|
8
8
|
*/
|
|
9
9
|
@objc(SecureStoragePlugin)
|
|
10
|
-
public class SecureStoragePlugin: CAPPlugin {
|
|
10
|
+
public class SecureStoragePlugin: CAPPlugin, CAPBridgedPlugin {
|
|
11
|
+
public let identifier = "SecureStoragePlugin"
|
|
12
|
+
public let jsName = "SecureStoragePlugin"
|
|
13
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
14
|
+
CAPPluginMethod(name: "set", returnType: CAPPluginReturnPromise),
|
|
15
|
+
CAPPluginMethod(name: "get", returnType: CAPPluginReturnPromise),
|
|
16
|
+
CAPPluginMethod(name: "keys", returnType: CAPPluginReturnPromise),
|
|
17
|
+
CAPPluginMethod(name: "remove", returnType: CAPPluginReturnPromise),
|
|
18
|
+
CAPPluginMethod(name: "clear", returnType: CAPPluginReturnPromise),
|
|
19
|
+
CAPPluginMethod(name: "getPlatform", returnType: CAPPluginReturnPromise),
|
|
20
|
+
]
|
|
11
21
|
var keychainwrapper: KeychainWrapper = KeychainWrapper.init(serviceName: "cap_sec")
|
|
12
22
|
|
|
13
23
|
@objc func set(_ call: CAPPluginCall) {
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
import Capacitor
|
|
3
|
+
import SwiftKeychainWrapper
|
|
4
|
+
|
|
5
|
+
@testable import Plugin
|
|
6
|
+
|
|
7
|
+
class PluginTests: XCTestCase {
|
|
8
|
+
|
|
9
|
+
func setupDedicatedWrapper() -> KeychainWrapper {
|
|
10
|
+
let wrapper = KeychainWrapper.init(serviceName: "cap_sec")
|
|
11
|
+
wrapper.removeAllKeys()
|
|
12
|
+
return wrapper
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func testSet() {
|
|
16
|
+
let key = "key"
|
|
17
|
+
let value = "Hello, World!"
|
|
18
|
+
let valueModified = "Modified"
|
|
19
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
20
|
+
KeychainWrapper.standard.set(value, forKey: key)
|
|
21
|
+
|
|
22
|
+
let plugin = SecureStoragePlugin()
|
|
23
|
+
|
|
24
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
25
|
+
"key": key,
|
|
26
|
+
"value": valueModified
|
|
27
|
+
], success: { (result, call) in
|
|
28
|
+
let resultValue = result!.data?["value"] as? Bool
|
|
29
|
+
XCTAssertTrue(resultValue ?? false)
|
|
30
|
+
// dedicated keychain wrapper
|
|
31
|
+
let dedicatedValue = keychainwrapper.string(forKey: key)
|
|
32
|
+
XCTAssertEqual(valueModified, dedicatedValue)
|
|
33
|
+
// standard keychain wrapper should not be modified
|
|
34
|
+
let standardValue = KeychainWrapper.standard.string(forKey: key)
|
|
35
|
+
XCTAssertEqual(value, standardValue)
|
|
36
|
+
}, error: { (err) in
|
|
37
|
+
XCTFail("Error shouldn't have been called")
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
plugin.set(call!)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func testGet() {
|
|
44
|
+
let key = "key"
|
|
45
|
+
let value = "Hello, World!"
|
|
46
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
47
|
+
keychainwrapper.set(value, forKey: key)
|
|
48
|
+
|
|
49
|
+
let plugin = SecureStoragePlugin()
|
|
50
|
+
|
|
51
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
52
|
+
"key": key
|
|
53
|
+
], success: { (result, call) in
|
|
54
|
+
let resultValue = result!.data?["value"] as? String
|
|
55
|
+
XCTAssertEqual(value, resultValue)
|
|
56
|
+
}, error: { (err) in
|
|
57
|
+
XCTFail("Error shouldn't have been called")
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
plugin.get(call!)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func testGetCopy() {
|
|
64
|
+
let key = "key"
|
|
65
|
+
let value = "Hello, World!"
|
|
66
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
67
|
+
|
|
68
|
+
KeychainWrapper.standard.set(value, forKey: key)
|
|
69
|
+
|
|
70
|
+
let plugin = SecureStoragePlugin()
|
|
71
|
+
|
|
72
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
73
|
+
"key": key
|
|
74
|
+
], success: { (result, call) in
|
|
75
|
+
let resultValue = result!.data?["value"] as? String
|
|
76
|
+
XCTAssertEqual(value, resultValue)
|
|
77
|
+
let dedicatedValue = keychainwrapper.string(forKey: key)
|
|
78
|
+
XCTAssertEqual(value, dedicatedValue)
|
|
79
|
+
let standardValue = KeychainWrapper.standard.string(forKey: key)
|
|
80
|
+
XCTAssertNil(standardValue)
|
|
81
|
+
}, error: { (err) in
|
|
82
|
+
XCTFail("Error shouldn't have been called")
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
plugin.get(call!)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func testKeys() {
|
|
89
|
+
let key = "key"
|
|
90
|
+
let key2 = "key2"
|
|
91
|
+
let value = "value"
|
|
92
|
+
|
|
93
|
+
let plugin = SecureStoragePlugin()
|
|
94
|
+
|
|
95
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
96
|
+
keychainwrapper.set(value, forKey: key)
|
|
97
|
+
keychainwrapper.set(value, forKey: key2)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
let callOne = CAPPluginCall(callbackId: "test", options: [:],
|
|
101
|
+
success: { (result, call) in
|
|
102
|
+
let resultValue = result!.data?["value"] as? Array<String>
|
|
103
|
+
XCTAssertEqual(2, resultValue!.count)
|
|
104
|
+
XCTAssertTrue(resultValue!.contains(key))
|
|
105
|
+
XCTAssertTrue(resultValue!.contains(key2))
|
|
106
|
+
}, error: { (err) in
|
|
107
|
+
XCTFail("Error shouldn't have been called")
|
|
108
|
+
})
|
|
109
|
+
plugin.keys(callOne!)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func testNonExistingGet() {
|
|
113
|
+
let key = "keyNonExisting"
|
|
114
|
+
|
|
115
|
+
let plugin = SecureStoragePlugin()
|
|
116
|
+
|
|
117
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
118
|
+
"key": key
|
|
119
|
+
], success: { (result, call) in
|
|
120
|
+
XCTFail("Error shouldn't have been called")
|
|
121
|
+
}, error: { (err) in
|
|
122
|
+
XCTAssertNotNil(err)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
plugin.get(call!)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func testNonExistingRemoveBoth() {
|
|
129
|
+
let key = "keyNonExisting"
|
|
130
|
+
|
|
131
|
+
let plugin = SecureStoragePlugin()
|
|
132
|
+
|
|
133
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
134
|
+
"key": key
|
|
135
|
+
], success: { (result, call) in
|
|
136
|
+
XCTFail("Error shouldn't have been called")
|
|
137
|
+
}, error: { (err) in
|
|
138
|
+
XCTAssertNotNil(err)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
plugin.remove(call!)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func testRemoveBoth() {
|
|
145
|
+
let key = "key"
|
|
146
|
+
let value = "Hello, World!"
|
|
147
|
+
// prefill dedicated keychain wrapper
|
|
148
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
149
|
+
keychainwrapper.set(value, forKey: key)
|
|
150
|
+
// prefill standard keychain wrapper
|
|
151
|
+
KeychainWrapper.standard.set(value, forKey: key)
|
|
152
|
+
|
|
153
|
+
let plugin = SecureStoragePlugin()
|
|
154
|
+
|
|
155
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
156
|
+
"key": key
|
|
157
|
+
], success: { (result, call) in
|
|
158
|
+
let resultValue = result!.data?["value"] as? Bool
|
|
159
|
+
XCTAssertTrue(resultValue ?? false)
|
|
160
|
+
// dedicated keychain wrapper
|
|
161
|
+
let dedicatedValue = keychainwrapper.string(forKey: key)
|
|
162
|
+
XCTAssertNil(dedicatedValue)
|
|
163
|
+
// standard keychain wrapper
|
|
164
|
+
let standardValueRemoved = KeychainWrapper.standard.string(forKey: key)
|
|
165
|
+
XCTAssertNil(standardValueRemoved)
|
|
166
|
+
}, error: { (err) in
|
|
167
|
+
XCTFail("Error shouldn't have been called")
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
plugin.remove(call!)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// same as testRemoveBoth, but don't prefill standard wrapper
|
|
174
|
+
func testRemove() {
|
|
175
|
+
let key = "key"
|
|
176
|
+
let value = "Hello, World!"
|
|
177
|
+
// prefill dedicated keychain wrapper
|
|
178
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
179
|
+
keychainwrapper.set(value, forKey: key)
|
|
180
|
+
|
|
181
|
+
let plugin = SecureStoragePlugin()
|
|
182
|
+
|
|
183
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
184
|
+
"key": key
|
|
185
|
+
], success: { (result, call) in
|
|
186
|
+
let resultValue = result!.data?["value"] as? Bool
|
|
187
|
+
XCTAssertTrue(resultValue ?? false)
|
|
188
|
+
// dedicated keychain wrapper
|
|
189
|
+
let dedicatedValue = keychainwrapper.string(forKey: key)
|
|
190
|
+
XCTAssertNil(dedicatedValue)
|
|
191
|
+
}, error: { (err) in
|
|
192
|
+
XCTFail("Error shouldn't have been called")
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
plugin.remove(call!)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
func testClear() {
|
|
199
|
+
let key = "key"
|
|
200
|
+
let value = "Hello, World!"
|
|
201
|
+
let standardOnlyKey = "standard key"
|
|
202
|
+
let standardOnlyValue = "standard value"
|
|
203
|
+
// prefill dedicated keychain wrapper
|
|
204
|
+
let keychainwrapper = setupDedicatedWrapper()
|
|
205
|
+
keychainwrapper.set(value, forKey: key)
|
|
206
|
+
keychainwrapper.set(value + "2", forKey: key + "2")
|
|
207
|
+
// prefill standard keychain wrapper
|
|
208
|
+
KeychainWrapper.standard.set(value, forKey: key)
|
|
209
|
+
KeychainWrapper.standard.set(standardOnlyValue, forKey: standardOnlyKey)
|
|
210
|
+
|
|
211
|
+
let plugin = SecureStoragePlugin()
|
|
212
|
+
|
|
213
|
+
let call = CAPPluginCall(callbackId: "test", options: [
|
|
214
|
+
"key": key
|
|
215
|
+
], success: { (result, call) in
|
|
216
|
+
let resultValue = result!.data?["value"] as? Bool
|
|
217
|
+
XCTAssertTrue(resultValue ?? false)
|
|
218
|
+
// key present in dedicated and standard wrapper removed
|
|
219
|
+
let dedicatedValue = keychainwrapper.string(forKey: key)
|
|
220
|
+
XCTAssertNil(dedicatedValue)
|
|
221
|
+
let dedicatedValue2 = keychainwrapper.string(forKey: key + "2")
|
|
222
|
+
XCTAssertNil(dedicatedValue2)
|
|
223
|
+
let standardValue = KeychainWrapper.standard.string(forKey: key)
|
|
224
|
+
XCTAssertNil(standardValue)
|
|
225
|
+
// key only defined in standard wrapper still present
|
|
226
|
+
let standardValue2 = KeychainWrapper.standard.string(forKey: standardOnlyKey)
|
|
227
|
+
XCTAssertEqual(standardOnlyValue, standardValue2)
|
|
228
|
+
}, error: { (err) in
|
|
229
|
+
XCTFail("Error shouldn't have been called")
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
plugin.clear(call!)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
func testGetPlatform() {
|
|
236
|
+
let plugin = SecureStoragePlugin()
|
|
237
|
+
let call = CAPPluginCall(callbackId: "test",
|
|
238
|
+
success: { (result, call) in
|
|
239
|
+
let resultValue = result!.data?["value"] as? String
|
|
240
|
+
XCTAssertEqual("ios", resultValue)
|
|
241
|
+
}, error: { (err) in
|
|
242
|
+
XCTFail("Error shouldn't have been called")
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
plugin.getPlatform(call!)
|
|
246
|
+
}
|
|
247
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "capacitor-secure-storage-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Securely store secrets such as usernames, passwords, tokens, certificates or other sensitive information (strings) on iOS & Android",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
"android/src/main/",
|
|
11
11
|
"android/build.gradle",
|
|
12
12
|
"dist/",
|
|
13
|
-
"ios/
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
14
16
|
"CapacitorSecureStoragePlugin.podspec"
|
|
15
17
|
],
|
|
16
18
|
"author": "martinkasa",
|
|
@@ -29,7 +31,7 @@
|
|
|
29
31
|
],
|
|
30
32
|
"scripts": {
|
|
31
33
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
32
|
-
"verify:ios": "
|
|
34
|
+
"verify:ios": "xcodebuild -scheme CapacitorSecureStoragePlugin -destination generic/platform=iOS",
|
|
33
35
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
34
36
|
"verify:web": "npm run build",
|
|
35
37
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
@@ -44,25 +46,25 @@
|
|
|
44
46
|
"prepublishOnly": "npm run build"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
|
-
"@capacitor/android": "^
|
|
48
|
-
"@capacitor/cli": "^
|
|
49
|
-
"@capacitor/core": "^
|
|
50
|
-
"@capacitor/docgen": "^0.3.
|
|
51
|
-
"@capacitor/ios": "^
|
|
49
|
+
"@capacitor/android": "^8.0.0",
|
|
50
|
+
"@capacitor/cli": "^8.0.0",
|
|
51
|
+
"@capacitor/core": "^8.0.0",
|
|
52
|
+
"@capacitor/docgen": "^0.3.1",
|
|
53
|
+
"@capacitor/ios": "^8.0.0",
|
|
52
54
|
"@ionic/eslint-config": "^0.4.0",
|
|
53
55
|
"@ionic/prettier-config": "^4.0.0",
|
|
54
56
|
"@ionic/swiftlint-config": "^2.0.0",
|
|
55
|
-
"eslint": "^8.57.
|
|
56
|
-
"prettier": "^3.
|
|
57
|
-
"prettier-plugin-java": "^2.
|
|
57
|
+
"eslint": "^8.57.1",
|
|
58
|
+
"prettier": "^3.6.2",
|
|
59
|
+
"prettier-plugin-java": "^2.7.7",
|
|
58
60
|
"release-it": "^17.2.1",
|
|
59
|
-
"rimraf": "^6.0
|
|
60
|
-
"rollup": "^4.
|
|
61
|
+
"rimraf": "^6.1.0",
|
|
62
|
+
"rollup": "^4.53.2",
|
|
61
63
|
"swiftlint": "^2.0.0",
|
|
62
|
-
"typescript": "
|
|
64
|
+
"typescript": "^5.9.3"
|
|
63
65
|
},
|
|
64
66
|
"peerDependencies": {
|
|
65
|
-
"@capacitor/core": ">=
|
|
67
|
+
"@capacitor/core": ">=8.0.0"
|
|
66
68
|
},
|
|
67
69
|
"prettier": "@ionic/prettier-config",
|
|
68
70
|
"swiftlint": "@ionic/swiftlint-config",
|
package/ios/Plugin/Info.plist
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
-
<plist version="1.0">
|
|
4
|
-
<dict>
|
|
5
|
-
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
-
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
-
<key>CFBundleExecutable</key>
|
|
8
|
-
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
-
<key>CFBundleIdentifier</key>
|
|
10
|
-
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
-
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
-
<string>6.0</string>
|
|
13
|
-
<key>CFBundleName</key>
|
|
14
|
-
<string>$(PRODUCT_NAME)</string>
|
|
15
|
-
<key>CFBundlePackageType</key>
|
|
16
|
-
<string>FMWK</string>
|
|
17
|
-
<key>CFBundleShortVersionString</key>
|
|
18
|
-
<string>1.0</string>
|
|
19
|
-
<key>CFBundleVersion</key>
|
|
20
|
-
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
-
<key>NSPrincipalClass</key>
|
|
22
|
-
<string></string>
|
|
23
|
-
</dict>
|
|
24
|
-
</plist>
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
#import <UIKit/UIKit.h>
|
|
2
|
-
|
|
3
|
-
//! Project version number for Plugin.
|
|
4
|
-
FOUNDATION_EXPORT double PluginVersionNumber;
|
|
5
|
-
|
|
6
|
-
//! Project version string for Plugin.
|
|
7
|
-
FOUNDATION_EXPORT const unsigned char PluginVersionString[];
|
|
8
|
-
|
|
9
|
-
// In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
|
|
10
|
-
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#import <Foundation/Foundation.h>
|
|
2
|
-
#import <Capacitor/Capacitor.h>
|
|
3
|
-
|
|
4
|
-
// Define the plugin using the CAP_PLUGIN Macro, and
|
|
5
|
-
// each method the plugin supports using the CAP_PLUGIN_METHOD macro.
|
|
6
|
-
CAP_PLUGIN(SecureStoragePlugin, "SecureStoragePlugin",
|
|
7
|
-
CAP_PLUGIN_METHOD(set, CAPPluginReturnPromise);
|
|
8
|
-
CAP_PLUGIN_METHOD(get, CAPPluginReturnPromise);
|
|
9
|
-
CAP_PLUGIN_METHOD(keys, CAPPluginReturnPromise);
|
|
10
|
-
CAP_PLUGIN_METHOD(remove, CAPPluginReturnPromise);
|
|
11
|
-
CAP_PLUGIN_METHOD(clear, CAPPluginReturnPromise);
|
|
12
|
-
CAP_PLUGIN_METHOD(getPlatform, CAPPluginReturnPromise);
|
|
13
|
-
)
|