react-native-nitro-auth 0.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.
Files changed (110) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +254 -0
  3. package/android/CMakeLists.txt +37 -0
  4. package/android/build.gradle +99 -0
  5. package/android/gradle.properties +4 -0
  6. package/android/src/main/AndroidManifest.xml +12 -0
  7. package/android/src/main/cpp/JniOnLoad.cpp +7 -0
  8. package/android/src/main/cpp/PlatformAuth+Android.cpp +293 -0
  9. package/android/src/main/java/com/auth/AuthAdapter.kt +286 -0
  10. package/android/src/main/java/com/auth/GoogleSignInActivity.kt +73 -0
  11. package/android/src/main/java/com/auth/NitroAuthModule.kt +19 -0
  12. package/android/src/main/java/com/auth/NitroAuthPackage.kt +16 -0
  13. package/app.plugin.js +64 -0
  14. package/cpp/AuthCache.cpp +105 -0
  15. package/cpp/AuthCache.hpp +20 -0
  16. package/cpp/HybridAuth.cpp +213 -0
  17. package/cpp/HybridAuth.hpp +47 -0
  18. package/cpp/JSONSerializer.hpp +57 -0
  19. package/cpp/PlatformAuth.hpp +25 -0
  20. package/ios/AuthAdapter.swift +200 -0
  21. package/ios/PlatformAuth+iOS.mm +119 -0
  22. package/lib/commonjs/Auth.nitro.js +6 -0
  23. package/lib/commonjs/Auth.nitro.js.map +1 -0
  24. package/lib/commonjs/Auth.web.js +256 -0
  25. package/lib/commonjs/Auth.web.js.map +1 -0
  26. package/lib/commonjs/global.d.js +6 -0
  27. package/lib/commonjs/global.d.js.map +1 -0
  28. package/lib/commonjs/index.js +52 -0
  29. package/lib/commonjs/index.js.map +1 -0
  30. package/lib/commonjs/index.web.js +52 -0
  31. package/lib/commonjs/index.web.js.map +1 -0
  32. package/lib/commonjs/service.js +9 -0
  33. package/lib/commonjs/service.js.map +1 -0
  34. package/lib/commonjs/service.web.js +13 -0
  35. package/lib/commonjs/service.web.js.map +1 -0
  36. package/lib/commonjs/ui/social-button.js +103 -0
  37. package/lib/commonjs/ui/social-button.js.map +1 -0
  38. package/lib/commonjs/ui/social-button.web.js +102 -0
  39. package/lib/commonjs/ui/social-button.web.js.map +1 -0
  40. package/lib/commonjs/use-auth.js +144 -0
  41. package/lib/commonjs/use-auth.js.map +1 -0
  42. package/lib/module/Auth.nitro.js +4 -0
  43. package/lib/module/Auth.nitro.js.map +1 -0
  44. package/lib/module/Auth.web.js +252 -0
  45. package/lib/module/Auth.web.js.map +1 -0
  46. package/lib/module/global.d.js +4 -0
  47. package/lib/module/global.d.js.map +1 -0
  48. package/lib/module/index.js +7 -0
  49. package/lib/module/index.js.map +1 -0
  50. package/lib/module/index.web.js +7 -0
  51. package/lib/module/index.web.js.map +1 -0
  52. package/lib/module/service.js +5 -0
  53. package/lib/module/service.js.map +1 -0
  54. package/lib/module/service.web.js +4 -0
  55. package/lib/module/service.web.js.map +1 -0
  56. package/lib/module/ui/social-button.js +97 -0
  57. package/lib/module/ui/social-button.js.map +1 -0
  58. package/lib/module/ui/social-button.web.js +96 -0
  59. package/lib/module/ui/social-button.web.js.map +1 -0
  60. package/lib/module/use-auth.js +140 -0
  61. package/lib/module/use-auth.js.map +1 -0
  62. package/lib/typescript/Auth.nitro.d.ts +38 -0
  63. package/lib/typescript/Auth.nitro.d.ts.map +1 -0
  64. package/lib/typescript/Auth.web.d.ts +32 -0
  65. package/lib/typescript/Auth.web.d.ts.map +1 -0
  66. package/lib/typescript/index.d.ts +5 -0
  67. package/lib/typescript/index.d.ts.map +1 -0
  68. package/lib/typescript/index.web.d.ts +5 -0
  69. package/lib/typescript/index.web.d.ts.map +1 -0
  70. package/lib/typescript/service.d.ts +3 -0
  71. package/lib/typescript/service.d.ts.map +1 -0
  72. package/lib/typescript/service.web.d.ts +2 -0
  73. package/lib/typescript/service.web.d.ts.map +1 -0
  74. package/lib/typescript/ui/social-button.d.ts +17 -0
  75. package/lib/typescript/ui/social-button.d.ts.map +1 -0
  76. package/lib/typescript/ui/social-button.web.d.ts +17 -0
  77. package/lib/typescript/ui/social-button.web.d.ts.map +1 -0
  78. package/lib/typescript/use-auth.d.ts +15 -0
  79. package/lib/typescript/use-auth.d.ts.map +1 -0
  80. package/nitro.json +15 -0
  81. package/nitrogen/generated/.gitattributes +1 -0
  82. package/nitrogen/generated/android/NitroAuth+autolinking.cmake +81 -0
  83. package/nitrogen/generated/android/NitroAuth+autolinking.gradle +27 -0
  84. package/nitrogen/generated/android/NitroAuthOnLoad.cpp +44 -0
  85. package/nitrogen/generated/android/NitroAuthOnLoad.hpp +25 -0
  86. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/auth/NitroAuthOnLoad.kt +35 -0
  87. package/nitrogen/generated/ios/NitroAuth+autolinking.rb +60 -0
  88. package/nitrogen/generated/ios/NitroAuth-Swift-Cxx-Bridge.cpp +17 -0
  89. package/nitrogen/generated/ios/NitroAuth-Swift-Cxx-Bridge.hpp +27 -0
  90. package/nitrogen/generated/ios/NitroAuth-Swift-Cxx-Umbrella.hpp +38 -0
  91. package/nitrogen/generated/ios/NitroAuthAutolinking.mm +35 -0
  92. package/nitrogen/generated/ios/NitroAuthAutolinking.swift +12 -0
  93. package/nitrogen/generated/shared/c++/AuthProvider.hpp +76 -0
  94. package/nitrogen/generated/shared/c++/AuthTokens.hpp +84 -0
  95. package/nitrogen/generated/shared/c++/AuthUser.hpp +107 -0
  96. package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +30 -0
  97. package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +85 -0
  98. package/nitrogen/generated/shared/c++/LoginOptions.hpp +81 -0
  99. package/package.json +113 -0
  100. package/react-native-nitro-auth.podspec +40 -0
  101. package/src/Auth.nitro.ts +50 -0
  102. package/src/Auth.web.ts +310 -0
  103. package/src/global.d.ts +38 -0
  104. package/src/index.ts +4 -0
  105. package/src/index.web.ts +4 -0
  106. package/src/service.ts +4 -0
  107. package/src/service.web.ts +1 -0
  108. package/src/ui/social-button.tsx +129 -0
  109. package/src/ui/social-button.web.tsx +128 -0
  110. package/src/use-auth.ts +157 -0
package/app.plugin.js ADDED
@@ -0,0 +1,64 @@
1
+ const {
2
+ withInfoPlist,
3
+ withEntitlementsPlist,
4
+ withStringsXml,
5
+ AndroidConfig,
6
+ createRunOncePlugin,
7
+ } = require("@expo/config-plugins");
8
+
9
+ const withNitroAuth = (config, props = {}) => {
10
+ const { ios = {}, android = {} } = props;
11
+
12
+ // 1. iOS Info.plist
13
+ config = withInfoPlist(config, (config) => {
14
+ if (ios.googleClientId) {
15
+ config.modResults.GIDClientID = ios.googleClientId;
16
+ }
17
+ if (ios.googleUrlScheme) {
18
+ const existingSchemes = config.modResults.CFBundleURLTypes || [];
19
+ if (
20
+ !existingSchemes.some((scheme) =>
21
+ scheme.CFBundleURLSchemes.includes(ios.googleUrlScheme)
22
+ )
23
+ ) {
24
+ config.modResults.CFBundleURLTypes = [
25
+ ...existingSchemes,
26
+ {
27
+ CFBundleURLSchemes: [ios.googleUrlScheme],
28
+ },
29
+ ];
30
+ }
31
+ }
32
+ return config;
33
+ });
34
+
35
+ // 2. iOS Entitlements
36
+ config = withEntitlementsPlist(config, (config) => {
37
+ config.modResults["com.apple.developer.applesignin"] = ["Default"];
38
+ return config;
39
+ });
40
+
41
+ // 3. Android Strings (for Google Client ID)
42
+ config = withStringsXml(config, (config) => {
43
+ if (android.googleClientId) {
44
+ config.modResults = AndroidConfig.Strings.setStringItem(
45
+ [
46
+ {
47
+ $: { name: "nitro_auth_google_client_id" },
48
+ _: android.googleClientId,
49
+ },
50
+ ],
51
+ config.modResults
52
+ );
53
+ }
54
+ return config;
55
+ });
56
+
57
+ return config;
58
+ };
59
+
60
+ module.exports = createRunOncePlugin(
61
+ withNitroAuth,
62
+ "react-native-nitro-auth",
63
+ "0.1.0"
64
+ );
@@ -0,0 +1,105 @@
1
+ #include "AuthCache.hpp"
2
+
3
+ #ifdef __APPLE__
4
+ #include <CoreFoundation/CoreFoundation.h>
5
+ #endif
6
+
7
+ #ifdef __ANDROID__
8
+ #include <jni.h>
9
+ #include <fbjni/fbjni.h>
10
+ #endif
11
+
12
+ namespace margelo::nitro::NitroAuth {
13
+
14
+ static const char* CACHE_KEY = "nitro_auth_user";
15
+
16
+ #ifdef __APPLE__
17
+ void AuthCache::setUserJson(const std::string& json) {
18
+ CFStringRef key = CFStringCreateWithCString(nullptr, CACHE_KEY, kCFStringEncodingUTF8);
19
+ CFStringRef value = CFStringCreateWithCString(nullptr, json.c_str(), kCFStringEncodingUTF8);
20
+ CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication);
21
+ CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
22
+ CFRelease(key);
23
+ CFRelease(value);
24
+ }
25
+
26
+ std::optional<std::string> AuthCache::getUserJson() {
27
+ CFStringRef key = CFStringCreateWithCString(nullptr, CACHE_KEY, kCFStringEncodingUTF8);
28
+ CFPropertyListRef value = CFPreferencesCopyAppValue(key, kCFPreferencesCurrentApplication);
29
+ CFRelease(key);
30
+
31
+ if (value && CFGetTypeID(value) == CFStringGetTypeID()) {
32
+ CFStringRef cfStr = (CFStringRef)value;
33
+ char buffer[4096];
34
+ if (CFStringGetCString(cfStr, buffer, sizeof(buffer), kCFStringEncodingUTF8)) {
35
+ CFRelease(value);
36
+ return std::string(buffer);
37
+ }
38
+ }
39
+ if (value) CFRelease(value);
40
+ return std::nullopt;
41
+ }
42
+
43
+ void AuthCache::clear() {
44
+ CFStringRef key = CFStringCreateWithCString(nullptr, CACHE_KEY, kCFStringEncodingUTF8);
45
+ CFPreferencesSetAppValue(key, nullptr, kCFPreferencesCurrentApplication);
46
+ CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
47
+ CFRelease(key);
48
+ }
49
+ #endif
50
+
51
+ #ifdef __ANDROID__
52
+ using namespace facebook::jni;
53
+
54
+ struct JContext : JavaClass<JContext> {
55
+ static constexpr auto kJavaDescriptor = "Landroid/content/Context;";
56
+ };
57
+
58
+ struct JAuthAdapter : facebook::jni::JavaClass<JAuthAdapter> {
59
+ static constexpr auto kJavaDescriptor = "Lcom/auth/AuthAdapter;";
60
+
61
+ static void setUserJson(facebook::jni::alias_ref<jobject> context, const std::string& json) {
62
+ static auto method = javaClassStatic()->getStaticMethod<void(alias_ref<JContext>, jstring)>("setUserJson");
63
+ method(javaClassStatic(), static_ref_cast<JContext>(context), make_jstring(json).get());
64
+ }
65
+
66
+ static facebook::jni::local_ref<jstring> getUserJson(facebook::jni::alias_ref<jobject> context) {
67
+ static auto method = javaClassStatic()->getStaticMethod<jstring(alias_ref<JContext>)>("getUserJson");
68
+ return method(javaClassStatic(), static_ref_cast<JContext>(context));
69
+ }
70
+
71
+ static void clearUser(facebook::jni::alias_ref<jobject> context) {
72
+ static auto method = javaClassStatic()->getStaticMethod<void(alias_ref<JContext>)>("clearUser");
73
+ method(javaClassStatic(), static_ref_cast<JContext>(context));
74
+ }
75
+ };
76
+
77
+ static facebook::jni::global_ref<jobject> gContext;
78
+
79
+ void AuthCache::setAndroidContext(void* context) {
80
+ gContext = facebook::jni::make_global(static_cast<jobject>(context));
81
+ }
82
+
83
+ void* AuthCache::getAndroidContext() {
84
+ return gContext.get();
85
+ }
86
+
87
+ void AuthCache::setUserJson(const std::string& json) {
88
+ if (!gContext) return;
89
+ JAuthAdapter::setUserJson(gContext, json);
90
+ }
91
+
92
+ std::optional<std::string> AuthCache::getUserJson() {
93
+ if (!gContext) return std::nullopt;
94
+ auto result = JAuthAdapter::getUserJson(gContext);
95
+ if (!result) return std::nullopt;
96
+ return result->toStdString();
97
+ }
98
+
99
+ void AuthCache::clear() {
100
+ if (!gContext) return;
101
+ JAuthAdapter::clearUser(gContext);
102
+ }
103
+ #endif
104
+
105
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <optional>
5
+
6
+ namespace margelo::nitro::NitroAuth {
7
+
8
+ class AuthCache {
9
+ public:
10
+ static void setUserJson(const std::string& json);
11
+ static std::optional<std::string> getUserJson();
12
+ static void clear();
13
+
14
+ #ifdef __ANDROID__
15
+ static void setAndroidContext(void* context);
16
+ static void* getAndroidContext();
17
+ #endif
18
+ };
19
+
20
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,213 @@
1
+ #include "HybridAuth.hpp"
2
+ #include "AuthCache.hpp"
3
+ #include "JSONSerializer.hpp"
4
+ #include "PlatformAuth.hpp"
5
+ #include <NitroModules/NitroLogger.hpp>
6
+ #include <chrono>
7
+
8
+ namespace margelo::nitro::NitroAuth {
9
+
10
+ HybridAuth::HybridAuth() : HybridObject(TAG) {
11
+ loadFromCache();
12
+ }
13
+
14
+ std::optional<AuthUser> HybridAuth::getCurrentUser() {
15
+ std::lock_guard<std::mutex> lock(_mutex);
16
+ return _currentUser;
17
+ }
18
+
19
+ std::vector<std::string> HybridAuth::getGrantedScopes() {
20
+ std::lock_guard<std::mutex> lock(_mutex);
21
+ return _grantedScopes;
22
+ }
23
+
24
+ bool HybridAuth::getHasPlayServices() {
25
+ return PlatformAuth::hasPlayServices();
26
+ }
27
+
28
+ void HybridAuth::loadFromCache() {
29
+ std::lock_guard<std::mutex> lock(_mutex);
30
+ auto json = AuthCache::getUserJson();
31
+ if (json) {
32
+ _currentUser = JSONSerializer::deserialize(*json);
33
+ if (_currentUser && _currentUser->scopes) {
34
+ _grantedScopes = *_currentUser->scopes;
35
+ }
36
+ }
37
+ }
38
+
39
+ void HybridAuth::saveToCache(const std::optional<AuthUser>& user) {
40
+ if (user) {
41
+ auto json = JSONSerializer::serialize(*user);
42
+ AuthCache::setUserJson(json);
43
+ } else {
44
+ AuthCache::clear();
45
+ }
46
+ }
47
+
48
+ void HybridAuth::notifyAuthStateChanged() {
49
+ std::optional<AuthUser> user;
50
+ std::vector<std::function<void(const std::optional<AuthUser>&)>> listeners;
51
+ {
52
+ std::lock_guard<std::mutex> lock(_mutex);
53
+ user = _currentUser;
54
+ for (auto const& [id, listener] : _listeners) {
55
+ listeners.push_back(listener);
56
+ }
57
+ }
58
+ for (const auto& listener : listeners) {
59
+ listener(user);
60
+ }
61
+ }
62
+
63
+ std::function<void()> HybridAuth::onAuthStateChanged(const std::function<void(const std::optional<AuthUser>&)>& callback) {
64
+ std::lock_guard<std::mutex> lock(_mutex);
65
+ int id = _nextListenerId++;
66
+ _listeners[id] = callback;
67
+
68
+ return [this, id]() {
69
+ std::lock_guard<std::mutex> lock(_mutex);
70
+ _listeners.erase(id);
71
+ };
72
+ }
73
+
74
+ void HybridAuth::logout() {
75
+ {
76
+ std::lock_guard<std::mutex> lock(_mutex);
77
+ _currentUser = std::nullopt;
78
+ _grantedScopes.clear();
79
+ saveToCache(std::nullopt);
80
+ }
81
+ PlatformAuth::logout();
82
+ notifyAuthStateChanged();
83
+ }
84
+
85
+ std::shared_ptr<Promise<void>> HybridAuth::login(AuthProvider provider, const std::optional<LoginOptions>& options) {
86
+ auto promise = Promise<void>::create();
87
+ std::vector<std::string> scopes;
88
+ std::optional<std::string> loginHint;
89
+ if (options) {
90
+ if (options->scopes) scopes = *options->scopes;
91
+ loginHint = options->loginHint;
92
+ }
93
+
94
+ auto loginPromise = PlatformAuth::login(provider, scopes, loginHint);
95
+ loginPromise->addOnResolvedListener([this, promise, scopes](const AuthUser& user) {
96
+ {
97
+ std::lock_guard<std::mutex> lock(_mutex);
98
+ _currentUser = user;
99
+ _grantedScopes = scopes;
100
+ if (_currentUser) _currentUser->scopes = scopes;
101
+ saveToCache(_currentUser);
102
+ }
103
+ notifyAuthStateChanged();
104
+ promise->resolve();
105
+ });
106
+
107
+ loginPromise->addOnRejectedListener([promise](const std::exception_ptr& error) {
108
+ promise->reject(error);
109
+ });
110
+ return promise;
111
+ }
112
+
113
+ std::shared_ptr<Promise<void>> HybridAuth::requestScopes(const std::vector<std::string>& scopes) {
114
+ auto promise = Promise<void>::create();
115
+ auto requestPromise = PlatformAuth::requestScopes(scopes);
116
+ requestPromise->addOnResolvedListener([this, promise, scopes](const AuthUser& user) {
117
+ {
118
+ std::lock_guard<std::mutex> lock(_mutex);
119
+ _currentUser = user;
120
+ for (const auto& scope : scopes) {
121
+ if (std::find(_grantedScopes.begin(), _grantedScopes.end(), scope) == _grantedScopes.end()) {
122
+ _grantedScopes.push_back(scope);
123
+ }
124
+ }
125
+ if (_currentUser) _currentUser->scopes = _grantedScopes;
126
+ saveToCache(_currentUser);
127
+ }
128
+ notifyAuthStateChanged();
129
+ promise->resolve();
130
+ });
131
+
132
+ requestPromise->addOnRejectedListener([promise](const std::exception_ptr& error) {
133
+ promise->reject(error);
134
+ });
135
+ return promise;
136
+ }
137
+
138
+ std::shared_ptr<Promise<void>> HybridAuth::revokeScopes(const std::vector<std::string>& scopes) {
139
+ auto promise = Promise<void>::create();
140
+ {
141
+ std::lock_guard<std::mutex> lock(_mutex);
142
+ _grantedScopes.erase(
143
+ std::remove_if(_grantedScopes.begin(), _grantedScopes.end(),
144
+ [&scopes](const std::string& s) {
145
+ return std::find(scopes.begin(), scopes.end(), s) != scopes.end();
146
+ }),
147
+ _grantedScopes.end()
148
+ );
149
+ if (_currentUser) {
150
+ _currentUser->scopes = _grantedScopes;
151
+ saveToCache(_currentUser);
152
+ }
153
+ }
154
+ notifyAuthStateChanged();
155
+ promise->resolve();
156
+ return promise;
157
+ }
158
+
159
+ std::shared_ptr<Promise<std::optional<std::string>>> HybridAuth::getAccessToken() {
160
+ auto promise = Promise<std::optional<std::string>>::create();
161
+ bool needsRefresh = false;
162
+ {
163
+ std::lock_guard<std::mutex> lock(_mutex);
164
+ if (_currentUser && _currentUser->accessToken) {
165
+ if (_currentUser->expirationTime) {
166
+ auto now = std::chrono::system_clock::now().time_since_epoch() / std::chrono::milliseconds(1);
167
+ if (now + 300000 > *_currentUser->expirationTime) needsRefresh = true;
168
+ }
169
+ if (!needsRefresh) {
170
+ promise->resolve(*_currentUser->accessToken);
171
+ return promise;
172
+ }
173
+ } else {
174
+ promise->resolve(std::nullopt);
175
+ return promise;
176
+ }
177
+ }
178
+
179
+ if (needsRefresh) {
180
+ auto refreshPromise = refreshToken();
181
+ refreshPromise->addOnResolvedListener([promise](const AuthTokens& tokens) {
182
+ promise->resolve(tokens.accessToken);
183
+ });
184
+ refreshPromise->addOnRejectedListener([promise](const std::exception_ptr& error) {
185
+ promise->reject(error);
186
+ });
187
+ }
188
+ return promise;
189
+ }
190
+
191
+ std::shared_ptr<Promise<AuthTokens>> HybridAuth::refreshToken() {
192
+ auto promise = Promise<AuthTokens>::create();
193
+ auto refreshPromise = PlatformAuth::refreshToken();
194
+ refreshPromise->addOnResolvedListener([this, promise](const AuthTokens& tokens) {
195
+ {
196
+ std::lock_guard<std::mutex> lock(_mutex);
197
+ if (_currentUser) {
198
+ _currentUser->accessToken = tokens.accessToken;
199
+ _currentUser->idToken = tokens.idToken;
200
+ saveToCache(_currentUser);
201
+ }
202
+ }
203
+ notifyAuthStateChanged();
204
+ promise->resolve(tokens);
205
+ });
206
+
207
+ refreshPromise->addOnRejectedListener([promise](const std::exception_ptr& error) {
208
+ promise->reject(error);
209
+ });
210
+ return promise;
211
+ }
212
+
213
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,47 @@
1
+ #pragma once
2
+
3
+ #include "HybridAuthSpec.hpp"
4
+ #include "AuthUser.hpp"
5
+ #include "LoginOptions.hpp"
6
+ #include "AuthTokens.hpp"
7
+ #include <optional>
8
+ #include <mutex>
9
+ #include <memory>
10
+ #include <string>
11
+ #include <map>
12
+
13
+ namespace margelo::nitro::NitroAuth {
14
+
15
+ class HybridAuth: public HybridAuthSpec {
16
+ public:
17
+ HybridAuth();
18
+
19
+ std::optional<AuthUser> getCurrentUser() override;
20
+ std::vector<std::string> getGrantedScopes() override;
21
+ bool getHasPlayServices() override;
22
+
23
+ std::shared_ptr<Promise<void>> login(AuthProvider provider, const std::optional<LoginOptions>& options) override;
24
+ std::shared_ptr<Promise<void>> requestScopes(const std::vector<std::string>& scopes) override;
25
+ std::shared_ptr<Promise<void>> revokeScopes(const std::vector<std::string>& scopes) override;
26
+ std::shared_ptr<Promise<std::optional<std::string>>> getAccessToken() override;
27
+ std::shared_ptr<Promise<AuthTokens>> refreshToken() override;
28
+
29
+ void logout() override;
30
+ std::function<void()> onAuthStateChanged(const std::function<void(const std::optional<AuthUser>&)>& callback) override;
31
+
32
+ private:
33
+ void loadFromCache();
34
+ void saveToCache(const std::optional<AuthUser>& user);
35
+ void notifyAuthStateChanged();
36
+
37
+ private:
38
+ std::optional<AuthUser> _currentUser;
39
+ std::vector<std::string> _grantedScopes;
40
+ std::map<int, std::function<void(const std::optional<AuthUser>&)>> _listeners;
41
+ int _nextListenerId = 0;
42
+ std::mutex _mutex;
43
+
44
+ static constexpr auto TAG = "Auth";
45
+ };
46
+
47
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,57 @@
1
+ #pragma once
2
+
3
+ #include "AuthUser.hpp"
4
+ #include <string>
5
+ #include <optional>
6
+ #include <vector>
7
+
8
+ namespace margelo::nitro::NitroAuth {
9
+
10
+ class JSONSerializer {
11
+ public:
12
+ static std::string serialize(const AuthUser& user) {
13
+ std::string json = "{";
14
+ json += "\"provider\":\"" + (user.provider == AuthProvider::GOOGLE ? std::string("google") : std::string("apple")) + "\",";
15
+ if (user.email) json += "\"email\":\"" + *user.email + "\",";
16
+ if (user.name) json += "\"name\":\"" + *user.name + "\",";
17
+ if (user.photo) json += "\"photo\":\"" + *user.photo + "\",";
18
+ if (user.idToken) json += "\"idToken\":\"" + *user.idToken + "\",";
19
+ if (user.scopes) {
20
+ json += "\"scopes\":[";
21
+ for (size_t i = 0; i < user.scopes->size(); ++i) {
22
+ json += "\"" + (*user.scopes)[i] + "\"";
23
+ if (i < user.scopes->size() - 1) json += ",";
24
+ }
25
+ json += "],";
26
+ }
27
+ if (json.back() == ',') json.pop_back();
28
+ json += "}";
29
+ return json;
30
+ }
31
+
32
+ static std::optional<AuthUser> deserialize(const std::string& json) {
33
+ if (json.find("{") == std::string::npos) return std::nullopt;
34
+
35
+ AuthUser user;
36
+ user.provider = (json.find("\"provider\":\"google\"") != std::string::npos) ? AuthProvider::GOOGLE : AuthProvider::APPLE;
37
+
38
+ auto extract = [&](const std::string& key) -> std::optional<std::string> {
39
+ std::string searchKey = "\"" + key + "\":\"";
40
+ size_t start = json.find(searchKey);
41
+ if (start == std::string::npos) return std::nullopt;
42
+ start += searchKey.length();
43
+ size_t end = json.find("\"", start);
44
+ if (end == std::string::npos) return std::nullopt;
45
+ return json.substr(start, end - start);
46
+ };
47
+
48
+ user.email = extract("email");
49
+ user.name = extract("name");
50
+ user.photo = extract("photo");
51
+ user.idToken = extract("idToken");
52
+
53
+ return user;
54
+ }
55
+ };
56
+
57
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #include "AuthProvider.hpp"
4
+ #include "AuthUser.hpp"
5
+ #include "AuthTokens.hpp"
6
+ #include <NitroModules/Promise.hpp>
7
+ #include <memory>
8
+ #include <vector>
9
+ #include <string>
10
+
11
+ namespace margelo::nitro::NitroAuth {
12
+
13
+ using namespace margelo::nitro;
14
+
15
+ class PlatformAuth {
16
+ public:
17
+ static std::shared_ptr<Promise<AuthUser>> login(AuthProvider provider, const std::vector<std::string>& scopes = {}, const std::optional<std::string>& loginHint = std::nullopt);
18
+ static std::shared_ptr<Promise<AuthUser>> requestScopes(const std::vector<std::string>& scopes);
19
+ static std::shared_ptr<Promise<AuthTokens>> refreshToken();
20
+ static std::shared_ptr<Promise<std::optional<AuthUser>>> silentRestore();
21
+ static bool hasPlayServices();
22
+ static void logout();
23
+ };
24
+
25
+ } // namespace margelo::nitro::NitroAuth