diff --git a/JavaScript/4-all/readme.md b/JavaScript/4-all/readme.md new file mode 100644 index 0000000..f03223d --- /dev/null +++ b/JavaScript/4-all/readme.md @@ -0,0 +1,22 @@ +## Вопросы + +- Зачем нужно объявлять константу STATIC_FILE_LENGTH? +- Как вызвать pathTraversal что бы он был равен true? +- Можно ли утверждать, чем больше проверок на безопасность тем лучше, + или в некоторых случаях они создают уязвимость? + +## Упражнения + +1. Обработайте ошибки: + +- когда файла не найден; ✓ +- когда нет прав на чтение файла или каталога; ✗ +- когда происходит попытка чтения файла из каталога выше. ✗ + +2. Создайте шаблоны страниц с ошибками в специальном каталоге. ✓ +3. Перепишите те места, которые возможно с использованием `fs.promises`. ✓ +4. Объедините все примеры в один: ✓ + +- отдача индекса каталога; ✓ +- кеширование; ✓ +- обработка ошибок. ✓ diff --git a/JavaScript/4-all/server.js b/JavaScript/4-all/server.js new file mode 100644 index 0000000..bdcaf68 --- /dev/null +++ b/JavaScript/4-all/server.js @@ -0,0 +1,86 @@ +'use strict'; + +const http = require('node:http'); +const fs = require('node:fs').promises; +const path = require('node:path'); + +const PORT = 8000; + +const STATIC_PATH = path.join(process.cwd(), './static'); + +const MIME_TYPE = { + default: 'application/octet-stream', + html: 'text/html; charset=UTF-8', + js: 'application/javascript; charset=UTF-8', + css: 'text/css', + png: 'image/png', + jpg: 'image/jpeg', + ico: 'image/x-icon', +}; + +const cache = new Map(); + +const cacheFile = async (filePath) => { + const key = filePath.substring(STATIC_PATH.length).replace(/\\/g, '/'); + const value = await fs.readFile(filePath); + cache.set(key, value); +}; + +const cacheDirectory = async (directoryPath) => { + const files = await fs.readdir(directoryPath, { withFileTypes: true }); + for (const file of files) { + const filePath = path.join(file.path, file.name); + if (file.isDirectory()) cacheDirectory(filePath); + else cacheFile(filePath); + } + const key = directoryPath.substring(STATIC_PATH.length).replace(/\\/g, '/'); + cache.set( + key || '/', + files.map((file) => file.name) + ); +}; + +cacheDirectory(STATIC_PATH); + +const folderIndex = (url) => { + const items = cache.get(url); + if (url !== '/' && items[0] !== '../') items.unshift('../'); + const list = items + .map((el) => { + const addres = path.join(url, el); + return `
  • ${el}
  • `; + }) + .join('\n'); + const file = `

    Directory files:

    `; + return file; +}; + +const prepareFile = (url) => { + const filePath = path.join(STATIC_PATH, url); + const pathTraversal = !filePath.startsWith(STATIC_PATH); + // console.log(pathTraversal) + const exists = cache.get(url); + const found = !pathTraversal && !!exists; + let cachePath = url; + if (!found) cachePath = '/errors/404.html'; + if (pathTraversal) cachePath = '/errors/traversal.html'; // Не знаю как установить true через браузер + if (!'readingRights') cachePath = '/errors/no-reading.html'; // Не представляю как это раелизовать без авторизации пользователя + const errorPath = + cachePath.startsWith('/errors/') && cachePath.endsWith('.html'); + const isDirectory = exists instanceof Array && !errorPath; + const ext = path.extname(cachePath).substring(1); + const content = isDirectory ? folderIndex(cachePath) : cache.get(cachePath); + return { found, ext: isDirectory ? 'html' : ext, content }; +}; + +http + .createServer((req, res) => { + const file = prepareFile(req.url); + const mimeType = MIME_TYPE[file.ext] || MIME_TYPE.default; + const statusCode = file.found ? 200 : 404; + res.writeHead(statusCode, { 'content-type': mimeType }); + res.end(file.content); + }) + .listen(PORT, () => + console.log(`Server is running: http://localhost:${PORT}`) + ); diff --git a/JavaScript/4-all/static/errors/404.html b/JavaScript/4-all/static/errors/404.html new file mode 100644 index 0000000..0c50a11 --- /dev/null +++ b/JavaScript/4-all/static/errors/404.html @@ -0,0 +1 @@ +

    file is not exists!

    diff --git a/JavaScript/4-all/static/errors/no-reading.html b/JavaScript/4-all/static/errors/no-reading.html new file mode 100644 index 0000000..4a4f630 --- /dev/null +++ b/JavaScript/4-all/static/errors/no-reading.html @@ -0,0 +1 @@ +

    You do not have permission to read this directory!

    diff --git a/JavaScript/4-all/static/errors/traversal.html b/JavaScript/4-all/static/errors/traversal.html new file mode 100644 index 0000000..0b64017 --- /dev/null +++ b/JavaScript/4-all/static/errors/traversal.html @@ -0,0 +1 @@ +

    Occurrd traversal path!

    diff --git a/JavaScript/4-all/static/favicon.ico b/JavaScript/4-all/static/favicon.ico new file mode 100644 index 0000000..e69de29 diff --git a/JavaScript/4-all/static/favicon.png b/JavaScript/4-all/static/favicon.png new file mode 100644 index 0000000..e69de29 diff --git a/JavaScript/4-all/static/images/Diophant.png b/JavaScript/4-all/static/images/Diophant.png new file mode 100644 index 0000000..4f75ad5 Binary files /dev/null and b/JavaScript/4-all/static/images/Diophant.png differ diff --git a/JavaScript/4-all/static/images/channel-xyz.jpg b/JavaScript/4-all/static/images/channel-xyz.jpg new file mode 100644 index 0000000..08eaa52 Binary files /dev/null and b/JavaScript/4-all/static/images/channel-xyz.jpg differ diff --git a/JavaScript/4-all/static/index.html b/JavaScript/4-all/static/index.html new file mode 100644 index 0000000..3e7d6ca --- /dev/null +++ b/JavaScript/4-all/static/index.html @@ -0,0 +1,15 @@ + + + + + + Document + + + + + + diff --git a/JavaScript/4-all/static/js/init.js b/JavaScript/4-all/static/js/init.js new file mode 100644 index 0000000..e921523 --- /dev/null +++ b/JavaScript/4-all/static/js/init.js @@ -0,0 +1 @@ +console.log('hello'); diff --git a/JavaScript/4-all/static/styles/style.css b/JavaScript/4-all/static/styles/style.css new file mode 100644 index 0000000..a6020bf --- /dev/null +++ b/JavaScript/4-all/static/styles/style.css @@ -0,0 +1,6 @@ +.hello { + background-color: black; + width: 200; + height: 60; + color: white; +}