react-native-nitro-auth 0.5.5 → 0.5.7
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 +30 -19
- package/android/proguard-rules.pro +7 -1
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/cpp/PlatformAuth+Android.cpp +261 -68
- package/android/src/main/java/com/auth/AuthAdapter.kt +250 -157
- package/android/src/main/java/com/auth/GoogleSignInActivity.kt +9 -5
- package/cpp/HybridAuth.cpp +79 -64
- package/cpp/HybridAuth.hpp +9 -7
- package/cpp/JSONSerializer.hpp +3 -0
- package/ios/AuthAdapter.swift +208 -66
- package/ios/PlatformAuth+iOS.mm +30 -4
- package/lib/commonjs/Auth.web.js +50 -10
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/index.web.js +30 -12
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/service.js +25 -19
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +65 -13
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/ui/social-button.js +19 -14
- package/lib/commonjs/ui/social-button.js.map +1 -1
- package/lib/commonjs/ui/social-button.web.js +16 -10
- package/lib/commonjs/ui/social-button.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +34 -10
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/auth-error.js +1 -1
- package/lib/commonjs/utils/auth-error.js.map +1 -1
- package/lib/commonjs/utils/logger.js +1 -0
- package/lib/commonjs/utils/logger.js.map +1 -1
- package/lib/module/Auth.web.js +50 -10
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/global.d.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +2 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/service.js +25 -19
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +65 -13
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/ui/social-button.js +19 -14
- package/lib/module/ui/social-button.js.map +1 -1
- package/lib/module/ui/social-button.web.js +16 -10
- package/lib/module/ui/social-button.web.js.map +1 -1
- package/lib/module/use-auth.js +34 -10
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/auth-error.js +1 -1
- package/lib/module/utils/auth-error.js.map +1 -1
- package/lib/module/utils/logger.js +1 -0
- package/lib/module/utils/logger.js.map +1 -1
- package/lib/typescript/commonjs/Auth.nitro.d.ts +2 -2
- package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +5 -1
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +2 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts +2 -18
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/auth-error.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/logger.d.ts.map +1 -1
- package/lib/typescript/module/Auth.nitro.d.ts +2 -2
- package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +5 -1
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +2 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts +2 -18
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/auth-error.d.ts.map +1 -1
- package/lib/typescript/module/utils/logger.d.ts.map +1 -1
- package/nitro.json +4 -1
- package/nitrogen/generated/ios/NitroAuth+autolinking.rb +2 -0
- package/package.json +3 -4
- package/src/Auth.nitro.ts +3 -1
- package/src/Auth.web.ts +77 -11
- package/src/global.d.ts +0 -11
- package/src/index.ts +5 -1
- package/src/index.web.ts +6 -1
- package/src/service.ts +26 -19
- package/src/service.web.ts +84 -15
- package/src/ui/social-button.tsx +21 -9
- package/src/ui/social-button.web.tsx +17 -4
- package/src/use-auth.ts +65 -9
- package/src/utils/auth-error.ts +2 -0
- package/src/utils/logger.ts +1 -0
package/README.md
CHANGED
|
@@ -308,12 +308,13 @@ To enable Microsoft Sign-In, you need to register an application in the Azure Po
|
|
|
308
308
|
- `nitro_auth_microsoft_client_id`
|
|
309
309
|
- `nitro_auth_microsoft_tenant` (optional)
|
|
310
310
|
- `nitro_auth_microsoft_b2c_domain` (optional)
|
|
311
|
-
-
|
|
311
|
+
- `MicrosoftAuthActivity` is **automatically declared** by the library manifest — no manual `AndroidManifest.xml` entry is required for basic Microsoft OAuth redirect handling. If you need to customize the intent-filter (e.g., restrict the host/path to your specific package and client ID), you can override it in your app manifest:
|
|
312
312
|
|
|
313
313
|
```xml
|
|
314
314
|
<activity
|
|
315
315
|
android:name="com.auth.MicrosoftAuthActivity"
|
|
316
|
-
android:exported="true"
|
|
316
|
+
android:exported="true"
|
|
317
|
+
android:launchMode="singleTask">
|
|
317
318
|
<intent-filter>
|
|
318
319
|
<action android:name="android.intent.action.VIEW" />
|
|
319
320
|
<category android:name="android.intent.category.DEFAULT" />
|
|
@@ -693,19 +694,23 @@ try {
|
|
|
693
694
|
}
|
|
694
695
|
```
|
|
695
696
|
|
|
696
|
-
| Error Code | Description
|
|
697
|
-
| ---------------------- |
|
|
698
|
-
| `cancelled` | The user cancelled the sign-in flow
|
|
699
|
-
| `
|
|
700
|
-
| `
|
|
701
|
-
| `
|
|
702
|
-
| `
|
|
703
|
-
| `
|
|
704
|
-
| `
|
|
705
|
-
| `
|
|
706
|
-
| `
|
|
707
|
-
| `
|
|
708
|
-
| `
|
|
697
|
+
| Error Code | Description |
|
|
698
|
+
| ---------------------- | --------------------------------------------------------------- |
|
|
699
|
+
| `cancelled` | The user cancelled the sign-in flow or dismissed the popup |
|
|
700
|
+
| `timeout` | The login popup/flow timed out |
|
|
701
|
+
| `popup_blocked` | The browser blocked the popup window |
|
|
702
|
+
| `network_error` | A network or connectivity error occurred |
|
|
703
|
+
| `configuration_error` | Missing client IDs, invalid tenant, or misconfigured setup |
|
|
704
|
+
| `not_signed_in` | The operation requires an authenticated user/session |
|
|
705
|
+
| `operation_in_progress`| Another auth flow of the same kind is already running |
|
|
706
|
+
| `unsupported_provider` | The provider is not supported on this platform |
|
|
707
|
+
| `invalid_state` | PKCE state mismatch — possible CSRF attack |
|
|
708
|
+
| `invalid_nonce` | Nonce mismatch in token response — possible replay attack |
|
|
709
|
+
| `token_error` | Token exchange or storage failed |
|
|
710
|
+
| `no_id_token` | No `id_token` in token response |
|
|
711
|
+
| `parse_error` | Failed to parse token response |
|
|
712
|
+
| `refresh_failed` | Refresh token flow failed (token may be expired or revoked) |
|
|
713
|
+
| `unknown` | An unknown or unmapped error occurred |
|
|
709
714
|
|
|
710
715
|
### Native Error Metadata
|
|
711
716
|
|
|
@@ -729,10 +734,12 @@ The `AuthUser.underlyingError` field carries a raw warning string when the provi
|
|
|
729
734
|
|
|
730
735
|
### Troubleshooting
|
|
731
736
|
|
|
732
|
-
- `configuration_error`: verify client IDs, URL schemes, and redirect URIs are set for the current platform.
|
|
733
|
-
- `invalid_state` or `invalid_nonce`: ensure the redirect URI in your provider console matches your app config exactly.
|
|
737
|
+
- `configuration_error`: verify client IDs, URL schemes, and redirect URIs are set for the current platform. On Android, check that the `microsoftTenant` is a non-empty valid value.
|
|
738
|
+
- `invalid_state` or `invalid_nonce`: ensure the redirect URI in your provider console matches your app config exactly. These indicate a potential CSRF or replay attack — do not retry silently.
|
|
739
|
+
- `refresh_failed`: the refresh token is likely expired or revoked. Clear the session and prompt the user to sign in again. On Android and web, structured error details from the provider (e.g. `invalid_grant`) are surfaced via `error.underlyingMessage`.
|
|
734
740
|
- `hasPlayServices` is false: prompt the user to install/update Google Play Services or disable One-Tap.
|
|
735
741
|
- Apple web login fails: confirm `appleWebClientId` is set and your domain is registered with Apple.
|
|
742
|
+
- Microsoft Android redirect hangs: confirm the `msauth://` redirect URI in your Azure app matches your package name and client ID.
|
|
736
743
|
|
|
737
744
|
### Automatic Token Refresh
|
|
738
745
|
|
|
@@ -798,6 +805,8 @@ This is useful for scenarios where:
|
|
|
798
805
|
- You need to ensure the user can select any account they've added to their device
|
|
799
806
|
- The cached session is interfering with the expected account selection UX
|
|
800
807
|
|
|
808
|
+
On Android, `forceAccountPicker` routes through the legacy Google Sign-In chooser to guarantee the account picker appears. Credential Manager / One-Tap remains the default when the chooser is not forced.
|
|
809
|
+
|
|
801
810
|
## API Reference
|
|
802
811
|
|
|
803
812
|
### Package Exports
|
|
@@ -825,7 +834,7 @@ import {
|
|
|
825
834
|
| Type | Definition |
|
|
826
835
|
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
827
836
|
| `AuthProvider` | `"google" \| "apple" \| "microsoft"` |
|
|
828
|
-
| `AuthErrorCode` | `"cancelled" \| "timeout" \| "popup_blocked" \| "network_error" \| "configuration_error" \| "unsupported_provider" \| "invalid_state" \| "invalid_nonce" \| "token_error" \| "no_id_token" \| "parse_error" \| "refresh_failed" \| "unknown"` |
|
|
837
|
+
| `AuthErrorCode` | `"cancelled" \| "timeout" \| "popup_blocked" \| "network_error" \| "configuration_error" \| "not_signed_in" \| "operation_in_progress" \| "unsupported_provider" \| "invalid_state" \| "invalid_nonce" \| "token_error" \| "no_id_token" \| "parse_error" \| "refresh_failed" \| "unknown"` |
|
|
829
838
|
| `MicrosoftPrompt` | `"login" \| "consent" \| "select_account" \| "none"` |
|
|
830
839
|
|
|
831
840
|
### `AuthUser`
|
|
@@ -864,7 +873,7 @@ import {
|
|
|
864
873
|
| `loginHint` | `string` | All | Prefills account identifier |
|
|
865
874
|
| `useOneTap` | `boolean` | Android | Use Credential Manager/One-Tap flow |
|
|
866
875
|
| `useSheet` | `boolean` | iOS | Use native Google Sign-In sheet |
|
|
867
|
-
| `forceAccountPicker` | `boolean` | All | Always show account chooser
|
|
876
|
+
| `forceAccountPicker` | `boolean` | All | Always show account chooser; Android Google uses the legacy chooser path |
|
|
868
877
|
| `useLegacyGoogleSignIn` | `boolean` | Android | Use legacy Google Sign-In (required when you need `serverAuthCode`) |
|
|
869
878
|
| `tenant` | `string` | Microsoft | Tenant (`common`, `organizations`, `consumers`, tenant id, or full authority URL) |
|
|
870
879
|
| `prompt` | `MicrosoftPrompt` | Microsoft | Prompt behavior |
|
|
@@ -998,6 +1007,8 @@ function toAuthErrorCode(raw: string): AuthErrorCode; // Returns "unknown" for u
|
|
|
998
1007
|
| `popup_blocked` | Browser blocked popup opening |
|
|
999
1008
|
| `network_error` | Network failure |
|
|
1000
1009
|
| `configuration_error` | Missing/invalid provider configuration |
|
|
1010
|
+
| `not_signed_in` | Operation requires an active authenticated user |
|
|
1011
|
+
| `operation_in_progress`| Another auth flow is already running |
|
|
1001
1012
|
| `unsupported_provider` | Provider not supported on this platform |
|
|
1002
1013
|
| `invalid_state` | PKCE state mismatch (possible CSRF) |
|
|
1003
1014
|
| `invalid_nonce` | Nonce mismatch in token response |
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
# Nitro Auth Proguard Rules
|
|
2
|
-
-keep class com.auth
|
|
2
|
+
-keep class com.auth.AuthAdapter {
|
|
3
|
+
public static <methods>;
|
|
4
|
+
}
|
|
5
|
+
-keep class com.auth.MicrosoftAuthActivity { *; }
|
|
6
|
+
-keep class com.auth.GoogleSignInActivity { *; }
|
|
7
|
+
-keep class com.auth.NitroAuthModule { *; }
|
|
8
|
+
-keep class com.auth.NitroAuthPackage { *; }
|
|
3
9
|
-keep class com.margelo.nitro.com.auth.** { *; }
|
|
4
10
|
-keep class com.google.android.gms.auth.api.signin.** { *; }
|
|
@@ -8,5 +8,17 @@
|
|
|
8
8
|
android:name="com.auth.GoogleSignInActivity"
|
|
9
9
|
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
|
10
10
|
android:exported="false" />
|
|
11
|
+
<activity
|
|
12
|
+
android:name="com.auth.MicrosoftAuthActivity"
|
|
13
|
+
android:exported="true"
|
|
14
|
+
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
|
15
|
+
android:launchMode="singleTask">
|
|
16
|
+
<intent-filter>
|
|
17
|
+
<action android:name="android.intent.action.VIEW" />
|
|
18
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
19
|
+
<category android:name="android.intent.category.BROWSABLE" />
|
|
20
|
+
<data android:scheme="msauth" />
|
|
21
|
+
</intent-filter>
|
|
22
|
+
</activity>
|
|
11
23
|
</application>
|
|
12
24
|
</manifest>
|
|
@@ -13,14 +13,6 @@ namespace margelo::nitro::NitroAuth {
|
|
|
13
13
|
|
|
14
14
|
using namespace facebook::jni;
|
|
15
15
|
|
|
16
|
-
struct JContext : JavaClass<JContext> {
|
|
17
|
-
static constexpr auto kJavaDescriptor = "Landroid/content/Context;";
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
struct JAuthAdapter : JavaClass<JAuthAdapter> {
|
|
21
|
-
static constexpr auto kJavaDescriptor = "Lcom/auth/AuthAdapter;";
|
|
22
|
-
};
|
|
23
|
-
|
|
24
16
|
static std::shared_ptr<Promise<AuthUser>> gLoginPromise;
|
|
25
17
|
static std::shared_ptr<Promise<AuthUser>> gScopesPromise;
|
|
26
18
|
static std::shared_ptr<Promise<AuthTokens>> gRefreshPromise;
|
|
@@ -29,29 +21,84 @@ static std::mutex gMutex;
|
|
|
29
21
|
static jclass gAuthAdapterClass = nullptr;
|
|
30
22
|
static jmethodID gLoginMethod = nullptr;
|
|
31
23
|
static jmethodID gRequestScopesMethod = nullptr;
|
|
24
|
+
static jmethodID gRefreshMethod = nullptr;
|
|
25
|
+
static jmethodID gRestoreMethod = nullptr;
|
|
26
|
+
static jmethodID gHasPlayMethod = nullptr;
|
|
27
|
+
static jmethodID gLogoutMethod = nullptr;
|
|
28
|
+
|
|
29
|
+
// Call from JNI_OnUnload or dispose to prevent stale refs after a module reload.
|
|
30
|
+
static void clearCachedJniRefs(JNIEnv* env) {
|
|
31
|
+
if (gAuthAdapterClass != nullptr) {
|
|
32
|
+
env->DeleteGlobalRef(gAuthAdapterClass);
|
|
33
|
+
gAuthAdapterClass = nullptr;
|
|
34
|
+
}
|
|
35
|
+
gLoginMethod = nullptr;
|
|
36
|
+
gRequestScopesMethod = nullptr;
|
|
37
|
+
gRefreshMethod = nullptr;
|
|
38
|
+
gRestoreMethod = nullptr;
|
|
39
|
+
gHasPlayMethod = nullptr;
|
|
40
|
+
gLogoutMethod = nullptr;
|
|
41
|
+
}
|
|
32
42
|
|
|
33
43
|
static void ensureAuthAdapterMethods(JNIEnv* env) {
|
|
34
|
-
if (gAuthAdapterClass != nullptr && gLoginMethod != nullptr
|
|
44
|
+
if (gAuthAdapterClass != nullptr && gLoginMethod != nullptr
|
|
45
|
+
&& gRequestScopesMethod != nullptr && gRefreshMethod != nullptr
|
|
46
|
+
&& gRestoreMethod != nullptr && gHasPlayMethod != nullptr
|
|
47
|
+
&& gLogoutMethod != nullptr) {
|
|
35
48
|
return;
|
|
36
49
|
}
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
if (gAuthAdapterClass == nullptr) {
|
|
52
|
+
jclass localAdapterClass = env->FindClass("com/auth/AuthAdapter");
|
|
53
|
+
if (localAdapterClass == nullptr) {
|
|
54
|
+
throw std::runtime_error("Unable to resolve com/auth/AuthAdapter");
|
|
55
|
+
}
|
|
56
|
+
gAuthAdapterClass = static_cast<jclass>(env->NewGlobalRef(localAdapterClass));
|
|
57
|
+
env->DeleteLocalRef(localAdapterClass);
|
|
41
58
|
}
|
|
42
|
-
gAuthAdapterClass = static_cast<jclass>(env->NewGlobalRef(localAdapterClass));
|
|
43
|
-
env->DeleteLocalRef(localAdapterClass);
|
|
44
59
|
|
|
45
|
-
gLoginMethod
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
60
|
+
if (gLoginMethod == nullptr) {
|
|
61
|
+
gLoginMethod = env->GetStaticMethodID(
|
|
62
|
+
gAuthAdapterClass,
|
|
63
|
+
"loginSync",
|
|
64
|
+
"(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;ZZZLjava/lang/String;Ljava/lang/String;)V"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
if (gRequestScopesMethod == nullptr) {
|
|
68
|
+
gRequestScopesMethod = env->GetStaticMethodID(
|
|
69
|
+
gAuthAdapterClass,
|
|
70
|
+
"requestScopesSync",
|
|
71
|
+
"(Landroid/content/Context;[Ljava/lang/String;)V"
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
if (gRefreshMethod == nullptr) {
|
|
75
|
+
gRefreshMethod = env->GetStaticMethodID(
|
|
76
|
+
gAuthAdapterClass,
|
|
77
|
+
"refreshTokenSync",
|
|
78
|
+
"(Landroid/content/Context;)V"
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (gRestoreMethod == nullptr) {
|
|
82
|
+
gRestoreMethod = env->GetStaticMethodID(
|
|
83
|
+
gAuthAdapterClass,
|
|
84
|
+
"restoreSession",
|
|
85
|
+
"(Landroid/content/Context;)V"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (gHasPlayMethod == nullptr) {
|
|
89
|
+
gHasPlayMethod = env->GetStaticMethodID(
|
|
90
|
+
gAuthAdapterClass,
|
|
91
|
+
"hasPlayServices",
|
|
92
|
+
"(Landroid/content/Context;)Z"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (gLogoutMethod == nullptr) {
|
|
96
|
+
gLogoutMethod = env->GetStaticMethodID(
|
|
97
|
+
gAuthAdapterClass,
|
|
98
|
+
"logoutSync",
|
|
99
|
+
"(Landroid/content/Context;)V"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
55
102
|
}
|
|
56
103
|
|
|
57
104
|
std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, const std::optional<LoginOptions>& options) {
|
|
@@ -61,11 +108,12 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
61
108
|
promise->reject(std::make_exception_ptr(std::runtime_error("Android Context not initialized")));
|
|
62
109
|
return promise;
|
|
63
110
|
}
|
|
64
|
-
|
|
111
|
+
|
|
65
112
|
{
|
|
66
113
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
67
114
|
if (gLoginPromise) {
|
|
68
|
-
|
|
115
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("operation_in_progress")));
|
|
116
|
+
return promise;
|
|
69
117
|
}
|
|
70
118
|
gLoginPromise = promise;
|
|
71
119
|
}
|
|
@@ -106,15 +154,20 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
106
154
|
try {
|
|
107
155
|
ensureAuthAdapterMethods(env);
|
|
108
156
|
} catch (...) {
|
|
157
|
+
{
|
|
158
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
159
|
+
gLoginPromise = nullptr;
|
|
160
|
+
}
|
|
109
161
|
promise->reject(std::current_exception());
|
|
110
162
|
return promise;
|
|
111
163
|
}
|
|
112
164
|
jclass stringClass = env->FindClass("java/lang/String");
|
|
113
165
|
jobjectArray jScopes = env->NewObjectArray(scopes.size(), stringClass, nullptr);
|
|
114
166
|
for (size_t i = 0; i < scopes.size(); i++) {
|
|
115
|
-
|
|
167
|
+
auto jstr = make_jstring(scopes[i]);
|
|
168
|
+
env->SetObjectArrayElement(jScopes, i, jstr.get());
|
|
116
169
|
}
|
|
117
|
-
|
|
170
|
+
|
|
118
171
|
local_ref<JString> providerRef = make_jstring(providerStr);
|
|
119
172
|
local_ref<JString> loginHintRef;
|
|
120
173
|
local_ref<JString> tenantRef;
|
|
@@ -130,8 +183,8 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
130
183
|
promptRef = make_jstring(prompt.value());
|
|
131
184
|
}
|
|
132
185
|
|
|
133
|
-
env->CallStaticVoidMethod(gAuthAdapterClass, gLoginMethod,
|
|
134
|
-
contextPtr,
|
|
186
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gLoginMethod,
|
|
187
|
+
contextPtr,
|
|
135
188
|
providerRef.get(),
|
|
136
189
|
nullptr,
|
|
137
190
|
jScopes,
|
|
@@ -144,7 +197,18 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::login(AuthProvider provider, co
|
|
|
144
197
|
|
|
145
198
|
env->DeleteLocalRef(jScopes);
|
|
146
199
|
env->DeleteLocalRef(stringClass);
|
|
147
|
-
|
|
200
|
+
|
|
201
|
+
if (env->ExceptionCheck()) {
|
|
202
|
+
env->ExceptionDescribe();
|
|
203
|
+
env->ExceptionClear();
|
|
204
|
+
{
|
|
205
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
206
|
+
gLoginPromise = nullptr;
|
|
207
|
+
}
|
|
208
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("JNI call failed")));
|
|
209
|
+
return promise;
|
|
210
|
+
}
|
|
211
|
+
|
|
148
212
|
return promise;
|
|
149
213
|
}
|
|
150
214
|
|
|
@@ -159,7 +223,8 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::requestScopes(const std::vector
|
|
|
159
223
|
{
|
|
160
224
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
161
225
|
if (gScopesPromise) {
|
|
162
|
-
|
|
226
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("operation_in_progress")));
|
|
227
|
+
return promise;
|
|
163
228
|
}
|
|
164
229
|
gScopesPromise = promise;
|
|
165
230
|
}
|
|
@@ -168,18 +233,35 @@ std::shared_ptr<Promise<AuthUser>> PlatformAuth::requestScopes(const std::vector
|
|
|
168
233
|
try {
|
|
169
234
|
ensureAuthAdapterMethods(env);
|
|
170
235
|
} catch (...) {
|
|
236
|
+
{
|
|
237
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
238
|
+
gScopesPromise = nullptr;
|
|
239
|
+
}
|
|
171
240
|
promise->reject(std::current_exception());
|
|
172
241
|
return promise;
|
|
173
242
|
}
|
|
174
243
|
jclass stringClass = env->FindClass("java/lang/String");
|
|
175
244
|
jobjectArray jScopes = env->NewObjectArray(scopes.size(), stringClass, nullptr);
|
|
176
245
|
for (size_t i = 0; i < scopes.size(); i++) {
|
|
177
|
-
|
|
246
|
+
auto jstr = make_jstring(scopes[i]);
|
|
247
|
+
env->SetObjectArrayElement(jScopes, i, jstr.get());
|
|
178
248
|
}
|
|
179
|
-
|
|
249
|
+
|
|
180
250
|
env->CallStaticVoidMethod(gAuthAdapterClass, gRequestScopesMethod, contextPtr, jScopes);
|
|
181
251
|
env->DeleteLocalRef(jScopes);
|
|
182
252
|
env->DeleteLocalRef(stringClass);
|
|
253
|
+
|
|
254
|
+
if (env->ExceptionCheck()) {
|
|
255
|
+
env->ExceptionDescribe();
|
|
256
|
+
env->ExceptionClear();
|
|
257
|
+
{
|
|
258
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
259
|
+
gScopesPromise = nullptr;
|
|
260
|
+
}
|
|
261
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("JNI call failed")));
|
|
262
|
+
return promise;
|
|
263
|
+
}
|
|
264
|
+
|
|
183
265
|
return promise;
|
|
184
266
|
}
|
|
185
267
|
|
|
@@ -194,14 +276,37 @@ std::shared_ptr<Promise<AuthTokens>> PlatformAuth::refreshToken() {
|
|
|
194
276
|
{
|
|
195
277
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
196
278
|
if (gRefreshPromise) {
|
|
197
|
-
|
|
279
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("operation_in_progress")));
|
|
280
|
+
return promise;
|
|
198
281
|
}
|
|
199
282
|
gRefreshPromise = promise;
|
|
200
283
|
}
|
|
201
284
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
285
|
+
JNIEnv* env = Environment::current();
|
|
286
|
+
try {
|
|
287
|
+
ensureAuthAdapterMethods(env);
|
|
288
|
+
} catch (...) {
|
|
289
|
+
{
|
|
290
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
291
|
+
gRefreshPromise = nullptr;
|
|
292
|
+
}
|
|
293
|
+
promise->reject(std::current_exception());
|
|
294
|
+
return promise;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gRefreshMethod, contextPtr);
|
|
298
|
+
|
|
299
|
+
if (env->ExceptionCheck()) {
|
|
300
|
+
env->ExceptionDescribe();
|
|
301
|
+
env->ExceptionClear();
|
|
302
|
+
{
|
|
303
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
304
|
+
gRefreshPromise = nullptr;
|
|
305
|
+
}
|
|
306
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("JNI call failed")));
|
|
307
|
+
return promise;
|
|
308
|
+
}
|
|
309
|
+
|
|
205
310
|
return promise;
|
|
206
311
|
}
|
|
207
312
|
|
|
@@ -216,33 +321,79 @@ std::shared_ptr<Promise<std::optional<AuthUser>>> PlatformAuth::silentRestore()
|
|
|
216
321
|
{
|
|
217
322
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
218
323
|
if (gSilentPromise) {
|
|
219
|
-
|
|
324
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("operation_in_progress")));
|
|
325
|
+
return promise;
|
|
220
326
|
}
|
|
221
327
|
gSilentPromise = promise;
|
|
222
328
|
}
|
|
223
329
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
330
|
+
JNIEnv* env = Environment::current();
|
|
331
|
+
try {
|
|
332
|
+
ensureAuthAdapterMethods(env);
|
|
333
|
+
} catch (...) {
|
|
334
|
+
{
|
|
335
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
336
|
+
gSilentPromise = nullptr;
|
|
337
|
+
}
|
|
338
|
+
promise->reject(std::current_exception());
|
|
339
|
+
return promise;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gRestoreMethod, contextPtr);
|
|
343
|
+
|
|
344
|
+
if (env->ExceptionCheck()) {
|
|
345
|
+
env->ExceptionDescribe();
|
|
346
|
+
env->ExceptionClear();
|
|
347
|
+
{
|
|
348
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
349
|
+
gSilentPromise = nullptr;
|
|
350
|
+
}
|
|
351
|
+
promise->reject(std::make_exception_ptr(std::runtime_error("JNI call failed")));
|
|
352
|
+
return promise;
|
|
353
|
+
}
|
|
354
|
+
|
|
227
355
|
return promise;
|
|
228
356
|
}
|
|
229
357
|
|
|
230
358
|
bool PlatformAuth::hasPlayServices() {
|
|
231
359
|
auto contextPtr = static_cast<jobject>(AuthCache::getAndroidContext());
|
|
232
360
|
if (!contextPtr) return false;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
361
|
+
|
|
362
|
+
JNIEnv* env = Environment::current();
|
|
363
|
+
try {
|
|
364
|
+
ensureAuthAdapterMethods(env);
|
|
365
|
+
} catch (...) {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
jboolean result = env->CallStaticBooleanMethod(gAuthAdapterClass, gHasPlayMethod, contextPtr);
|
|
370
|
+
|
|
371
|
+
if (env->ExceptionCheck()) {
|
|
372
|
+
env->ExceptionDescribe();
|
|
373
|
+
env->ExceptionClear();
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return result;
|
|
237
378
|
}
|
|
238
379
|
|
|
239
380
|
void PlatformAuth::logout() {
|
|
240
381
|
auto contextPtr = static_cast<jobject>(AuthCache::getAndroidContext());
|
|
241
382
|
if (!contextPtr) return;
|
|
242
383
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
384
|
+
JNIEnv* env = Environment::current();
|
|
385
|
+
try {
|
|
386
|
+
ensureAuthAdapterMethods(env);
|
|
387
|
+
} catch (...) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
env->CallStaticVoidMethod(gAuthAdapterClass, gLogoutMethod, contextPtr);
|
|
392
|
+
|
|
393
|
+
if (env->ExceptionCheck()) {
|
|
394
|
+
env->ExceptionDescribe();
|
|
395
|
+
env->ExceptionClear();
|
|
396
|
+
}
|
|
246
397
|
}
|
|
247
398
|
|
|
248
399
|
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeInitialize(JNIEnv*, jclass, jobject context) {
|
|
@@ -250,22 +401,30 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeInitialize(JNI
|
|
|
250
401
|
}
|
|
251
402
|
|
|
252
403
|
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginSuccess(
|
|
253
|
-
JNIEnv* env, jclass,
|
|
254
|
-
jstring provider, jstring email, jstring name, jstring photo, jstring idToken, jstring accessToken, jstring serverAuthCode, jobjectArray scopes, jobject expirationTime) {
|
|
255
|
-
|
|
404
|
+
JNIEnv* env, jclass,
|
|
405
|
+
jstring origin, jstring provider, jstring email, jstring name, jstring photo, jstring idToken, jstring accessToken, jstring serverAuthCode, jobjectArray scopes, jobject expirationTime) {
|
|
406
|
+
|
|
407
|
+
const char* originCStr = env->GetStringUTFChars(origin, nullptr);
|
|
408
|
+
std::string originStr(originCStr);
|
|
409
|
+
env->ReleaseStringUTFChars(origin, originCStr);
|
|
410
|
+
|
|
256
411
|
std::shared_ptr<Promise<AuthUser>> loginPromise;
|
|
257
412
|
std::shared_ptr<Promise<AuthUser>> scopesPromise;
|
|
258
413
|
std::shared_ptr<Promise<std::optional<AuthUser>>> silentPromise;
|
|
259
414
|
{
|
|
260
415
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
416
|
+
if (originStr == "login") {
|
|
417
|
+
loginPromise = gLoginPromise;
|
|
418
|
+
gLoginPromise = nullptr;
|
|
419
|
+
} else if (originStr == "scopes") {
|
|
420
|
+
scopesPromise = gScopesPromise;
|
|
421
|
+
gScopesPromise = nullptr;
|
|
422
|
+
} else if (originStr == "silent") {
|
|
423
|
+
silentPromise = gSilentPromise;
|
|
424
|
+
gSilentPromise = nullptr;
|
|
425
|
+
}
|
|
267
426
|
}
|
|
268
|
-
|
|
427
|
+
|
|
269
428
|
AuthUser user;
|
|
270
429
|
const char* providerCStr = env->GetStringUTFChars(provider, nullptr);
|
|
271
430
|
std::string providerStr(providerCStr);
|
|
@@ -333,19 +492,27 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginSuccess
|
|
|
333
492
|
}
|
|
334
493
|
|
|
335
494
|
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginError(
|
|
336
|
-
JNIEnv* env, jclass, jstring error, jstring underlyingError) {
|
|
337
|
-
|
|
495
|
+
JNIEnv* env, jclass, jstring origin, jstring error, jstring underlyingError) {
|
|
496
|
+
|
|
497
|
+
const char* originCStr = env->GetStringUTFChars(origin, nullptr);
|
|
498
|
+
std::string originStr(originCStr);
|
|
499
|
+
env->ReleaseStringUTFChars(origin, originCStr);
|
|
500
|
+
|
|
338
501
|
std::shared_ptr<Promise<AuthUser>> loginPromise;
|
|
339
502
|
std::shared_ptr<Promise<AuthUser>> scopesPromise;
|
|
340
503
|
std::shared_ptr<Promise<std::optional<AuthUser>>> silentPromise;
|
|
341
504
|
{
|
|
342
505
|
std::lock_guard<std::mutex> lock(gMutex);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
506
|
+
if (originStr == "login") {
|
|
507
|
+
loginPromise = gLoginPromise;
|
|
508
|
+
gLoginPromise = nullptr;
|
|
509
|
+
} else if (originStr == "scopes") {
|
|
510
|
+
scopesPromise = gScopesPromise;
|
|
511
|
+
gScopesPromise = nullptr;
|
|
512
|
+
} else if (originStr == "silent") {
|
|
513
|
+
silentPromise = gSilentPromise;
|
|
514
|
+
gSilentPromise = nullptr;
|
|
515
|
+
}
|
|
349
516
|
}
|
|
350
517
|
|
|
351
518
|
const char* errorCStr = env->GetStringUTFChars(error, nullptr);
|
|
@@ -364,7 +531,7 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnLoginError(
|
|
|
364
531
|
if (loginPromise) loginPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
365
532
|
if (scopesPromise) scopesPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
366
533
|
if (silentPromise) {
|
|
367
|
-
if (errorStr == "
|
|
534
|
+
if (errorStr == "not_signed_in") silentPromise->resolve(std::nullopt);
|
|
368
535
|
else silentPromise->reject(std::make_exception_ptr(std::runtime_error(errorStr)));
|
|
369
536
|
}
|
|
370
537
|
}
|
|
@@ -423,4 +590,30 @@ extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeOnRefreshError
|
|
|
423
590
|
}
|
|
424
591
|
}
|
|
425
592
|
|
|
593
|
+
extern "C" JNIEXPORT void JNICALL Java_com_auth_AuthAdapter_nativeDispose(JNIEnv* env, jclass) {
|
|
594
|
+
std::shared_ptr<Promise<AuthUser>> loginPromise;
|
|
595
|
+
std::shared_ptr<Promise<AuthUser>> scopesPromise;
|
|
596
|
+
std::shared_ptr<Promise<AuthTokens>> refreshPromise;
|
|
597
|
+
std::shared_ptr<Promise<std::optional<AuthUser>>> silentPromise;
|
|
598
|
+
{
|
|
599
|
+
std::lock_guard<std::mutex> lock(gMutex);
|
|
600
|
+
loginPromise = std::move(gLoginPromise);
|
|
601
|
+
scopesPromise = std::move(gScopesPromise);
|
|
602
|
+
refreshPromise = std::move(gRefreshPromise);
|
|
603
|
+
silentPromise = std::move(gSilentPromise);
|
|
604
|
+
gLoginPromise = nullptr;
|
|
605
|
+
gScopesPromise = nullptr;
|
|
606
|
+
gRefreshPromise = nullptr;
|
|
607
|
+
gSilentPromise = nullptr;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
auto disposed = std::make_exception_ptr(std::runtime_error("disposed"));
|
|
611
|
+
if (loginPromise) loginPromise->reject(disposed);
|
|
612
|
+
if (scopesPromise) scopesPromise->reject(disposed);
|
|
613
|
+
if (refreshPromise) refreshPromise->reject(disposed);
|
|
614
|
+
if (silentPromise) silentPromise->reject(disposed);
|
|
615
|
+
|
|
616
|
+
clearCachedJniRefs(env);
|
|
617
|
+
}
|
|
618
|
+
|
|
426
619
|
} // namespace margelo::nitro::NitroAuth
|