From 70e7ec8e5d0b0c2e9cbdd6bc4ad379900923b1db Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sat, 9 May 2020 14:37:48 +0200 Subject: [PATCH] Implement config validation --- package.json | 1 + src/server.js | 3 +- src/utils/config.js | 25 ++++++++ src/utils/configSchema.json | 121 ++++++++++++++++++++++++++++++++++++ yarn.lock | 10 +++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/utils/config.js create mode 100644 src/utils/configSchema.json diff --git a/package.json b/package.json index 82354b5..5f5c026 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "author": "Matúš Námešný", "license": "MIT", "dependencies": { + "ajv": "^6.12.2", "async": "^3.1.0", "axios": "^0.19.1", "chokidar": "^3.3.0", diff --git a/src/server.js b/src/server.js index 0a203b1..a9397b3 100644 --- a/src/server.js +++ b/src/server.js @@ -9,6 +9,7 @@ import { ServerRenderer } from './utils/serverRender' import { Scanner } from './utils/scanner' import { FileStorage } from './utils/storage/file' import { MongoStorage } from './utils/storage/mongo' +import { Config } from './utils/config' import { Api } from './utils/api' const configPath = process.argv[2] || path.join(process.cwd(), 'config/config.json') @@ -16,7 +17,7 @@ const configPath = process.argv[2] || path.join(process.cwd(), 'config/config.js const app = express() app.set('trust proxy', true) -const config = jsonfile.readFileSync(configPath) +const config = new Config(jsonfile.readFileSync(configPath)) if (config == null) { throw new Error('Config file not found!') } diff --git a/src/utils/config.js b/src/utils/config.js new file mode 100644 index 0000000..41eb6c6 --- /dev/null +++ b/src/utils/config.js @@ -0,0 +1,25 @@ +import Ajv from 'ajv' +import configSchema from './configSchema.json' + +export class Config { + constructor (configFile) { + const ajv = new Ajv() + + var valid = ajv.validate(configSchema, configFile) + if (!valid) { + throw ajv.errors + } + + this.title = configFile.title + this.name = configFile.name + this.email = configFile.email || '' + this.social = configFile.social || [] + this.baseUrl = configFile.baseUrl || 'localhost' + this.contentPath = configFile.contentPath || './content' + this.storage = configFile.storage || 'file' + if (this.storage === 'mongo') { + this.mongoUrl = configFile.mongoUrl + } + this.specialFiles = configFile.specialFiles || ['about.md'] + } +} diff --git a/src/utils/configSchema.json b/src/utils/configSchema.json new file mode 100644 index 0000000..6b90d7e --- /dev/null +++ b/src/utils/configSchema.json @@ -0,0 +1,121 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://example.com/example.json", + "type": "object", + "title": "The root schema", + "description": "The root schema comprises the entire JSON document.", + "default": {}, + "required": [ + "title", + "name", + "baseUrl" + ], + "additionalProperties": true, + "properties": { + "title": { + "$id": "#/properties/title", + "type": "string", + "title": "The title schema", + "description": "The title of the website" + }, + "name": { + "$id": "#/properties/name", + "type": "string", + "title": "The name schema", + "description": "Your name", + "examples": [ + "John Doe" + ] + }, + "email": { + "$id": "#/properties/email", + "type": "string", + "title": "The email schema", + "description": "Your email", + "default": "", + "examples": [ + "john.doe@example.com" + ] + }, + "social": { + "$id": "#/properties/social", + "type": "object", + "title": "The social schema", + "description": "Links to your social accounts", + "default": {}, + "examples": [ + { + "linkedin": "https://www.linkedin.com/in/johndoe/", + "codepen": "https://codepen.io/johndoe/", + "github": "https://github.com/johndoe" + } + ], + "additionalProperties": true + }, + "baseUrl": { + "$id": "#/properties/baseUrl", + "type": "string", + "title": "The baseUrl schema", + "description": "Base URL of your website", + "examples": [ + "example.com" + ] + }, + "storage": { + "$id": "#/properties/storage", + "type": "string", + "enum": ["mongo", "file"], + "title": "The storage schema", + "description": "The content storage configuration", + "default": "file" + }, + "mongourl": { + "$id": "#/properties/mongourl", + "type": "string", + "title": "The mongourl schema", + "description": "Sets MongoDb url if mongo is specified as a storage option.", + "examples": [ + "mongodb://localhost:27017" + ] + }, + "contentPath": { + "$id": "#/properties/contentPath", + "type": "string", + "title": "The contentPath schema", + "description": "The path to your content.", + "examples": [ + "./content" + ] + }, + "specialFiles": { + "$id": "#/properties/specialFiles", + "type": "array", + "title": "The specialFiles schema", + "description": "Files that are not normal blog posts.", + "default": [], + "examples": [ + [ + "about.md", + "resume.md" + ] + ], + "additionalItems": true, + "items": { + "$id": "#/properties/specialFiles/items", + "anyOf": [ + { + "$id": "#/properties/specialFiles/items/anyOf/0", + "type": "string", + "title": "The first anyOf schema", + "description": "An explanation about the purpose of this instance.", + "default": "", + "examples": [ + "about.md", + "resume.md" + ] + } + ] + } + } + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 63889e7..01b5fe7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1116,6 +1116,16 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.2: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"