From 1ec8af1ceeb21a01a659cca91f7a1aa91776abd3 Mon Sep 17 00:00:00 2001 From: Ural Date: Fri, 17 Dec 2021 23:52:45 +0500 Subject: [PATCH] Add files --- client.mjs | 352 +++++++++++++++++++++++++++-------------------------- server.mjs | 64 ++++++++-- 2 files changed, 232 insertions(+), 184 deletions(-) diff --git a/client.mjs b/client.mjs index a05a777..3890414 100644 --- a/client.mjs +++ b/client.mjs @@ -1,186 +1,192 @@ export class Client { - /** - * Должен возвращать имя пользователя или null - * если пользователь не залогинен - * - * @return {Promise} username - * */ - async getUser() { - throw new Error("Not implemented"); - } + /** + * Должен возвращать имя пользователя или null + * если пользователь не залогинен + * + * @return {Promise} username + * */ + async getUser() { + return fetch('api/user').then(async res => (await res.json()).username); + } - /** - * Должен логинить пользователя с именем username - * и возвращать его имя - * - * @param {string} username - * @return {Promise} username - * */ - async loginUser(username) { - throw new Error("Not implemented"); - } + /** + * Должен логинить пользователя с именем username + * и возвращать его имя + * + * @param {string} username + * @return {Promise} username + * */ + async loginUser(username) { + return fetch(`api/login?username=${username}`).then(async res => (await res.json()).username); + } - /** - * Должен разлогинивать текущего пользователя - * - * @return {void} - * */ - async logoutUser() { - throw new Error("Not implemented"); - } + /** + * Должен разлогинивать текущего пользователя + * + * @return {void} + * */ + async logoutUser() { + await fetch('api/logout'); + } - /** - * Должен возвращать информацию о компании - * - * @typedef {Object} Headquarters - * @property {string} address - * @property {string} city - * @property {string} state - * - * @typedef {Object} About - * @property {string} founder - * @property {string} founded - * @property {number} employees - * @property {string} ceo - * @property {string} coo - * @property {string} cto - * @property {number} valuation - * @property {Headquarters} headquarters - * @property {string} summary - * @return {Promise} - * */ - async getInfo() { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о компании + * + * @typedef {Object} Headquarters + * @property {string} address + * @property {string} city + * @property {string} state + * + * @typedef {Object} About + * @property {string} founder + * @property {string} founded + * @property {number} employees + * @property {string} ceo + * @property {string} coo + * @property {string} cto + * @property {number} valuation + * @property {Headquarters} headquarters + * @property {string} summary + * @return {Promise} + * */ + async getInfo() { + return (await fetch('https://api.spacexdata.com/v3/info')).json(); + } - /** - * Должен возвращать информацию о всех событиях - * - * @typedef {Object} EventBrief - * @property {number} id - * @property {string} title - * - * @return {Promise} - * */ - async getHistory() { - throw new Error("Not implemented"); - } - /** - * Должен возвращать информацию о запрошенном событии - * - * @typedef {Object} EventFull - * @property {number} id - * @property {string} title - * @property {string} event_date_utc - * @property {string} details - * @property {Object.} links - * - * @param {number} id - * @return {Promise} - * */ - async getHistoryEvent(id) { - throw new Error("Not implemented"); - } + /* --8-- */ + /** + * Должен возвращать информацию о всех событиях + * + * @typedef {Object} EventBrief + * @property {number} id + * @property {string} title + * + * @return {Promise} + * */ + async getHistory() { + return (await fetch('https://api.spacexdata.com/v3/history')).json(); + } - /** - * Должен возвращать информацию о всех ракетах - * - * @typedef {Object} RocketBrief - * @property {number} rocket_id - * @property {string} rocket_name - * - * @return {Promise} - * */ - async getRockets() { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о запрошенном событии + * + * @typedef {Object} EventFull + * @property {number} id + * @property {string} title + * @property {string} event_date_utc + * @property {string} details + * @property {Object.} links + * + * @param {number} id + * @return {Promise} + * */ + async getHistoryEvent(id) { + return (await fetch(`https://api.spacexdata.com/v3/history/${id}`)).json(); + } - /** - * Должен возвращать информацию о запрошенной ракете - * - * @typedef {Object} RocketFull - * @property {number} rocket_id - * @property {string} rocket_name - * @property {string} first_flight - * @property {string} description - * @property {string} wikipedia - * @property {string[]} flickr_images - * Смотри источник данных: - * @property {Object} height - * @property {Object} diameter - * @property {Object} mass - * @property {Object} engines - * @property {Object} first_stage - * @property {Object} second_stage - * - * @param {string} id - * @return {Promise} - * */ - async getRocket(id) { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о всех ракетах + * + * @typedef {Object} RocketBrief + * @property {number} rocket_id + * @property {string} rocket_name + * + * @return {Promise} + * */ + async getRockets() { + return (await fetch('https://api.spacexdata.com/v3/rockets')).json(); + } - /** - * Должен возвращать информацию о машине в космосе - * - * @typedef {Object} Roadster - * @property {string} name - * @property {string} launch_date_utc - * @property {string} details - * @property {number} earth_distance_km - * @property {number} mars_distance_km - * @property {string} wikipedia - * - * @return {Promise} - * */ - async getRoadster() { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о запрошенной ракете + * + * @typedef {Object} RocketFull + * @property {number} rocket_id + * @property {string} rocket_name + * @property {string} first_flight + * @property {string} description + * @property {string} wikipedia + * @property {string[]} flickr_images + * Смотри источник данных: + * @property {Object} height + * @property {Object} diameter + * @property {Object} mass + * @property {Object} engines + * @property {Object} first_stage + * @property {Object} second_stage + * + * @param {string} id + * @return {Promise} + * */ + async getRocket(id) { + return (await fetch(`https://api.spacexdata.com/v3/rockets/${id}`)).json(); + } - /** - * Должен возвращать информацию о всех посланных на Марс предметах - * - * @typedef {Object} Item - * @property {!string} id - * @property {!string} name - * @property {!string} phone - * @property {?number} weight - * @property {?string} color - * @property {?boolean} important - * - * @return {Promise} - * */ - async getSentToMars() { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о машине в космосе + * + * @typedef {Object} Roadster + * @property {string} name + * @property {string} launch_date_utc + * @property {string} details + * @property {number} earth_distance_km + * @property {number} mars_distance_km + * @property {string} wikipedia + * + * @return {Promise} + * */ + async getRoadster() { + return (await fetch('https://api.spacexdata.com/v3/roadster')).json(); + } - /** - * Должен посылать на марс переданный предмет и - * возвращать информацию о всех посланных на Марс предметах - * - * @typedef {Object} ItemToSend - * @property {!string} name - * @property {!string} phone - * @property {?number} weight - * @property {?string} color - * @property {?boolean} important - * - * @param {ItemToSend} item - * @return {Promise} - * */ - async sendToMars(item) { - throw new Error("Not implemented"); - } + /** + * Должен возвращать информацию о всех посланных на Марс предметах + * + * @typedef {Object} Item + * @property {!string} id + * @property {!string} name + * @property {!string} phone + * @property {?number} weight + * @property {?string} color + * @property {?boolean} important + * + * @return {Promise} + * */ + async getSentToMars() { + throw new Error("Not implemented"); + } - /** - * Должен отменять отправку на марс переданного предмета и - * возвращать информацию о всех посланных на Марс предметах - * - * @param {Item} item - * @return {Promise} - * */ - async cancelSendingToMars(item) { - throw new Error("Not implemented"); - } + /** + * Должен посылать на марс переданный предмет и + * возвращать информацию о всех посланных на Марс предметах + * + * @typedef {Object} ItemToSend + * @property {!string} name + * @property {!string} phone + * @property {?number} weight + * @property {?string} color + * @property {?boolean} important + * + * @param {ItemToSend} item + * @return {Promise} + * */ + async sendToMars(item) { + throw new Error("Not implemented"); + } + + /** + * Должен отменять отправку на марс переданного предмета и + * возвращать информацию о всех посланных на Марс предметах + * + * @param {Item} item + * @return {Promise} + * */ + async cancelSendingToMars(item) { + return (await fetch('api/user/sendToMars/cancel', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({'item': item}) + }).json()); + } } diff --git a/server.mjs b/server.mjs index 75d9cbe..6adc216 100644 --- a/server.mjs +++ b/server.mjs @@ -3,25 +3,67 @@ import fs from "fs"; import express from "express"; import https from "https"; import cookieParser from "cookie-parser"; -import bodyParser from "body-parser"; -import fetch from "node-fetch"; const rootDir = process.cwd(); const port = 3000; const app = express(); +/* --7-- */ +const validUrls = ['login', 'api', 'static']; +const redirectingMiddleware = function (req, res, next) { + const root = req.url.split('/')[1]; + const shouldBeSkipped = validUrls.includes(root); + const isFile = path.extname(root) !== ''; + if (shouldBeSkipped || isFile || req.cookies.username) { + return next() + } else { + res.redirect('/login'); + } +}; + +/* --1-- */ +app.use(express.static('spa/build')); +/* --5-- */ +app.use(cookieParser()); +app.use(redirectingMiddleware); + app.get("/client.mjs", (_, res) => { - res.header("Cache-Control", "private, no-cache, no-store, must-revalidate"); - res.sendFile(path.join(rootDir, "client.mjs"), { - maxAge: -1, - cacheControl: false, - }); + res.header("Cache-Control", "private, no-cache, no-store, must-revalidate"); + res.sendFile(path.join(rootDir, "client.mjs"), { + maxAge: -1, + cacheControl: false, + }); }); -app.get("/", (_, res) => { - res.send(":)"); +/* --4-- */ +/* --6-- */ +app.get('/api/login', (req, res) => { + const username = req.query.username; + res.cookie('username', username, { + httpOnly: true, + secure: true, + sameSite: 'Strict' + }); + res.json({ username }); }); -app.listen(port, () => { - console.log(`App listening on port ${port}`); +app.get('/api/user', (req, res) => { + const username = req.cookies.username; + res.json({ username }); +}) + +app.get('/api/logout', (req, res) => { + res.clearCookie('username'); + res.redirect('/'); }); + +/* --2-- */ +app.get(/.*/, (req, res) => { + res.sendFile(path.join(rootDir, 'spa', 'build', 'index.html')); +}) + +/* --3-- */ +https.createServer({ + key: fs.readFileSync("certs/server.key"), + cert: fs.readFileSync("certs/server.cert"), +}, app).listen(port);