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;
|
2019-07-18 09:05:16 +02:00
|
|
|
const { keyBy, last, filter } = require("lodash/fp");
|
2019-07-16 23:14:57 +02:00
|
|
|
const {
|
|
|
|
masterAppPackage,
|
|
|
|
applictionVersionPackage,
|
|
|
|
applictionVersionPublicPaths
|
|
|
|
} = require("../utilities/createAppPackage");
|
2019-10-11 18:14:23 +02:00
|
|
|
const { determineVersionId } = require("./runtimePackages");
|
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;
|
2019-07-18 09:05:16 +02:00
|
|
|
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-07-18 09:05:16 +02:00
|
|
|
}
|
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-10-11 18:14:23 +02:00
|
|
|
const versionId = determineVersionId(instance.version);
|
2019-06-25 23:48:22 +02:00
|
|
|
|
2019-07-05 17:56:53 +02:00
|
|
|
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(
|
2019-07-05 17:56:53 +02:00
|
|
|
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}`);
|
2019-07-05 17:56:53 +02:00
|
|
|
const dsConfig = JSON.parse(session.instanceDatastoreConfig);
|
|
|
|
const instanceDatastore = getInstanceDatastore(dsConfig)
|
2019-10-11 18:14:23 +02:00
|
|
|
|
|
|
|
const versionId = determineVersionId(session.instanceVersion);
|
2019-07-07 10:03:37 +02:00
|
|
|
|
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-10-11 18:14:23 +02:00
|
|
|
const versionId = determineVersionId(app.defaultVersion);
|
2019-09-12 16:55:36 +02:00
|
|
|
const appPublicPaths = applictionVersionPublicPaths(
|
2019-10-11 18:14:23 +02:00
|
|
|
context,
|
2019-09-12 16:55:36 +02:00
|
|
|
app.name,
|
2019-10-11 18:14:23 +02:00
|
|
|
versionId);
|
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-06-16 23:17:22 +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;
|
|
|
|
}
|
2019-07-05 17:56:53 +02:00
|
|
|
}
|
|
|
|
|
2019-06-16 23:17:22 +02:00
|
|
|
const getFullAccessInstanceApiForUsername = async (appname, username) => {
|
|
|
|
|
|
|
|
if(isMaster(appname)) {
|
2019-06-26 23:29:28 +02:00
|
|
|
return bb;
|
2019-06-16 23:17:22 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
const app = await getApplication(appname);
|
2019-07-11 08:35:29 +02:00
|
|
|
const user = await getUser(app.id, username);
|
2019-06-16 23:17:22 +02:00
|
|
|
|
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);
|
2019-06-16 23:17:22 +02:00
|
|
|
const instanceDatastore = getInstanceDatastore(
|
2019-07-05 17:56:53 +02:00
|
|
|
dsConfig
|
|
|
|
);
|
|
|
|
|
2019-10-11 18:14:23 +02:00
|
|
|
const versionId = determineVersionId(
|
|
|
|
(await bb.recordApi.load(user.instance.key)).version
|
|
|
|
);
|
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);
|
2019-07-05 17:56:53 +02:00
|
|
|
|
|
|
|
return await getApisWithFullAccess(
|
|
|
|
instanceDatastore,
|
2019-07-09 08:29:50 +02:00
|
|
|
appPackage);
|
2019-06-16 23:17:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
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-10-11 18:14:23 +02:00
|
|
|
const listApplications = () => applications;
|
|
|
|
|
|
|
|
|
2019-06-14 11:05:46 +02:00
|
|
|
return ({
|
|
|
|
getApplication,
|
|
|
|
getSession,
|
|
|
|
deleteSession,
|
|
|
|
authenticate,
|
2019-06-16 23:17:22 +02:00
|
|
|
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-10-11 18:14:23 +02:00
|
|
|
bbMaster:bb,
|
|
|
|
listApplications
|
2019-06-14 11:05:46 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
}
|