capacitor-secure-storage-plugin 0.11.0 → 0.12.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 +1 -1
- package/Package.swift +30 -0
- package/README.md +2 -0
- package/ios/{Plugin/SecureStoragePluginPlugin.swift → Sources/SecureStoragePlugin/SecureStoragePlugin.swift} +11 -1
- package/ios/Tests/SecureStoragePluginTests/SecureStoragePluginTests.swift +247 -0
- package/package.json +5 -3
- package/ios/Plugin/Info.plist +0 -24
- package/ios/Plugin/SecureStoragePluginPlugin.h +0 -10
- package/ios/Plugin/SecureStoragePluginPlugin.m +0 -13
|
@@ -10,7 +10,7 @@ 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/
|
|
13
|
+
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
14
|
s.ios.deployment_target = '14.0'
|
|
15
15
|
s.dependency 'Capacitor'
|
|
16
16
|
s.dependency 'SwiftKeychainWrapper'
|
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(.v14)],
|
|
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: "7.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
|
@@ -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.12.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",
|
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
|
-
)
|