386 lines
11 KiB
JavaScript
386 lines
11 KiB
JavaScript
const {
|
|
getApisWithFullAccess,
|
|
getApisForSession,
|
|
getMasterApisWithFullAccess,
|
|
} = require("./budibaseApi")
|
|
const getDatastore = require("./datastore")
|
|
const getDatabaseManager = require("./databaseManager")
|
|
const { $ } = require("@budibase/core").common
|
|
const { keyBy, values, cloneDeep } = require("lodash/fp")
|
|
const {
|
|
masterAppPackage,
|
|
applictionVersionPackage,
|
|
applictionVersionPublicPaths,
|
|
deleteCachedPackage,
|
|
} = require("../utilities/createAppPackage")
|
|
const { determineVersionId, LATEST_VERSIONID } = require("./runtimePackages")
|
|
|
|
const isMaster = appname => appname === "_master"
|
|
|
|
module.exports = async context => {
|
|
const { config } = context
|
|
const datastoreModule = getDatastore(config)
|
|
|
|
const databaseManager = getDatabaseManager(
|
|
datastoreModule,
|
|
config.datastoreConfig
|
|
)
|
|
|
|
const masterDatastore = datastoreModule.getDatastore(
|
|
databaseManager.masterDatastoreConfig
|
|
)
|
|
|
|
const bb = await getMasterApisWithFullAccess(context)
|
|
|
|
let applications
|
|
const loadApplications = async () => {
|
|
const apps = await bb.indexApi.listItems("/all_applications")
|
|
applications = $(apps, [keyBy("name")])
|
|
}
|
|
await loadApplications()
|
|
|
|
const getInstanceDatastore = instanceDatastoreConfig =>
|
|
datastoreModule.getDatastore(instanceDatastoreConfig)
|
|
|
|
const getCustomSessionId = (appname, sessionId) =>
|
|
isMaster(appname)
|
|
? bb.recordApi.customId("mastersession", sessionId)
|
|
: bb.recordApi.customId("session", sessionId)
|
|
|
|
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
|
|
|
|
await loadApplications()
|
|
|
|
return await getApplication(nameOrKey, true)
|
|
}
|
|
|
|
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 createAppUser = async (appname, instance, user, password) => {
|
|
if (isMaster(appname)) {
|
|
throw new Error("This method is for creating app users - not on master!")
|
|
}
|
|
|
|
const versionId = determineVersionId(instance.version)
|
|
const dsConfig = JSON.parse(instance.datastoreconfig)
|
|
const appPackage = await applictionVersionPackage(
|
|
context,
|
|
appname,
|
|
versionId,
|
|
instance.key
|
|
)
|
|
|
|
const bbInstance = await getApisWithFullAccess(
|
|
datastoreModule.getDatastore(dsConfig),
|
|
appPackage
|
|
)
|
|
|
|
await bbInstance.authApi.createUser(user, password)
|
|
}
|
|
|
|
const authenticate = async (sessionId, appname, username, password) => {
|
|
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)
|
|
session.username = username
|
|
await bb.recordApi.save(session)
|
|
return session
|
|
}
|
|
|
|
const app = await getApplication(appname)
|
|
|
|
const userInMaster = await getUser(app.id, username)
|
|
if (!userInMaster) return null
|
|
|
|
const { instance, bbInstance } = await getFullAccessApiForInstanceId(
|
|
appname,
|
|
userInMaster.instance.id,
|
|
app.id
|
|
)
|
|
|
|
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
|
|
session.instanceKey = instance.key
|
|
session.username = username
|
|
session.instanceVersion = instance.version.key
|
|
await bb.recordApi.save(session)
|
|
return session
|
|
}
|
|
|
|
const getFullAccessApiForInstanceId = async (appname, instanceId, appId) => {
|
|
if (!appId) {
|
|
const app = await getApplication(appname)
|
|
appId = app.id
|
|
}
|
|
const instanceKey = `/applications/${appId}/instances/${instanceId}`
|
|
const instance = await bb.recordApi.load(instanceKey)
|
|
|
|
const versionId = determineVersionId(instance.version)
|
|
|
|
const dsConfig = JSON.parse(instance.datastoreconfig)
|
|
const appPackage = await applictionVersionPackage(
|
|
context,
|
|
appname,
|
|
versionId,
|
|
instance.key
|
|
)
|
|
return {
|
|
bbInstance: await getApisWithFullAccess(
|
|
getInstanceDatastore(dsConfig),
|
|
appPackage
|
|
),
|
|
instance,
|
|
publicPath: appPackage.mainUiPath,
|
|
sharedPath: appPackage.sharedPath,
|
|
}
|
|
}
|
|
|
|
const getFullAccessApiForMaster = async () => {
|
|
const masterPkg = masterAppPackage(context)
|
|
const instance = await getApisWithFullAccess(masterDatastore, masterPkg)
|
|
|
|
return {
|
|
instance,
|
|
publicPath: masterPkg.unauthenticatedUiPath,
|
|
sharedPath: masterPkg.sharedPath,
|
|
}
|
|
}
|
|
|
|
const getInstanceApiForSession = async (appname, sessionId) => {
|
|
if (isMaster(appname)) {
|
|
const customId = bb.recordApi.customId("mastersession", sessionId)
|
|
const masterPkg = masterAppPackage(context)
|
|
try {
|
|
const session = await bb.recordApi.load(`/sessions/${customId}`)
|
|
return {
|
|
instance: await getApisForSession(
|
|
masterDatastore,
|
|
masterAppPackage(context),
|
|
session
|
|
),
|
|
publicPath: masterPkg.mainUiPath,
|
|
sharedPath: masterPkg.sharedPath,
|
|
}
|
|
} catch (_) {
|
|
return {
|
|
instance: null,
|
|
publicPath: masterPkg.unauthenticatedUiPath,
|
|
sharedPath: masterPkg.sharedPath,
|
|
}
|
|
}
|
|
} else {
|
|
const app = await getApplication(appname)
|
|
const customId = bb.recordApi.customId("session", sessionId)
|
|
try {
|
|
const session = await bb.recordApi.load(
|
|
`/applications/${app.id}/sessions/${customId}`
|
|
)
|
|
const dsConfig = JSON.parse(session.instanceDatastoreConfig)
|
|
const instanceDatastore = getInstanceDatastore(dsConfig)
|
|
|
|
const versionId = determineVersionId(session.instanceVersion)
|
|
|
|
const appPackage = await applictionVersionPackage(
|
|
context,
|
|
appname,
|
|
versionId,
|
|
session.instanceKey
|
|
)
|
|
|
|
return {
|
|
instance: await getApisForSession(
|
|
instanceDatastore,
|
|
appPackage,
|
|
session
|
|
),
|
|
publicPath: appPackage.mainUiPath,
|
|
sharedPath: appPackage.sharedPath,
|
|
}
|
|
} catch (_) {
|
|
const versionId = determineVersionId(app.defaultVersion)
|
|
const appPublicPaths = applictionVersionPublicPaths(
|
|
context,
|
|
app.name,
|
|
versionId
|
|
)
|
|
return {
|
|
instance: null,
|
|
publicPath: appPublicPaths.unauthenticatedUiPath,
|
|
sharedPath: appPublicPaths.sharedPath,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
return bb
|
|
} else {
|
|
const app = await getApplication(appname)
|
|
const user = await getUser(app.id, username)
|
|
|
|
if (!user) return null
|
|
|
|
const dsConfig = JSON.parse(user.instance.datastoreconfig)
|
|
const instanceDatastore = getInstanceDatastore(dsConfig)
|
|
|
|
const versionId = determineVersionId(
|
|
(await bb.recordApi.load(user.instance.key)).version
|
|
)
|
|
|
|
const appPackage = await applictionVersionPackage(
|
|
context,
|
|
appname,
|
|
versionId,
|
|
user.instance.key
|
|
)
|
|
|
|
return await getApisWithFullAccess(instanceDatastore, appPackage)
|
|
}
|
|
}
|
|
|
|
const removeSessionsForUser = async (appname, username) => {
|
|
if (isMaster(appname)) {
|
|
const sessions = await bb.indexApi.listItems("/mastersessions_by_user", {
|
|
rangeStartParams: { username },
|
|
rangeEndParams: { username },
|
|
searchPhrase: `username:${username}`,
|
|
})
|
|
|
|
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`,
|
|
{
|
|
rangeStartParams: { username },
|
|
rangeEndParams: { username },
|
|
searchPhrase: `username:${username}`,
|
|
}
|
|
)
|
|
|
|
for (let session of sessions) {
|
|
await bb.recordApi.delete(session.key)
|
|
}
|
|
}
|
|
}
|
|
|
|
const clearAllSessions = async appname => {
|
|
if (isMaster(appname)) {
|
|
await bb.collectionApi.delete("/mastersessions")
|
|
} else {
|
|
const app = await getApplication(appname)
|
|
await bb.collectionApi.delete(`/applications/${app.id}/sessions`)
|
|
}
|
|
}
|
|
|
|
const getApplicationWithInstances = async appname => {
|
|
const app = cloneDeep(await getApplication(appname))
|
|
|
|
app.instances = await bb.indexApi.listItems(
|
|
`/applications/${app.id}/allinstances`
|
|
)
|
|
return app
|
|
}
|
|
|
|
const disableUser = async (app, username) => {
|
|
await removeSessionsForUser(app.name, username)
|
|
const userInMaster = await getUser(app.id, username)
|
|
userInMaster.active = false
|
|
await bb.recordApi.save(userInMaster)
|
|
}
|
|
|
|
const enableUser = async (app, username) => {
|
|
const userInMaster = await getUser(app.id, username)
|
|
userInMaster.active = true
|
|
await bb.recordApi.save(userInMaster)
|
|
}
|
|
|
|
const deleteLatestPackageFromCache = appname => {
|
|
deleteCachedPackage(context, appname, LATEST_VERSIONID)
|
|
}
|
|
|
|
const listApplications = () => values(applications)
|
|
|
|
return {
|
|
getApplication,
|
|
getSession,
|
|
deleteSession,
|
|
authenticate,
|
|
getInstanceApiForSession,
|
|
getFullAccessInstanceApiForUsername,
|
|
removeSessionsForUser,
|
|
disableUser,
|
|
enableUser,
|
|
getUser,
|
|
createAppUser,
|
|
bbMaster: bb,
|
|
listApplications,
|
|
getFullAccessApiForInstanceId,
|
|
getFullAccessApiForMaster,
|
|
getApplicationWithInstances,
|
|
deleteLatestPackageFromCache,
|
|
clearAllSessions,
|
|
}
|
|
}
|