@capgo/capacitor-autofill-save-password 7.0.4 → 7.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -6
- package/android/src/main/java/ee/forgr/autofill_password/SavePasswordPlugin.java +65 -9
- package/dist/docs.json +47 -0
- package/dist/esm/definitions.d.ts +20 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +2 -1
- package/dist/esm/web.js +4 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +4 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +4 -1
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/SavePasswordPlugin/SavePasswordPlugin.swift +77 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,8 +5,8 @@ Prompt to display dialog for saving password to keychain from webview app
|
|
|
5
5
|
<a href="https://capgo.app/"><img src='https://raw.githubusercontent.com/Cap-go/capgo/main/assets/capgo_banner.png' alt='Capgo - Instant updates for capacitor'/></a>
|
|
6
6
|
|
|
7
7
|
<div align="center">
|
|
8
|
-
<h2><a href="https://capgo.app/?ref=plugin"> ➡️ Get Instant updates for your App with Capgo
|
|
9
|
-
<h2><a href="https://capgo.app/consulting/?ref=plugin">
|
|
8
|
+
<h2><a href="https://capgo.app/?ref=plugin"> ➡️ Get Instant updates for your App with Capgo</a></h2>
|
|
9
|
+
<h2><a href="https://capgo.app/consulting/?ref=plugin"> Missing a feature? We’ll build the plugin for you 💪</a></h2>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
12
|
Fork of original plugin to work with Capacitor 7
|
|
@@ -82,6 +82,7 @@ with
|
|
|
82
82
|
<docgen-index>
|
|
83
83
|
|
|
84
84
|
* [`promptDialog(...)`](#promptdialog)
|
|
85
|
+
* [`readPassword()`](#readpassword)
|
|
85
86
|
* [Interfaces](#interfaces)
|
|
86
87
|
|
|
87
88
|
</docgen-index>
|
|
@@ -104,14 +105,36 @@ Save a password to the keychain.
|
|
|
104
105
|
--------------------
|
|
105
106
|
|
|
106
107
|
|
|
108
|
+
### readPassword()
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
readPassword() => Promise<ReadPasswordResult>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS.
|
|
115
|
+
|
|
116
|
+
**Returns:** <code>Promise<<a href="#readpasswordresult">ReadPasswordResult</a>></code>
|
|
117
|
+
|
|
118
|
+
--------------------
|
|
119
|
+
|
|
120
|
+
|
|
107
121
|
### Interfaces
|
|
108
122
|
|
|
109
123
|
|
|
110
124
|
#### Options
|
|
111
125
|
|
|
112
|
-
| Prop | Type | Description
|
|
113
|
-
| -------------- | ------------------- |
|
|
114
|
-
| **`username`** | <code>string</code> | The username to save.
|
|
115
|
-
| **`password`** | <code>string</code> | The password to save.
|
|
126
|
+
| Prop | Type | Description |
|
|
127
|
+
| -------------- | ------------------- | -------------------------------------------------------------------------- |
|
|
128
|
+
| **`username`** | <code>string</code> | The username to save. |
|
|
129
|
+
| **`password`** | <code>string</code> | The password to save. |
|
|
130
|
+
| **`url`** | <code>string</code> | The url to save the password for. (For example: "web.capgo.app") iOS only. |
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
#### ReadPasswordResult
|
|
134
|
+
|
|
135
|
+
| Prop | Type | Description |
|
|
136
|
+
| -------------- | ------------------- | ----------------------------- |
|
|
137
|
+
| **`username`** | <code>string</code> | The username of the password. |
|
|
138
|
+
| **`password`** | <code>string</code> | The password of the password. |
|
|
116
139
|
|
|
117
140
|
</docgen-api>
|
|
@@ -3,26 +3,31 @@ package ee.forgr.autofill_password;
|
|
|
3
3
|
import android.app.Activity;
|
|
4
4
|
import android.os.Build;
|
|
5
5
|
import android.util.Log;
|
|
6
|
-
|
|
7
|
-
import androidx.credentials.CredentialManager;
|
|
8
|
-
import androidx.credentials.CreatePasswordRequest;
|
|
6
|
+
import androidx.core.content.ContextCompat;
|
|
9
7
|
import androidx.credentials.CreateCredentialResponse;
|
|
10
|
-
import androidx.credentials.
|
|
8
|
+
import androidx.credentials.CreatePasswordRequest;
|
|
9
|
+
import androidx.credentials.CredentialManager;
|
|
11
10
|
import androidx.credentials.CredentialManagerCallback;
|
|
11
|
+
import androidx.credentials.GetCredentialRequest;
|
|
12
|
+
import androidx.credentials.GetCredentialResponse;
|
|
13
|
+
import androidx.credentials.GetPasswordOption;
|
|
14
|
+
import androidx.credentials.PasswordCredential;
|
|
15
|
+
import androidx.credentials.PendingGetCredentialRequest;
|
|
12
16
|
import androidx.credentials.exceptions.CreateCredentialException;
|
|
13
|
-
|
|
17
|
+
import androidx.credentials.exceptions.GetCredentialException;
|
|
18
|
+
import com.getcapacitor.JSObject;
|
|
14
19
|
import com.getcapacitor.Plugin;
|
|
15
20
|
import com.getcapacitor.PluginCall;
|
|
16
21
|
import com.getcapacitor.PluginMethod;
|
|
17
22
|
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
18
|
-
|
|
23
|
+
import java.util.Arrays;
|
|
19
24
|
import java.util.HashMap;
|
|
25
|
+
import java.util.List;
|
|
20
26
|
import java.util.Map;
|
|
21
27
|
|
|
22
|
-
import androidx.core.content.ContextCompat;
|
|
23
|
-
|
|
24
28
|
@CapacitorPlugin(name = "SavePassword")
|
|
25
29
|
public class SavePasswordPlugin extends Plugin {
|
|
30
|
+
|
|
26
31
|
private static final String TAG = "CredentialManager";
|
|
27
32
|
private CredentialManager credentialManager;
|
|
28
33
|
private Map<String, PendingGetCredentialRequest> pendingRequestsByElementId = new HashMap<>();
|
|
@@ -59,7 +64,7 @@ public class SavePasswordPlugin extends Plugin {
|
|
|
59
64
|
try {
|
|
60
65
|
// Build request directly with username & password (API 1.5.0 signature)
|
|
61
66
|
CreatePasswordRequest request = new CreatePasswordRequest(username, password);
|
|
62
|
-
|
|
67
|
+
|
|
63
68
|
// Execute on main thread
|
|
64
69
|
bridge.executeOnMainThread(() -> {
|
|
65
70
|
Activity activity = getActivity();
|
|
@@ -95,6 +100,57 @@ public class SavePasswordPlugin extends Plugin {
|
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
@PluginMethod
|
|
104
|
+
public void readPassword(final PluginCall call) {
|
|
105
|
+
if (!isCredentialManagerAvailable(call)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
GetCredentialRequest request = new GetCredentialRequest(List.of(new GetPasswordOption()));
|
|
111
|
+
|
|
112
|
+
bridge.executeOnMainThread(() -> {
|
|
113
|
+
Activity activity = getActivity();
|
|
114
|
+
if (activity == null) {
|
|
115
|
+
call.reject("Activity not available");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
credentialManager.getCredentialAsync(
|
|
121
|
+
activity,
|
|
122
|
+
request,
|
|
123
|
+
null,
|
|
124
|
+
ContextCompat.getMainExecutor(getContext()),
|
|
125
|
+
new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
|
|
126
|
+
@Override
|
|
127
|
+
public void onResult(GetCredentialResponse response) {
|
|
128
|
+
if (response.getCredential() instanceof PasswordCredential) {
|
|
129
|
+
PasswordCredential credential = (PasswordCredential) response.getCredential();
|
|
130
|
+
JSObject result = new JSObject();
|
|
131
|
+
result.put("username", credential.getId());
|
|
132
|
+
result.put("password", credential.getPassword());
|
|
133
|
+
call.resolve(result);
|
|
134
|
+
} else {
|
|
135
|
+
call.reject("No password credential found");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@Override
|
|
140
|
+
public void onError(GetCredentialException e) {
|
|
141
|
+
call.reject("Error retrieving credential: " + e.getMessage(), e);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
} catch (Exception e) {
|
|
146
|
+
call.reject("Error retrieving credential", e);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
} catch (Exception e) {
|
|
150
|
+
call.reject("Error building get credential request", e);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
98
154
|
private boolean isCredentialManagerAvailable(PluginCall call) {
|
|
99
155
|
if (credentialManager == null) {
|
|
100
156
|
call.reject("Credential Manager not available on this device");
|
package/dist/docs.json
CHANGED
|
@@ -44,6 +44,23 @@
|
|
|
44
44
|
"Options"
|
|
45
45
|
],
|
|
46
46
|
"slug": "promptdialog"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "readPassword",
|
|
50
|
+
"signature": "() => Promise<ReadPasswordResult>",
|
|
51
|
+
"parameters": [],
|
|
52
|
+
"returns": "Promise<ReadPasswordResult>",
|
|
53
|
+
"tags": [
|
|
54
|
+
{
|
|
55
|
+
"name": "returns",
|
|
56
|
+
"text": "The retrieved password credentials"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"docs": "Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS.",
|
|
60
|
+
"complexTypes": [
|
|
61
|
+
"ReadPasswordResult"
|
|
62
|
+
],
|
|
63
|
+
"slug": "readpassword"
|
|
47
64
|
}
|
|
48
65
|
],
|
|
49
66
|
"properties": []
|
|
@@ -78,6 +95,36 @@
|
|
|
78
95
|
"docs": "The password to save.",
|
|
79
96
|
"complexTypes": [],
|
|
80
97
|
"type": "string"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"name": "url",
|
|
101
|
+
"tags": [],
|
|
102
|
+
"docs": "The url to save the password for. (For example: \"web.capgo.app\")\niOS only.",
|
|
103
|
+
"complexTypes": [],
|
|
104
|
+
"type": "string | undefined"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"name": "ReadPasswordResult",
|
|
110
|
+
"slug": "readpasswordresult",
|
|
111
|
+
"docs": "",
|
|
112
|
+
"tags": [],
|
|
113
|
+
"methods": [],
|
|
114
|
+
"properties": [
|
|
115
|
+
{
|
|
116
|
+
"name": "username",
|
|
117
|
+
"tags": [],
|
|
118
|
+
"docs": "The username of the password.",
|
|
119
|
+
"complexTypes": [],
|
|
120
|
+
"type": "string"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "password",
|
|
124
|
+
"tags": [],
|
|
125
|
+
"docs": "The password of the password.",
|
|
126
|
+
"complexTypes": [],
|
|
127
|
+
"type": "string"
|
|
81
128
|
}
|
|
82
129
|
]
|
|
83
130
|
}
|
|
@@ -11,6 +11,21 @@ export interface Options {
|
|
|
11
11
|
* The password to save.
|
|
12
12
|
*/
|
|
13
13
|
password: string;
|
|
14
|
+
/**
|
|
15
|
+
* The url to save the password for. (For example: "web.capgo.app")
|
|
16
|
+
* iOS only.
|
|
17
|
+
*/
|
|
18
|
+
url?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ReadPasswordResult {
|
|
21
|
+
/**
|
|
22
|
+
* The username of the password.
|
|
23
|
+
*/
|
|
24
|
+
username: string;
|
|
25
|
+
/**
|
|
26
|
+
* The password of the password.
|
|
27
|
+
*/
|
|
28
|
+
password: string;
|
|
14
29
|
}
|
|
15
30
|
/**
|
|
16
31
|
* @interface SavePasswordPlugin
|
|
@@ -28,4 +43,9 @@ export interface SavePasswordPlugin {
|
|
|
28
43
|
* });
|
|
29
44
|
*/
|
|
30
45
|
promptDialog(options: Options): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS.
|
|
48
|
+
* @returns {Promise<ReadPasswordResult>} The retrieved password credentials
|
|
49
|
+
*/
|
|
50
|
+
readPassword(): Promise<ReadPasswordResult>;
|
|
31
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface Options\n * @description The options for the prompt.\n */\nexport interface Options {\n /**\n * The username to save.\n */\n username: string;\n /**\n * The password to save.\n */\n password: string;\n}\n\n/**\n * @interface SavePasswordPlugin\n * @description Capacitor plugin for saving passwords to the keychain.\n */\nexport interface SavePasswordPlugin {\n /**\n * Save a password to the keychain.\n * @param {Options} options - The options for the password.\n * @returns {Promise<void>} Success status\n * @example\n * await SavePassword.promptDialog({\n * username: 'your-username',\n * password: 'your-password'\n * });\n */\n promptDialog(options: Options): Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface Options\n * @description The options for the prompt.\n */\nexport interface Options {\n /**\n * The username to save.\n */\n username: string;\n /**\n * The password to save.\n */\n password: string;\n /**\n * The url to save the password for. (For example: \"web.capgo.app\")\n * iOS only.\n */\n url?: string;\n}\n\nexport interface ReadPasswordResult {\n /**\n * The username of the password.\n */\n username: string;\n /**\n * The password of the password.\n */\n password: string;\n}\n\n/**\n * @interface SavePasswordPlugin\n * @description Capacitor plugin for saving passwords to the keychain.\n */\nexport interface SavePasswordPlugin {\n /**\n * Save a password to the keychain.\n * @param {Options} options - The options for the password.\n * @returns {Promise<void>} Success status\n * @example\n * await SavePassword.promptDialog({\n * username: 'your-username',\n * password: 'your-password'\n * });\n */\n promptDialog(options: Options): Promise<void>;\n\n /**\n * Read a password from the keychain. Requires the developer to setup associated domain for the app for iOS.\n * @returns {Promise<ReadPasswordResult>} The retrieved password credentials\n */\n readPassword(): Promise<ReadPasswordResult>;\n}\n"]}
|
package/dist/esm/web.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
|
-
import type { Options, SavePasswordPlugin } from './definitions';
|
|
2
|
+
import type { Options, ReadPasswordResult, SavePasswordPlugin } from './definitions';
|
|
3
3
|
export declare class SavePasswordWeb extends WebPlugin implements SavePasswordPlugin {
|
|
4
|
+
readPassword(): Promise<ReadPasswordResult>;
|
|
4
5
|
promptDialog(options: Options): Promise<void>;
|
|
5
6
|
}
|
package/dist/esm/web.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
2
|
export class SavePasswordWeb extends WebPlugin {
|
|
3
|
+
readPassword() {
|
|
4
|
+
throw new Error('Method not implemented.');
|
|
5
|
+
}
|
|
3
6
|
async promptDialog(options) {
|
|
4
|
-
throw new Error(
|
|
7
|
+
throw new Error('Not implemented on web' + JSON.stringify(options));
|
|
5
8
|
}
|
|
6
9
|
}
|
|
7
10
|
//# sourceMappingURL=web.js.map
|
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;AAI5C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAC5C,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { Options, SavePasswordPlugin } from './definitions';\n\nexport class SavePasswordWeb extends WebPlugin implements SavePasswordPlugin {\n async promptDialog(options: Options): Promise<void> {\n throw new Error(
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,eAAgB,SAAQ,SAAS;IAC5C,YAAY;QACV,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IACD,KAAK,CAAC,YAAY,CAAC,OAAgB;QACjC,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { Options, ReadPasswordResult, SavePasswordPlugin } from './definitions';\n\nexport class SavePasswordWeb extends WebPlugin implements SavePasswordPlugin {\n readPassword(): Promise<ReadPasswordResult> {\n throw new Error('Method not implemented.');\n }\n async promptDialog(options: Options): Promise<void> {\n throw new Error('Not implemented on web' + JSON.stringify(options));\n }\n}\n"]}
|
package/dist/plugin.cjs.js
CHANGED
|
@@ -7,8 +7,11 @@ const SavePassword = core.registerPlugin('SavePassword', {
|
|
|
7
7
|
});
|
|
8
8
|
|
|
9
9
|
class SavePasswordWeb extends core.WebPlugin {
|
|
10
|
+
readPassword() {
|
|
11
|
+
throw new Error('Method not implemented.');
|
|
12
|
+
}
|
|
10
13
|
async promptDialog(options) {
|
|
11
|
-
throw new Error(
|
|
14
|
+
throw new Error('Not implemented on web' + JSON.stringify(options));
|
|
12
15
|
}
|
|
13
16
|
}
|
|
14
17
|
|
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 SavePassword = registerPlugin('SavePassword', {\n web: () => import('./web').then((m) => new m.SavePasswordWeb()),\n});\nexport * from './definitions';\nexport { SavePassword };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SavePasswordWeb extends WebPlugin {\n async promptDialog(options) {\n throw new Error(
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SavePassword = registerPlugin('SavePassword', {\n web: () => import('./web').then((m) => new m.SavePasswordWeb()),\n});\nexport * from './definitions';\nexport { SavePassword };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SavePasswordWeb extends WebPlugin {\n readPassword() {\n throw new Error('Method not implemented.');\n }\n async promptDialog(options) {\n throw new Error('Not implemented on web' + JSON.stringify(options));\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,YAAY,GAAGA,mBAAc,CAAC,cAAc,EAAE;AACpD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;AACnE,CAAC;;ACFM,MAAM,eAAe,SAASC,cAAS,CAAC;AAC/C,IAAI,YAAY,GAAG;AACnB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;AAClD;AACA,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;AAChC,QAAQ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAC3E;AACA;;;;;;;;;"}
|
package/dist/plugin.js
CHANGED
|
@@ -6,8 +6,11 @@ var capacitorSavePassword = (function (exports, core) {
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
class SavePasswordWeb extends core.WebPlugin {
|
|
9
|
+
readPassword() {
|
|
10
|
+
throw new Error('Method not implemented.');
|
|
11
|
+
}
|
|
9
12
|
async promptDialog(options) {
|
|
10
|
-
throw new Error(
|
|
13
|
+
throw new Error('Not implemented on web' + JSON.stringify(options));
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
|
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 SavePassword = registerPlugin('SavePassword', {\n web: () => import('./web').then((m) => new m.SavePasswordWeb()),\n});\nexport * from './definitions';\nexport { SavePassword };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SavePasswordWeb extends WebPlugin {\n async promptDialog(options) {\n throw new Error(
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst SavePassword = registerPlugin('SavePassword', {\n web: () => import('./web').then((m) => new m.SavePasswordWeb()),\n});\nexport * from './definitions';\nexport { SavePassword };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class SavePasswordWeb extends WebPlugin {\n readPassword() {\n throw new Error('Method not implemented.');\n }\n async promptDialog(options) {\n throw new Error('Not implemented on web' + JSON.stringify(options));\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,YAAY,GAAGA,mBAAc,CAAC,cAAc,EAAE;IACpD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,eAAe,EAAE,CAAC;IACnE,CAAC;;ICFM,MAAM,eAAe,SAASC,cAAS,CAAC;IAC/C,IAAI,YAAY,GAAG;IACnB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC;IAClD;IACA,IAAI,MAAM,YAAY,CAAC,OAAO,EAAE;IAChC,QAAQ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3E;IACA;;;;;;;;;;;;;;;"}
|
|
@@ -1,62 +1,100 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Capacitor
|
|
3
|
+
import Security
|
|
4
|
+
import AuthenticationServices
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Please read the Capacitor iOS Plugin Development Guide
|
|
6
8
|
* here: https://capacitorjs.com/docs/plugins/ios
|
|
7
9
|
*/
|
|
8
10
|
@objc(SavePasswordPlugin)
|
|
9
|
-
public class SavePasswordPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
11
|
+
public class SavePasswordPlugin: CAPPlugin, CAPBridgedPlugin, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
|
10
12
|
public let identifier = "SavePasswordPlugin"
|
|
11
13
|
|
|
12
14
|
public let jsName = "SavePassword"
|
|
13
15
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
14
|
-
CAPPluginMethod(name: "promptDialog", returnType: CAPPluginReturnPromise)
|
|
16
|
+
CAPPluginMethod(name: "promptDialog", returnType: CAPPluginReturnPromise),
|
|
17
|
+
CAPPluginMethod(name: "readPassword", returnType: CAPPluginReturnPromise)
|
|
15
18
|
]
|
|
16
19
|
|
|
17
20
|
@objc func promptDialog(_ call: CAPPluginCall) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
guard let username = call.getString("username"),
|
|
22
|
+
let password = call.getString("password") else {
|
|
23
|
+
call.reject("Username and password are required")
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
guard let url = call.getString("url") else {
|
|
27
|
+
call.reject("URL is required for iOS shared web credentials")
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
let fqdn = url as CFString
|
|
31
|
+
let user = username as CFString
|
|
32
|
+
let pass = password as CFString
|
|
33
|
+
SecAddSharedWebCredential(fqdn, user, pass) { error in
|
|
34
|
+
DispatchQueue.main.async {
|
|
35
|
+
if let error = error {
|
|
36
|
+
let cfError = error as CFError
|
|
37
|
+
let description = CFErrorCopyDescription(cfError) as String? ?? "Unknown error"
|
|
38
|
+
call.reject("Failed to save credential", description)
|
|
39
|
+
} else {
|
|
40
|
+
call.resolve()
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
23
45
|
|
|
24
|
-
|
|
46
|
+
@objc func readPassword(_ call: CAPPluginCall) {
|
|
47
|
+
if #available(iOS 12.0, *) {
|
|
25
48
|
DispatchQueue.main.async {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
49
|
+
let passwordRequest = ASAuthorizationPasswordProvider().createRequest()
|
|
50
|
+
let authController = ASAuthorizationController(authorizationRequests: [passwordRequest])
|
|
51
|
+
self.currentReadCall = call
|
|
52
|
+
authController.delegate = self
|
|
53
|
+
authController.presentationContextProvider = self
|
|
54
|
+
authController.performRequests()
|
|
31
55
|
}
|
|
56
|
+
} else {
|
|
57
|
+
call.reject("Password autofill not available on this iOS version")
|
|
32
58
|
}
|
|
33
59
|
}
|
|
34
|
-
}
|
|
35
60
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
private var currentReadCall: CAPPluginCall?
|
|
62
|
+
private var currentCall: CAPPluginCall?
|
|
63
|
+
|
|
64
|
+
public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
|
65
|
+
if let passwordCredential = authorization.credential as? ASPasswordCredential {
|
|
66
|
+
if let call = currentReadCall {
|
|
67
|
+
call.resolve([
|
|
68
|
+
"username": passwordCredential.user,
|
|
69
|
+
"password": passwordCredential.password
|
|
70
|
+
])
|
|
71
|
+
currentReadCall = nil
|
|
72
|
+
return
|
|
73
|
+
}
|
|
74
|
+
currentCall?.resolve([
|
|
75
|
+
"username": passwordCredential.user,
|
|
76
|
+
"password": passwordCredential.password
|
|
77
|
+
])
|
|
78
|
+
} else {
|
|
79
|
+
currentReadCall?.resolve()
|
|
80
|
+
currentReadCall = nil
|
|
81
|
+
currentCall?.resolve()
|
|
82
|
+
currentCall = nil
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
|
87
|
+
if let call = currentReadCall {
|
|
88
|
+
call.reject("Autofill failed", error.localizedDescription)
|
|
89
|
+
currentReadCall = nil
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
currentCall?.reject("Autofill failed", error.localizedDescription)
|
|
93
|
+
currentCall = nil
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// MARK: - ASAuthorizationControllerPresentationContextProviding
|
|
97
|
+
public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
|
98
|
+
return self.bridge?.viewController?.view.window ?? ASPresentationAnchor()
|
|
61
99
|
}
|
|
62
100
|
}
|
package/package.json
CHANGED