replaces sanitization
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { DeepRequired } from 'ts-essentials';
|
||||
import { PayloadRequest } from '../express/types/payloadRequest';
|
||||
|
||||
export type Permission = {
|
||||
@@ -67,30 +68,28 @@ export interface IncomingAuthType {
|
||||
verify?:
|
||||
| boolean
|
||||
| {
|
||||
generateEmailHTML: GenerateVerifyEmailHTML;
|
||||
generateEmailSubject: GenerateVerifyEmailSubject;
|
||||
generateEmailHTML?: GenerateVerifyEmailHTML;
|
||||
generateEmailSubject?: GenerateVerifyEmailSubject;
|
||||
};
|
||||
maxLoginAttempts?: number;
|
||||
lockTime?: number;
|
||||
useAPIKey?: boolean;
|
||||
cookies?:
|
||||
| {
|
||||
cookies?: {
|
||||
secure?: boolean;
|
||||
sameSite?: string;
|
||||
domain?: string;
|
||||
}
|
||||
| boolean;
|
||||
forgotPassword?: {
|
||||
generateEmailHTML?: GenerateForgotPasswordEmailHTML,
|
||||
generateEmailSubject?: GenerateForgotPasswordEmailSubject,
|
||||
}
|
||||
}
|
||||
|
||||
export interface Auth extends Omit<IncomingAuthType, 'verify' | 'forgotPassword'> {
|
||||
export interface Auth extends Omit<DeepRequired<IncomingAuthType>, 'verify' | 'forgotPassword'> {
|
||||
verify?: {
|
||||
generateEmailHTML?: GenerateVerifyEmailHTML
|
||||
generateEmailSubject?: GenerateVerifyEmailSubject
|
||||
}
|
||||
} | boolean
|
||||
forgotPassword?: {
|
||||
generateEmailHTML?: GenerateForgotPasswordEmailHTML
|
||||
generateEmailSubject?: GenerateForgotPasswordEmailSubject
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import merge from 'deepmerge';
|
||||
import { PayloadCollectionConfig, CollectionConfig } from './types';
|
||||
import { CollectionConfig, PayloadCollectionConfig } from './types';
|
||||
import sanitizeFields from '../../fields/config/sanitize';
|
||||
import toKebabCase from '../../utilities/toKebabCase';
|
||||
import baseAuthFields from '../../fields/baseFields/baseFields';
|
||||
@@ -58,20 +58,30 @@ const sanitizeCollection = (collections: PayloadCollectionConfig[], collection:
|
||||
// Make copy of collection config
|
||||
// /////////////////////////////////
|
||||
|
||||
const sanitized: PayloadCollectionConfig = { ...collection };
|
||||
const sanitized = { ...collection };
|
||||
sanitized.slug = toKebabCase(sanitized.slug);
|
||||
sanitized.labels = !sanitized.labels ? formatLabels(sanitized.slug) : sanitized.labels;
|
||||
|
||||
// /////////////////////////////////
|
||||
// Add required base fields
|
||||
// Ensure that collection has required object structure
|
||||
// /////////////////////////////////
|
||||
|
||||
if (collection.upload) {
|
||||
if (typeof collection.upload === 'object') {
|
||||
sanitized.upload = collection.upload;
|
||||
} else {
|
||||
sanitized.upload = {};
|
||||
}
|
||||
if (!sanitized.hooks) sanitized.hooks = {};
|
||||
if (!sanitized.access) sanitized.access = {};
|
||||
if (!sanitized.admin) sanitized.admin = {};
|
||||
|
||||
if (!sanitized.hooks.beforeOperation) sanitized.hooks.beforeOperation = [];
|
||||
if (!sanitized.hooks.beforeValidate) sanitized.hooks.beforeValidate = [];
|
||||
if (!sanitized.hooks.beforeChange) sanitized.hooks.beforeChange = [];
|
||||
if (!sanitized.hooks.afterChange) sanitized.hooks.afterChange = [];
|
||||
if (!sanitized.hooks.beforeRead) sanitized.hooks.beforeRead = [];
|
||||
if (!sanitized.hooks.afterRead) sanitized.hooks.afterRead = [];
|
||||
if (!sanitized.hooks.beforeDelete) sanitized.hooks.beforeDelete = [];
|
||||
if (!sanitized.hooks.afterDelete) sanitized.hooks.afterDelete = [];
|
||||
|
||||
|
||||
if (sanitized.upload) {
|
||||
if (sanitized.upload === true) sanitized.upload = {};
|
||||
|
||||
if (!sanitized.upload.staticDir) sanitized.upload.staticDir = sanitized.slug;
|
||||
if (!sanitized.upload.staticURL) sanitized.upload.staticURL = `/${sanitized.slug}`;
|
||||
@@ -91,13 +101,18 @@ const sanitizeCollection = (collections: PayloadCollectionConfig[], collection:
|
||||
];
|
||||
}
|
||||
|
||||
if (collection.auth) {
|
||||
if (sanitized.auth) {
|
||||
if (typeof collection.auth === 'object') {
|
||||
sanitized.auth = collection.auth;
|
||||
} else {
|
||||
sanitized.auth = {};
|
||||
}
|
||||
|
||||
if (!sanitized.hooks.beforeLogin) sanitized.hooks.beforeLogin = [];
|
||||
if (!sanitized.hooks.afterLogin) sanitized.hooks.afterLogin = [];
|
||||
if (!sanitized.hooks.afterForgotPassword) sanitized.hooks.afterForgotPassword = [];
|
||||
if (!sanitized.auth.forgotPassword) sanitized.auth.forgotPassword = {};
|
||||
|
||||
let authFields = baseAuthFields;
|
||||
|
||||
if (sanitized.auth.useAPIKey) {
|
||||
@@ -105,13 +120,10 @@ const sanitizeCollection = (collections: PayloadCollectionConfig[], collection:
|
||||
}
|
||||
|
||||
if (sanitized.auth.verify) {
|
||||
if (sanitized.auth.verify === true) sanitized.auth.verify = {};
|
||||
authFields = authFields.concat(baseVerificationFields);
|
||||
}
|
||||
|
||||
if (!sanitized?.hooks?.beforeLogin) sanitized.hooks.beforeLogin = [];
|
||||
if (!sanitized?.hooks?.afterLogin) sanitized.hooks.afterLogin = [];
|
||||
if (!sanitized?.hooks?.afterForgotPassword) sanitized.hooks.afterForgotPassword = [];
|
||||
|
||||
sanitized.auth.maxLoginAttempts = typeof sanitized.auth.maxLoginAttempts === 'undefined' ? 5 : sanitized.auth.maxLoginAttempts;
|
||||
sanitized.auth.lockTime = sanitized.auth.lockTime || 600000; // 10 minutes
|
||||
|
||||
@@ -129,7 +141,6 @@ const sanitizeCollection = (collections: PayloadCollectionConfig[], collection:
|
||||
if (!sanitized.auth.cookies.secure) sanitized.auth.cookies.secure = false;
|
||||
if (!sanitized.auth.cookies.sameSite) sanitized.auth.cookies.sameSite = 'Lax';
|
||||
}
|
||||
|
||||
authFields = mergeBaseFields(sanitized.fields, authFields);
|
||||
|
||||
sanitized.fields = [
|
||||
@@ -145,7 +156,7 @@ const sanitizeCollection = (collections: PayloadCollectionConfig[], collection:
|
||||
const validRelationships = collections.map((c) => c.slug);
|
||||
sanitized.fields = sanitizeFields(sanitized.fields, validRelationships);
|
||||
|
||||
return sanitized;
|
||||
return sanitized as CollectionConfig;
|
||||
};
|
||||
|
||||
export default sanitizeCollection;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { PaginateModel, Document, PassportLocalModel } from 'mongoose';
|
||||
import { Access } from '../../config/types';
|
||||
import { Field } from '../../fields/config/types';
|
||||
import { PayloadRequest } from '../../express/types/payloadRequest';
|
||||
import { Auth } from '../../auth/types';
|
||||
import { IncomingAuthType, Auth } from '../../auth/types';
|
||||
import { IncomingUploadType, Upload } from '../../uploads/types';
|
||||
|
||||
interface CollectionModel extends PaginateModel<Document>, PassportLocalModel<Document>{}
|
||||
|
||||
@@ -79,20 +80,6 @@ export type AfterForgotPasswordHook = (args?: {
|
||||
args?: any;
|
||||
}) => any;
|
||||
|
||||
export type ImageSize = {
|
||||
name: string,
|
||||
width: number,
|
||||
height: number,
|
||||
crop: string, // comes from sharp package
|
||||
};
|
||||
|
||||
export type Upload = {
|
||||
imageSizes?: ImageSize[];
|
||||
staticURL?: string;
|
||||
staticDir?: string;
|
||||
adminThumbnail?: string;
|
||||
}
|
||||
|
||||
export type PayloadCollectionConfig = {
|
||||
slug: string;
|
||||
labels?: {
|
||||
@@ -126,13 +113,13 @@ export type PayloadCollectionConfig = {
|
||||
admin?: Access;
|
||||
unlock?: Access;
|
||||
};
|
||||
auth?: Auth | boolean;
|
||||
upload?: Upload | boolean;
|
||||
auth?: IncomingAuthType | boolean;
|
||||
upload?: IncomingUploadType | boolean;
|
||||
};
|
||||
|
||||
export interface CollectionConfig extends DeepRequired<PayloadCollectionConfig> {
|
||||
auth: DeepRequired<Auth>
|
||||
upload: DeepRequired<Upload>
|
||||
export interface CollectionConfig extends Omit<DeepRequired<PayloadCollectionConfig>, 'auth' | 'upload'> {
|
||||
auth: Auth | boolean
|
||||
upload: Upload | boolean
|
||||
}
|
||||
|
||||
export type Collection = {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { PayloadConfig, Config } from './types';
|
||||
import sanitize from './sanitize';
|
||||
import validate from './validate';
|
||||
|
||||
/**
|
||||
* @description Builds and validates Payload configuration
|
||||
@@ -8,8 +7,7 @@ import validate from './validate';
|
||||
* @returns Built and sanitized Payload Config
|
||||
*/
|
||||
export function buildConfig(config: PayloadConfig): Config {
|
||||
const validated = validate(config);
|
||||
const sanitized = sanitize(validated);
|
||||
const sanitized = sanitize(config);
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import path from 'path';
|
||||
import { Config } from './types';
|
||||
import findConfig from './find';
|
||||
import validate from './validate';
|
||||
|
||||
const removedExtensions = ['.scss', '.css', '.svg', '.png', '.jpg', '.eot', '.ttf', '.woff', '.woff2'];
|
||||
|
||||
@@ -14,14 +15,16 @@ const loadConfig = (): Config => {
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
let publicConfig = require(configPath);
|
||||
let config = require(configPath);
|
||||
|
||||
if (publicConfig.default) publicConfig = publicConfig.default;
|
||||
if (config.default) config = config.default;
|
||||
|
||||
const validatedConfig = validate(config);
|
||||
|
||||
return {
|
||||
...publicConfig,
|
||||
...validatedConfig,
|
||||
paths: {
|
||||
...(publicConfig.paths || {}),
|
||||
...(validatedConfig.paths || {}),
|
||||
configDir: path.dirname(configPath),
|
||||
config: configPath,
|
||||
},
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { Config } from './types';
|
||||
import { PayloadConfig, Config } from './types';
|
||||
import defaultUser from '../auth/defaultUser';
|
||||
import sanitizeCollection from '../collections/config/sanitize';
|
||||
import { InvalidConfiguration } from '../errors';
|
||||
import sanitizeGlobals from '../globals/config/sanitize';
|
||||
import checkDuplicateCollections from '../utilities/checkDuplicateCollections';
|
||||
|
||||
const sanitizeConfig = (config: Config): Config => {
|
||||
const sanitizeConfig = (config: PayloadConfig): Config => {
|
||||
const sanitizedConfig = { ...config };
|
||||
|
||||
sanitizedConfig.csrf.push(config.serverURL);
|
||||
if (sanitizedConfig.publicENV === undefined) sanitizedConfig.publicENV = {};
|
||||
|
||||
if (sanitizedConfig.defaultDepth === undefined) sanitizedConfig.defaultDepth = 2;
|
||||
|
||||
sanitizedConfig.collections = sanitizedConfig.collections.map((collection) => sanitizeCollection(sanitizedConfig.collections, collection));
|
||||
checkDuplicateCollections(sanitizedConfig.collections);
|
||||
@@ -19,6 +21,21 @@ const sanitizeConfig = (config: Config): Config => {
|
||||
sanitizedConfig.globals = [];
|
||||
}
|
||||
|
||||
if (!sanitizedConfig.cookiePrefix) sanitizedConfig.cookiePrefix = 'payload';
|
||||
|
||||
sanitizedConfig.csrf = [
|
||||
...(Array.isArray(config.csrf) ? config.csrf : []),
|
||||
config.serverURL,
|
||||
];
|
||||
|
||||
sanitizedConfig.admin = config.admin || {};
|
||||
|
||||
if (!sanitizedConfig.admin.meta) {
|
||||
sanitizedConfig.admin.meta = {};
|
||||
}
|
||||
|
||||
sanitizedConfig.upload = config.upload || {};
|
||||
|
||||
if (!sanitizedConfig.admin.user) {
|
||||
sanitizedConfig.admin.user = 'users';
|
||||
sanitizedConfig.collections.push(sanitizeCollection(sanitizedConfig.collections, defaultUser));
|
||||
@@ -26,7 +43,33 @@ const sanitizeConfig = (config: Config): Config => {
|
||||
throw new InvalidConfiguration(`${sanitizedConfig.admin.user} is not a valid admin user collection`);
|
||||
}
|
||||
|
||||
return sanitizedConfig;
|
||||
sanitizedConfig.email = config.email || {};
|
||||
// if (!sanitizedConfig.email.transport) sanitizedConfig.email.transport = 'mock';
|
||||
|
||||
sanitizedConfig.graphQL = config.graphQL || {};
|
||||
sanitizedConfig.graphQL.maxComplexity = (sanitizedConfig.graphQL && sanitizedConfig.graphQL.maxComplexity) ? sanitizedConfig.graphQL.maxComplexity : 1000;
|
||||
sanitizedConfig.graphQL.disablePlaygroundInProduction = (sanitizedConfig.graphQL && sanitizedConfig.graphQL.disablePlaygroundInProduction !== undefined) ? sanitizedConfig.graphQL.disablePlaygroundInProduction : true;
|
||||
|
||||
sanitizedConfig.routes = {
|
||||
admin: (config.routes && config.routes.admin) ? config.routes.admin : '/admin',
|
||||
api: (config.routes && config.routes.api) ? config.routes.api : '/api',
|
||||
graphQL: (config.routes && config.routes.graphQL) ? config.routes.graphQL : '/graphql',
|
||||
graphQLPlayground: (config.routes && config.routes.graphQLPlayground) ? config.routes.graphQLPlayground : '/graphql-playground',
|
||||
};
|
||||
|
||||
sanitizedConfig.rateLimit = config.rateLimit || {};
|
||||
sanitizedConfig.rateLimit.window = sanitizedConfig?.rateLimit?.window || 15 * 60 * 100; // 15min default
|
||||
sanitizedConfig.rateLimit.max = sanitizedConfig?.rateLimit?.max || 500;
|
||||
|
||||
if (!sanitizedConfig.express) {
|
||||
sanitizedConfig.express = {
|
||||
json: {},
|
||||
};
|
||||
}
|
||||
|
||||
sanitizedConfig.hooks = { ...(config.hooks || {}) };
|
||||
|
||||
return sanitizedConfig as Config;
|
||||
};
|
||||
|
||||
export default sanitizeConfig;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import express, { Express, Router } from 'express';
|
||||
import crypto from 'crypto';
|
||||
import { TestAccount } from 'nodemailer';
|
||||
import { AuthenticateOptions } from 'passport';
|
||||
import {
|
||||
Config,
|
||||
EmailOptions,
|
||||
|
||||
@@ -8,10 +8,7 @@ export type Where = {
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export type Document = {
|
||||
id: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
export type Document = any;
|
||||
|
||||
export type CreateOptions = {
|
||||
collection: string;
|
||||
|
||||
@@ -18,3 +18,24 @@ export type FileData = {
|
||||
height: number;
|
||||
sizes: FileSizes;
|
||||
};
|
||||
|
||||
export type ImageSize = {
|
||||
name: string,
|
||||
width: number,
|
||||
height: number,
|
||||
crop: string, // comes from sharp package
|
||||
};
|
||||
|
||||
export type IncomingUploadType = {
|
||||
imageSizes?: ImageSize[];
|
||||
staticURL?: string;
|
||||
staticDir?: string;
|
||||
adminThumbnail?: string;
|
||||
}
|
||||
|
||||
export type Upload = {
|
||||
imageSizes?: ImageSize[]
|
||||
staticURL: string
|
||||
staticDir: string
|
||||
adminThumbnail?: string
|
||||
}
|
||||
|
||||
4
src/utilities/canUseDOM.ts
Normal file
4
src/utilities/canUseDOM.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export default !!(
|
||||
(typeof window !== 'undefined'
|
||||
&& window.document && window.document.createElement)
|
||||
);
|
||||
@@ -1,9 +1,9 @@
|
||||
import { DuplicateCollection } from '../errors';
|
||||
import { CollectionConfig } from '../collections/config/types';
|
||||
import { PayloadCollectionConfig } from '../collections/config/types';
|
||||
|
||||
const getDuplicates = (arr: string[]) => arr.filter((item, index) => arr.indexOf(item) !== index);
|
||||
|
||||
const checkDuplicateCollections = (collections: CollectionConfig[]): void => {
|
||||
const checkDuplicateCollections = (collections: PayloadCollectionConfig[]): void => {
|
||||
const duplicateSlugs = getDuplicates(collections.map((c) => c.slug));
|
||||
if (duplicateSlugs.length > 0) {
|
||||
throw new DuplicateCollection('slug', duplicateSlugs);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export default {};
|
||||
export default () => {};
|
||||
|
||||
Reference in New Issue
Block a user