2020-09-02 11:45:55 +00:00
|
|
|
if (process.argv.length !== 5) {
|
|
|
|
|
console.error("Takes three arguments, the MongoDB URL (like 'mongodb://localhost:27017/mobtools'),\n" +
|
|
|
|
|
"\tthe encryption salt and the encryption password used by the server connecting to this DB.");
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MONGODB_URL = process.argv[2];
|
|
|
|
|
const ENCRYPTION_SALT = process.argv[3];
|
|
|
|
|
const ENCRYPTION_PASSWORD = process.argv[4];
|
|
|
|
|
|
|
|
|
|
const { MongoClient, ObjectID } = require("mongodb");
|
|
|
|
|
const fs = require("fs");
|
|
|
|
|
const path = require("path");
|
|
|
|
|
const CryptoJS = require("crypto-js");
|
|
|
|
|
|
|
|
|
|
const mongoClient = new MongoClient(MONGODB_URL, {
|
|
|
|
|
useNewUrlParser: true,
|
|
|
|
|
useUnifiedTopology: true,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.time("total time taken");
|
|
|
|
|
main()
|
|
|
|
|
.then(() => console.log("\nFinished Successfully."))
|
|
|
|
|
.catch(error => console.error(error))
|
|
|
|
|
.finally(() => {
|
|
|
|
|
mongoClient.close();
|
|
|
|
|
console.timeEnd("total time taken");
|
|
|
|
|
console.log();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
const con = await mongoClient.connect();
|
|
|
|
|
const db = con.db();
|
|
|
|
|
|
|
|
|
|
const pluginPackageNameByIds = {};
|
|
|
|
|
for (const plugin of await db.collection("plugin").find().toArray()) {
|
|
|
|
|
pluginPackageNameByIds[plugin._id.toString()] = plugin.packageName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const templateOrganizationId = (await db.collection("config").findOne({name: "template-organization"})).config.organizationId;
|
|
|
|
|
|
|
|
|
|
const organization = await db.collection("organization").findOne({_id: ObjectID(templateOrganizationId)});
|
|
|
|
|
|
|
|
|
|
const $datasources = await db.collection("datasource")
|
|
|
|
|
.find({organizationId: templateOrganizationId, deleted: false})
|
|
|
|
|
.map(datasource => {
|
|
|
|
|
const datasourceConfiguration = datasource.datasourceConfiguration;
|
|
|
|
|
|
|
|
|
|
if (datasourceConfiguration.authentication && datasourceConfiguration.authentication.password) {
|
|
|
|
|
datasourceConfiguration.authentication.password = decrypt(datasourceConfiguration.authentication.password);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
name: datasource.name,
|
|
|
|
|
$pluginPackageName: pluginPackageNameByIds[datasource.pluginId],
|
|
|
|
|
datasourceConfiguration: datasourceConfiguration,
|
|
|
|
|
invalids: datasource.invalids,
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
_class: datasource._class,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.toArray();
|
|
|
|
|
|
|
|
|
|
const allPageIds = [];
|
|
|
|
|
const allDefaultPageIds = new Set();
|
|
|
|
|
const $applications = await db.collection("application")
|
|
|
|
|
.find({organizationId: templateOrganizationId, deleted: false, isPublic: true})
|
|
|
|
|
.map(application => {
|
|
|
|
|
allPageIds.push(...application.pages.map(page => ObjectID(page._id)));
|
|
|
|
|
allDefaultPageIds.add(application.pages.filter(page => page.isDefault)[0]._id.toString());
|
|
|
|
|
return {
|
|
|
|
|
name: application.name,
|
|
|
|
|
isPublic: true,
|
|
|
|
|
$pages: [],
|
|
|
|
|
pages: application.pages,
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
_class: application._class,
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.toArray();
|
|
|
|
|
|
|
|
|
|
const actionsByPageId = {};
|
|
|
|
|
for (const action of await db.collection("action").find({organizationId: templateOrganizationId, deleted: false}).toArray()) {
|
|
|
|
|
if (!actionsByPageId[action.pageId]) {
|
|
|
|
|
actionsByPageId[action.pageId] = [];
|
|
|
|
|
}
|
|
|
|
|
let $isEmbedded = typeof action.datasource._id === "undefined";
|
|
|
|
|
actionsByPageId[action.pageId].push({
|
|
|
|
|
name: action.name,
|
|
|
|
|
datasource: {
|
|
|
|
|
$isEmbedded,
|
|
|
|
|
name: action.datasource.name,
|
|
|
|
|
$pluginPackageName: pluginPackageNameByIds[action.datasource.pluginId],
|
|
|
|
|
datasourceConfiguration: action.datasource.datasourceConfiguration,
|
|
|
|
|
invalids: action.datasource.invalids,
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
},
|
|
|
|
|
actionConfiguration: action.actionConfiguration,
|
|
|
|
|
pluginType: action.pluginType,
|
|
|
|
|
executeOnLoad: action.executeOnLoad,
|
|
|
|
|
dynamicBindingPathList: action.dynamicBindingPathList,
|
|
|
|
|
isValid: action.isValid,
|
|
|
|
|
invalids: action.invalids,
|
|
|
|
|
jsonPathKeys: action.jsonPathKeys,
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
_class: action._class,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const pagesById = {};
|
|
|
|
|
for (const page of await db.collection("page").find({_id: {$in: allPageIds}}).toArray()) {
|
|
|
|
|
const pageId = page._id.toString();
|
|
|
|
|
|
|
|
|
|
for (const layout of page.layouts) {
|
|
|
|
|
delete layout._id;
|
|
|
|
|
for (const actionSet of layout.layoutOnLoadActions) {
|
|
|
|
|
for (const action of actionSet) {
|
|
|
|
|
delete action._id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const actionSet of layout.publishedLayoutOnLoadActions) {
|
|
|
|
|
for (const action of actionSet) {
|
|
|
|
|
delete action._id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pagesById[pageId] = {
|
|
|
|
|
name: page.name,
|
|
|
|
|
$isDefault: allDefaultPageIds.has(pageId),
|
|
|
|
|
$actions: actionsByPageId[pageId],
|
|
|
|
|
layouts: page.layouts,
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
_class: page._class,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const application of $applications) {
|
|
|
|
|
application.$pages = [];
|
|
|
|
|
for (const page of application.pages) {
|
|
|
|
|
application.$pages.push(pagesById[page._id]);
|
|
|
|
|
}
|
|
|
|
|
delete application.pages;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const finalData = {
|
|
|
|
|
name: organization.name,
|
|
|
|
|
organizationSettings: organization.organizationSettings,
|
|
|
|
|
slug: organization.slug,
|
|
|
|
|
userRoles: [],
|
|
|
|
|
deleted: false,
|
|
|
|
|
policies: [],
|
|
|
|
|
_class: organization._class,
|
|
|
|
|
$datasources,
|
|
|
|
|
$applications,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (finalData.slug !== "example-apps") {
|
|
|
|
|
console.warn("The slug of the organization in the generated dump is not `example-apps`. This might be significant.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fs.writeFileSync(
|
|
|
|
|
findExamplesJsonPath(),
|
|
|
|
|
JSON.stringify(finalData, null, 2)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findExamplesJsonPath() {
|
|
|
|
|
let projectDir = __dirname;
|
|
|
|
|
|
2022-02-03 04:12:38 +00:00
|
|
|
while (projectDir !== null && !fs.existsSync(path.join(projectDir, "appsmith-server"))) {
|
2020-09-02 11:45:55 +00:00
|
|
|
projectDir = path.dirname(projectDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return path.join(projectDir, "appsmith-server", "src", "main", "resources", "examples-organization.json");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
* Author: flohall
|
|
|
|
|
* date: 2019-11-05
|
|
|
|
|
* file: module/textEncryptor.js
|
|
|
|
|
* Original: <https://stackoverflow.com/a/58720652/151048>.
|
|
|
|
|
*/
|
|
|
|
|
const key = CryptoJS.PBKDF2(ENCRYPTION_PASSWORD, ENCRYPTION_SALT, {
|
|
|
|
|
keySize: 256 / 32,
|
|
|
|
|
iterations: 1024
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const decryptConfig = {
|
|
|
|
|
// same as NULL_IV_GENERATOR of AesBytesEncryptor - so encryption creates always same cipher text for same input
|
|
|
|
|
iv: {words: [0, 0, 0, 0, 0, 0, 0, 0], sigBytes: 0},
|
|
|
|
|
padding: CryptoJS.pad.Pkcs7,
|
|
|
|
|
mode: CryptoJS.mode.CBC
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function decrypt(text) {
|
|
|
|
|
return CryptoJS.AES
|
|
|
|
|
.decrypt({ciphertext: CryptoJS.enc.Hex.parse(text)}, key, decryptConfig)
|
|
|
|
|
.toString(CryptoJS.enc.Utf8);
|
|
|
|
|
}
|