diff --git a/package-lock.json b/package-lock.json index 01337f5..d3b1261 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "2.2.3", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/abort-controller": "^3.374.0", "@aws-sdk/client-s3": "^3.181.0", "@codex-team/config-loader": "0.1.0-rc1", "@codexteam/shortcuts": "^1.2.0", @@ -20,6 +21,7 @@ "cookie-parser": "^1.4.5", "csurf": "^1.2.2", "debug": "^4.3.2", + "editorjs-header-with-alignment": "^1.0.1", "express": "^4.17.1", "file-type": "^16.5.4", "fs-extra": "^10.1.0", @@ -50,9 +52,9 @@ "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.16.11", "@codexteam/misprints": "^1.0.0", + "@coolbytes/editorjs-delimiter": "^1.0.3", "@editorjs/checklist": "^1.3.0", "@editorjs/code": "^2.7.0", - "@editorjs/delimiter": "^1.2.0", "@editorjs/editorjs": "^2.25.0", "@editorjs/embed": "^2.5.1", "@editorjs/header": "^2.6.2", @@ -427,17 +429,39 @@ } }, "node_modules/@aws-sdk/abort-controller": { - "version": "3.178.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.178.0.tgz", - "integrity": "sha512-ptDkCB06BJrYdhKzamM9yI15LxcGkPczY80hzKAY/aecm09alnW27uCt5HJJx2nCd18IUH28ZO1sc7DTLOWb3A==", - "license": "Apache-2.0", - "peer": true, + "version": "3.374.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.374.0.tgz", + "integrity": "sha512-pO1pqFBdIF28ZvnJmg58Erj35RLzXsTrjvHghdc/xgtSvodFFCNrUsPg6AP3On8eiw9elpHoS4P8jMx1pHDXEw==", + "deprecated": "This package has moved to @smithy/abort-controller", "dependencies": { - "@aws-sdk/types": "3.178.0", - "tslib": "^2.3.1" + "@smithy/abort-controller": "^1.0.1", + "tslib": "^2.5.0" }, "engines": { - "node": ">= 12.0.0" + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/abort-controller/node_modules/@smithy/abort-controller": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-1.1.0.tgz", + "integrity": "sha512-5imgGUlZL4dW4YWdMYAKLmal9ny/tlenM81QZY7xYyb76z9Z/QOg7oM5Ak9HQl8QfFTlGVWwcMXl+54jroRgEQ==", + "dependencies": { + "@smithy/types": "^1.2.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/abort-controller/node_modules/@smithy/types": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-1.2.0.tgz", + "integrity": "sha512-z1r00TvBqF3dh4aHhya7nz1HhvCg4TRmw51fjMrh5do3h+ngSstt/yKlNbHeb9QxJmFbmN8KEVSWgb1bRvfEoA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, "node_modules/@aws-sdk/client-cognito-identity": { @@ -3524,6 +3548,12 @@ "integrity": "sha512-Udb8lkwhXEiPoLm7krtUv2f8jYQTutHxsLecmsMvMbOxMJ49LA/EUUzn8Fo32mxOFrI7qozOovspLhHb+y60nQ==", "license": "MIT" }, + "node_modules/@coolbytes/editorjs-delimiter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@coolbytes/editorjs-delimiter/-/editorjs-delimiter-1.0.3.tgz", + "integrity": "sha512-Ix0z5ujv12Y+JXkUypxtdX36OsDBNyjLo/k8oPxBcq6UxCS1F96dXvE9XRb/tpN6qW8BbWUfViyBbeOLAbGkLw==", + "dev": true + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -3600,13 +3630,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@editorjs/delimiter": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@editorjs/delimiter/-/delimiter-1.2.0.tgz", - "integrity": "sha512-GKsCFPk85vH5FuCuVQ48NTLc9hk0T3DsBH9zABaicTYIJayFcUa8N4/Y+L3i4tduzDqqyvoxkv+5n43GmC5gEA==", - "dev": true, - "license": "MIT" - }, "node_modules/@editorjs/editorjs": { "version": "2.30.8", "resolved": "https://registry.npmjs.org/@editorjs/editorjs/-/editorjs-2.30.8.tgz", @@ -7964,6 +7987,11 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/editorjs-header-with-alignment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/editorjs-header-with-alignment/-/editorjs-header-with-alignment-1.0.1.tgz", + "integrity": "sha512-L7cDSx/H3wgb9dg05HH9xPMotj3tkoElTd0TeY81pxvO0+tPV+yRZ9hV7fUyZolYUObKfYL9QS+yeTY/YCht5g==" + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", diff --git a/package.json b/package.json index 95e9754..7e3ed08 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "test:js": "cross-env NODE_ENV=testing mocha --recursive ./dist/test --exit", "test": "cross-env NODE_ENV=testing ts-mocha -n loader=ts-node/esm ./src/test/*.ts ./src/test/**/*.ts --exit ", "lint": "eslint --fix --ext .ts ./src/backend", - "editor-upgrade": "yarn add -D @editorjs/{editorjs,header,code,delimiter,list,link,image,table,inline-code,marker,warning,checklist,raw}@latest" + "editor-upgrade": "yarn add -D @editorjs/{editorjs,header,code,list,link,image,table,inline-code,marker,warning,checklist,raw}@latest" }, "dependencies": { "@aws-sdk/abort-controller": "^3.374.0", @@ -37,6 +37,8 @@ "cookie-parser": "^1.4.5", "csurf": "^1.2.2", "debug": "^4.3.2", + "editorjs-header-with-alignment": "^1.0.1", + "editorjs-alert": "^1.1.4", "express": "^4.17.1", "file-type": "^16.5.4", "fs-extra": "^10.1.0", @@ -66,10 +68,11 @@ "@codexteam/misprints": "^1.0.0", "@editorjs/checklist": "^1.3.0", "@editorjs/code": "^2.7.0", - "@editorjs/delimiter": "^1.2.0", + "@coolbytes/editorjs-delimiter": "^1.0.3", "@editorjs/editorjs": "^2.25.0", "@editorjs/embed": "^2.5.1", "@editorjs/header": "^2.6.2", + "@editorjs/paragraph": "^2.11.7", "@editorjs/image": "^2.6.2", "@editorjs/inline-code": "^1.3.1", "@editorjs/link": "^2.4.0", diff --git a/src/backend/server.ts b/src/backend/server.ts index ce48e49..9641e29 100644 --- a/src/backend/server.ts +++ b/src/backend/server.ts @@ -102,16 +102,23 @@ function createApp(): express.Express { if (appConfig.hawk?.backendToken && err instanceof Error) { HawkCatcher.send(err); } + // CSRF error (from csurf) + if (err && typeof err === 'object' && 'code' in err && (err as any).code === 'EBADCSRFTOKEN') { + res.status(403); + return res.render('error', { status: 403, message: 'Invalid CSRF token' }); + } // only send Http based exception to client. if (err instanceof HttpException) { - // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; - // render the error page res.status(err.status || 500); - res.render('error'); + if (err.status === 403) { + return res.render('error', { status: 403, message: 'Доступ запрещён' }); + } + return res.render('error'); } - next(err); + // fallback for other errors + res.status(500).render('error', { status: 500, message: 'Internal Server Error' }); }); return app; diff --git a/src/backend/views/pages/blocks/alert.twig b/src/backend/views/pages/blocks/alert.twig new file mode 100644 index 0000000..3fa9e56 --- /dev/null +++ b/src/backend/views/pages/blocks/alert.twig @@ -0,0 +1,10 @@ +