I have this script which change all passwords of existing FireBase Authentication users that we use for testing purposes in order to reset users to a "clean" state.
var admin = require('firebase-admin');
// Input args
var jsonKey = process.argv[2];
var projectId = process.argv[3];
var newPassword = process.argv[4];
var serviceAccount = require(jsonKey);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://" + projectId + ".firebaseio.com"
});
// FIXME Only for debug purposes
var index = 1;
/**
* https://firebase.google.com/docs/auth/admin/manage-users#update_a_user
*/
function nextUser(uid, timeout) {
setTimeout(() => {
admin.auth().updateUser(uid, {
password : newPassword
})
.then(function() {
console.log(index++ + ') Successfully updated user', uid);
})
.catch(function(error) {
console.log(index++ + ') Error updating user:', error);
});
}, timeout);
}
/**
* https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
* https://stackoverflow.com/a/58028558
*/
function listAllUsers(nextPageToken) {
let timeout = 0;
admin.auth().listUsers(1000, nextPageToken)
.then(function (listUsersResult) {
console.log("Retrieved " + listUsersResult.users.length + " users");
listUsersResult.users.forEach(function (userRecord) {
timeout = timeout + 100
nextUser(userRecord.uid, timeout)
});
if (listUsersResult.pageToken) {
listAllUsers(listUsersResult.pageToken);
}
})
.catch(function (error) {
console.log('Error listing users:', error);
});
}
listAllUsers();
The script is launched from a local machine with
node <filename.js> <path of jsonkey> <projectid> <new password>
As you can see the iterator is running with timeouts, this is needed after I encountered a problem with "Exceeded quota for updating account information" which I tried to solve with this answer
The script is running fine, all users are processed (I added a sequential counter only for this kind of debug) correctly and not "quota" error is thrown. The problem is that at the end of the script the shell prompt does not exit, the process remains hanging and I need a CTRL+C
to kill it. Besides the annoying part of this behaviour, this is blocking a much wider script which call this one and does not proceed to next line of commands.
It seems that after all setTimeout
function has been executed, the main process is not automatically shutting down.
How can I solve this?
EDIT
I tried different approaches:
- https://repl.it/repls/RoundedAnchoredDos, does not work, the firebase-app is deleted before all users has been processed
- https://repl.it/repls/DelightfulUnfoldedHexagon, works, it is a synchronous version where one user at a time is processed and after last user firebase is deleted
The second version works, but it is very slow. So I started from initial script and I added a "monitor" which wait for all users to be completed (with a very dirty counter) and close the script at the end
var admin = require('firebase-admin');
// Input args
var jsonKey = process.argv[2];
var projectId = process.argv[3];
var newPassword = process.argv[4];
var serviceAccount = require(jsonKey);
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://" + projectId + ".firebaseio.com"
});
// Index to count all users that have been queued for processing
var queued = 0;
// Index to count all user that have completed the task
var completed = 0;
/**
* https://firebase.google.com/docs/auth/admin/manage-users#update_a_user
*/
function nextUser(uid, timeout) {
setTimeout(() => {
/* ------ Process User Implementation ------ */
admin.auth().updateUser(uid, {
password : newPassword
})
.then(function() {
console.log(++completed + ') Successfully updated user ', uid);
})
.catch(function(error) {
console.log(++completed + ') Error updating user:', error);
});
/* ------ Process User Implementation ------ */
}, timeout);
queued++;
}
/**
* https://firebase.google.com/docs/auth/admin/manage-users#list_all_users
* https://stackoverflow.com/a/58028558
*/
function listAllUsers(nextPageToken) {
let timeout = 0;
admin.auth().listUsers(1000, nextPageToken)
.then(function (listUsersResult) {
console.log("Retrieved " + listUsersResult.users.length + " users");
listUsersResult.users.forEach(function (userRecord) {
timeout = timeout + 100
nextUser(userRecord.uid, timeout)
});
if (listUsersResult.pageToken) {
listAllUsers(listUsersResult.pageToken);
} else {
waitForEnd();
}
})
.catch(function (error) {
console.log('Error listing users:', error);
});
}
function waitForEnd() {
if(completed < queued) {
console.log("> " + completed + "/" + queued + " completed, waiting...");
setTimeout(waitForEnd, 5000);
} else {
console.log("> " + completed + "/" + queued + " completed, exiting...");
admin.app().delete();
}
}
listAllUsers();
It works, it's rapid. Enough for me as it is a testing script