@capgo/capacitor-social-login 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CapgoCapacitorSocialLogin.podspec +21 -0
  2. package/Package.swift +37 -0
  3. package/README.md +457 -0
  4. package/android/build.gradle +64 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/ee/forgr/capacitor/social/login/AppleProvider.java +376 -0
  7. package/android/src/main/java/ee/forgr/capacitor/social/login/FacebookProvider.java +175 -0
  8. package/android/src/main/java/ee/forgr/capacitor/social/login/GoogleProvider.java +305 -0
  9. package/android/src/main/java/ee/forgr/capacitor/social/login/SocialLoginPlugin.java +161 -0
  10. package/android/src/main/java/ee/forgr/capacitor/social/login/helpers/JsonHelper.java +18 -0
  11. package/android/src/main/java/ee/forgr/capacitor/social/login/helpers/SocialProvider.java +13 -0
  12. package/android/src/main/res/.gitkeep +0 -0
  13. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  14. package/android/src/main/res/layout/dialog_custom_layout.xml +43 -0
  15. package/android/src/main/res/values/styles.xml +14 -0
  16. package/dist/docs.json +613 -0
  17. package/dist/esm/definitions.d.ts +191 -0
  18. package/dist/esm/definitions.js +2 -0
  19. package/dist/esm/definitions.js.map +1 -0
  20. package/dist/esm/index.d.ts +4 -0
  21. package/dist/esm/index.js +7 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/web.d.ts +17 -0
  24. package/dist/esm/web.js +29 -0
  25. package/dist/esm/web.js.map +1 -0
  26. package/dist/plugin.cjs.js +43 -0
  27. package/dist/plugin.cjs.js.map +1 -0
  28. package/dist/plugin.js +46 -0
  29. package/dist/plugin.js.map +1 -0
  30. package/ios/Sources/SocialLoginPlugin/AppleProvider.swift +516 -0
  31. package/ios/Sources/SocialLoginPlugin/FacebookProvider.swift +108 -0
  32. package/ios/Sources/SocialLoginPlugin/GoogleProvider.swift +165 -0
  33. package/ios/Sources/SocialLoginPlugin/SocialLoginPlugin.swift +322 -0
  34. package/ios/Tests/SocialLoginPluginTests/SocialLoginPluginTests.swift +15 -0
  35. package/package.json +87 -0
@@ -0,0 +1,376 @@
1
+ package ee.forgr.capacitor.social.login;
2
+
3
+ import android.annotation.SuppressLint;
4
+ import android.app.Activity;
5
+ import android.app.Dialog;
6
+ import android.content.Context;
7
+ import android.graphics.Bitmap;
8
+ import android.graphics.Color;
9
+ import android.graphics.Rect;
10
+ import android.graphics.drawable.ColorDrawable;
11
+ import android.net.Uri;
12
+ import android.util.Log;
13
+ import android.view.Gravity;
14
+ import android.view.View;
15
+ import android.view.Window;
16
+ import android.view.WindowManager;
17
+ import android.webkit.WebResourceRequest;
18
+ import android.webkit.WebView;
19
+ import android.webkit.WebViewClient;
20
+ import android.widget.ImageButton;
21
+ import android.widget.ProgressBar;
22
+ import androidx.annotation.NonNull;
23
+ import com.auth0.android.jwt.JWT;
24
+ import com.getcapacitor.JSObject;
25
+ import com.getcapacitor.PluginCall;
26
+ import ee.forgr.capacitor.social.login.helpers.SocialProvider;
27
+ import java.io.IOException;
28
+ import java.util.Objects;
29
+ import java.util.UUID;
30
+ import okhttp3.Call;
31
+ import okhttp3.Callback;
32
+ import okhttp3.FormBody;
33
+ import okhttp3.OkHttpClient;
34
+ import okhttp3.Request;
35
+ import okhttp3.Response;
36
+ import org.json.JSONException;
37
+ import org.json.JSONObject;
38
+ import org.json.JSONTokener;
39
+
40
+ public class AppleProvider implements SocialProvider {
41
+
42
+ private static final String SCOPE = "name%20email";
43
+ private static final String AUTHURL =
44
+ "https://appleid.apple.com/auth/authorize";
45
+ private static final String TOKENURL = "https://appleid.apple.com/auth/token";
46
+ private static final String SHARED_PREFERENCE_NAME =
47
+ "APPLE_LOGIN_Q16ob0k_SHARED_PERF";
48
+
49
+ private String appleAuthURLFull;
50
+ private Dialog appledialog;
51
+
52
+ private String idToken;
53
+ private String refreshToken;
54
+ private String accessToken;
55
+
56
+ private final String clientId;
57
+ private final String redirectUrl;
58
+ private final Activity activity;
59
+ private final Context context;
60
+
61
+ public AppleProvider(
62
+ String redirectUrl,
63
+ String clientId,
64
+ Activity activity,
65
+ Context context
66
+ ) {
67
+ this.redirectUrl = redirectUrl;
68
+ this.clientId = clientId;
69
+ this.activity = activity;
70
+ this.context = context;
71
+ }
72
+
73
+ public void initialize(JSONObject config) {
74
+ this.idToken = config.optString("idToken", null);
75
+ this.refreshToken = config.optString("refreshToken", null);
76
+ this.accessToken = config.optString("accessToken", null);
77
+ Log.i(
78
+ SocialLoginPlugin.LOG_TAG,
79
+ String.format("Apple restoreState: %s", config)
80
+ );
81
+ }
82
+
83
+ @Override
84
+ public void login(PluginCall call, JSONObject config) {
85
+ String state = UUID.randomUUID().toString();
86
+ this.appleAuthURLFull = AUTHURL +
87
+ "?client_id=" +
88
+ this.clientId +
89
+ "&redirect_uri=" +
90
+ this.redirectUrl +
91
+ "&response_type=code&scope=" +
92
+ SCOPE +
93
+ "&response_mode=form_post&state=" +
94
+ state;
95
+
96
+ if (context == null || activity == null) {
97
+ call.reject("Context or Activity is null");
98
+ return;
99
+ }
100
+
101
+ call.setKeepAlive(true);
102
+ activity.runOnUiThread(() ->
103
+ setupWebview(context, activity, call, appleAuthURLFull)
104
+ );
105
+ }
106
+
107
+ @Override
108
+ public void logout(PluginCall call) {
109
+ if (this.idToken == null || this.idToken.isEmpty()) {
110
+ call.reject("Not logged in; Cannot logout");
111
+ return;
112
+ }
113
+
114
+ context
115
+ .getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
116
+ .edit()
117
+ .clear()
118
+ .apply();
119
+ this.idToken = null;
120
+ this.refreshToken = null;
121
+ this.accessToken = null;
122
+
123
+ call.resolve();
124
+ }
125
+
126
+ @Override
127
+ public void getAuthorizationCode(PluginCall call) {
128
+ if (this.idToken != null && !this.idToken.isEmpty()) {
129
+ call.resolve(new JSObject().put("code", this.idToken));
130
+ } else {
131
+ call.reject("Apple-login not logged in!");
132
+ }
133
+ }
134
+
135
+ @Override
136
+ public void isLoggedIn(PluginCall call) {
137
+ if (this.idToken != null && !this.idToken.isEmpty()) {
138
+ try {
139
+ JWT jwt = new JWT(this.idToken);
140
+ boolean isLoggedIn = !jwt.isExpired(0);
141
+ call.resolve(new JSObject().put("isLoggedIn", isLoggedIn));
142
+ } catch (Exception e) {
143
+ call.reject("Error checking login status", e);
144
+ }
145
+ } else {
146
+ call.resolve(new JSObject().put("isLoggedIn", false));
147
+ }
148
+ }
149
+
150
+ @Override
151
+ public void getCurrentUser(PluginCall call) {
152
+ call.reject("Not implemented");
153
+ }
154
+
155
+ @Override
156
+ public void refresh(PluginCall call) {
157
+ call.reject("Not implemented");
158
+ }
159
+
160
+ private class AppleWebViewClient extends WebViewClient {
161
+
162
+ private final Activity activity;
163
+ private final String clientId;
164
+ private final String redirectUrl;
165
+ private final PluginCall call;
166
+
167
+ public AppleWebViewClient(
168
+ Activity activity,
169
+ PluginCall call,
170
+ String redirectUrl,
171
+ String clientId
172
+ ) {
173
+ this.activity = activity;
174
+ this.redirectUrl = redirectUrl;
175
+ this.clientId = clientId;
176
+ this.call = call;
177
+ }
178
+
179
+ @Override
180
+ public boolean shouldOverrideUrlLoading(
181
+ WebView view,
182
+ WebResourceRequest request
183
+ ) {
184
+ String url = request.getUrl().toString();
185
+ if (url.startsWith(redirectUrl)) {
186
+ handleUrl(url);
187
+ if (url.contains("success=")) {
188
+ appledialog.dismiss();
189
+ }
190
+ return true;
191
+ }
192
+ return false;
193
+ }
194
+
195
+ @Override
196
+ public void onPageFinished(WebView view, String url) {
197
+ super.onPageFinished(view, url);
198
+ Rect displayRectangle = new Rect();
199
+ Window window = activity.getWindow();
200
+ window.getDecorView().getWindowVisibleDisplayFrame(displayRectangle);
201
+ view.setLayoutParams(
202
+ new android.view.ViewGroup.LayoutParams(
203
+ android.view.ViewGroup.LayoutParams.MATCH_PARENT,
204
+ (int) (displayRectangle.height() * 0.9f)
205
+ )
206
+ );
207
+ }
208
+
209
+ private void handleUrl(String url) {
210
+ Uri uri = Uri.parse(url);
211
+ String success = uri.getQueryParameter("success");
212
+ if ("true".equals(success)) {
213
+ String accessToken = uri.getQueryParameter("access_token");
214
+ if (accessToken != null) {
215
+ String refreshToken = uri.getQueryParameter("refresh_token");
216
+ String idToken = uri.getQueryParameter("id_token");
217
+ try {
218
+ persistState(idToken, refreshToken, accessToken);
219
+ call.resolve(new JSObject().put("success", true));
220
+ } catch (JSONException e) {
221
+ Log.e(SocialLoginPlugin.LOG_TAG, "Cannot persist state", e);
222
+ call.reject("Cannot persist state", e);
223
+ }
224
+ } else {
225
+ String appleAuthCode = uri.getQueryParameter("code");
226
+ String appleClientSecret = uri.getQueryParameter("client_secret");
227
+ requestForAccessToken(appleAuthCode, appleClientSecret);
228
+ }
229
+ } else {
230
+ call.reject("We couldn't get the Auth Code");
231
+ }
232
+ }
233
+
234
+ private void requestForAccessToken(String code, String clientSecret) {
235
+ OkHttpClient client = new OkHttpClient();
236
+ FormBody formBody = new FormBody.Builder()
237
+ .add("grant_type", "authorization_code")
238
+ .add("code", code)
239
+ .add("redirect_uri", redirectUrl)
240
+ .add("client_id", clientId)
241
+ .add("client_secret", clientSecret)
242
+ .build();
243
+
244
+ Request request = new Request.Builder()
245
+ .url(TOKENURL)
246
+ .post(formBody)
247
+ .build();
248
+
249
+ client
250
+ .newCall(request)
251
+ .enqueue(
252
+ new Callback() {
253
+ @Override
254
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
255
+ AppleWebViewClient.this.call.reject("Cannot get access_token", e);
256
+ }
257
+
258
+ @Override
259
+ public void onResponse(
260
+ @NonNull Call call,
261
+ @NonNull Response response
262
+ ) throws IOException {
263
+ try {
264
+ if (!response.isSuccessful()) throw new IOException(
265
+ "Unexpected code " + response
266
+ );
267
+
268
+ String responseData = Objects.requireNonNull(
269
+ response.body()
270
+ ).string();
271
+ JSONObject jsonObject = (JSONObject) new JSONTokener(
272
+ responseData
273
+ ).nextValue();
274
+ String accessToken = jsonObject.getString("access_token");
275
+ String refreshToken = jsonObject.getString("refresh_token");
276
+ String idToken = jsonObject.getString("id_token");
277
+
278
+ persistState(idToken, refreshToken, accessToken);
279
+ AppleWebViewClient.this.call.resolve(
280
+ new JSObject().put("success", true)
281
+ );
282
+ } catch (Exception e) {
283
+ AppleWebViewClient.this.call.reject(
284
+ "Cannot get access_token",
285
+ e
286
+ );
287
+ } finally {
288
+ response.close();
289
+ }
290
+ }
291
+ }
292
+ );
293
+ }
294
+
295
+ private void persistState(
296
+ String idToken,
297
+ String refreshToken,
298
+ String accessToken
299
+ ) throws JSONException {
300
+ JSONObject object = new JSONObject();
301
+ object.put("idToken", idToken);
302
+ object.put("refreshToken", refreshToken);
303
+ object.put("accessToken", accessToken);
304
+
305
+ AppleProvider.this.idToken = idToken;
306
+ AppleProvider.this.refreshToken = refreshToken;
307
+ AppleProvider.this.accessToken = accessToken;
308
+
309
+ activity
310
+ .getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE)
311
+ .edit()
312
+ .putString(SHARED_PREFERENCE_NAME, object.toString())
313
+ .apply();
314
+ }
315
+ }
316
+
317
+ @SuppressLint("SetJavaScriptEnabled")
318
+ private void setupWebview(
319
+ Context context,
320
+ Activity activity,
321
+ PluginCall call,
322
+ String url
323
+ ) {
324
+ this.appledialog = new Dialog(context, R.style.CustomDialogTheme);
325
+ Window window = appledialog.getWindow();
326
+ if (window != null) {
327
+ window.setLayout(
328
+ WindowManager.LayoutParams.MATCH_PARENT,
329
+ WindowManager.LayoutParams.MATCH_PARENT
330
+ );
331
+ window.setGravity(Gravity.TOP);
332
+ window.setBackgroundDrawable(new ColorDrawable(Color.WHITE));
333
+ window.setDimAmount(0.0f);
334
+ }
335
+
336
+ View customView = activity
337
+ .getLayoutInflater()
338
+ .inflate(R.layout.dialog_custom_layout, null);
339
+ WebView webView = customView.findViewById(R.id.webview);
340
+ ProgressBar progressBar = customView.findViewById(R.id.progress_bar);
341
+
342
+ webView.setVerticalScrollBarEnabled(false);
343
+ webView.setHorizontalScrollBarEnabled(false);
344
+
345
+ AppleWebViewClient webViewClient = new AppleWebViewClient(
346
+ activity,
347
+ call,
348
+ this.redirectUrl,
349
+ this.clientId
350
+ ) {
351
+ @Override
352
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
353
+ super.onPageStarted(view, url, favicon);
354
+ progressBar.setVisibility(View.VISIBLE);
355
+ }
356
+
357
+ @Override
358
+ public void onPageFinished(WebView view, String url) {
359
+ super.onPageFinished(view, url);
360
+ progressBar.setVisibility(View.GONE);
361
+ }
362
+ };
363
+
364
+ webView.setWebViewClient(webViewClient);
365
+
366
+ webView.getSettings().setJavaScriptEnabled(true);
367
+ webView.loadUrl(url);
368
+
369
+ ImageButton closeButton = customView.findViewById(R.id.close_button);
370
+ closeButton.setOnClickListener(v -> appledialog.dismiss());
371
+
372
+ appledialog.setContentView(customView);
373
+
374
+ appledialog.show();
375
+ }
376
+ }
@@ -0,0 +1,175 @@
1
+ package ee.forgr.capacitor.social.login;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Intent;
5
+ import android.os.Bundle;
6
+ import android.util.Log;
7
+ import com.facebook.AccessToken;
8
+ import com.facebook.CallbackManager;
9
+ import com.facebook.FacebookCallback;
10
+ import com.facebook.FacebookException;
11
+ import com.facebook.GraphRequest;
12
+ import com.facebook.GraphResponse;
13
+ import com.facebook.login.LoginManager;
14
+ import com.facebook.login.LoginResult;
15
+ import com.getcapacitor.JSObject;
16
+ import com.getcapacitor.PluginCall;
17
+ import ee.forgr.capacitor.social.login.helpers.JsonHelper;
18
+ import ee.forgr.capacitor.social.login.helpers.SocialProvider;
19
+ import java.util.Collection;
20
+ import org.json.JSONException;
21
+ import org.json.JSONObject;
22
+
23
+ public class FacebookProvider implements SocialProvider {
24
+
25
+ private static final String LOG_TAG = "FacebookProvider";
26
+
27
+ private Activity activity;
28
+ private CallbackManager callbackManager;
29
+
30
+ public FacebookProvider(Activity activity) {
31
+ this.activity = activity;
32
+ }
33
+
34
+ public void initialize(JSONObject _config) {
35
+ this.callbackManager = CallbackManager.Factory.create();
36
+
37
+ LoginManager.getInstance()
38
+ .registerCallback(
39
+ callbackManager,
40
+ new FacebookCallback<LoginResult>() {
41
+ @Override
42
+ public void onSuccess(LoginResult loginResult) {
43
+ Log.d(LOG_TAG, "LoginManager.onSuccess");
44
+ }
45
+
46
+ @Override
47
+ public void onCancel() {
48
+ Log.d(LOG_TAG, "LoginManager.onCancel");
49
+ }
50
+
51
+ @Override
52
+ public void onError(FacebookException exception) {
53
+ Log.e(LOG_TAG, "LoginManager.onError", exception);
54
+ }
55
+ }
56
+ );
57
+ }
58
+
59
+ @Override
60
+ public void login(PluginCall call, JSONObject config) {
61
+ try {
62
+ Collection<String> permissions = JsonHelper.jsonArrayToList(
63
+ config.getJSONArray("permissions")
64
+ );
65
+ LoginManager.getInstance()
66
+ .registerCallback(
67
+ callbackManager,
68
+ new FacebookCallback<LoginResult>() {
69
+ @Override
70
+ public void onSuccess(LoginResult loginResult) {
71
+ Log.d(LOG_TAG, "LoginManager.onSuccess");
72
+ AccessToken accessToken = loginResult.getAccessToken();
73
+ JSObject result = new JSObject();
74
+ result.put("accessToken", accessToken.getToken());
75
+ result.put("userId", accessToken.getUserId());
76
+ call.resolve(result);
77
+ }
78
+
79
+ @Override
80
+ public void onCancel() {
81
+ Log.d(LOG_TAG, "LoginManager.onCancel");
82
+ call.reject("Login cancelled");
83
+ }
84
+
85
+ @Override
86
+ public void onError(FacebookException exception) {
87
+ Log.e(LOG_TAG, "LoginManager.onError", exception);
88
+ call.reject(exception.getMessage());
89
+ }
90
+ }
91
+ );
92
+ LoginManager.getInstance().logIn(activity, permissions);
93
+ } catch (JSONException e) {
94
+ call.reject("Invalid permissions format");
95
+ }
96
+ }
97
+
98
+ @Override
99
+ public void logout(PluginCall call) {
100
+ LoginManager.getInstance().logOut();
101
+ call.resolve();
102
+ }
103
+
104
+ @Override
105
+ public void getAuthorizationCode(PluginCall call) {
106
+ AccessToken accessToken = AccessToken.getCurrentAccessToken();
107
+ if (accessToken != null && !accessToken.isExpired()) {
108
+ call.resolve(new JSObject().put("code", accessToken.getToken()));
109
+ } else {
110
+ call.reject("No valid access token found");
111
+ }
112
+ }
113
+
114
+ @Override
115
+ public void isLoggedIn(PluginCall call) {
116
+ AccessToken accessToken = AccessToken.getCurrentAccessToken();
117
+ call.resolve(
118
+ new JSObject()
119
+ .put("isLoggedIn", accessToken != null && !accessToken.isExpired())
120
+ );
121
+ }
122
+
123
+ @Override
124
+ public void getCurrentUser(PluginCall call) {
125
+ AccessToken accessToken = AccessToken.getCurrentAccessToken();
126
+ if (accessToken == null) {
127
+ call.reject(
128
+ "You're not logged in. Call FacebookLogin.login() first to obtain an access token."
129
+ );
130
+ return;
131
+ }
132
+
133
+ if (accessToken.isExpired()) {
134
+ call.reject("AccessToken is expired.");
135
+ return;
136
+ }
137
+
138
+ GraphRequest graphRequest = GraphRequest.newMeRequest(
139
+ accessToken,
140
+ new GraphRequest.GraphJSONObjectCallback() {
141
+ @Override
142
+ public void onCompleted(JSONObject object, GraphResponse response) {
143
+ if (response.getError() != null) {
144
+ call.reject(response.getError().getErrorMessage());
145
+ } else {
146
+ try {
147
+ call.resolve(JSObject.fromJSONObject(object));
148
+ } catch (JSONException e) {
149
+ call.reject("Error parsing user data: " + e.getMessage());
150
+ }
151
+ }
152
+ }
153
+ }
154
+ );
155
+
156
+ Bundle parameters = new Bundle();
157
+ parameters.putString("fields", "id,name,email");
158
+ graphRequest.setParameters(parameters);
159
+ graphRequest.executeAsync();
160
+ }
161
+
162
+ @Override
163
+ public void refresh(PluginCall call) {
164
+ // Not implemented for Facebook
165
+ call.reject("Not implemented");
166
+ }
167
+
168
+ public boolean handleOnActivityResult(
169
+ int requestCode,
170
+ int resultCode,
171
+ Intent data
172
+ ) {
173
+ return callbackManager.onActivityResult(requestCode, resultCode, data);
174
+ }
175
+ }