Expose admin users to JS (#1100)

The JS binding used to conflate `SyncUser::is_admin()` with the user being created by calling `Realm.Sync.User.adminToken()`, but now that we expose a user’s role on the server under `is_admin()` this supposition is no longer correct.

#1097 attempted to fix one such case, but fixing it only uncovered another: in `UserClass<T>::all_users()`.  I’ve gone through all the callsites of `SyncUser::is_admin()` to make sure they don’t assume an admin token user.
This commit is contained in:
Yavor Georgiev 2017-06-27 20:32:34 +02:00 committed by GitHub
parent e6818d693d
commit 7ab3aff82f
3 changed files with 26 additions and 43 deletions

View File

@ -1,3 +1,14 @@
vNext Release notes (TBD)
=============================================================
### Breaking changes
* None
### Enhancements
* None
### Bug fixes
* Fix admin users not appearing in `Realm.Sync.User.all`, which broke getting an access token for them.
1.8.2 Release notes (2017-6-26)
=============================================================
### Breaking changes

View File

@ -55,6 +55,10 @@ function scheduleAccessTokenRefresh(user, localRealmPath, realmUrl, expirationDa
setTimeout(() => refreshAccessToken(user, localRealmPath, realmUrl), timeout);
}
function print_error() {
(console.error || console.log).apply(console, arguments);
}
function refreshAccessToken(user, localRealmPath, realmUrl) {
let parsedRealmUrl = url_parse(realmUrl);
const url = auth_url(user.server);
@ -88,7 +92,7 @@ function refreshAccessToken(user, localRealmPath, realmUrl) {
if (errorHandler) {
errorHandler(session, error);
} else {
(console.error || console.log).call(console, `Unhandled session token refresh error: ${error}`);
print_error('Unhandled session token refresh error', error);
}
} else if (session.state !== 'invalid') {
parsedRealmUrl.set('pathname', json.access_token.token_data.path);
@ -101,6 +105,8 @@ function refreshAccessToken(user, localRealmPath, realmUrl) {
const tokenExpirationDate = new Date(json.access_token.token_data.expires * 1000);
scheduleAccessTokenRefresh(newUser, localRealmPath, realmUrl, tokenExpirationDate);
}
} else {
print_error(`Unhandled session token refresh error: could not look up session at path ${localRealmPath}`);
}
}
});

View File

@ -134,35 +134,13 @@ template<typename T>
void UserClass<T>::all_users(ContextType ctx, ObjectType object, ReturnValue &return_value) {
auto users = Object::create_empty(ctx);
for (auto user : SyncManager::shared().all_logged_in_users()) {
if (!user->is_admin()) {
if (user->token_type() == SyncUser::TokenType::Normal) {
Object::set_property(ctx, users, user->identity(), create_object<T, UserClass<T>>(ctx, new SharedUser(user)), ReadOnly | DontDelete);
}
}
return_value.set(users);
}
/*
template<typename T>
void UserClass<T>::current_user(ContextType ctx, ObjectType object, ReturnValue &return_value) {
SharedUser *current = nullptr;
for (auto user : SyncManager::shared().all_logged_in_users()) {
if (!user->is_admin()) {
if (current != nullptr) {
throw std::runtime_error("More than one user logged in currently.");
}
current = new SharedUser(user);
}
}
if (current != nullptr) {
return_value.set(create_object<T, UserClass<T>>(ctx, current));
}
else {
return_value.set_undefined();
}
}
*/
template<typename T>
void UserClass<T>::logout(ContextType ctx, FunctionType, ObjectType this_object, size_t, const ValueType[], ReturnValue &) {
get_internal<T, UserClass<T>>(this_object)->get()->log_out();
@ -403,26 +381,14 @@ void SyncClass<T>::populate_sync_config(ContextType ctx, ObjectType realm_constr
EventLoopDispatcher<SyncBindSessionHandler> bind([protected_ctx, protected_sync](const std::string& path, const realm::SyncConfig& config, std::shared_ptr<SyncSession>) {
HANDLESCOPE
if (config.user->token_type() == SyncUser::TokenType::Admin) {
// FIXME: This log-in callback is called while the object store still holds some sync-related locks.
// Notify the object store of the access token asynchronously to avoid the deadlock that would result
// from reentering the object store here.
auto thread = std::thread([path, config]{
auto session = SyncManager::shared().get_existing_active_session(path);
session->refresh_access_token(config.user->refresh_token(), config.realm_url);
});
thread.detach();
}
else {
ObjectType user_constructor = Object::validated_get_object(protected_ctx, protected_sync, std::string("User"));
FunctionType refreshAccessToken = Object::validated_get_function(protected_ctx, user_constructor, std::string("_refreshAccessToken"));
ObjectType user_constructor = Object::validated_get_object(protected_ctx, protected_sync, std::string("User"));
FunctionType refreshAccessToken = Object::validated_get_function(protected_ctx, user_constructor, std::string("_refreshAccessToken"));
ValueType arguments[3];
arguments[0] = create_object<T, UserClass<T>>(protected_ctx, new SharedUser(config.user));
arguments[1] = Value::from_string(protected_ctx, path.c_str());
arguments[2] = Value::from_string(protected_ctx, config.realm_url.c_str());
Function::call(protected_ctx, refreshAccessToken, 3, arguments);
}
ValueType arguments[3];
arguments[0] = create_object<T, UserClass<T>>(protected_ctx, new SharedUser(config.user));
arguments[1] = Value::from_string(protected_ctx, path.c_str());
arguments[2] = Value::from_string(protected_ctx, config.realm_url.c_str());
Function::call(protected_ctx, refreshAccessToken, 3, arguments);
});
std::function<SyncSessionErrorHandler> error_handler;