import basicAuth from "express-basic-auth";
import express from "express";
import querystring from "querystring";
import fs from "fs-extra";
import { Low, JSONFile } from "lowdb";
app.use(express.static("public"));
// Docs: https://github.com/typicode/lowdb
const adapter = new JSONFile("db.json");
const db = new Low(adapter);
db.data ||= { loggedInUsers: [] };
users: { admin: "password123" },
async (request, response) => {
const { loggedInUsers } = db.data;
const { user } = request.query;
// Add the user to the database
if (!loggedInUsers.includes(user)) {
loggedInUsers.push(user);
// Create query parameters for redirect back to Canva
const params = querystring.stringify({
state: request.query.state,
// Redirect back to Canva
response.redirect(302, `https://canva.com/apps/configured?${params}`);
// Handle upload requests
app.post("/publish/resources/upload", async (request, response) => {
const { loggedInUsers } = db.data;
const { user } = request.body;
if (loggedInUsers.includes(user)) {
// Ensure the "public" directory exists
await fs.ensureDir("public");
// Get the first asset from the "assets" array
const [asset] = request.body.assets;
const image = await jimp.read(asset.url);
const filePath = path.join("public", asset.name);
await image.writeAsync(filePath);
// Respond with the URL of the published design
protocol: request.protocol,
host: request.get("host"),
// The user not is logged-in
errorCode: "CONFIGURATION_REQUIRED",
// Handle authentication requests
app.post("/configuration", async (request, response) => {
const { loggedInUsers } = db.data;
const { user } = request.body;
if (loggedInUsers.includes(user)) {
// The user is not logged-in
errorCode: "CONFIGURATION_REQUIRED",
// Handle disconnection requests
app.post("/configuration/delete", async (request, response) => {
// Remove the current user from the database
db.data.loggedInUsers = db.data.loggedInUsers.filter((user) => {
return user !== request.body.user;
app.listen(process.env.PORT || 3000);