budibase/packages/server/src/api/controllers/static.js

210 lines
5.5 KiB
JavaScript
Raw Normal View History

2020-05-07 11:53:34 +02:00
const send = require("koa-send")
const { resolve, join } = require("path")
2020-06-19 17:59:46 +02:00
const jwt = require("jsonwebtoken")
2020-06-29 11:27:38 +02:00
const fetch = require("node-fetch")
const fs = require("fs")
2020-09-16 13:18:47 +02:00
const uuid = require("uuid")
2020-09-17 17:36:39 +02:00
const {
budibaseAppsDir,
budibaseTempDir,
} = require("../../utilities/budibaseDir")
const CouchDB = require("../../db")
const setBuilderToken = require("../../utilities/builder/setBuilderToken")
const { ANON_LEVEL_ID } = require("../../utilities/accessLevels")
const fileProcessor = require("../../utilities/fileProcessor")
exports.serveBuilder = async function(ctx) {
2020-09-17 17:36:39 +02:00
let builderPath = resolve(__dirname, "../../../builder")
2020-06-19 17:59:46 +02:00
if (ctx.file === "index.html") {
setBuilderToken(ctx)
}
2020-05-06 13:17:15 +02:00
await send(ctx, ctx.file, { root: ctx.devPath || builderPath })
}
exports.deleteLocalFileUpload = async function(ctx) {
try {
2020-09-17 17:36:39 +02:00
const db = new CouchDB(ctx.user.instanceId)
let fileUploads = await db.get("_local/fileuploads")
2020-09-17 17:36:39 +02:00
fileUploads.uploads = fileUploads.uploads.filter(
upload => upload.fileName !== ctx.params.fileName
)
await db.put(fileUploads)
ctx.body = {
2020-09-17 17:36:39 +02:00
message: `${ctx.fileName} deleted.`,
}
} catch (err) {
ctx.throw(500, err)
}
}
exports.processLocalFileUpload = async function(ctx) {
const { files } = ctx.request.body
2020-09-17 17:36:39 +02:00
const attachmentsPath = resolve(
budibaseAppsDir(),
ctx.user.appId,
"attachments"
)
// create attachments dir if it doesnt exist
2020-09-17 17:36:39 +02:00
!fs.existsSync(attachmentsPath) &&
fs.mkdirSync(attachmentsPath, { recursive: true })
2020-09-16 13:18:47 +02:00
const filesToProcess = files.map(file => {
const fileExtension = [...file.path.split(".")].pop()
// filenames converted to UUIDs so they are unique
const fileName = `${uuid.v4()}.${fileExtension}`
2020-09-16 13:18:47 +02:00
return {
...file,
fileName,
2020-09-16 13:18:47 +02:00
extension: fileExtension,
outputPath: join(attachmentsPath, fileName),
2020-09-17 13:45:28 +02:00
clientUrl: join("/attachments", fileName),
2020-09-16 13:18:47 +02:00
}
})
2020-09-17 17:36:39 +02:00
const fileProcessOperations = filesToProcess.map(file =>
fileProcessor.process(file)
)
try {
2020-09-16 13:18:47 +02:00
// TODO: get file sizes of images after resize
2020-09-17 17:38:33 +02:00
await Promise.all(fileProcessOperations)
2020-09-16 13:18:47 +02:00
2020-09-17 17:36:39 +02:00
let pendingFileUploads
2020-09-16 13:18:47 +02:00
// local document used to track which files need to be uploaded
// db.get throws an error if the document doesn't exist
// need to use a promise to default
2020-09-17 17:36:39 +02:00
const db = new CouchDB(ctx.user.instanceId)
await db
.get("_local/fileuploads")
.then(data => {
pendingFileUploads = data
})
.catch(() => {
pendingFileUploads = { _id: "_local/fileuploads", uploads: [] }
2020-09-16 13:18:47 +02:00
})
2020-09-17 17:38:33 +02:00
pendingFileUploads.uploads = [...filesToProcess, ...pendingFileUploads.uploads]
await db.put(pendingFileUploads)
2020-09-16 13:18:47 +02:00
2020-09-17 17:36:39 +02:00
ctx.body = filesToProcess
} catch (err) {
2020-09-17 17:36:39 +02:00
ctx.throw(500, err)
}
}
exports.serveApp = async function(ctx) {
2020-07-07 22:29:20 +02:00
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
2020-06-29 11:27:38 +02:00
2020-05-03 12:33:20 +02:00
// default to homedir
const appPath = resolve(
2020-05-11 16:42:42 +02:00
budibaseAppsDir(),
2020-05-03 12:33:20 +02:00
ctx.params.appId,
"public",
2020-06-29 11:27:38 +02:00
mainOrAuth
2020-05-07 11:53:34 +02:00
)
2020-07-07 18:47:18 +02:00
let appId = ctx.params.appId
if (process.env.CLOUD) {
appId = ctx.subdomains[1]
}
2020-07-07 22:29:20 +02:00
// only set the appId cookie for /appId .. we COULD check for valid appIds
// but would like to avoid that DB hit
2020-07-07 18:47:18 +02:00
const looksLikeAppId = /^[0-9a-f]{32}$/.test(appId)
2020-06-19 18:21:24 +02:00
if (looksLikeAppId && !ctx.isAuthenticated) {
2020-06-19 17:59:46 +02:00
const anonUser = {
2020-06-18 17:59:31 +02:00
userId: "ANON",
accessLevelId: ANON_LEVEL_ID,
2020-07-07 18:47:18 +02:00
appId,
2020-06-18 17:59:31 +02:00
}
2020-06-19 17:59:46 +02:00
const anonToken = jwt.sign(anonUser, ctx.config.jwtSecret)
2020-06-18 17:59:31 +02:00
ctx.cookies.set("budibase:token", anonToken, {
path: "/",
httpOnly: false,
})
}
2020-07-09 12:21:42 +02:00
if (process.env.CLOUD) {
2020-07-07 22:29:20 +02:00
const S3_URL = `https://${appId}.app.budi.live/assets/${appId}/${mainOrAuth}/${ctx.file ||
"index.production.html"}`
2020-07-08 17:31:26 +02:00
const response = await fetch(S3_URL)
2020-06-29 11:27:38 +02:00
const body = await response.text()
2020-07-07 22:29:20 +02:00
ctx.body = body
return
2020-06-29 11:27:38 +02:00
}
2020-07-06 20:43:40 +02:00
await send(ctx, ctx.file || "index.html", { root: ctx.devPath || appPath })
}
exports.serveAttachment = async function(ctx) {
2020-09-17 17:36:39 +02:00
const appId = ctx.user.appId
const attachmentsPath = resolve(budibaseAppsDir(), appId, "attachments")
// Serve from CloudFront
if (process.env.CLOUD) {
2020-09-17 17:36:39 +02:00
const S3_URL = `https://cdn.app.budi.live/assets/${appId}/attachments/${ctx.file}`
const response = await fetch(S3_URL)
const body = await response.text()
ctx.body = body
return
}
await send(ctx, ctx.file, { root: attachmentsPath })
}
exports.serveAppAsset = async function(ctx) {
// default to homedir
2020-07-07 22:29:20 +02:00
const mainOrAuth = ctx.isAuthenticated ? "main" : "unauthenticated"
2020-06-29 11:27:38 +02:00
const appPath = resolve(
budibaseAppsDir(),
2020-06-18 17:59:31 +02:00
ctx.user.appId,
"public",
2020-06-29 11:27:38 +02:00
mainOrAuth
)
2020-05-03 12:33:20 +02:00
2020-07-06 20:43:40 +02:00
await send(ctx, ctx.file, { root: ctx.devPath || appPath })
}
exports.serveComponentLibrary = async function(ctx) {
2020-05-06 13:17:15 +02:00
// default to homedir
let componentLibraryPath = resolve(
2020-05-11 16:42:42 +02:00
budibaseAppsDir(),
2020-06-18 17:59:31 +02:00
ctx.user.appId,
2020-05-07 11:53:34 +02:00
"node_modules",
decodeURI(ctx.query.library),
"package",
"dist"
2020-05-07 11:53:34 +02:00
)
2020-05-06 13:17:15 +02:00
if (ctx.isDev) {
componentLibraryPath = join(
2020-05-11 16:42:42 +02:00
budibaseTempDir(),
decodeURI(ctx.query.library),
"dist"
2020-05-07 11:53:34 +02:00
)
}
// TODO: component libs should be versioned based on app version
2020-07-06 20:43:40 +02:00
if (process.env.CLOUD) {
const appId = ctx.user.appId
2020-07-07 22:29:20 +02:00
const S3_URL = encodeURI(
`https://${appId}.app.budi.live/assets/componentlibrary/${ctx.query.library}/dist/index.js`
)
2020-07-06 20:43:40 +02:00
const response = await fetch(S3_URL)
const body = await response.text()
2020-07-07 22:29:20 +02:00
ctx.type = "application/javascript"
ctx.body = body
2020-07-06 20:43:40 +02:00
return
}
2020-06-29 11:27:38 +02:00
await send(ctx, "/index.js", { root: componentLibraryPath })
}