react-native-nitro-auth 0.5.1 → 0.5.4
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 +362 -190
- package/android/build.gradle +2 -5
- package/android/src/main/cpp/PlatformAuth+Android.cpp +84 -18
- package/android/src/main/java/com/auth/AuthAdapter.kt +82 -182
- package/android/src/main/java/com/auth/NitroAuthPackage.kt +1 -1
- package/app.plugin.js +2 -9
- package/cpp/AuthCache.cpp +0 -134
- package/cpp/AuthCache.hpp +0 -7
- package/cpp/HybridAuth.cpp +57 -63
- package/cpp/HybridAuth.hpp +3 -4
- package/ios/AuthAdapter.swift +23 -25
- package/lib/commonjs/Auth.web.js +523 -201
- package/lib/commonjs/Auth.web.js.map +1 -1
- package/lib/commonjs/index.js +0 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +0 -12
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/js-storage-adapter.js +2 -0
- package/lib/commonjs/js-storage-adapter.js.map +1 -0
- package/lib/commonjs/service.js +9 -86
- package/lib/commonjs/service.js.map +1 -1
- package/lib/commonjs/service.web.js +1 -5
- package/lib/commonjs/service.web.js.map +1 -1
- package/lib/commonjs/ui/social-button.js +44 -29
- package/lib/commonjs/ui/social-button.js.map +1 -1
- package/lib/commonjs/ui/social-button.web.js +44 -29
- package/lib/commonjs/ui/social-button.web.js.map +1 -1
- package/lib/commonjs/use-auth.js +56 -42
- package/lib/commonjs/use-auth.js.map +1 -1
- package/lib/commonjs/utils/logger.js +12 -4
- package/lib/commonjs/utils/logger.js.map +1 -1
- package/lib/module/Auth.web.js +523 -201
- package/lib/module/Auth.web.js.map +1 -1
- package/lib/module/index.js +0 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +0 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/js-storage-adapter.js +2 -0
- package/lib/module/js-storage-adapter.js.map +1 -0
- package/lib/module/service.js +9 -86
- package/lib/module/service.js.map +1 -1
- package/lib/module/service.web.js +1 -5
- package/lib/module/service.web.js.map +1 -1
- package/lib/module/ui/social-button.js +44 -29
- package/lib/module/ui/social-button.js.map +1 -1
- package/lib/module/ui/social-button.web.js +44 -29
- package/lib/module/ui/social-button.web.js.map +1 -1
- package/lib/module/use-auth.js +56 -42
- package/lib/module/use-auth.js.map +1 -1
- package/lib/module/utils/logger.js +12 -4
- package/lib/module/utils/logger.js.map +1 -1
- package/lib/typescript/commonjs/Auth.nitro.d.ts +3 -3
- package/lib/typescript/commonjs/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/commonjs/Auth.web.d.ts +25 -6
- package/lib/typescript/commonjs/Auth.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +1 -2
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.web.d.ts +0 -1
- package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/js-storage-adapter.d.ts +6 -0
- package/lib/typescript/commonjs/js-storage-adapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/service.d.ts +1 -8
- package/lib/typescript/commonjs/service.d.ts.map +1 -1
- package/lib/typescript/commonjs/service.web.d.ts +1 -8
- package/lib/typescript/commonjs/service.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.d.ts +6 -6
- package/lib/typescript/commonjs/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/social-button.web.d.ts +6 -6
- package/lib/typescript/commonjs/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/use-auth.d.ts +4 -4
- package/lib/typescript/commonjs/use-auth.d.ts.map +1 -1
- package/lib/typescript/commonjs/utils/logger.d.ts +4 -4
- package/lib/typescript/commonjs/utils/logger.d.ts.map +1 -1
- package/lib/typescript/module/Auth.nitro.d.ts +3 -3
- package/lib/typescript/module/Auth.nitro.d.ts.map +1 -1
- package/lib/typescript/module/Auth.web.d.ts +25 -6
- package/lib/typescript/module/Auth.web.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +1 -2
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/index.web.d.ts +0 -1
- package/lib/typescript/module/index.web.d.ts.map +1 -1
- package/lib/typescript/module/js-storage-adapter.d.ts +6 -0
- package/lib/typescript/module/js-storage-adapter.d.ts.map +1 -0
- package/lib/typescript/module/service.d.ts +1 -8
- package/lib/typescript/module/service.d.ts.map +1 -1
- package/lib/typescript/module/service.web.d.ts +1 -8
- package/lib/typescript/module/service.web.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.d.ts +6 -6
- package/lib/typescript/module/ui/social-button.d.ts.map +1 -1
- package/lib/typescript/module/ui/social-button.web.d.ts +6 -6
- package/lib/typescript/module/ui/social-button.web.d.ts.map +1 -1
- package/lib/typescript/module/use-auth.d.ts +4 -4
- package/lib/typescript/module/use-auth.d.ts.map +1 -1
- package/lib/typescript/module/utils/logger.d.ts +4 -4
- package/lib/typescript/module/utils/logger.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroAuth+autolinking.cmake +0 -1
- package/nitrogen/generated/shared/c++/AuthTokens.hpp +5 -1
- package/nitrogen/generated/shared/c++/AuthUser.hpp +5 -1
- package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +0 -1
- package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +0 -5
- package/package.json +11 -8
- package/react-native-nitro-auth.podspec +1 -1
- package/src/Auth.nitro.ts +4 -3
- package/src/Auth.web.ts +700 -246
- package/src/global.d.ts +0 -1
- package/src/index.ts +1 -2
- package/src/index.web.ts +0 -1
- package/src/js-storage-adapter.ts +5 -0
- package/src/service.ts +13 -106
- package/src/service.web.ts +0 -7
- package/src/ui/social-button.tsx +66 -43
- package/src/ui/social-button.web.tsx +67 -44
- package/src/use-auth.ts +116 -72
- package/src/utils/logger.ts +12 -4
- package/ios/KeychainStore.swift +0 -43
- package/lib/commonjs/AuthStorage.nitro.js +0 -6
- package/lib/commonjs/AuthStorage.nitro.js.map +0 -1
- package/lib/module/AuthStorage.nitro.js +0 -4
- package/lib/module/AuthStorage.nitro.js.map +0 -1
- package/lib/typescript/commonjs/AuthStorage.nitro.d.ts +0 -26
- package/lib/typescript/commonjs/AuthStorage.nitro.d.ts.map +0 -1
- package/lib/typescript/module/AuthStorage.nitro.d.ts +0 -26
- package/lib/typescript/module/AuthStorage.nitro.d.ts.map +0 -1
- package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.cpp +0 -23
- package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.hpp +0 -65
- package/src/AuthStorage.nitro.ts +0 -26
package/cpp/AuthCache.cpp
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
#include "AuthCache.hpp"
|
|
2
2
|
|
|
3
|
-
#ifdef __APPLE__
|
|
4
|
-
#include <CoreFoundation/CoreFoundation.h>
|
|
5
|
-
#include <Security/Security.h>
|
|
6
|
-
#endif
|
|
7
|
-
|
|
8
3
|
#ifdef __ANDROID__
|
|
9
4
|
#include <jni.h>
|
|
10
5
|
#include <fbjni/fbjni.h>
|
|
@@ -12,121 +7,9 @@
|
|
|
12
7
|
|
|
13
8
|
namespace margelo::nitro::NitroAuth {
|
|
14
9
|
|
|
15
|
-
#ifdef __APPLE__
|
|
16
|
-
static CFStringRef kService = CFSTR("react-native-nitro-auth");
|
|
17
|
-
static CFStringRef kAccount = CFSTR("nitro_auth_user");
|
|
18
|
-
static CFStringRef kLegacyCacheKey = CFSTR("nitro_auth_user");
|
|
19
|
-
|
|
20
|
-
static CFMutableDictionaryRef createKeychainQuery() {
|
|
21
|
-
CFMutableDictionaryRef query = CFDictionaryCreateMutable(
|
|
22
|
-
kCFAllocatorDefault,
|
|
23
|
-
0,
|
|
24
|
-
&kCFTypeDictionaryKeyCallBacks,
|
|
25
|
-
&kCFTypeDictionaryValueCallBacks
|
|
26
|
-
);
|
|
27
|
-
CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
|
|
28
|
-
CFDictionarySetValue(query, kSecAttrService, kService);
|
|
29
|
-
CFDictionarySetValue(query, kSecAttrAccount, kAccount);
|
|
30
|
-
return query;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
static std::optional<std::string> getLegacyUserJson() {
|
|
34
|
-
CFPropertyListRef value = CFPreferencesCopyAppValue(kLegacyCacheKey, kCFPreferencesCurrentApplication);
|
|
35
|
-
if (value && CFGetTypeID(value) == CFStringGetTypeID()) {
|
|
36
|
-
CFStringRef cfStr = static_cast<CFStringRef>(value);
|
|
37
|
-
char buffer[4096];
|
|
38
|
-
if (CFStringGetCString(cfStr, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
|
|
39
|
-
CFRelease(value);
|
|
40
|
-
return std::string(buffer);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (value) CFRelease(value);
|
|
44
|
-
return std::nullopt;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static void clearLegacyUserJson() {
|
|
48
|
-
CFPreferencesSetAppValue(kLegacyCacheKey, nullptr, kCFPreferencesCurrentApplication);
|
|
49
|
-
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
void AuthCache::setUserJson(const std::string& json) {
|
|
53
|
-
CFMutableDictionaryRef query = createKeychainQuery();
|
|
54
|
-
SecItemDelete(query);
|
|
55
|
-
|
|
56
|
-
CFDataRef data = CFDataCreate(
|
|
57
|
-
kCFAllocatorDefault,
|
|
58
|
-
reinterpret_cast<const UInt8*>(json.data()),
|
|
59
|
-
static_cast<CFIndex>(json.size())
|
|
60
|
-
);
|
|
61
|
-
CFDictionarySetValue(query, kSecValueData, data);
|
|
62
|
-
CFDictionarySetValue(query, kSecAttrAccessible, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly);
|
|
63
|
-
|
|
64
|
-
SecItemAdd(query, nullptr);
|
|
65
|
-
CFRelease(data);
|
|
66
|
-
CFRelease(query);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
std::optional<std::string> AuthCache::getUserJson() {
|
|
70
|
-
CFMutableDictionaryRef query = createKeychainQuery();
|
|
71
|
-
CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
|
|
72
|
-
CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitOne);
|
|
73
|
-
|
|
74
|
-
CFTypeRef result = nullptr;
|
|
75
|
-
OSStatus status = SecItemCopyMatching(query, &result);
|
|
76
|
-
CFRelease(query);
|
|
77
|
-
|
|
78
|
-
if (status != errSecSuccess || result == nullptr) {
|
|
79
|
-
if (result) CFRelease(result);
|
|
80
|
-
auto legacy = getLegacyUserJson();
|
|
81
|
-
if (legacy) {
|
|
82
|
-
AuthCache::setUserJson(*legacy);
|
|
83
|
-
clearLegacyUserJson();
|
|
84
|
-
return legacy;
|
|
85
|
-
}
|
|
86
|
-
return std::nullopt;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
CFDataRef data = static_cast<CFDataRef>(result);
|
|
90
|
-
const UInt8* bytes = CFDataGetBytePtr(data);
|
|
91
|
-
const CFIndex length = CFDataGetLength(data);
|
|
92
|
-
std::string value(reinterpret_cast<const char*>(bytes), static_cast<size_t>(length));
|
|
93
|
-
CFRelease(result);
|
|
94
|
-
return value;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
void AuthCache::clear() {
|
|
98
|
-
CFMutableDictionaryRef query = createKeychainQuery();
|
|
99
|
-
SecItemDelete(query);
|
|
100
|
-
CFRelease(query);
|
|
101
|
-
}
|
|
102
|
-
#endif
|
|
103
|
-
|
|
104
10
|
#ifdef __ANDROID__
|
|
105
11
|
using namespace facebook::jni;
|
|
106
12
|
|
|
107
|
-
struct JContext : JavaClass<JContext> {
|
|
108
|
-
static constexpr auto kJavaDescriptor = "Landroid/content/Context;";
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
struct JAuthAdapter : facebook::jni::JavaClass<JAuthAdapter> {
|
|
112
|
-
static constexpr auto kJavaDescriptor = "Lcom/auth/AuthAdapter;";
|
|
113
|
-
|
|
114
|
-
static void setUserJson(facebook::jni::alias_ref<jobject> context, const std::string& json) {
|
|
115
|
-
static auto method = javaClassStatic()->getStaticMethod<void(alias_ref<JContext>, jstring)>("setUserJson");
|
|
116
|
-
method(javaClassStatic(), static_ref_cast<JContext>(context), make_jstring(json).get());
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
static facebook::jni::local_ref<jstring> getUserJson(facebook::jni::alias_ref<jobject> context) {
|
|
120
|
-
static auto method = javaClassStatic()->getStaticMethod<jstring(alias_ref<JContext>)>("getUserJson");
|
|
121
|
-
return method(javaClassStatic(), static_ref_cast<JContext>(context));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
static void clearUser(facebook::jni::alias_ref<jobject> context) {
|
|
125
|
-
static auto method = javaClassStatic()->getStaticMethod<void(alias_ref<JContext>)>("clearUser");
|
|
126
|
-
method(javaClassStatic(), static_ref_cast<JContext>(context));
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
13
|
static facebook::jni::global_ref<jobject> gContext;
|
|
131
14
|
|
|
132
15
|
void AuthCache::setAndroidContext(void* context) {
|
|
@@ -136,23 +19,6 @@ void AuthCache::setAndroidContext(void* context) {
|
|
|
136
19
|
void* AuthCache::getAndroidContext() {
|
|
137
20
|
return gContext.get();
|
|
138
21
|
}
|
|
139
|
-
|
|
140
|
-
void AuthCache::setUserJson(const std::string& json) {
|
|
141
|
-
if (!gContext) return;
|
|
142
|
-
JAuthAdapter::setUserJson(gContext, json);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
std::optional<std::string> AuthCache::getUserJson() {
|
|
146
|
-
if (!gContext) return std::nullopt;
|
|
147
|
-
auto result = JAuthAdapter::getUserJson(gContext);
|
|
148
|
-
if (!result) return std::nullopt;
|
|
149
|
-
return result->toStdString();
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
void AuthCache::clear() {
|
|
153
|
-
if (!gContext) return;
|
|
154
|
-
JAuthAdapter::clearUser(gContext);
|
|
155
|
-
}
|
|
156
22
|
#endif
|
|
157
23
|
|
|
158
24
|
} // namespace margelo::nitro::NitroAuth
|
package/cpp/AuthCache.hpp
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <string>
|
|
4
|
-
#include <optional>
|
|
5
|
-
|
|
6
3
|
namespace margelo::nitro::NitroAuth {
|
|
7
4
|
|
|
8
5
|
class AuthCache {
|
|
9
6
|
public:
|
|
10
|
-
static void setUserJson(const std::string& json);
|
|
11
|
-
static std::optional<std::string> getUserJson();
|
|
12
|
-
static void clear();
|
|
13
|
-
|
|
14
7
|
#ifdef __ANDROID__
|
|
15
8
|
static void setAndroidContext(void* context);
|
|
16
9
|
static void* getAndroidContext();
|
package/cpp/HybridAuth.cpp
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#include "HybridAuth.hpp"
|
|
2
|
-
#include "AuthCache.hpp"
|
|
3
|
-
#include "JSONSerializer.hpp"
|
|
4
2
|
#include "PlatformAuth.hpp"
|
|
5
3
|
#include <NitroModules/NitroLogger.hpp>
|
|
6
4
|
#include <chrono>
|
|
@@ -10,7 +8,7 @@ namespace margelo::nitro::NitroAuth {
|
|
|
10
8
|
bool HybridAuth::sLoggingEnabled = false;
|
|
11
9
|
|
|
12
10
|
HybridAuth::HybridAuth() : HybridObject(TAG) {
|
|
13
|
-
|
|
11
|
+
// In-memory only - no internal persistence.
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
std::optional<AuthUser> HybridAuth::getCurrentUser() {
|
|
@@ -27,41 +25,6 @@ bool HybridAuth::getHasPlayServices() {
|
|
|
27
25
|
return PlatformAuth::hasPlayServices();
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
void HybridAuth::loadFromCache() {
|
|
31
|
-
std::lock_guard<std::mutex> lock(_mutex);
|
|
32
|
-
std::optional<std::string> json;
|
|
33
|
-
|
|
34
|
-
if (_storageAdapter) {
|
|
35
|
-
json = _storageAdapter->load("nitro_auth_user");
|
|
36
|
-
} else {
|
|
37
|
-
json = AuthCache::getUserJson();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (json) {
|
|
41
|
-
_currentUser = JSONSerializer::deserialize(*json);
|
|
42
|
-
if (_currentUser && _currentUser->scopes) {
|
|
43
|
-
_grantedScopes = *_currentUser->scopes;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
void HybridAuth::saveToCache(const std::optional<AuthUser>& user) {
|
|
49
|
-
if (user) {
|
|
50
|
-
auto json = JSONSerializer::serialize(*user);
|
|
51
|
-
if (_storageAdapter) {
|
|
52
|
-
_storageAdapter->save("nitro_auth_user", json);
|
|
53
|
-
} else {
|
|
54
|
-
AuthCache::setUserJson(json);
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
if (_storageAdapter) {
|
|
58
|
-
_storageAdapter->remove("nitro_auth_user");
|
|
59
|
-
} else {
|
|
60
|
-
AuthCache::clear();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
28
|
void HybridAuth::notifyAuthStateChanged() {
|
|
66
29
|
std::optional<AuthUser> user;
|
|
67
30
|
std::vector<std::function<void(const std::optional<AuthUser>&)>> listeners;
|
|
@@ -104,7 +67,6 @@ void HybridAuth::logout() {
|
|
|
104
67
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
105
68
|
_currentUser = std::nullopt;
|
|
106
69
|
_grantedScopes.clear();
|
|
107
|
-
saveToCache(std::nullopt);
|
|
108
70
|
}
|
|
109
71
|
PlatformAuth::logout();
|
|
110
72
|
notifyAuthStateChanged();
|
|
@@ -114,18 +76,27 @@ std::shared_ptr<Promise<void>> HybridAuth::silentRestore() {
|
|
|
114
76
|
auto promise = Promise<void>::create();
|
|
115
77
|
auto silentPromise = PlatformAuth::silentRestore();
|
|
116
78
|
silentPromise->addOnResolvedListener([this, promise](const std::optional<AuthUser>& user) {
|
|
117
|
-
|
|
79
|
+
{
|
|
118
80
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
119
81
|
_currentUser = user;
|
|
120
|
-
if (user
|
|
121
|
-
|
|
82
|
+
if (user) {
|
|
83
|
+
if (user->scopes) {
|
|
84
|
+
_grantedScopes = *user->scopes;
|
|
85
|
+
} else {
|
|
86
|
+
_grantedScopes.clear();
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
_grantedScopes.clear();
|
|
90
|
+
}
|
|
122
91
|
}
|
|
92
|
+
// Always resolve - no session is not an error, just means user is logged out
|
|
123
93
|
notifyAuthStateChanged();
|
|
124
94
|
promise->resolve();
|
|
125
95
|
});
|
|
126
96
|
|
|
127
|
-
silentPromise->addOnRejectedListener([promise](const std::exception_ptr&
|
|
128
|
-
|
|
97
|
+
silentPromise->addOnRejectedListener([promise](const std::exception_ptr&) {
|
|
98
|
+
// Silently ignore errors during restore - user will be logged out
|
|
99
|
+
promise->resolve();
|
|
129
100
|
});
|
|
130
101
|
return promise;
|
|
131
102
|
}
|
|
@@ -138,11 +109,18 @@ std::shared_ptr<Promise<void>> HybridAuth::login(AuthProvider provider, const st
|
|
|
138
109
|
{
|
|
139
110
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
140
111
|
_currentUser = user;
|
|
141
|
-
if (
|
|
112
|
+
if (user.scopes && !user.scopes->empty()) {
|
|
113
|
+
_grantedScopes = *user.scopes;
|
|
114
|
+
} else if (options && options->scopes && !options->scopes->empty()) {
|
|
142
115
|
_grantedScopes = *options->scopes;
|
|
116
|
+
} else {
|
|
117
|
+
_grantedScopes.clear();
|
|
118
|
+
}
|
|
119
|
+
if (_currentUser) {
|
|
120
|
+
_currentUser->scopes = _grantedScopes.empty()
|
|
121
|
+
? std::nullopt
|
|
122
|
+
: std::make_optional(_grantedScopes);
|
|
143
123
|
}
|
|
144
|
-
if (_currentUser) _currentUser->scopes = _grantedScopes;
|
|
145
|
-
saveToCache(_currentUser);
|
|
146
124
|
}
|
|
147
125
|
notifyAuthStateChanged();
|
|
148
126
|
promise->resolve();
|
|
@@ -167,7 +145,6 @@ std::shared_ptr<Promise<void>> HybridAuth::requestScopes(const std::vector<std::
|
|
|
167
145
|
}
|
|
168
146
|
}
|
|
169
147
|
if (_currentUser) _currentUser->scopes = _grantedScopes;
|
|
170
|
-
saveToCache(_currentUser);
|
|
171
148
|
}
|
|
172
149
|
notifyAuthStateChanged();
|
|
173
150
|
promise->resolve();
|
|
@@ -192,7 +169,6 @@ std::shared_ptr<Promise<void>> HybridAuth::revokeScopes(const std::vector<std::s
|
|
|
192
169
|
);
|
|
193
170
|
if (_currentUser) {
|
|
194
171
|
_currentUser->scopes = _grantedScopes;
|
|
195
|
-
saveToCache(_currentUser);
|
|
196
172
|
}
|
|
197
173
|
}
|
|
198
174
|
notifyAuthStateChanged();
|
|
@@ -233,15 +209,36 @@ std::shared_ptr<Promise<std::optional<std::string>>> HybridAuth::getAccessToken(
|
|
|
233
209
|
}
|
|
234
210
|
|
|
235
211
|
std::shared_ptr<Promise<AuthTokens>> HybridAuth::refreshToken() {
|
|
236
|
-
|
|
212
|
+
std::shared_ptr<Promise<AuthTokens>> promise;
|
|
213
|
+
{
|
|
214
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
215
|
+
if (_refreshInFlight) {
|
|
216
|
+
return _refreshInFlight;
|
|
217
|
+
}
|
|
218
|
+
promise = Promise<AuthTokens>::create();
|
|
219
|
+
_refreshInFlight = promise;
|
|
220
|
+
}
|
|
221
|
+
|
|
237
222
|
auto refreshPromise = PlatformAuth::refreshToken();
|
|
238
223
|
refreshPromise->addOnResolvedListener([this, promise](const AuthTokens& tokens) {
|
|
239
224
|
{
|
|
240
225
|
std::lock_guard<std::mutex> lock(_mutex);
|
|
241
226
|
if (_currentUser) {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
227
|
+
if (tokens.accessToken.has_value()) {
|
|
228
|
+
_currentUser->accessToken = tokens.accessToken;
|
|
229
|
+
}
|
|
230
|
+
if (tokens.idToken.has_value()) {
|
|
231
|
+
_currentUser->idToken = tokens.idToken;
|
|
232
|
+
}
|
|
233
|
+
if (tokens.refreshToken.has_value()) {
|
|
234
|
+
_currentUser->refreshToken = tokens.refreshToken;
|
|
235
|
+
}
|
|
236
|
+
if (tokens.expirationTime.has_value()) {
|
|
237
|
+
_currentUser->expirationTime = tokens.expirationTime;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (_refreshInFlight == promise) {
|
|
241
|
+
_refreshInFlight = nullptr;
|
|
245
242
|
}
|
|
246
243
|
}
|
|
247
244
|
notifyTokensRefreshed(tokens);
|
|
@@ -249,7 +246,13 @@ std::shared_ptr<Promise<AuthTokens>> HybridAuth::refreshToken() {
|
|
|
249
246
|
promise->resolve(tokens);
|
|
250
247
|
});
|
|
251
248
|
|
|
252
|
-
refreshPromise->addOnRejectedListener([promise](const std::exception_ptr& error) {
|
|
249
|
+
refreshPromise->addOnRejectedListener([this, promise](const std::exception_ptr& error) {
|
|
250
|
+
{
|
|
251
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
252
|
+
if (_refreshInFlight == promise) {
|
|
253
|
+
_refreshInFlight = nullptr;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
253
256
|
promise->reject(error);
|
|
254
257
|
});
|
|
255
258
|
return promise;
|
|
@@ -259,15 +262,6 @@ void HybridAuth::setLoggingEnabled(bool enabled) {
|
|
|
259
262
|
sLoggingEnabled = enabled;
|
|
260
263
|
}
|
|
261
264
|
|
|
262
|
-
void HybridAuth::setStorageAdapter(const std::optional<std::shared_ptr<HybridAuthStorageAdapterSpec>>& adapter) {
|
|
263
|
-
std::lock_guard<std::mutex> lock(_mutex);
|
|
264
|
-
_storageAdapter = adapter.value_or(nullptr);
|
|
265
|
-
if (_storageAdapter) {
|
|
266
|
-
loadFromCache();
|
|
267
|
-
notifyAuthStateChanged();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
265
|
void HybridAuth::notifyTokensRefreshed(const AuthTokens& tokens) {
|
|
272
266
|
std::vector<std::function<void(const AuthTokens&)>> listeners;
|
|
273
267
|
{
|
package/cpp/HybridAuth.hpp
CHANGED
|
@@ -31,11 +31,10 @@ public:
|
|
|
31
31
|
std::function<void()> onAuthStateChanged(const std::function<void(const std::optional<AuthUser>&)>& callback) override;
|
|
32
32
|
std::function<void()> onTokensRefreshed(const std::function<void(const AuthTokens&)>& callback) override;
|
|
33
33
|
void setLoggingEnabled(bool enabled) override;
|
|
34
|
-
|
|
34
|
+
// Note: setStorageAdapter is kept internally but not exposed in public API
|
|
35
|
+
// Storage is in-memory only by default
|
|
35
36
|
|
|
36
37
|
private:
|
|
37
|
-
void loadFromCache();
|
|
38
|
-
void saveToCache(const std::optional<AuthUser>& user);
|
|
39
38
|
void notifyAuthStateChanged();
|
|
40
39
|
void notifyTokensRefreshed(const AuthTokens& tokens);
|
|
41
40
|
|
|
@@ -45,9 +44,9 @@ private:
|
|
|
45
44
|
std::map<int, std::function<void(const std::optional<AuthUser>&)>> _listeners;
|
|
46
45
|
int _nextListenerId = 0;
|
|
47
46
|
|
|
48
|
-
std::shared_ptr<HybridAuthStorageAdapterSpec> _storageAdapter;
|
|
49
47
|
std::map<int, std::function<void(const AuthTokens&)>> _tokenListeners;
|
|
50
48
|
int _nextTokenListenerId = 0;
|
|
49
|
+
std::shared_ptr<Promise<AuthTokens>> _refreshInFlight;
|
|
51
50
|
|
|
52
51
|
std::mutex _mutex;
|
|
53
52
|
|
package/ios/AuthAdapter.swift
CHANGED
|
@@ -7,6 +7,11 @@ import CommonCrypto
|
|
|
7
7
|
|
|
8
8
|
@objc
|
|
9
9
|
public class AuthAdapter: NSObject {
|
|
10
|
+
private static let defaultMicrosoftScopes = ["openid", "email", "profile", "offline_access", "User.Read"]
|
|
11
|
+
private static var inMemoryMicrosoftRefreshToken: String?
|
|
12
|
+
private static var inMemoryMicrosoftScopes: [String] = defaultMicrosoftScopes
|
|
13
|
+
private static var inMemoryGoogleServerAuthCode: String?
|
|
14
|
+
|
|
10
15
|
@objc
|
|
11
16
|
public static func login(provider: String, scopes: [String], loginHint: String?, useSheet: Bool, forceAccountPicker: Bool = false, tenant: String? = nil, prompt: String? = nil, completion: @escaping (NSDictionary?, String?) -> Void) {
|
|
12
17
|
if provider == "google" {
|
|
@@ -258,9 +263,9 @@ public class AuthAdapter: NSObject {
|
|
|
258
263
|
let expirationTime = Date().timeIntervalSince1970 * 1000 + expiresIn * 1000
|
|
259
264
|
|
|
260
265
|
if !refreshToken.isEmpty {
|
|
261
|
-
|
|
266
|
+
inMemoryMicrosoftRefreshToken = refreshToken
|
|
262
267
|
}
|
|
263
|
-
|
|
268
|
+
inMemoryMicrosoftScopes = scopes.isEmpty ? defaultMicrosoftScopes : scopes
|
|
264
269
|
|
|
265
270
|
let resultData: [String: Any] = [
|
|
266
271
|
"provider": "microsoft",
|
|
@@ -283,6 +288,8 @@ public class AuthAdapter: NSObject {
|
|
|
283
288
|
guard parts.count >= 2 else { return [:] }
|
|
284
289
|
|
|
285
290
|
var base64 = parts[1]
|
|
291
|
+
.replacingOccurrences(of: "-", with: "+")
|
|
292
|
+
.replacingOccurrences(of: "_", with: "/")
|
|
286
293
|
let remainder = base64.count % 4
|
|
287
294
|
if remainder > 0 {
|
|
288
295
|
base64 += String(repeating: "=", count: 4 - remainder)
|
|
@@ -313,6 +320,9 @@ public class AuthAdapter: NSObject {
|
|
|
313
320
|
return
|
|
314
321
|
}
|
|
315
322
|
|
|
323
|
+
let serverAuthCode = result?.serverAuthCode ?? ""
|
|
324
|
+
inMemoryGoogleServerAuthCode = serverAuthCode.isEmpty ? nil : serverAuthCode
|
|
325
|
+
|
|
316
326
|
let data: [String: Any] = [
|
|
317
327
|
"provider": "google",
|
|
318
328
|
"email": user.profile?.email ?? "",
|
|
@@ -320,7 +330,7 @@ public class AuthAdapter: NSObject {
|
|
|
320
330
|
"photo": user.profile?.imageURL(withDimension: 300)?.absoluteString ?? "",
|
|
321
331
|
"idToken": user.idToken?.tokenString ?? "",
|
|
322
332
|
"accessToken": user.accessToken.tokenString,
|
|
323
|
-
"serverAuthCode":
|
|
333
|
+
"serverAuthCode": serverAuthCode,
|
|
324
334
|
"expirationTime": (user.accessToken.expirationDate?.timeIntervalSince1970 ?? 0) * 1000,
|
|
325
335
|
"underlyingError": ""
|
|
326
336
|
]
|
|
@@ -353,12 +363,11 @@ public class AuthAdapter: NSObject {
|
|
|
353
363
|
}
|
|
354
364
|
return
|
|
355
365
|
}
|
|
356
|
-
guard
|
|
366
|
+
guard inMemoryMicrosoftRefreshToken != nil else {
|
|
357
367
|
completion(nil, "No user logged in")
|
|
358
368
|
return
|
|
359
369
|
}
|
|
360
|
-
let
|
|
361
|
-
let mergedScopes = Array(Set(storedScopes + scopes))
|
|
370
|
+
let mergedScopes = Array(Set(inMemoryMicrosoftScopes + scopes))
|
|
362
371
|
loginMicrosoft(scopes: mergedScopes, loginHint: nil, tenant: nil, prompt: nil, completion: completion)
|
|
363
372
|
}
|
|
364
373
|
|
|
@@ -399,7 +408,7 @@ public class AuthAdapter: NSObject {
|
|
|
399
408
|
"photo": user.profile?.imageURL(withDimension: 300)?.absoluteString ?? "",
|
|
400
409
|
"idToken": user.idToken?.tokenString ?? "",
|
|
401
410
|
"accessToken": user.accessToken.tokenString,
|
|
402
|
-
"serverAuthCode": "",
|
|
411
|
+
"serverAuthCode": inMemoryGoogleServerAuthCode ?? "",
|
|
403
412
|
"expirationTime": (user.accessToken.expirationDate?.timeIntervalSince1970 ?? 0) * 1000
|
|
404
413
|
]
|
|
405
414
|
completion(data as NSDictionary)
|
|
@@ -413,7 +422,7 @@ public class AuthAdapter: NSObject {
|
|
|
413
422
|
}
|
|
414
423
|
|
|
415
424
|
private static func tryMicrosoftSilentRefresh(completion: @escaping (NSDictionary?) -> Void) {
|
|
416
|
-
guard let refreshToken =
|
|
425
|
+
guard let refreshToken = inMemoryMicrosoftRefreshToken else {
|
|
417
426
|
completion(nil)
|
|
418
427
|
return
|
|
419
428
|
}
|
|
@@ -459,7 +468,7 @@ public class AuthAdapter: NSObject {
|
|
|
459
468
|
let expirationTime = Date().timeIntervalSince1970 * 1000 + expiresIn * 1000
|
|
460
469
|
|
|
461
470
|
if !newRefreshToken.isEmpty {
|
|
462
|
-
|
|
471
|
+
inMemoryMicrosoftRefreshToken = newRefreshToken
|
|
463
472
|
}
|
|
464
473
|
|
|
465
474
|
let resultData: [String: Any] = [
|
|
@@ -478,7 +487,7 @@ public class AuthAdapter: NSObject {
|
|
|
478
487
|
}
|
|
479
488
|
|
|
480
489
|
private static func tryMicrosoftRefreshForTokenRefresh(completion: @escaping (NSDictionary?, String?) -> Void) {
|
|
481
|
-
guard let refreshToken =
|
|
490
|
+
guard let refreshToken = inMemoryMicrosoftRefreshToken else {
|
|
482
491
|
completion(nil, "No user logged in")
|
|
483
492
|
return
|
|
484
493
|
}
|
|
@@ -523,7 +532,7 @@ public class AuthAdapter: NSObject {
|
|
|
523
532
|
let expiresIn = json["expires_in"] as? Double ?? 0
|
|
524
533
|
let expirationTime = Date().timeIntervalSince1970 * 1000 + expiresIn * 1000
|
|
525
534
|
if !newRefreshToken.isEmpty {
|
|
526
|
-
|
|
535
|
+
inMemoryMicrosoftRefreshToken = newRefreshToken
|
|
527
536
|
}
|
|
528
537
|
let tokensData: [String: Any] = [
|
|
529
538
|
"accessToken": accessToken,
|
|
@@ -551,20 +560,9 @@ public class AuthAdapter: NSObject {
|
|
|
551
560
|
@objc
|
|
552
561
|
public static func logout() {
|
|
553
562
|
GIDSignIn.sharedInstance.signOut()
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
private static func getStoredMicrosoftRefreshToken() -> String? {
|
|
559
|
-
if let token = KeychainStore.get("nitro_auth_microsoft_refresh_token") {
|
|
560
|
-
return token
|
|
561
|
-
}
|
|
562
|
-
if let legacy = UserDefaults.standard.string(forKey: "nitro_auth_microsoft_refresh_token") {
|
|
563
|
-
KeychainStore.set(legacy, for: "nitro_auth_microsoft_refresh_token")
|
|
564
|
-
UserDefaults.standard.removeObject(forKey: "nitro_auth_microsoft_refresh_token")
|
|
565
|
-
return legacy
|
|
566
|
-
}
|
|
567
|
-
return nil
|
|
563
|
+
inMemoryMicrosoftRefreshToken = nil
|
|
564
|
+
inMemoryMicrosoftScopes = defaultMicrosoftScopes
|
|
565
|
+
inMemoryGoogleServerAuthCode = nil
|
|
568
566
|
}
|
|
569
567
|
}
|
|
570
568
|
|