Skip to content

Commit

Permalink
fix: safe loading of content type names such as then
Browse files Browse the repository at this point in the history
  • Loading branch information
innerdvations committed Apr 29, 2024
1 parent 53cf1f1 commit 19fab61
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export const getReservedNames = () => {
'date-time',
'time',
'upload',
'then', // https://github.com/strapi/strapi/issues/15557
'document',
'then', // no longer an issue but still restricting for being a javascript keyword
],
// attributes are compared with snake_case(name), so only snake_case is needed here and camelCase + UPPER_CASE matches will still be caught
attributes: [
Expand Down
25 changes: 15 additions & 10 deletions packages/core/core/src/loaders/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default async function loadAPIs(strapi: Core.Strapi) {
const apiName = normalizeName(apiFD.name);
const api = await loadAPI(apiName, join(strapi.dirs.dist.api, apiFD.name));

// @ts-expect-error TODO verify that it's a valid api, not missing bootstrap, register, and destroy
apis[apiName] = api;
}

Expand Down Expand Up @@ -85,7 +86,7 @@ const validateContentTypesUnicity = (apis: APIs) => {
};

const loadAPI = async (apiName: string, dir: string) => {
const [index, config, routes, controllers, services, policies, middlewares, contentTypes] =
const [index, config, routes, controllers, services, policies, middlewares, contentTypes] = (
await Promise.all([
loadIndex(dir),
loadDir(join(dir, 'config')),
Expand All @@ -95,7 +96,8 @@ const loadAPI = async (apiName: string, dir: string) => {
loadDir(join(dir, 'policies')),
loadDir(join(dir, 'middlewares')),
loadContentTypes(apiName, join(dir, 'content-types')),
]);
])
).map((result) => result?.result);

return {
...(index || {}),
Expand All @@ -115,6 +117,7 @@ const loadIndex = async (dir: string) => {
}
};

// because this is async and its contents are dynamic, we must return it within an object to avoid a property called `then` being interpreted as a Promise
const loadContentTypes = async (apiName: string, dir: string) => {
if (!(await fse.pathExists(dir))) {
return;
Expand All @@ -130,7 +133,7 @@ const loadContentTypes = async (apiName: string, dir: string) => {
}

const contentTypeName = normalizeName(fd.name);
const loadedContentType = await loadDir(join(dir, fd.name));
const loadedContentType = (await loadDir(join(dir, fd.name)))?.result;

if (isEmpty(loadedContentType) || isEmpty(loadedContentType.schema)) {
throw new Error(`Could not load content type found at ${dir}`);
Expand All @@ -150,9 +153,10 @@ const loadContentTypes = async (apiName: string, dir: string) => {
contentTypes[normalizeName(contentTypeName)] = contentType;
}

return contentTypes;
return { result: contentTypes };
};

// because this is async and its contents are dynamic, we must return it within an object to avoid a property called `then` being interpreted as a Promise
const loadDir = async (dir: string) => {
if (!(await fse.pathExists(dir))) {
return;
Expand All @@ -168,21 +172,22 @@ const loadDir = async (dir: string) => {

const key = basename(fd.name, extname(fd.name));

root[normalizeName(key)] = await loadFile(join(dir, fd.name));
root[normalizeName(key)] = (await loadFile(join(dir, fd.name))).result;
}

return root;
return { result: root };
};

const loadFile = (file: string) => {
// because this is async and its contents are dynamic, we must return it as an array to avoid a property called `then` being interpreted as a Promise
const loadFile = async (file: string): Promise<{ result: unknown }> => {
const ext = extname(file);

switch (ext) {
case '.js':
return importDefault(file);
return { result: importDefault(file) };
case '.json':
return fse.readJSON(file);
return { result: await fse.readJSON(file) };
default:
return {};
return { result: {} };
}
};

0 comments on commit 19fab61

Please sign in to comment.