1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2016 Realm Inc.
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 ////////////////////////////////////////////////////////////////////////////
19 #include "sync/sync_user.hpp"
21 #include "sync/impl/sync_metadata.hpp"
22 #include "sync/sync_manager.hpp"
23 #include "sync/sync_session.hpp"
27 SyncUserContextFactory SyncUser::s_binding_context_factory;
28 std::mutex SyncUser::s_binding_context_factory_mutex;
30 SyncUser::SyncUser(std::string refresh_token,
32 util::Optional<std::string> server_url,
33 util::Optional<std::string> local_identity,
35 : m_state(State::Active)
36 , m_server_url(server_url.value_or(""))
37 , m_token_type(token_type)
38 , m_refresh_token(std::move(refresh_token))
39 , m_identity(std::move(identity))
42 std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
43 if (s_binding_context_factory) {
44 m_binding_context = s_binding_context_factory();
47 if (token_type == TokenType::Normal) {
48 REALM_ASSERT(m_server_url.length() > 0);
49 bool updated = SyncManager::shared().perform_metadata_update([=](const auto& manager) {
50 auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
51 metadata->set_user_token(m_refresh_token);
52 m_is_admin = metadata->is_admin();
53 m_local_identity = metadata->local_uuid();
56 m_local_identity = m_identity;
58 // Admin token users. The local identity serves as the directory path.
59 REALM_ASSERT(local_identity);
60 m_local_identity = std::move(*local_identity);
64 std::vector<std::shared_ptr<SyncSession>> SyncUser::all_sessions()
66 std::lock_guard<std::mutex> lock(m_mutex);
67 std::vector<std::shared_ptr<SyncSession>> sessions;
68 if (m_state == State::Error) {
71 for (auto it = m_sessions.begin(); it != m_sessions.end();) {
72 if (auto ptr_to_session = it->second.lock()) {
73 if (!ptr_to_session->is_in_error_state()) {
74 sessions.emplace_back(std::move(ptr_to_session));
79 // This session is bad, destroy it.
80 it = m_sessions.erase(it);
85 std::shared_ptr<SyncSession> SyncUser::session_for_on_disk_path(const std::string& path)
87 std::lock_guard<std::mutex> lock(m_mutex);
88 if (m_state == State::Error) {
91 auto it = m_sessions.find(path);
92 if (it == m_sessions.end()) {
95 auto locked = it->second.lock();
97 // Remove the session from the map, because it has fatally errored out or the entry is invalid.
103 void SyncUser::update_refresh_token(std::string token)
105 std::vector<std::shared_ptr<SyncSession>> sessions_to_revive;
107 std::unique_lock<std::mutex> lock(m_mutex);
108 if (auto session = m_management_session.lock())
109 sessions_to_revive.emplace_back(std::move(session));
111 if (auto session = m_permission_session.lock())
112 sessions_to_revive.emplace_back(std::move(session));
118 m_refresh_token = token;
120 case State::LoggedOut: {
121 sessions_to_revive.reserve(m_waiting_sessions.size());
122 m_refresh_token = token;
123 m_state = State::Active;
124 for (auto& pair : m_waiting_sessions) {
125 if (auto ptr = pair.second.lock()) {
126 m_sessions[pair.first] = ptr;
127 sessions_to_revive.emplace_back(std::move(ptr));
130 m_waiting_sessions.clear();
134 // Update persistent user metadata.
135 if (m_token_type != TokenType::Admin) {
136 SyncManager::shared().perform_metadata_update([=](const auto& manager) {
137 auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
138 metadata->set_user_token(token);
142 // (Re)activate all pending sessions.
143 // Note that we do this after releasing the lock, since the session may
144 // need to access protected User state in the process of binding itself.
145 for (auto& session : sessions_to_revive) {
146 session->revive_if_needed();
150 void SyncUser::log_out()
152 if (m_token_type == TokenType::Admin) {
153 // Admin-token users cannot be logged out.
156 std::lock_guard<std::mutex> lock(m_mutex);
157 if (m_state == State::LoggedOut) {
160 m_state = State::LoggedOut;
161 // Move all active sessions into the waiting sessions pool. If the user is
162 // logged back in, they will automatically be reactivated.
163 for (auto& pair : m_sessions) {
164 if (auto ptr = pair.second.lock()) {
166 m_waiting_sessions[pair.first] = ptr;
170 // Deactivate the sessions for the management and admin Realms.
171 if (auto session = m_management_session.lock())
174 if (auto session = m_permission_session.lock())
177 // Mark the user as 'dead' in the persisted metadata Realm.
178 SyncManager::shared().perform_metadata_update([=](const auto& manager) {
179 auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url, false);
181 metadata->mark_for_removal();
185 void SyncUser::set_is_admin(bool is_admin)
187 if (m_token_type == TokenType::Admin) {
190 m_is_admin = is_admin;
191 SyncManager::shared().perform_metadata_update([=](const auto& manager) {
192 auto metadata = manager.get_or_make_user_metadata(m_identity, m_server_url);
193 metadata->set_is_admin(is_admin);
197 void SyncUser::invalidate()
199 std::lock_guard<std::mutex> lock(m_mutex);
200 m_state = State::Error;
203 std::string SyncUser::refresh_token() const
205 std::lock_guard<std::mutex> lock(m_mutex);
206 return m_refresh_token;
209 SyncUser::State SyncUser::state() const
211 std::lock_guard<std::mutex> lock(m_mutex);
215 void SyncUser::register_session(std::shared_ptr<SyncSession> session)
217 const std::string& path = session->path();
218 std::unique_lock<std::mutex> lock(m_mutex);
221 // Immediately ask the session to come online.
222 m_sessions[path] = session;
224 session->revive_if_needed();
226 case State::LoggedOut:
227 m_waiting_sessions[path] = session;
234 void SyncUser::set_binding_context_factory(SyncUserContextFactory factory)
236 std::lock_guard<std::mutex> lock(s_binding_context_factory_mutex);
237 s_binding_context_factory = std::move(factory);
240 void SyncUser::register_management_session(const std::string& path)
242 std::lock_guard<std::mutex> lock(m_mutex);
243 if (m_management_session.lock() || m_state == State::Error)
246 m_management_session = SyncManager::shared().get_existing_session(path);
249 void SyncUser::register_permission_session(const std::string& path)
251 std::lock_guard<std::mutex> lock(m_mutex);
252 if (m_permission_session.lock() || m_state == State::Error)
255 m_permission_session = SyncManager::shared().get_existing_session(path);
261 size_t hash<realm::SyncUserIdentifier>::operator()(const realm::SyncUserIdentifier& k) const
263 return ((hash<string>()(k.user_id) ^ (hash<string>()(k.auth_server_url) << 1)) >> 1);