budibase/packages/server/utilities/masterAppInternal.js

306 lines
10 KiB
JavaScript
Raw Normal View History

2019-07-09 08:29:50 +02:00
const {
getApisWithFullAccess,
getApisForSession,
getMasterApisWithFullAccess
} = require("./budibaseApi");
2019-06-14 11:05:46 +02:00
const getDatastore = require("./datastore");
const getDatabaseManager = require("./databaseManager");
2019-09-10 07:14:45 +02:00
const {$, splitKey} = require("@budibase/core").common;
const { keyBy, last, filter } = require("lodash/fp");
2019-07-16 23:14:57 +02:00
const {
masterAppPackage,
applictionVersionPackage,
applictionVersionPublicPaths
} = require("../utilities/createAppPackage");
2019-06-14 11:05:46 +02:00
const isMaster = appname => appname === "_master";
2019-07-09 08:29:50 +02:00
module.exports = async (context) => {
2019-06-14 11:05:46 +02:00
2019-07-09 08:29:50 +02:00
const { config } = context;
2019-06-14 18:01:01 +02:00
const datastoreModule = getDatastore(config);
2019-06-14 11:05:46 +02:00
const databaseManager = getDatabaseManager(
2019-06-14 18:01:01 +02:00
datastoreModule,
2019-06-14 11:05:46 +02:00
config.datastoreConfig);
2019-06-14 18:01:01 +02:00
const masterDatastore = datastoreModule.getDatastore(
databaseManager.masterDatastoreConfig);
2019-07-09 08:29:50 +02:00
const bb = await getMasterApisWithFullAccess(context);
2019-06-14 11:05:46 +02:00
let applications;
const loadApplications = async () => {
const apps = await bb.indexApi.listItems("/all_applications");
applications = $(apps, [
filter(a => !!a.defaultVersion.key),
2019-06-14 11:05:46 +02:00
keyBy("name")
]);
}
2019-06-14 11:05:46 +02:00
await loadApplications();
2019-06-14 18:01:01 +02:00
const getInstanceDatastore = (instanceDatastoreConfig) =>
datastoreModule.getDatastore(instanceDatastoreConfig);
2019-06-14 11:05:46 +02:00
const getCustomSessionId = (appname, sessionId) =>
isMaster(appname)
? bb.recordApi.customId("mastersession", sessionId)
: bb.recordApi.customId("session", sessionId);
2019-07-11 08:35:29 +02:00
const getApplication = async (nameOrKey, isRetry=false) => {
if(applications[nameOrKey])
return applications[nameOrKey];
for(let name in applications) {
const a = applications[name];
if(a.key === nameOrKey) return a;
if(a.id === nameOrKey) return a;
}
if(isRetry) return;
2019-06-14 11:05:46 +02:00
await loadApplications();
2019-07-11 08:35:29 +02:00
return await getApplication(nameOrKey, true);
2019-06-14 11:05:46 +02:00
};
const getSession = async (sessionId, appname) => {
const customSessionId = getCustomSessionId(appname, sessionId);
if(isMaster(appname)) {
return await bb.recordApi.load(`/sessions/${customSessionId}`);
}
else {
const app = await getApplication(appname);
return await bb.recordApi.load(`/applications/${app.id}/sessions/${customSessionId}`);
}
};
const deleteSession = async (sessionId, appname) => {
const customSessionId = getCustomSessionId(appname, sessionId);
if(isMaster(appname)) {
return await bb.recordApi.delete(`/sessions/${customSessionId}`);
}
else {
const app = await getApplication(appname);
return await bb.recordApi.delete(`/applications/${app.id}/sessions/${customSessionId}`);
}
};
const authenticate = async (sessionId, appname, username, password, instanceName="default") => {
if(isMaster(appname)) {
const authUser = await bb.authApi.authenticate(username, password);
if(!authUser) {
return null;
}
const session = bb.recordApi.getNew("/sessions", "mastersession");
bb.recordApi.setCustomId(session, sessionId);
session.user_json = JSON.stringify(authUser);
2019-06-19 23:05:53 +02:00
session.username = username;
2019-06-14 11:05:46 +02:00
await bb.recordApi.save(session);
return session;
}
const app = await getApplication(appname);
2019-07-11 08:35:29 +02:00
const userInMaster = await getUser(app.id, username);
2019-07-07 10:03:37 +02:00
if(!userInMaster) return null;
2019-06-14 11:05:46 +02:00
const instance = await bb.recordApi.load(
2019-07-11 08:35:29 +02:00
userInMaster.instance.key);
2019-06-14 11:05:46 +02:00
2019-06-25 23:48:22 +02:00
const versionId = $(instance.version.key, [
splitKey,
last
]);
const dsConfig = JSON.parse(instance.datastoreconfig);
2019-07-09 08:29:50 +02:00
const appPackage = await applictionVersionPackage(
context, appname, versionId, instance.key);
2019-06-14 11:05:46 +02:00
const bbInstance = await getApisWithFullAccess(
datastoreModule.getDatastore(dsConfig),
2019-07-09 08:29:50 +02:00
appPackage
2019-06-25 23:48:22 +02:00
);
2019-06-14 11:05:46 +02:00
const authUser = await bbInstance.authApi.authenticate(username, password);
if(!authUser) {
return null;
}
const session = bb.recordApi.getNew(`/applications/${app.id}/sessions`, "session");
bb.recordApi.setCustomId(session, sessionId);
session.user_json = JSON.stringify(authUser);
session.instanceDatastoreConfig = instance.datastoreconfig;
2019-07-09 08:29:50 +02:00
session.instanceKey = instance.key;
2019-06-19 23:05:53 +02:00
session.username = username;
2019-07-07 10:03:37 +02:00
session.instanceVersion = instance.version.key;
2019-06-14 11:05:46 +02:00
await bb.recordApi.save(session);
return session;
};
const getInstanceApiForSession = async (appname, sessionId) => {
if(isMaster(appname)) {
2019-06-14 18:01:01 +02:00
const customId = bb.recordApi.customId("mastersession", sessionId);
2019-07-16 23:14:57 +02:00
const masterPkg = masterAppPackage(context);
2019-06-21 15:00:24 +02:00
try {
const session = await bb.recordApi.load(`/sessions/${customId}`);
2019-07-16 23:14:57 +02:00
return ({
instance: await getApisForSession(
masterDatastore,
masterAppPackage(context),
session),
2019-09-12 16:55:36 +02:00
publicPath: masterPkg.mainUiPath,
sharedPath: masterPkg.sharedPath
2019-07-16 23:14:57 +02:00
});
2019-06-25 23:48:22 +02:00
2019-06-21 15:00:24 +02:00
} catch(_) {
2019-07-16 23:14:57 +02:00
return ({
instance: null,
2019-09-12 16:55:36 +02:00
publicPath: masterPkg.unauthenticatedUiPath,
sharedPath: masterPkg.sharedPath
2019-07-16 23:14:57 +02:00
});
2019-06-21 15:00:24 +02:00
}
2019-06-14 11:05:46 +02:00
}
else {
const app = await getApplication(appname);
const customId = bb.recordApi.customId("session", sessionId);
2019-06-21 15:00:24 +02:00
try {
const session = await bb.recordApi.load(`/applications/${app.id}/sessions/${customId}`);
const dsConfig = JSON.parse(session.instanceDatastoreConfig);
const instanceDatastore = getInstanceDatastore(dsConfig)
2019-07-07 10:03:37 +02:00
const versionId = $(session.instanceVersion,[
splitKey,
last
]);
2019-07-09 08:29:50 +02:00
const appPackage = await applictionVersionPackage(
context, appname, versionId, session.instanceKey);
2019-07-16 23:14:57 +02:00
return ({
instance: await getApisForSession(
instanceDatastore,
appPackage,
session),
2019-09-12 16:55:36 +02:00
publicPath: appPackage.mainUiPath,
sharedPath: appPackage.sharedPath
2019-07-16 23:14:57 +02:00
});
2019-06-21 15:00:24 +02:00
} catch(_) {
2019-09-12 16:55:36 +02:00
const appPublicPaths = applictionVersionPublicPaths(
app.name,
app.defaultVersion.id);
2019-07-16 23:14:57 +02:00
return ({
instance:null,
2019-09-12 16:55:36 +02:00
publicPath: appPublicPaths.unauthenticatedUiPath,
sharedPath: appPublicPaths.sharedPath
2019-07-16 23:14:57 +02:00
});
2019-06-21 15:00:24 +02:00
}
2019-06-14 11:05:46 +02:00
}
};
2019-07-11 08:35:29 +02:00
const getUser = async (appId, username ) => {
const userId = bb.recordApi.customId("user", username);
try {
return await bb.recordApi.load(
`/applications/${appId}/users/${userId}`);
} catch(_) {
//empty
return;
}
}
const getFullAccessInstanceApiForUsername = async (appname, username) => {
if(isMaster(appname)) {
2019-06-26 23:29:28 +02:00
return bb;
}
else {
const app = await getApplication(appname);
2019-07-11 08:35:29 +02:00
const user = await getUser(app.id, username);
2019-07-07 10:03:37 +02:00
if(!user) return null;
2019-07-11 08:35:29 +02:00
const dsConfig = JSON.parse(user.instance.datastoreconfig);
const instanceDatastore = getInstanceDatastore(
dsConfig
);
2019-07-11 08:35:29 +02:00
const versionId = $((await bb.recordApi.load(user.instance.key)).version.key, [
splitKey,
last
]);
2019-07-09 08:29:50 +02:00
const appPackage = await applictionVersionPackage(
2019-07-11 08:35:29 +02:00
context, appname, versionId, user.instance.key);
return await getApisWithFullAccess(
instanceDatastore,
2019-07-09 08:29:50 +02:00
appPackage);
}
};
2019-06-14 11:05:46 +02:00
2019-06-19 23:05:53 +02:00
const removeSessionsForUser = async (appname, username) => {
if(isMaster(appname)) {
const sessions = await bb.indexApi.listItems(
"/mastersessions_by_user",
{
2019-06-21 09:42:37 +02:00
rangeStartParams:{username},
2019-06-21 15:00:24 +02:00
rangeEndParams:{username},
searchPhrase:`username:${username}`
2019-06-19 23:05:53 +02:00
}
);
for(let session of sessions) {
await bb.recordApi.delete(session.key);
}
}
else {
const app = await getApplication(appname);
const sessions = await bb.indexApi.listItems(
`/applications/${app.id}/sessions_by_user`,
{
2019-07-11 08:35:29 +02:00
rangeStartParams:{username},
rangeEndParams:{username},
2019-06-19 23:05:53 +02:00
searchPhrase:`username:${username}`
}
);
for(let session of sessions) {
await bb.recordApi.delete(session.key);
}
}
}
2019-07-09 08:29:50 +02:00
const disableUser = async (app, username) => {
2019-07-11 08:35:29 +02:00
await removeSessionsForUser(app.name, username);
const userInMaster = await getUser(app.id, username);
2019-07-09 08:29:50 +02:00
userInMaster.active = false;
await bb.recordApi.save(userInMaster);
}
const enableUser = async (app, username) => {
2019-07-11 08:35:29 +02:00
const userInMaster = await getUser(app.id, username);
2019-07-09 08:29:50 +02:00
userInMaster.active = true;
await bb.recordApi.save(userInMaster);
}
2019-06-14 11:05:46 +02:00
return ({
getApplication,
getSession,
deleteSession,
authenticate,
getInstanceApiForSession,
getFullAccessInstanceApiForUsername,
2019-06-25 23:48:22 +02:00
removeSessionsForUser,
2019-07-09 08:29:50 +02:00
disableUser,
enableUser,
2019-07-11 08:35:29 +02:00
getUser,
2019-06-25 23:48:22 +02:00
bbMaster:bb
2019-06-14 11:05:46 +02:00
});
}