Skip to content

Instantly share code, notes, and snippets.

@torresalmonte
Created March 19, 2020 22:47
Show Gist options
  • Save torresalmonte/525911416feee9643c647199471dfaa8 to your computer and use it in GitHub Desktop.
Save torresalmonte/525911416feee9643c647199471dfaa8 to your computer and use it in GitHub Desktop.
Script to delete the excess of security rulesets
const admin = require('firebase-admin');
const {sleep} = require('sleep');
// asumes the existance of the GOOGLE_APPLICATION_CREDENCIAL env variable
const firebaseApp = admin.initializeApp();
async function getRulesets(projectId, firebaseApp, pageToken) {
pageToken = pageToken || '';
let token = await firebaseApp.options.credential.getAccessToken();
let accessToken = token.access_token;
let url = `https://firebaserules.googleapis.com/v1/projects/${projectId}/rulesets?pageToken=${pageToken}`;
const request = {
url: url,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
method: 'GET'
};
let response = null;
try {
response = await firebaseApp.options.credential.credential_.httpClient.send(request);
} catch (err) {
console.error(err);
}
rules = response ? response.parsedData : {};
return rules;
} // getRulesets
/**
*
* @param {Firebase App instance} firebaseApp
* @param {Ruleset name, as received in the JSON response} rulesetName
*/
async function deleteRuleset(firebaseApp, rulesetName) {
if (!firebaseApp || !rulesetName) {
throw new Exception("firebaseApp and ruleset name required");
}
let token = await firebaseApp.options.credential.getAccessToken();
let accessToken = token.access_token;
let url = `https://firebaserules.googleapis.com/v1/${rulesetName}`;
const request = {
url: url,
headers: {
'Authorization': `Bearer ${accessToken}`
},
method: 'DELETE'
};
let response = null;
try {
let result = await firebaseApp.options.credential.credential_.httpClient.send(request);
response = result.parsedData;
} catch (err) {
console.error(err);
}
return response;
} // deleteRuleset
// WARNING: deleting storage rulesets
// make sure to backup the current ruleset
(async () => {
// NOTE: set the Firebase projectId
const projectId = "marzipan-548fc";
let pageToken = null;
let pageCounter = 0;
let rulesCounter = 0;
while (true) {
// skip Firestore rulesets
let rules = await getRulesets(projectId, firebaseApp, pageToken);
if (rules.rulesets) {
pageCounter++;
for (let ruleset of rules.rulesets) {
//console.log(ruleset);
// we just remove the Storage rulesets
if (ruleset.metadata.services == 'firebase.storage') {
// we keep the first entry
if (rulesCounter > 0) {
console.log(`DELETING ${ruleset.name}`);
// WARNING: the following line will remove the entry from the history
// This cannot be undone, so make sure you have a backup of the Storage ruleset
let result = await deleteRuleset(firebaseApp, ruleset.name);
//console.log(result);
// TODO: manage error states (like 429 on firebaserules.googleapis.com)
}
rulesCounter++;
} else {
console.log('...skipping Firestore ruleset...');
}
}
pageToken = rules.nextPageToken || null;
}
if (!pageToken) {
// finish the cycle
break;
}
// small pause to avoid hitting a query limit
console.log(`---- 10s pause to prevent hitting limits ----`);
sleep(10);
} // while
console.log(`PAGES: ${pageCounter}`);
console.log(`DELETED STORAGE RULESETS: ${rulesCounter - 1}`);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment