cordova-plugin-oauth 4.0.0 → 4.1.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/README.md +20 -3
- package/package.json +40 -15
- package/plugin.xml +5 -2
- package/src/android/OAuthPlugin.java +87 -117
- package/src/ios/OAuthPlugin.swift +73 -18
- package/www/oauth.js +107 -2
- package/.editorconfig +0 -20
- package/CODE_OF_CONDUCT.md +0 -77
package/README.md
CHANGED
|
@@ -38,11 +38,11 @@ Installation
|
|
|
38
38
|
------------
|
|
39
39
|
|
|
40
40
|
```
|
|
41
|
-
cordova plugin add cordova-plugin-oauth [--variable URL_SCHEME=mycoolapp]
|
|
41
|
+
cordova plugin add cordova-plugin-oauth [--variable URL_SCHEME=mycoolapp] [--variable URL_HOSTNAME=callback]
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
By default, the plugin registers the app ID as a scheme to be used as the
|
|
45
|
-
OAuth callback URL, and expects a host of `oauth_callback` (i.e., if your
|
|
45
|
+
OAuth callback URL, and expects a default host of `oauth_callback` (i.e., if your
|
|
46
46
|
app's ID is `com.example.foo`, your OAuth redirect URL should be
|
|
47
47
|
`com.example.foo://oauth_callback`).
|
|
48
48
|
|
|
@@ -50,6 +50,9 @@ The scheme for the OAuth callback URL can be changed by providing a
|
|
|
50
50
|
`URL_SCHEME` variable when installing. If your `URL_SCHEME` is `mycoolapp`,
|
|
51
51
|
then your OAuth redirect URL should be `mycoolapp://oauth_callback`.
|
|
52
52
|
|
|
53
|
+
The hostname endpoint can be changed by providing a `URL_HOSTNAME` variable
|
|
54
|
+
when installing.
|
|
55
|
+
|
|
53
56
|
|
|
54
57
|
Supported Platforms
|
|
55
58
|
-------------------
|
|
@@ -69,13 +72,22 @@ Usage
|
|
|
69
72
|
window.open(endpoint, 'oauth:google', '');
|
|
70
73
|
```
|
|
71
74
|
|
|
75
|
+
Alternatively, you can include `oauth=yes` in the window features string:
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
var endpoint = 'https://accounts.google.com/o/oauth2/v2/auth?....';
|
|
79
|
+
window.open(endpoint, '_self', 'oauth=yes');
|
|
80
|
+
```
|
|
81
|
+
|
|
72
82
|
2. The plugin will open the OAuth login page in a new browser window.
|
|
73
83
|
|
|
74
84
|
3. When the OAuth process is complete and it redirects to your app scheme, the
|
|
75
85
|
plugin will send a message to the Cordova app.
|
|
76
86
|
|
|
77
87
|
The message begins with `oauth::` and is followed by a JSON object
|
|
78
|
-
containing all of the key/value pairs from the OAuth redirect query string
|
|
88
|
+
containing all of the key/value pairs from the OAuth redirect query string
|
|
89
|
+
or fragment parameters. The complete OAuth callback URL is available in a
|
|
90
|
+
`oauth_callback_url` property.
|
|
79
91
|
|
|
80
92
|
```javascript
|
|
81
93
|
// Called from a callback URL like
|
|
@@ -113,4 +125,9 @@ Licence
|
|
|
113
125
|
Released under the Apache 2.0 Licence.
|
|
114
126
|
Copyright © 2020-2022 Ayogo Health Inc.
|
|
115
127
|
|
|
128
|
+
This project includes the [EventTarget polyfill][etpoly], copyright © 2018,
|
|
129
|
+
Andrea Giammarchi under the [ISC Licence][isc].
|
|
130
|
+
|
|
116
131
|
[coc]: https://github.com/AyogoHealth/cordova-plugin-oauth/blob/main/CODE_OF_CONDUCT.md
|
|
132
|
+
[etpoly]: https://github.com/ungap/event-target
|
|
133
|
+
[isc]: https://github.com/ungap/event-target/blob/master/LICENSE
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cordova-plugin-oauth",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"author": "Ayogo Health Inc. <info@ayogo.com>",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Darryl Pogue <darryl@dpogue.ca>",
|
|
@@ -9,31 +9,56 @@
|
|
|
9
9
|
],
|
|
10
10
|
"description": "Cordova plugin for performing OAuth login flows.",
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
|
-
"repository":
|
|
13
|
-
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/AyogoHealth/cordova-plugin-oauth.git"
|
|
15
|
-
},
|
|
12
|
+
"repository": "github:AyogoHealth/cordova-plugin-oauth.git",
|
|
16
13
|
"keywords": [
|
|
17
14
|
"cordova",
|
|
18
15
|
"ecosystem:cordova",
|
|
19
16
|
"cordova-android",
|
|
20
17
|
"cordova-ios"
|
|
21
18
|
],
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"www",
|
|
22
|
+
"plugin.xml"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"version": "sed -i -e \"s/\\(<plugin [^>]*id=\\\"$npm_package_name\\\" [^>]*version=\\\"\\)[^\\\"]*\\\"/\\1$npm_package_version\\\"/\" plugin.xml && git add plugin.xml"
|
|
26
|
+
},
|
|
22
27
|
"cordova": {
|
|
28
|
+
"id": "cordova-plugin-oauth",
|
|
23
29
|
"platforms": [
|
|
24
30
|
"ios",
|
|
25
31
|
"android"
|
|
26
32
|
]
|
|
27
33
|
},
|
|
28
|
-
"engines":
|
|
29
|
-
{
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
34
|
+
"engines": {
|
|
35
|
+
"cordovaDependencies": {
|
|
36
|
+
"1.0.0": {
|
|
37
|
+
"cordova-android": ">= 8.0.0",
|
|
38
|
+
"cordova-ios": ">= 5.0.0"
|
|
39
|
+
},
|
|
40
|
+
"2.0.0": {
|
|
41
|
+
"cordova-android": ">= 8.0.0",
|
|
42
|
+
"cordova-ios": ">= 5.0.0"
|
|
43
|
+
},
|
|
44
|
+
"3.0.0": {
|
|
45
|
+
"cordova-android": ">= 8.0.0",
|
|
46
|
+
"cordova-ios": ">= 6.1.0"
|
|
47
|
+
},
|
|
48
|
+
"4.0.0": {
|
|
49
|
+
"cordova-android": ">= 9.0.0",
|
|
50
|
+
"cordova-ios": ">= 6.1.0"
|
|
51
|
+
},
|
|
52
|
+
"5.0.0": {
|
|
53
|
+
"cordova": ">100"
|
|
54
|
+
}
|
|
36
55
|
}
|
|
37
|
-
|
|
38
|
-
"dependencies": {}
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {},
|
|
58
|
+
"devEngines": {
|
|
59
|
+
"packageManager": {
|
|
60
|
+
"name": "npm",
|
|
61
|
+
"onFail": "ignore"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
39
64
|
}
|
package/plugin.xml
CHANGED
|
@@ -14,7 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
14
14
|
See the License for the specific language governing permissions and
|
|
15
15
|
limitations under the License.
|
|
16
16
|
-->
|
|
17
|
-
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-oauth" version="4.
|
|
17
|
+
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-oauth" version="4.1.0">
|
|
18
18
|
<name>cordova-plugin-oauth</name>
|
|
19
19
|
<description>Cordova plugin for performing OAuth login flows.</description>
|
|
20
20
|
<keywords>cordova,ios,android,oauth</keywords>
|
|
@@ -23,6 +23,7 @@ limitations under the License.
|
|
|
23
23
|
<issues>https://github.com/AyogoHealth/cordova-plugin-oauth/issues</issues>
|
|
24
24
|
|
|
25
25
|
<preference name="URL_SCHEME" default="$PACKAGE_NAME" />
|
|
26
|
+
<preference name="URL_HOSTNAME" default="oauth_callback" />
|
|
26
27
|
|
|
27
28
|
<engines>
|
|
28
29
|
<engine name="cordova-ios" version=">= 6.1.0" />
|
|
@@ -35,6 +36,7 @@ limitations under the License.
|
|
|
35
36
|
|
|
36
37
|
<config-file target="config.xml" parent="/*">
|
|
37
38
|
<preference name="OAuthScheme" value="$URL_SCHEME"/>
|
|
39
|
+
<preference name="OAuthHostname" value="$URL_HOSTNAME"/>
|
|
38
40
|
</config-file>
|
|
39
41
|
|
|
40
42
|
<platform name="ios">
|
|
@@ -66,6 +68,7 @@ limitations under the License.
|
|
|
66
68
|
<config-file target="res/xml/config.xml" parent="/*">
|
|
67
69
|
<feature name="OAuth">
|
|
68
70
|
<param name="android-package" value="com.ayogo.cordova.oauth.OAuthPlugin" />
|
|
71
|
+
<param name="onload" value="true" />
|
|
69
72
|
</feature>
|
|
70
73
|
</config-file>
|
|
71
74
|
|
|
@@ -76,7 +79,7 @@ limitations under the License.
|
|
|
76
79
|
<category android:name="android.intent.category.DEFAULT" />
|
|
77
80
|
<category android:name="android.intent.category.BROWSABLE" />
|
|
78
81
|
|
|
79
|
-
<data android:scheme="$URL_SCHEME" android:host="
|
|
82
|
+
<data android:scheme="$URL_SCHEME" android:host="$URL_HOSTNAME" />
|
|
80
83
|
</intent-filter>
|
|
81
84
|
</config-file>
|
|
82
85
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2019 Ayogo Health Inc.
|
|
2
|
+
* Copyright 2019 - 2022 Ayogo Health Inc.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -16,49 +16,33 @@
|
|
|
16
16
|
|
|
17
17
|
package com.ayogo.cordova.oauth;
|
|
18
18
|
|
|
19
|
-
import android.app.Activity;
|
|
20
|
-
import android.content.Context;
|
|
21
19
|
import android.content.Intent;
|
|
22
|
-
import android.content.IntentFilter;
|
|
23
|
-
import android.content.pm.PackageManager;
|
|
24
|
-
import android.content.pm.ResolveInfo;
|
|
25
20
|
import android.net.Uri;
|
|
26
21
|
import androidx.browser.customtabs.CustomTabsIntent;
|
|
27
22
|
import android.text.TextUtils;
|
|
23
|
+
import java.net.URLDecoder;
|
|
28
24
|
|
|
29
25
|
import java.util.ArrayList;
|
|
30
26
|
import java.util.List;
|
|
31
27
|
|
|
32
28
|
import org.apache.cordova.CallbackContext;
|
|
29
|
+
import org.apache.cordova.CordovaArgs;
|
|
33
30
|
import org.apache.cordova.CordovaInterface;
|
|
34
31
|
import org.apache.cordova.CordovaPlugin;
|
|
35
32
|
import org.apache.cordova.CordovaWebView;
|
|
33
|
+
import org.apache.cordova.CordovaWebViewEngine;
|
|
36
34
|
import org.apache.cordova.LOG;
|
|
37
35
|
import org.apache.cordova.PluginResult;
|
|
38
36
|
|
|
39
|
-
import org.json.JSONArray;
|
|
40
37
|
import org.json.JSONException;
|
|
41
38
|
import org.json.JSONObject;
|
|
42
39
|
|
|
43
40
|
|
|
44
41
|
public class OAuthPlugin extends CordovaPlugin {
|
|
45
42
|
private final String TAG = "OAuthPlugin";
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
static final String STABLE_PACKAGE = "com.android.chrome";
|
|
50
|
-
static final String BETA_PACKAGE = "com.chrome.beta";
|
|
51
|
-
static final String DEV_PACKAGE = "com.chrome.dev";
|
|
52
|
-
static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
|
|
53
|
-
private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE = "android.support.customtabs.extra.KEEP_ALIVE";
|
|
54
|
-
private static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService";
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* The name of the package to use for the custom tab service.
|
|
59
|
-
*/
|
|
60
|
-
private String tabProvider = null;
|
|
61
|
-
|
|
43
|
+
private CallbackContext oauthCallback = null;
|
|
44
|
+
private boolean didFinishLoading = false;
|
|
45
|
+
private String lastOAuthResult = null;
|
|
62
46
|
|
|
63
47
|
/**
|
|
64
48
|
* Executes the request.
|
|
@@ -75,14 +59,14 @@ public class OAuthPlugin extends CordovaPlugin {
|
|
|
75
59
|
* @return Whether the action was valid.
|
|
76
60
|
*/
|
|
77
61
|
@Override
|
|
78
|
-
public boolean execute(String action,
|
|
62
|
+
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) {
|
|
79
63
|
if ("startOAuth".equals(action)) {
|
|
80
64
|
try {
|
|
81
65
|
String authEndpoint = args.getString(0);
|
|
66
|
+
oauthCallback = callbackContext;
|
|
82
67
|
|
|
83
68
|
this.startOAuth(authEndpoint);
|
|
84
69
|
|
|
85
|
-
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
|
|
86
70
|
return true;
|
|
87
71
|
} catch (JSONException e) {
|
|
88
72
|
callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR));
|
|
@@ -95,6 +79,14 @@ public class OAuthPlugin extends CordovaPlugin {
|
|
|
95
79
|
}
|
|
96
80
|
|
|
97
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Called when the activity is becoming visible to the user.
|
|
84
|
+
*/
|
|
85
|
+
@Override
|
|
86
|
+
public void onStart() {
|
|
87
|
+
onNewIntent(cordova.getActivity().getIntent());
|
|
88
|
+
}
|
|
89
|
+
|
|
98
90
|
|
|
99
91
|
/**
|
|
100
92
|
* Called when the activity receives a new intent.
|
|
@@ -109,19 +101,40 @@ public class OAuthPlugin extends CordovaPlugin {
|
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
final Uri uri = intent.getData();
|
|
104
|
+
String callbackHost = preferences.getString("oauthhostname", "oauth_callback");
|
|
112
105
|
|
|
113
|
-
if (uri.getHost().equals(
|
|
106
|
+
if (uri.getHost().equals(callbackHost)) {
|
|
114
107
|
LOG.i(TAG, "OAuth called back with parameters.");
|
|
115
108
|
|
|
116
109
|
try {
|
|
117
110
|
JSONObject jsobj = new JSONObject();
|
|
111
|
+
jsobj.put("oauth_callback_url", uri.toString());
|
|
112
|
+
|
|
113
|
+
// Parse fragment parameters
|
|
114
|
+
if (uri.getFragment() != null) {
|
|
115
|
+
String fragment = uri.getFragment();
|
|
116
|
+
String[] pairs = fragment.split("&");
|
|
117
|
+
for (String pair : pairs) {
|
|
118
|
+
String[] keyValue = pair.split("=");
|
|
119
|
+
if (keyValue.length == 2) {
|
|
120
|
+
// Decode the fragment parameter before adding it to the JSONObject
|
|
121
|
+
String key = keyValue[0];
|
|
122
|
+
String value = keyValue[1];
|
|
123
|
+
jsobj.put(key, value);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
118
127
|
|
|
128
|
+
// Parse query parameters
|
|
119
129
|
for (String queryKey : uri.getQueryParameterNames()) {
|
|
120
130
|
jsobj.put(queryKey, uri.getQueryParameter(queryKey));
|
|
121
131
|
}
|
|
122
132
|
|
|
123
|
-
|
|
124
|
-
|
|
133
|
+
if (this.didFinishLoading) {
|
|
134
|
+
dispatchOAuthMessage(jsobj.toString());
|
|
135
|
+
} else {
|
|
136
|
+
this.lastOAuthResult = jsobj.toString();
|
|
137
|
+
}
|
|
125
138
|
} catch (JSONException e) {
|
|
126
139
|
LOG.e(TAG, "JSON Serialization failed");
|
|
127
140
|
e.printStackTrace();
|
|
@@ -129,119 +142,76 @@ public class OAuthPlugin extends CordovaPlugin {
|
|
|
129
142
|
}
|
|
130
143
|
}
|
|
131
144
|
|
|
132
|
-
|
|
133
145
|
/**
|
|
134
|
-
*
|
|
146
|
+
* Called when the activity will start interacting with the user.
|
|
135
147
|
*
|
|
136
|
-
*
|
|
148
|
+
* We use this method to indicate to the JavaScript side that the OAuth
|
|
149
|
+
* window has closed (regardless of login status).
|
|
137
150
|
*/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
|
142
|
-
CustomTabsIntent customTabsIntent = builder.build();
|
|
151
|
+
@Override
|
|
152
|
+
public void onResume(boolean multitasking) {
|
|
153
|
+
super.onResume(multitasking);
|
|
143
154
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
if (oauthCallback != null) {
|
|
156
|
+
oauthCallback.sendPluginResult(new PluginResult(PluginResult.Status.OK));
|
|
157
|
+
oauthCallback = null;
|
|
147
158
|
}
|
|
148
|
-
|
|
149
|
-
customTabsIntent.launchUrl(this.cordova.getActivity(), Uri.parse(url));
|
|
150
159
|
}
|
|
151
160
|
|
|
152
161
|
|
|
153
162
|
/**
|
|
154
|
-
*
|
|
163
|
+
* Called when a message is sent to plugin.
|
|
155
164
|
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
*
|
|
159
|
-
* This is <strong>not</strong> threadsafe.
|
|
160
|
-
*
|
|
161
|
-
* @return The package name recommended to use for connecting to custom
|
|
162
|
-
* tabs related components.
|
|
165
|
+
* @param id The message id
|
|
166
|
+
* @param data The message data
|
|
167
|
+
* @return Object to stop propagation or null
|
|
163
168
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
PackageManager pm = this.cordova.getActivity().getPackageManager();
|
|
170
|
-
|
|
171
|
-
// Get default VIEW intent handler.
|
|
172
|
-
Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
|
|
173
|
-
ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
|
|
174
|
-
String defaultViewHandlerPackageName = null;
|
|
175
|
-
|
|
176
|
-
if (defaultViewHandlerInfo != null) {
|
|
177
|
-
defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// Get all apps that can handle VIEW intents.
|
|
182
|
-
List<ResolveInfo> resolvedActivityList = pm.queryIntentActivities(activityIntent, PackageManager.MATCH_ALL);
|
|
183
|
-
List<String> packagesSupportingCustomTabs = new ArrayList<>();
|
|
184
|
-
|
|
185
|
-
for (ResolveInfo info : resolvedActivityList) {
|
|
186
|
-
Intent serviceIntent = new Intent();
|
|
187
|
-
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
|
|
188
|
-
serviceIntent.setPackage(info.activityInfo.packageName);
|
|
169
|
+
@Override
|
|
170
|
+
public Object onMessage(String id, Object data) {
|
|
171
|
+
if (id.equals("onPageFinished")) {
|
|
172
|
+
this.didFinishLoading = true;
|
|
189
173
|
|
|
190
|
-
if (
|
|
191
|
-
|
|
174
|
+
if (this.lastOAuthResult != null) {
|
|
175
|
+
this.dispatchOAuthMessage(this.lastOAuthResult);
|
|
176
|
+
this.lastOAuthResult = null;
|
|
192
177
|
}
|
|
193
178
|
}
|
|
194
|
-
|
|
195
|
-
// Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
|
|
196
|
-
// and service calls.
|
|
197
|
-
if (packagesSupportingCustomTabs.isEmpty()) {
|
|
198
|
-
this.tabProvider = null;
|
|
199
|
-
} else if (packagesSupportingCustomTabs.size() == 1) {
|
|
200
|
-
this.tabProvider = packagesSupportingCustomTabs.get(0);
|
|
201
|
-
} else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) && !this.hasSpecializedHandlerIntents(activityIntent) && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
|
|
202
|
-
this.tabProvider = defaultViewHandlerPackageName;
|
|
203
|
-
} else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
|
|
204
|
-
this.tabProvider = STABLE_PACKAGE;
|
|
205
|
-
} else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
|
|
206
|
-
this.tabProvider = BETA_PACKAGE;
|
|
207
|
-
} else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
|
|
208
|
-
this.tabProvider = DEV_PACKAGE;
|
|
209
|
-
} else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
|
|
210
|
-
this.tabProvider = LOCAL_PACKAGE;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return this.tabProvider;
|
|
179
|
+
return null;
|
|
214
180
|
}
|
|
215
181
|
|
|
216
182
|
|
|
217
183
|
/**
|
|
218
|
-
*
|
|
184
|
+
* Launches the custom tab with the OAuth endpoint URL.
|
|
219
185
|
*
|
|
220
|
-
* @param
|
|
221
|
-
* @return Whether there is a specialized handler for the given intent.
|
|
186
|
+
* @param url The URL of the OAuth endpoint.
|
|
222
187
|
*/
|
|
223
|
-
private
|
|
224
|
-
|
|
225
|
-
PackageManager pm = this.cordova.getActivity().getPackageManager();
|
|
226
|
-
List<ResolveInfo> handlers = pm.queryIntentActivities(intent, PackageManager.GET_RESOLVED_FILTER);
|
|
188
|
+
private void startOAuth(String url) {
|
|
189
|
+
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
|
227
190
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
191
|
+
CustomTabsIntent customTabsIntent = builder.build();
|
|
192
|
+
customTabsIntent.intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
|
|
193
|
+
customTabsIntent.intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
194
|
+
customTabsIntent.intent.putExtra("android.support.customtabs.extra.ENABLE_URLBAR_HIDING", true);
|
|
195
|
+
customTabsIntent.intent.putExtra("android.support.customtabs.extra.EXTRA_ENABLE_INSTANT_APPS", false);
|
|
196
|
+
customTabsIntent.intent.putExtra("android.support.customtabs.extra.SEND_TO_EXTERNAL_HANDLER", false);
|
|
197
|
+
customTabsIntent.intent.putExtra("androidx.browser.customtabs.extra.SHARE_STATE", 2);
|
|
198
|
+
customTabsIntent.intent.putExtra("androidx.browser.customtabs.extra.DISABLE_BACKGROUND_INTERACTION", false);
|
|
199
|
+
customTabsIntent.intent.putExtra("org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_DOWNLOAD_BUTTON", true);
|
|
200
|
+
customTabsIntent.intent.putExtra("org.chromium.chrome.browser.customtabs.EXTRA_DISABLE_STAR_BUTTON", true);
|
|
231
201
|
|
|
232
|
-
|
|
233
|
-
|
|
202
|
+
customTabsIntent.launchUrl(this.cordova.getActivity(), Uri.parse(url));
|
|
203
|
+
}
|
|
234
204
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
205
|
+
@SuppressWarnings("deprecation")
|
|
206
|
+
private void dispatchOAuthMessage(final String msg) {
|
|
207
|
+
final String msgData = msg.replace("'", "\\'").replace("\n", "\\n").replace("\r", "\\r").replace("\t", "\\t");
|
|
208
|
+
final String jsCode = "window.dispatchEvent(new MessageEvent('message', { data: 'oauth::" + msgData + "' }));";
|
|
238
209
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
210
|
+
CordovaWebViewEngine engine = this.webView.getEngine();
|
|
211
|
+
if (engine != null) {
|
|
212
|
+
engine.evaluateJavascript(jsCode, null);
|
|
213
|
+
} else {
|
|
214
|
+
this.webView.sendJavascript(jsCode);
|
|
243
215
|
}
|
|
244
|
-
|
|
245
|
-
return false;
|
|
246
216
|
}
|
|
247
217
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright 2019 Ayogo Health Inc.
|
|
2
|
+
* Copyright 2019 - 2022 Ayogo Health Inc.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -14,11 +14,19 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
#if canImport(Cordova)
|
|
18
|
+
import Cordova
|
|
19
|
+
#endif
|
|
20
|
+
|
|
17
21
|
import os.log
|
|
18
22
|
import Foundation
|
|
19
23
|
import AuthenticationServices
|
|
20
24
|
import SafariServices
|
|
21
25
|
|
|
26
|
+
extension NSNotification.Name {
|
|
27
|
+
static let CDVPluginOAuthCancelled = NSNotification.Name("CDVPluginOAuthCancelledNotification");
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
@objc protocol OAuthSessionProvider {
|
|
23
31
|
init(_ endpoint : URL, callbackScheme : String)
|
|
24
32
|
func start() -> Void
|
|
@@ -37,6 +45,8 @@ class ASWebAuthenticationSessionOAuthSessionProvider : OAuthSessionProvider {
|
|
|
37
45
|
self.aswas = ASWebAuthenticationSession(url: endpoint, callbackURLScheme: callbackURLScheme, completionHandler: { (callBack:URL?, error:Error?) in
|
|
38
46
|
if let incomingUrl = callBack {
|
|
39
47
|
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginHandleOpenURL, object: incomingUrl)
|
|
48
|
+
} else {
|
|
49
|
+
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginOAuthCancelled, object: nil)
|
|
40
50
|
}
|
|
41
51
|
})
|
|
42
52
|
}
|
|
@@ -64,6 +74,8 @@ class SFAuthenticationSessionOAuthSessionProvider : OAuthSessionProvider {
|
|
|
64
74
|
self.sfas = SFAuthenticationSession(url: endpoint, callbackURLScheme: callbackScheme, completionHandler: { (callBack:URL?, error:Error?) in
|
|
65
75
|
if let incomingUrl = callBack {
|
|
66
76
|
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginHandleOpenURL, object: incomingUrl)
|
|
77
|
+
} else {
|
|
78
|
+
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginOAuthCancelled, object: nil)
|
|
67
79
|
}
|
|
68
80
|
})
|
|
69
81
|
}
|
|
@@ -86,6 +98,9 @@ class SFSafariViewControllerOAuthSessionProvider : OAuthSessionProvider {
|
|
|
86
98
|
|
|
87
99
|
required init(_ endpoint : URL, callbackScheme : String) {
|
|
88
100
|
self.sfvc = SFSafariViewController(url: endpoint)
|
|
101
|
+
if #available(iOS 11.0, *) {
|
|
102
|
+
self.sfvc.dismissButtonStyle = .cancel
|
|
103
|
+
}
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
func start() {
|
|
@@ -119,14 +134,19 @@ class SafariAppOAuthSessionProvider : OAuthSessionProvider {
|
|
|
119
134
|
|
|
120
135
|
@objc(CDVOAuthPlugin)
|
|
121
136
|
class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticationPresentationContextProviding {
|
|
137
|
+
/** This exists for testing purposes */
|
|
138
|
+
static var forcedVersion : UInt32 = UInt32.max
|
|
139
|
+
|
|
122
140
|
var authSystem : OAuthSessionProvider?
|
|
141
|
+
var closeCallbackId : String?
|
|
123
142
|
var callbackScheme : String?
|
|
124
143
|
var logger : OSLog?
|
|
125
144
|
|
|
126
145
|
override func pluginInitialize() {
|
|
127
146
|
let urlScheme = self.commandDelegate.settings["oauthscheme"] as! String
|
|
147
|
+
let urlHostname = self.commandDelegate.settings["oauthhostname"] as? String ?? "oauth_callback";
|
|
128
148
|
|
|
129
|
-
self.callbackScheme = "\(urlScheme)
|
|
149
|
+
self.callbackScheme = "\(urlScheme)://\(urlHostname)"
|
|
130
150
|
if #available(iOS 10.0, *) {
|
|
131
151
|
self.logger = OSLog(subsystem: urlScheme, category: "Cordova")
|
|
132
152
|
}
|
|
@@ -135,6 +155,11 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
135
155
|
selector: #selector(OAuthPlugin._handleOpenURL(_:)),
|
|
136
156
|
name: NSNotification.Name.CDVPluginHandleOpenURL,
|
|
137
157
|
object: nil)
|
|
158
|
+
|
|
159
|
+
NotificationCenter.default.addObserver(self,
|
|
160
|
+
selector: #selector(OAuthPlugin._handleCancel(_:)),
|
|
161
|
+
name: NSNotification.Name.CDVPluginOAuthCancelled,
|
|
162
|
+
object: nil)
|
|
138
163
|
}
|
|
139
164
|
|
|
140
165
|
|
|
@@ -149,7 +174,9 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
149
174
|
return
|
|
150
175
|
}
|
|
151
176
|
|
|
152
|
-
|
|
177
|
+
self.closeCallbackId = command.callbackId
|
|
178
|
+
|
|
179
|
+
if OAuthPlugin.forcedVersion >= 12, #available(iOS 12.0, *) {
|
|
153
180
|
self.authSystem = ASWebAuthenticationSessionOAuthSessionProvider(url, callbackScheme:self.callbackScheme!)
|
|
154
181
|
|
|
155
182
|
if #available(iOS 13.0, *) {
|
|
@@ -157,9 +184,9 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
157
184
|
aswas.delegate = self
|
|
158
185
|
}
|
|
159
186
|
}
|
|
160
|
-
} else if #available(iOS 11.0, *) {
|
|
187
|
+
} else if OAuthPlugin.forcedVersion >= 11, #available(iOS 11.0, *) {
|
|
161
188
|
self.authSystem = SFAuthenticationSessionOAuthSessionProvider(url, callbackScheme:self.callbackScheme!)
|
|
162
|
-
} else if #available(iOS 9.0, *) {
|
|
189
|
+
} else if OAuthPlugin.forcedVersion >= 9, #available(iOS 9.0, *) {
|
|
163
190
|
self.authSystem = SFSafariViewControllerOAuthSessionProvider(url, callbackScheme:self.callbackScheme!)
|
|
164
191
|
|
|
165
192
|
if let sfvc = self.authSystem as? SFSafariViewControllerOAuthSessionProvider {
|
|
@@ -172,7 +199,6 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
172
199
|
|
|
173
200
|
self.authSystem?.start()
|
|
174
201
|
|
|
175
|
-
self.commandDelegate.send(CDVPluginResult(status: .ok), callbackId: command.callbackId)
|
|
176
202
|
return
|
|
177
203
|
}
|
|
178
204
|
|
|
@@ -181,24 +207,38 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
181
207
|
self.authSystem?.cancel()
|
|
182
208
|
self.authSystem = nil
|
|
183
209
|
|
|
184
|
-
var jsobj : [String : String] = [:]
|
|
210
|
+
var jsobj : [String : String] = ["oauth_callback_url": url.absoluteString]
|
|
185
211
|
let queryItems = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
212
|
+
let fragment = url.fragment
|
|
213
|
+
|
|
214
|
+
// Parse fragment parameters
|
|
215
|
+
if let fragment = fragment {
|
|
216
|
+
let pairs = fragment.split(separator: "&")
|
|
217
|
+
for pair in pairs {
|
|
218
|
+
let keyValue = pair.split(separator: "=")
|
|
219
|
+
if keyValue.count == 2,
|
|
220
|
+
let key = keyValue[0].removingPercentEncoding,
|
|
221
|
+
let value = keyValue[1].removingPercentEncoding {
|
|
222
|
+
jsobj[String(key)] = String(value)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
189
225
|
}
|
|
190
226
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
} else {
|
|
194
|
-
NSLog("OAuth called back with parameters.")
|
|
227
|
+
queryItems?.forEach {
|
|
228
|
+
jsobj[$0.name] = $0.value
|
|
195
229
|
}
|
|
196
230
|
|
|
197
231
|
do {
|
|
198
232
|
let data = try JSONSerialization.data(withJSONObject: jsobj)
|
|
199
|
-
let msg = String(data: data, encoding: .utf8)!
|
|
200
233
|
|
|
201
|
-
|
|
234
|
+
if let msg = String(data: data, encoding: .utf8) {
|
|
235
|
+
let jsMsg = msg.replacingOccurrences(of: "'", with: "\\'")
|
|
236
|
+
.replacingOccurrences(of: "\n", with: "\\n")
|
|
237
|
+
.replacingOccurrences(of: "\r", with: "\\r")
|
|
238
|
+
.replacingOccurrences(of: "\t", with: "\\t")
|
|
239
|
+
|
|
240
|
+
self.webViewEngine.evaluateJavaScript("window.dispatchEvent(new MessageEvent('message', { data: 'oauth::\(jsMsg)' }));", completionHandler: nil)
|
|
241
|
+
}
|
|
202
242
|
} catch {
|
|
203
243
|
let errStr = "JSON Serialization failed: \(error)"
|
|
204
244
|
if #available(iOS 10.0, *) {
|
|
@@ -220,13 +260,28 @@ class OAuthPlugin : CDVPlugin, SFSafariViewControllerDelegate, ASWebAuthenticati
|
|
|
220
260
|
}
|
|
221
261
|
|
|
222
262
|
self.parseToken(from: url)
|
|
263
|
+
|
|
264
|
+
if let cb = self.closeCallbackId {
|
|
265
|
+
self.commandDelegate.send(CDVPluginResult(status: .ok), callbackId: cb)
|
|
266
|
+
}
|
|
267
|
+
self.closeCallbackId = nil
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
@objc internal func _handleCancel(_ notification : NSNotification) {
|
|
272
|
+
if let cb = self.closeCallbackId {
|
|
273
|
+
self.commandDelegate.send(CDVPluginResult(status: .ok), callbackId: cb)
|
|
274
|
+
}
|
|
275
|
+
self.closeCallbackId = nil
|
|
223
276
|
}
|
|
224
277
|
|
|
225
278
|
|
|
226
279
|
@available(iOS 9.0, *)
|
|
227
280
|
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
|
|
228
|
-
|
|
229
|
-
|
|
281
|
+
self.authSystem?.cancel()
|
|
282
|
+
self.authSystem = nil
|
|
283
|
+
|
|
284
|
+
NotificationCenter.default.post(name: NSNotification.Name.CDVPluginOAuthCancelled, object: nil)
|
|
230
285
|
}
|
|
231
286
|
|
|
232
287
|
@available(iOS 13.0, *)
|
package/www/oauth.js
CHANGED
|
@@ -18,10 +18,115 @@ var exec = require('cordova/exec');
|
|
|
18
18
|
var modulemapper = require('cordova/modulemapper');
|
|
19
19
|
var noop = function() { };
|
|
20
20
|
|
|
21
|
+
// https://github.com/ungap/event-target
|
|
22
|
+
/**
|
|
23
|
+
* Copyright (c) 2018, Andrea Giammarchi, @WebReflection
|
|
24
|
+
*
|
|
25
|
+
* Permission to use, copy, modify, and/or distribute this software for any
|
|
26
|
+
* purpose with or without fee is hereby granted, provided that the above
|
|
27
|
+
* copyright notice and this permission notice appear in all copies.
|
|
28
|
+
*
|
|
29
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
30
|
+
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
31
|
+
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
32
|
+
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
33
|
+
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
34
|
+
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
35
|
+
* PERFORMANCE OF THIS SOFTWARE.
|
|
36
|
+
*/
|
|
37
|
+
var EventTargetPolyfill = (function(Object, wm) {
|
|
38
|
+
var create = Object.create;
|
|
39
|
+
var defineProperty = Object.defineProperty;
|
|
40
|
+
var proto = EventTarget.prototype;
|
|
41
|
+
define(proto, 'addEventListener', function (type, listener, options) {
|
|
42
|
+
for (var
|
|
43
|
+
secret = wm.get(this),
|
|
44
|
+
listeners = secret[type] || (secret[type] = []),
|
|
45
|
+
i = 0, length = listeners.length; i < length; i++
|
|
46
|
+
) {
|
|
47
|
+
if (listeners[i].listener === listener)
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
listeners.push({target: this, listener: listener, options: options});
|
|
51
|
+
});
|
|
52
|
+
define(proto, 'dispatchEvent', function (event) {
|
|
53
|
+
var secret = wm.get(this);
|
|
54
|
+
var listeners = secret[event.type];
|
|
55
|
+
if (listeners) {
|
|
56
|
+
define(event, 'target', this);
|
|
57
|
+
define(event, 'currentTarget', this);
|
|
58
|
+
listeners.slice(0).some(dispatch, event);
|
|
59
|
+
delete event.currentTarget;
|
|
60
|
+
delete event.target;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
});
|
|
64
|
+
define(proto, 'removeEventListener', function (type, listener) {
|
|
65
|
+
for (var
|
|
66
|
+
secret = wm.get(this),
|
|
67
|
+
/* istanbul ignore next */
|
|
68
|
+
listeners = secret[type] || (secret[type] = []),
|
|
69
|
+
i = 0, length = listeners.length; i < length; i++
|
|
70
|
+
) {
|
|
71
|
+
if (listeners[i].listener === listener) {
|
|
72
|
+
listeners.splice(i, 1);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return EventTarget;
|
|
78
|
+
|
|
79
|
+
function EventTarget() {'use strict';
|
|
80
|
+
wm.set(this, create(null));
|
|
81
|
+
}
|
|
82
|
+
function define(target, name, value) {
|
|
83
|
+
defineProperty(
|
|
84
|
+
target,
|
|
85
|
+
name,
|
|
86
|
+
{
|
|
87
|
+
configurable: true,
|
|
88
|
+
writable: true,
|
|
89
|
+
value: value
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
function dispatch(info) {
|
|
94
|
+
var options = info.options;
|
|
95
|
+
if (options && options.once)
|
|
96
|
+
info.target.removeEventListener(this.type, info.listener);
|
|
97
|
+
if (typeof info.listener === 'function')
|
|
98
|
+
info.listener.call(info.target, this);
|
|
99
|
+
else
|
|
100
|
+
info.listener.handleEvent(this);
|
|
101
|
+
return this._stopImmediatePropagationFlag;
|
|
102
|
+
}
|
|
103
|
+
})(Object, new WeakMap());
|
|
104
|
+
|
|
21
105
|
|
|
22
106
|
module.exports = function(url, name, features) {
|
|
23
|
-
|
|
24
|
-
|
|
107
|
+
var nameMatch = name && name.match && name.match(/^oauth:/);
|
|
108
|
+
var featureMatch = features && features.match && features.match(/^(?:.+,)?(oauth)(?:[=,].*)?$/i);
|
|
109
|
+
|
|
110
|
+
if (nameMatch || featureMatch) {
|
|
111
|
+
var wnd = null;
|
|
112
|
+
if (window.EventTarget) {
|
|
113
|
+
wnd = new EventTarget();
|
|
114
|
+
} else {
|
|
115
|
+
wnd = new EventTargetPolyfill();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function success() {
|
|
119
|
+
if (wnd) {
|
|
120
|
+
if (wnd.onclose) {
|
|
121
|
+
wnd.onclose();
|
|
122
|
+
}
|
|
123
|
+
wnd.dispatchEvent(new Event('close'));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
cordova.exec(success, noop, 'OAuth', 'startOAuth', [url]);
|
|
128
|
+
|
|
129
|
+
return wnd;
|
|
25
130
|
} else {
|
|
26
131
|
var originalWindowOpen = modulemapper.getOriginalSymbol(window, 'open');
|
|
27
132
|
return originalWindowOpen.apply(window, arguments);
|
package/.editorconfig
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Copyright 2017 Ayogo Health Inc
|
|
2
|
-
root = true
|
|
3
|
-
|
|
4
|
-
[*]
|
|
5
|
-
end_of_line = lf
|
|
6
|
-
indent_style = space
|
|
7
|
-
insert_final_newline = true
|
|
8
|
-
charset = utf-8
|
|
9
|
-
trim_trailing_whitespace = true
|
|
10
|
-
indent_size = 2
|
|
11
|
-
|
|
12
|
-
[*.java]
|
|
13
|
-
indent_size = 4
|
|
14
|
-
|
|
15
|
-
[*.swift]
|
|
16
|
-
indent_size = 4
|
|
17
|
-
|
|
18
|
-
[*.md]
|
|
19
|
-
indent_size = 4
|
|
20
|
-
trim_trailing_whitespace = false
|
package/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
-
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
|
9
|
-
level of experience, education, socio-economic status, nationality, personal
|
|
10
|
-
appearance, race, religion, or sexual identity and orientation.
|
|
11
|
-
|
|
12
|
-
## Our Standards
|
|
13
|
-
|
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
|
15
|
-
include:
|
|
16
|
-
|
|
17
|
-
* Using welcoming and inclusive language
|
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
|
19
|
-
* Gracefully accepting constructive criticism
|
|
20
|
-
* Focusing on what is best for the community
|
|
21
|
-
* Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior by participants include:
|
|
24
|
-
|
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
-
advances
|
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
-
* Public or private harassment
|
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
|
30
|
-
address, without explicit permission
|
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
-
professional setting
|
|
33
|
-
|
|
34
|
-
## Our Responsibilities
|
|
35
|
-
|
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
-
response to any instances of unacceptable behavior.
|
|
39
|
-
|
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
-
threatening, offensive, or harmful.
|
|
45
|
-
|
|
46
|
-
## Scope
|
|
47
|
-
|
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
-
when an individual is representing the project or its community. Examples of
|
|
50
|
-
representing a project or community include using an official project e-mail
|
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
|
53
|
-
further defined and clarified by project maintainers.
|
|
54
|
-
|
|
55
|
-
## Enforcement
|
|
56
|
-
|
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
-
reported by contacting the project team at opensource@ayogo.com. All
|
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
|
63
|
-
|
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
-
members of the project's leadership.
|
|
67
|
-
|
|
68
|
-
## Attribution
|
|
69
|
-
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
-
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
72
|
-
|
|
73
|
-
[homepage]: https://www.contributor-covenant.org
|
|
74
|
-
|
|
75
|
-
For answers to common questions about this code of conduct, see
|
|
76
|
-
https://www.contributor-covenant.org/faq
|
|
77
|
-
|