From 617b0038063f1b3f804719882982acf1466bf7a0 Mon Sep 17 00:00:00 2001 From: dimasikBurdin <81648493+dimasikBurdin@users.noreply.github.com> Date: Fri, 17 Dec 2021 14:48:00 +0500 Subject: [PATCH] 1-8 --- README.md | 18 ++++++++--------- client.mjs | 27 +++++++++++++++---------- package-lock.json | 3 ++- package.json | 15 +++++++++++++- server.mjs | 51 +++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 89 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index aea0feb..5f8795d 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,21 @@ Код приложения лежит в папке `spa`, собранная версия уже лежит в папке `spa/build`. Для выполнения задания трогать код приложения не потребуется, но если захочешь что-то поменять, не забудь установить зависимости (`npm install` в папке `spa`) и собрать новую версию приложения (`npm run build`). -0. Поставь зависимости и запусти сервер. ++++0. Поставь зависимости и запусти сервер. - Для этого перейди в директорию задачи и выполни команду `npm install`. - После установки зависимостей, выполни команду `npm run start`. - После запуска, перейди по адресу [localhost:3000](http://localhost:3000) -1. Сделай так, чтобы сервер смог отдавать статические файлы из директории `spa/build`. В express для этого есть middleware `express.static`. Подробнее можно прочитать [здесь](https://expressjs.com/en/starter/static-files.html) ++++1. Сделай так, чтобы сервер смог отдавать статические файлы из директории `spa/build`. В express для этого есть middleware `express.static`. Подробнее можно прочитать [здесь](https://expressjs.com/en/starter/static-files.html) -2. Сделай так, чтобы при заходе на любой неизвестный адрес, сервер возвращал файл `spa/build/index.html`. В этом помогут специальные символы [в путях](https://expressjs.com/en/guide/routing.html#route-paths) ++++2. Сделай так, чтобы при заходе на любой неизвестный адрес, сервер возвращал файл `spa/build/index.html`. В этом помогут специальные символы [в путях](https://expressjs.com/en/guide/routing.html#route-paths) -3. Сделай так, чтобы наш сайт работал по https. В этом поможет [этот небольшой пост](https://timonweb.com/posts/running-expressjs-server-over-https/). Сертификат уже сгенерирован и лежит в папке `/certs`. ++++3. Сделай так, чтобы наш сайт работал по https. В этом поможет [этот небольшой пост](https://timonweb.com/posts/running-expressjs-server-over-https/). Сертификат уже сгенерирован и лежит в папке `/certs`. Обрати внимание, что придётся разрешить Chrome работать с само-подписанными сертификатами для localhost. Это можно сделать включив флаг `chrome://flags/#allow-insecure-localhost`. -4. Изучи файл `client.mjs`. В нём лежит заготовка клиента, который будет делать запросы на сервер. ++++4. Изучи файл `client.mjs`. В нём лежит заготовка клиента, который будет делать запросы на сервер. **!!! В этом интенсиве сначала надо реализовать логинизацию. Без этого остальные странички не будут отображаться** @@ -36,19 +36,19 @@ Отправлять ответ можно с помощью [res.json](https://expressjs.com/en/4x/api.html#res.json). -5. Сохрани имя пользователя в [cookie](https://expressjs.com/en/4x/api.html#req.cookies) (не забудь подключить `cookie-parser` [middleware](https://expressjs.com/en/resources/middleware/cookie-parser.html)). ++++5. Сохрани имя пользователя в [cookie](https://expressjs.com/en/4x/api.html#req.cookies) (не забудь подключить `cookie-parser` [middleware](https://expressjs.com/en/resources/middleware/cookie-parser.html)). Сделай так, чтобы методы `.getUser()`, `.loginUser()`, `.logoutUser()` работали с cookie -6. Сделай так, чтобы cookie с именем пользователя была `HttpOnly`, `Secure`, и имела `SameSite` политику `Strict`. В этом помогут дополнительные опции [res.cookie](https://expressjs.com/en/4x/api.html#res.cookie). ++++6. Сделай так, чтобы cookie с именем пользователя была `HttpOnly`, `Secure`, и имела `SameSite` политику `Strict`. В этом помогут дополнительные опции [res.cookie](https://expressjs.com/en/4x/api.html#res.cookie). -7. Сделай так, чтобы при заходе на любой роут приложения, кроме api, статики и `/login` без cookie происходил редирект на страницу `/login`. ++++7. Сделай так, чтобы при заходе на любой роут приложения, кроме api, статики и `/login` без cookie происходил редирект на страницу `/login`. Для этого придётся написать `middleware` и проверять наличие cookie в запросе. Как написать узнай [здесь](https://expressjs.com/en/guide/writing-middleware.html). Сделай так, чтобы middleware применялось только для путей, которые непосредственно отдают `index.html` -8. Оживи остальные страницы кроме `/sendToMars`. А именно `About`, `History`, `Rockets`, `Roadster`. ++++8. Оживи остальные страницы кроме `/sendToMars`. А именно `About`, `History`, `Rockets`, `Roadster`. В качестве источника данных используй [публичное API](https://docs.spacexdata.com/). Методы в нём названы похожим образом. diff --git a/client.mjs b/client.mjs index a05a777..b1115ff 100644 --- a/client.mjs +++ b/client.mjs @@ -6,7 +6,9 @@ export class Client { * @return {Promise} username * */ async getUser() { - throw new Error("Not implemented"); + return fetch('api/user').then(async res=>{ + return (await res.json())['username']; + }) } /** @@ -16,8 +18,13 @@ export class Client { * @param {string} username * @return {Promise} username * */ - async loginUser(username) { - throw new Error("Not implemented"); + async loginUser(username) { + return fetch(`api/login?username=${username}`).then(async res=>{ + let json = await res.json(); + let username = json['username']; + console.log("client/login: "+username) + return username; + }) } /** @@ -26,7 +33,7 @@ export class Client { * @return {void} * */ async logoutUser() { - throw new Error("Not implemented"); + await fetch('api/logout'); } /** @@ -50,7 +57,7 @@ export class Client { * @return {Promise} * */ async getInfo() { - throw new Error("Not implemented"); + return (await fetch('https://api.spacexdata.com/v3/info')).json(); } /** @@ -63,7 +70,7 @@ export class Client { * @return {Promise} * */ async getHistory() { - throw new Error("Not implemented"); + return (await fetch('https://api.spacexdata.com/v3/history')).json(); } /** @@ -80,7 +87,7 @@ export class Client { * @return {Promise} * */ async getHistoryEvent(id) { - throw new Error("Not implemented"); + return (await fetch(`https://api.spacexdata.com/v3/history/${id}`)).json(); } /** @@ -93,7 +100,7 @@ export class Client { * @return {Promise} * */ async getRockets() { - throw new Error("Not implemented"); + return (await fetch('https://api.spacexdata.com/v3/rockets')).json(); } /** @@ -118,7 +125,7 @@ export class Client { * @return {Promise} * */ async getRocket(id) { - throw new Error("Not implemented"); + return (await fetch(`https://api.spacexdata.com/v3/rocket/${id}`)).json(); } /** @@ -135,7 +142,7 @@ export class Client { * @return {Promise} * */ async getRoadster() { - throw new Error("Not implemented"); + return (await fetch('https://api.spacexdata.com/v3/roadster')).json(); } /** diff --git a/package-lock.json b/package-lock.json index 87f8931..ee2febe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,8 @@ { "name": "space-y", - "requires": true, + "version": "1.0.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@sindresorhus/is": { "version": "0.14.0", diff --git a/package.json b/package.json index 42f1001..01d8cc5 100644 --- a/package.json +++ b/package.json @@ -28,5 +28,18 @@ "devDependencies": { "better-npm-run": "0.1.1", "prettier": "^2.2.1" - } + }, + "description": "В задании будем делать серверную часть и клиенсткие запросы для приложения SpaceY. Приложение представляет собой SPA (Single Page Application), которое умеет работать без перезагрузки страниц браузером.", + "version": "1.0.0", + "main": "index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/Irit-Basic-JS/9-space-y.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/Irit-Basic-JS/9-space-y/issues" + }, + "homepage": "https://github.com/Irit-Basic-JS/9-space-y#readme" } diff --git a/server.mjs b/server.mjs index 75d9cbe..fa3fd43 100644 --- a/server.mjs +++ b/server.mjs @@ -9,6 +9,21 @@ import fetch from "node-fetch"; const rootDir = process.cwd(); const port = 3000; const app = express(); +const notRedirectingUrls = ['login', 'api', 'static']; + +app.use(express.static('spa/build')) +app.use(cookieParser()); + +app.get('/*', (req, res, next) => { + const root = req.url.split('/')[1]; + const shouldBeSkipped = notRedirectingUrls.includes(root); + const isFile = root.split('.').length > 1; + const haveCookie = typeof(req.cookies.username) !== 'undefined'; + + if (!shouldBeSkipped && !isFile && !haveCookie) + res.redirect('/login'); + else next(); +}); app.get("/client.mjs", (_, res) => { res.header("Cache-Control", "private, no-cache, no-store, must-revalidate"); @@ -18,10 +33,38 @@ app.get("/client.mjs", (_, res) => { }); }); -app.get("/", (_, res) => { - res.send(":)"); +app.get("/api/login", (req,res)=>{ + console.log("api/login: start" ); + let username = req.query.username; + console.log("api/login: " + username); + res.cookie('username', username, {httpOnly : true, secure : true, sameSite : "strict"}); + res.json({'username':username}); }); -app.listen(port, () => { - console.log(`App listening on port ${port}`); +app.get("/api/user", (req, res) => { + let username = req.cookies.username; + console.log("api/user: " + username); + res.json({'username':username}); }); + +app.get("/api/logout", (req, res)=>{ + console.log('api/logout: start'); + res.clearCookie('username'); + res.redirect('/'); +}); + +app.get('/*', (_, res) => { + res.redirect('/'); +}); + +https + .createServer( + { + key: fs.readFileSync("certs/server.key"), + cert: fs.readFileSync("certs/server.cert"), + }, + app + ) + .listen(port, function() { + console.log(`Port is ${port}`) + }) \ No newline at end of file