firebase-tools
Version:
Command-Line Interface for Firebase
137 lines (136 loc) • 6.51 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.actuate = exports.askQuestions = exports.DEFAULT_RULES = void 0;
const clc = require("colorette");
const prompt_1 = require("../../prompt");
const logger_1 = require("../../logger");
const utils = require("../../utils");
const database_1 = require("../../management/database");
const ora = require("ora");
const ensureApiEnabled_1 = require("../../ensureApiEnabled");
const getDefaultDatabaseInstance_1 = require("../../getDefaultDatabaseInstance");
const error_1 = require("../../error");
const apiv2_1 = require("../../apiv2");
const api_1 = require("../../api");
const DEFAULT_RULES_FILENAME = "database.rules.json";
exports.DEFAULT_RULES = JSON.stringify({ rules: { ".read": "auth != null", ".write": "auth != null" } }, null, 2);
async function getDBRules(instanceDetails) {
if (!instanceDetails || !instanceDetails.name) {
return exports.DEFAULT_RULES;
}
const client = new apiv2_1.Client({ urlPrefix: instanceDetails.databaseUrl });
const response = await client.request({
method: "GET",
path: "/.settings/rules.json",
responseType: "stream",
resolveOnHTTPError: true,
});
if (response.status !== 200) {
throw new error_1.FirebaseError(`Failed to fetch current rules. Code: ${response.status}`);
}
return await response.response.text();
}
function writeDBRules(rules, filename, config) {
config.writeProjectFile(filename, rules);
logger_1.logger.info(`Future modifications to ${clc.bold(filename)} will update Realtime Database Security Rules when you run`);
logger_1.logger.info(clc.bold("firebase deploy") + ".");
}
async function createDefaultDatabaseInstance(project) {
const selectedLocation = await (0, prompt_1.select)({
message: "Please choose the location for your default Realtime Database instance:",
choices: [
{ name: "us-central1", value: database_1.DatabaseLocation.US_CENTRAL1 },
{ name: "europe-west1", value: database_1.DatabaseLocation.EUROPE_WEST1 },
{ name: "asia-southeast1", value: database_1.DatabaseLocation.ASIA_SOUTHEAST1 },
],
});
let instanceName = `${project}-default-rtdb`;
const checkOutput = await (0, database_1.checkInstanceNameAvailable)(project, instanceName, database_1.DatabaseInstanceType.DEFAULT_DATABASE, selectedLocation);
if (!checkOutput.available) {
if (!checkOutput.suggestedIds || checkOutput.suggestedIds.length === 0) {
logger_1.logger.debug(`No instance names were suggested instead of conventional instance name: ${instanceName}`);
throw new error_1.FirebaseError("Failed to create default RTDB instance");
}
instanceName = checkOutput.suggestedIds[0];
logger_1.logger.info(`${clc.yellow("WARNING:")} your project ID has the legacy name format, so your default Realtime Database instance will be named differently: ${instanceName}`);
}
const spinner = ora(`Creating your default Realtime Database instance: ${instanceName}`).start();
try {
const createdInstance = await (0, database_1.createInstance)(project, instanceName, selectedLocation, database_1.DatabaseInstanceType.DEFAULT_DATABASE);
spinner.succeed();
return createdInstance;
}
catch (err) {
spinner.fail();
throw err;
}
}
async function initializeDatabaseInstance(projectId) {
await (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.rtdbManagementOrigin)(), "database", false);
logger_1.logger.info();
const instance = await (0, getDefaultDatabaseInstance_1.getDefaultDatabaseInstance)({ project: projectId });
if (instance !== "") {
return await (0, database_1.getDatabaseInstanceDetails)(projectId, instance);
}
const createDefault = await (0, prompt_1.confirm)({
message: "It seems like you haven’t initialized Realtime Database in your project yet. Do you want to set it up?",
default: true,
});
if (createDefault) {
return await createDefaultDatabaseInstance(projectId);
}
return null;
}
async function askQuestions(setup, config) {
logger_1.logger.info();
logger_1.logger.info("Firebase Realtime Database Security Rules allow you to define how your data should be");
logger_1.logger.info("structured and when your data can be read from and written to.");
logger_1.logger.info();
const rulesFilename = await (0, prompt_1.input)({
message: "What file should be used for Realtime Database Security Rules?",
default: DEFAULT_RULES_FILENAME,
});
if (!rulesFilename) {
throw new error_1.FirebaseError("Must specify location for Realtime Database rules file.");
}
const info = {
rulesFilename,
rules: exports.DEFAULT_RULES,
writeRules: true,
};
if (setup.projectId) {
const instanceDetails = await initializeDatabaseInstance(setup.projectId);
if (instanceDetails) {
info.rules = await getDBRules(instanceDetails);
utils.logBullet(`Downloaded the existing Realtime Database Security Rules of database ${clc.bold(instanceDetails.name)} from the Firebase console`);
}
}
info.writeRules = await config.confirmWriteProjectFile(rulesFilename, info.rules);
setup.featureInfo = setup.featureInfo || {};
setup.featureInfo.database = info;
}
exports.askQuestions = askQuestions;
async function actuate(setup, config) {
var _a;
const info = (_a = setup.featureInfo) === null || _a === void 0 ? void 0 : _a.database;
if (!info) {
throw new error_1.FirebaseError("No database RequiredInfo found in setup actuate.");
}
info.rules = info.rules || exports.DEFAULT_RULES;
info.rulesFilename = info.rulesFilename || "database.rules.json";
setup.config.database = { rules: info.rulesFilename };
if (info.writeRules) {
if (info.rules === exports.DEFAULT_RULES) {
writeDBRules(info.rules, info.rulesFilename, config);
}
else {
writeDBRules(info.rules, info.rulesFilename, config);
}
}
else {
logger_1.logger.info("Skipping overwrite of Realtime Database Security Rules.");
logger_1.logger.info(`The security rules defined in ${clc.bold(info.rulesFilename)} will be published when you run ${clc.bold("firebase deploy")}.`);
}
return Promise.resolve();
}
exports.actuate = actuate;
;