Add typescript/multiplayer-backend
This commit is contained in:
commit
7908f1221e
|
@ -1,6 +1,6 @@
|
||||||
# Javascript
|
# Javascript
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| -------------------------------------- | -------------------------------------------------- |
|
| ---------------------------------------- | -------------------------------------------------- |
|
||||||
| [clever-dots](./clever-dots/) | Half broken genetic algorithm implementation in js |
|
| [clever-dots](./clever-dots/) | Half broken genetic algorithm implementation in js |
|
||||||
| [linear-regression](linear-regression) | Basic linear regression implementation |
|
| [linear-regression](./linear-regression) | Basic linear regression implementation |
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Typescript
|
# Typescript
|
||||||
|
|
||||||
| Name | Description |
|
| Name | Description |
|
||||||
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [lunardash](./lunardash/) | Rhythm game I dropped super early into development |
|
| [lunardash](./lunardash/) | Rhythm game I dropped super early into development |
|
||||||
| [option](./option/) | Typescript implementation of the `Maybe` monad |
|
| [monadic](./monadic) | Custom web framework inspired by [halogen](https://github.com/purescript-halogen/purescript-halogen) |
|
||||||
| [wave38](./wave38/) | Remake of [wave37](https://github.com/Mateiadrielrafael/wave37) I dropped super early into development. |
|
| [multiplayer-backend](./multiplayer-backend) | Unfinished server for some multiplayer game. Later rebranded into `pleix-backend` |
|
||||||
| [pleix-frontend](./pleix-frontend/) | No idea what `pleix` was supposed to be, but this was essentially just a bunch of experiments with [lit-html](https://lit.dev/) |
|
| [og-website](./og-website) | My first ever personal website |
|
||||||
| [monadic](./monadic) | Custom web framework inspired by [halogen](https://github.com/purescript-halogen/purescript-halogen) |
|
| [option](./option/) | Typescript implementation of the `Maybe` monad |
|
||||||
| [og-website](./og-website) | My first ever personal website |
|
| [pleix-frontend](./pleix-frontend/) | No idea what `pleix` was supposed to be, but this was essentially just a bunch of experiments with [lit-html](https://lit.dev/) |
|
||||||
|
| [wave38](./wave38/) | Remake of [wave37](https://github.com/Mateiadrielrafael/wave37) I dropped super early into development. |
|
||||||
|
|
61
typescript/multiplayer-backend/.gitignore
vendored
Normal file
61
typescript/multiplayer-backend/.gitignore
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# TypeScript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# next.js build output
|
||||||
|
.next
|
21
typescript/multiplayer-backend/LICENSE
Normal file
21
typescript/multiplayer-backend/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Matei Adriel
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
3
typescript/multiplayer-backend/README.md
Normal file
3
typescript/multiplayer-backend/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# mp-game-server
|
||||||
|
|
||||||
|
This was one of my older projects, with it i learned how to use express-session, and eventually (for some reason) i did sessions manually (well, at least i tried).
|
26
typescript/multiplayer-backend/config.ts
Normal file
26
typescript/multiplayer-backend/config.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//interfaces
|
||||||
|
export interface routeList {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
export interface whiteListUrl {
|
||||||
|
url: string
|
||||||
|
methods?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
//routes
|
||||||
|
export const baseUrl = "./src/routes/"
|
||||||
|
export const routes: routeList = {
|
||||||
|
"/logs": "logging/logs.ts",
|
||||||
|
"/auth": "auth/auth.ts"
|
||||||
|
}
|
||||||
|
|
||||||
|
//whitelist of urls
|
||||||
|
export const whiteList: whiteListUrl[] = [{
|
||||||
|
url: "localhost:4200"
|
||||||
|
},{
|
||||||
|
url: "localhost:8000"
|
||||||
|
},{
|
||||||
|
url: "localhost:3000"
|
||||||
|
}]
|
||||||
|
|
||||||
|
export const staticRoutes:string[] = []
|
12
typescript/multiplayer-backend/firebase-admin.json
Normal file
12
typescript/multiplayer-backend/firebase-admin.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"type": "service_account",
|
||||||
|
"project_id": "planets-io",
|
||||||
|
"private_key_id": "64f5c2a6dab6521e5a7236332aca1b72bc49cd4b",
|
||||||
|
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCsQqNWLgveNEud\nvPbYNStN3+KXGqnV2km6JUDQ431oQ4uObKZ8neG6T0cSbQv5j7BmBjLAZIkIGKCc\nLEfRDyUOPlP3l1eBf1txpBoj5YsnH7dBBbi1TqbKihJF0nuCzrYn0zUpVqVIVH8q\nKbs1twFecxd9OIxBY+MaGUI2FQsu8O1m7Xs2RCsur61CAFTvtKeJFdsDAOAuK33b\nws5Nu3WY0cw7yDNGQAY7kDmWNIL4pfbcN1aVsOAQZcF/W/QtEfnaZSfcE1M410tE\n8H0NCXuupsyyoWWuOt/crFmFK3Fd6bg2MHbHJt3y7Xl12xI7OZWdeOiQ0zdri8+j\n6CULzRNLAgMBAAECggEAPtjvK8WP+el9fxbOvpIjcv2Qd424UfgatwnZbHzbJ7uh\nAnz8fvHBRc6fwQa8/Dei5Y40XQIxBp2pl2EGcK1EWT5/NxFl0S7Mh5kWGmuoicUm\nAFici7We371hLk09V7ugNMZ3mlXs5odBf/oKve2/V5zJAJwte7v8QuzdPcsOsfiG\nWguvSMQ1IoQn92KSFpYbxkXtfN3eQ34pE/zKMbkneoNmNaTZG3tfBjIoODvzas/x\nw0Ey8np5LOAmPnPpf92x7dj6vOtMdGtHZMhBwzc0kPE4UXy/EfIXOjIyG82nRckF\njxVANNvBGCqTfW0O+mTbUVUUcvKTpJ3JrPbG5vRNTQKBgQDbnI+MyL1xmRRT9uJR\nxyJeLQZWPc/dfVmn3uitQXHrVO0QWbAJb8NpOF0YrMKa1ODzTvJgYGLpVk3bvQT4\nu1MQKSycK5bT2wl7nRlhBNeFD6kng1YZ1jmEa/0ec1+Fl/Z8Pl2Rocj/U4YrfHna\nOAVz2Pk4cv/WT8MrnLS5w6XaZQKBgQDIzYqBNdzfCf1filAAb/SeDi2+871qVl2n\nDGTj09q8Q2GBlHiReWCKYz3ENyKxQ/93OUbNFnAzqkVYgCfBhMetq6/B3wcJblO7\nMdYAOi9Bxj+yYN7M5iRCQrNT/pYMyaVngrpTYp6Yyi4OBK4X2bTnN29mdHEXgmQh\nJIbXRtsD7wKBgB5KDqZ9PVvAoEQgZgCfdYcFsL0OU3AaDNaRcQgMYbjygqvhotz6\nVDpb8sMneMPAHrKQLe/K+3lxVNW80UW5GHC/LQ7xGCFqMXmiJlDySQNqMItpmuN/\nX3l7J3MeuIsFdZKXS3J9nOpSS8wNpATL+zyKLX1ypwSZBbMrLuX8LRDdAoGAGJKu\npGlHAjRiwVJXv/XzZXQuvPNu9phjFZI6tnayid9lC0p0BrlnyweiA2UL5c2AccKc\nm3RnfqsTmWT1eIUbOnGMLJlybwEFVh8fJR/5sH7mRJn+Kezv+vvWnizFiAMVLrmc\nu5+R8Pis8iI4e8q0jKcIBu2w+UOHpVam+ak+HBkCgYBdPjpnl8Wn/0qtRSX2H4u9\nweF1R1KSRdLtWrG7JIB3gyEsHW6yhAmwKNj1ss4wG9/P7YF7QGKQLQJ6VJ56Snjy\n6gUVamFo8apu+rNFj1U+mok/UbltgzlMrP1G/G/yUJTp16547IvSrR4a8+TecWTg\n3QpvQ5GdifLzmzTL4MGDCg==\n-----END PRIVATE KEY-----\n",
|
||||||
|
"client_email": "firebase-adminsdk-ssnid@planets-io.iam.gserviceaccount.com",
|
||||||
|
"client_id": "112323453968848896098",
|
||||||
|
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||||
|
"token_uri": "https://oauth2.googleapis.com/token",
|
||||||
|
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||||
|
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-ssnid%40planets-io.iam.gserviceaccount.com"
|
||||||
|
}
|
6
typescript/multiplayer-backend/nodemon.json
Normal file
6
typescript/multiplayer-backend/nodemon.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"watch": ["src"],
|
||||||
|
"ext": "ts",
|
||||||
|
"ignore": ["src/**/*.spec.ts"],
|
||||||
|
"exec": "ts-node ./src/main.ts"
|
||||||
|
}
|
3375
typescript/multiplayer-backend/package-lock.json
generated
Normal file
3375
typescript/multiplayer-backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
45
typescript/multiplayer-backend/package.json
Normal file
45
typescript/multiplayer-backend/package.json
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"name": "mp-game-back-end",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "a multiplayer game (idk for now)",
|
||||||
|
"main": "src/main.ts",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nodemon"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "\u0016https://github.com/Mateiadrielrafael/mp-game-server"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"mp"
|
||||||
|
],
|
||||||
|
"author": "Matei Adriel",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/chalk": "^2.2.0",
|
||||||
|
"@types/cors": "^2.8.5",
|
||||||
|
"@types/dotenv": "^6.1.1",
|
||||||
|
"@types/express": "^4.16.1",
|
||||||
|
"@types/express-session": "^1.15.12",
|
||||||
|
"@types/express-validator": "^3.0.0",
|
||||||
|
"@types/lodash": "^4.14.123",
|
||||||
|
"@types/mongoose": "^5.5.0",
|
||||||
|
"@types/morgan": "^1.7.35",
|
||||||
|
"nodemon": "^1.18.10",
|
||||||
|
"ts-node": "^8.0.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bcryptjs": "^2.4.3",
|
||||||
|
"chalk": "^2.4.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^7.0.0",
|
||||||
|
"express": "^4.16.4",
|
||||||
|
"express-validator": "^5.3.1",
|
||||||
|
"lodash": "^4.17.11",
|
||||||
|
"mongoose": "^5.5.7",
|
||||||
|
"morgan": "^1.9.1",
|
||||||
|
"ts-mongoose": "0.0.14",
|
||||||
|
"typescript": "^3.4.1"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./preventGlobalError"
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Request, Response } from "express";
|
||||||
|
|
||||||
|
export const preventGlobalErrors = (func: (req: Request, res: Response) => any) => {
|
||||||
|
return async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
await func(req,res)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
res.json({
|
||||||
|
succes: false,
|
||||||
|
errors: [err]
|
||||||
|
}).status(400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./respond"
|
10
typescript/multiplayer-backend/src/common/respond/respond.ts
Normal file
10
typescript/multiplayer-backend/src/common/respond/respond.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { Response } from "express";
|
||||||
|
|
||||||
|
export const respond = (res:Response, succes = true, data: any = {},
|
||||||
|
errors:any[] = [], status = 200) => {
|
||||||
|
res.json({
|
||||||
|
succes,
|
||||||
|
data,
|
||||||
|
errors
|
||||||
|
}).status(status)
|
||||||
|
}
|
45
typescript/multiplayer-backend/src/createServer.ts
Normal file
45
typescript/multiplayer-backend/src/createServer.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import * as express from "express"
|
||||||
|
import chalk from "chalk";
|
||||||
|
import * as cors from "cors"
|
||||||
|
|
||||||
|
import { staticRoutes } from "../config";
|
||||||
|
import { routes } from "./routes"
|
||||||
|
import { json } from "body-parser";
|
||||||
|
import { morganChalk } from "./middleware/morgan";
|
||||||
|
import { sessionMiddleware } from "./middleware/sessions"
|
||||||
|
|
||||||
|
// const firestore = store(sessions)
|
||||||
|
export interface serverSetupResults {
|
||||||
|
app: express.Application
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setupServer = (): Promise<serverSetupResults> =>
|
||||||
|
new Promise(async (res, rej) => {
|
||||||
|
try {
|
||||||
|
//create express app
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
cors(),
|
||||||
|
json(),
|
||||||
|
morganChalk,
|
||||||
|
sessionMiddleware
|
||||||
|
)
|
||||||
|
|
||||||
|
//load static routes
|
||||||
|
staticRoutes.forEach(route => {
|
||||||
|
app.use(express.static(`${route}`))
|
||||||
|
})
|
||||||
|
|
||||||
|
//Load normal routes
|
||||||
|
for (let i in routes) {
|
||||||
|
app.use(`/${i}`, routes[i])
|
||||||
|
}
|
||||||
|
console.log(chalk.bold.green("👏 Succesfully creatd server!"))
|
||||||
|
|
||||||
|
res({ app })
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
rej(err)
|
||||||
|
}
|
||||||
|
})
|
27
typescript/multiplayer-backend/src/main.ts
Normal file
27
typescript/multiplayer-backend/src/main.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { config } from "dotenv"
|
||||||
|
import { setupServer } from "./createServer";
|
||||||
|
import { connected } from "./services/db/mongo"
|
||||||
|
import chalk from "chalk";
|
||||||
|
|
||||||
|
//⚓ connect to mongodb
|
||||||
|
connected.then(val => {
|
||||||
|
console.log(chalk.bold.green("⚓ Succesfully connected to mongoDb!!!"))
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
console.log(chalk.bold.red("😭 Something went wrong when connecting to mongoDb!!!"))
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
//🗻 extract env variables
|
||||||
|
config()
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
|
||||||
|
//create the server
|
||||||
|
const { app } = await setupServer()
|
||||||
|
|
||||||
|
//start listeing to requests
|
||||||
|
app.listen(process.env.PORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,26 @@
|
||||||
|
import * as morgan from "morgan"
|
||||||
|
import chalk from "chalk"
|
||||||
|
|
||||||
|
const { floor } = Math
|
||||||
|
|
||||||
|
export const morganChalk = morgan(function (tokens, req, res) {
|
||||||
|
const status = Number(tokens.status(req,res))
|
||||||
|
const statusFirstDigit = floor(status / 100)
|
||||||
|
|
||||||
|
const emoji = (status === 200) ?
|
||||||
|
"👌" : (status === 203) ?
|
||||||
|
"🔎" : (status == 202) ?
|
||||||
|
"🚧" : (status === 302) ?
|
||||||
|
"🏹" : (statusFirstDigit === 2) ?
|
||||||
|
"🌝" : (statusFirstDigit === 4) ?
|
||||||
|
"😠" :
|
||||||
|
"❓"
|
||||||
|
|
||||||
|
return [
|
||||||
|
chalk.bold(`${emoji} `),
|
||||||
|
chalk.green.bold(tokens.method(req, res)),
|
||||||
|
chalk.red.bold(tokens.status(req, res)),
|
||||||
|
chalk.blue.italic(tokens.url(req, res)),
|
||||||
|
chalk.yellow(`${tokens['response-time'](req, res)} ms`),
|
||||||
|
].join(' ');
|
||||||
|
});
|
12
typescript/multiplayer-backend/src/middleware/reddirect.ts
Normal file
12
typescript/multiplayer-backend/src/middleware/reddirect.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { Request, Response } from "express"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* boilerplate for reddirecting
|
||||||
|
* @param url the url to reddirect to
|
||||||
|
* @returns the middleware
|
||||||
|
*/
|
||||||
|
export const reddirect = (url: string) =>
|
||||||
|
(req: Request, res: Response, next: any) => {
|
||||||
|
res.redirect(url)
|
||||||
|
next()
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./sessions"
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Response, Request } from "express";
|
||||||
|
import { SessionDataDoc, SessionData } from "../../models/SessionData"
|
||||||
|
|
||||||
|
const getToken = (req: Request) => {
|
||||||
|
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { // Authorization: Bearer g1jipjgi1ifjioj
|
||||||
|
// Handle token presented as a Bearer token in the Authorization header
|
||||||
|
return req.headers.authorization.split(' ')[1];
|
||||||
|
} else if (req.query && req.query.token) {
|
||||||
|
// Handle token presented as URI param
|
||||||
|
return req.query.token;
|
||||||
|
} else if (req.cookies && req.cookies.token) {
|
||||||
|
// Handle token presented as a cookie parameter
|
||||||
|
return req.cookies.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we return null, we couldn't find a token.
|
||||||
|
// In this case, the JWT middleware will return a 401 (unauthorized) to the client for this request
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sessionMiddleware = async (req: Request, res: Response, next: Function) => {
|
||||||
|
const token = getToken(req)
|
||||||
|
|
||||||
|
//if we are trying to get an token, allow this
|
||||||
|
if (req.path === "/token")
|
||||||
|
return next()
|
||||||
|
|
||||||
|
//if we dont have any token
|
||||||
|
if (!token)
|
||||||
|
return res.json({ succes: false }).status(400)
|
||||||
|
|
||||||
|
//try searching for the object in the database
|
||||||
|
const result = await SessionData.findOne({ token })
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return res.json({ succes: false }).status(400)
|
||||||
|
|
||||||
|
const data = JSON.parse(result.data)
|
||||||
|
|
||||||
|
if (!req.session)
|
||||||
|
//@ts-ignore
|
||||||
|
req.session = {}
|
||||||
|
|
||||||
|
for (let i in data)
|
||||||
|
req.session[i] = data[i]
|
||||||
|
|
||||||
|
req.session.save = async () => {
|
||||||
|
const toSave:any = {}
|
||||||
|
|
||||||
|
for (let i in req.session) {
|
||||||
|
if (i == "save") continue
|
||||||
|
|
||||||
|
toSave[i] = req.session[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
const data:string = JSON.stringify(toSave)
|
||||||
|
|
||||||
|
return await result.updateOne({
|
||||||
|
token,
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
9
typescript/multiplayer-backend/src/models/Password.ts
Normal file
9
typescript/multiplayer-backend/src/models/Password.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { createSchema, Type, typedModel, ExtractDoc } from "ts-mongoose"
|
||||||
|
|
||||||
|
const PasswordSchema = createSchema({
|
||||||
|
uid: Type.string(),
|
||||||
|
password: Type.string()
|
||||||
|
})
|
||||||
|
|
||||||
|
export const Passsord = typedModel("Password", PasswordSchema)
|
||||||
|
export type PasswordDoc = ExtractDoc<typeof PasswordSchema>;
|
9
typescript/multiplayer-backend/src/models/SessionData.ts
Normal file
9
typescript/multiplayer-backend/src/models/SessionData.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { createSchema, Type, typedModel, ExtractDoc } from "ts-mongoose"
|
||||||
|
|
||||||
|
const SessionDataSchema = createSchema({
|
||||||
|
token: Type.string(),
|
||||||
|
data: Type.string()
|
||||||
|
})
|
||||||
|
|
||||||
|
export const SessionData = typedModel("SessionData", SessionDataSchema)
|
||||||
|
export type SessionDataDoc = ExtractDoc<typeof SessionDataSchema>;
|
13
typescript/multiplayer-backend/src/models/User.ts
Normal file
13
typescript/multiplayer-backend/src/models/User.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { createSchema, Type, typedModel, ExtractDoc } from "ts-mongoose"
|
||||||
|
|
||||||
|
const UserSchema = createSchema({
|
||||||
|
name: Type.string(),
|
||||||
|
email: Type.string(),
|
||||||
|
photo: Type.string(),
|
||||||
|
friends: Type.array().of(Type.string()),
|
||||||
|
description: Type.optionalString(),
|
||||||
|
uid: Type.string()
|
||||||
|
})
|
||||||
|
|
||||||
|
export const User = typedModel("User", UserSchema)
|
||||||
|
export type UserDoc = ExtractDoc<typeof UserSchema>;
|
151
typescript/multiplayer-backend/src/routes/auth/auth.ts
Normal file
151
typescript/multiplayer-backend/src/routes/auth/auth.ts
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
import { Router, Response, Request } from "express"
|
||||||
|
import * as validator from "express-validator"
|
||||||
|
import { generateUid, encodePassword } from "../../services/auth/signup";
|
||||||
|
import { savePassword } from "../../services/auth/signup";
|
||||||
|
import { config } from "dotenv"
|
||||||
|
import { compare } from "bcryptjs";
|
||||||
|
import { User, UserDoc } from "../../models/User";
|
||||||
|
import { Passsord } from "../../models/Password";
|
||||||
|
import { preventGlobalErrors } from "../../common/preventGlobalError";
|
||||||
|
import { respond } from "../../common/respond";
|
||||||
|
|
||||||
|
//extract env variables
|
||||||
|
config()
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
const authHandler = preventGlobalErrors(async (req: Request, res: Response) => {
|
||||||
|
//if already logged in return the uid
|
||||||
|
if (req.session.uid)
|
||||||
|
return respond(res, true, { uid: req.session.uid })
|
||||||
|
|
||||||
|
//get data from body
|
||||||
|
const { password, email, name } = req.body
|
||||||
|
|
||||||
|
//check if the email isnt used
|
||||||
|
if (await User.findOne({ email }))
|
||||||
|
return respond(res, false, { email }, ["email is already used"], 400)
|
||||||
|
|
||||||
|
//validate
|
||||||
|
req.check("email", "email isnt valid").isEmail()
|
||||||
|
const errors = req.validationErrors() as any[]
|
||||||
|
|
||||||
|
if (errors)
|
||||||
|
return respond(res, false, {}, errors, 400)
|
||||||
|
|
||||||
|
//generate an uid
|
||||||
|
const uid = await generateUid()
|
||||||
|
|
||||||
|
const user = new User({
|
||||||
|
email, name, uid,
|
||||||
|
friends: [],
|
||||||
|
photo: process.env.DEFAULTPROFILEPIC
|
||||||
|
} as UserDoc) //used for my editor to help me
|
||||||
|
|
||||||
|
//save things in session
|
||||||
|
req.session.uid = uid
|
||||||
|
req.session.save(() => { })
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
encodePassword(password).then(result => savePassword(uid, result)),
|
||||||
|
user.save()
|
||||||
|
])
|
||||||
|
|
||||||
|
//send uid back
|
||||||
|
return respond(res,true,{ uid })
|
||||||
|
})
|
||||||
|
|
||||||
|
const account = async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
if (!req.session.uid)
|
||||||
|
res.json({
|
||||||
|
succes: false,
|
||||||
|
data: {},
|
||||||
|
errors: ["uid doesnt exist"]
|
||||||
|
}).status(203)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
succes: true,
|
||||||
|
data: {
|
||||||
|
uid: req.session.uid
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
//send erros to clinet
|
||||||
|
res.json({ succes: false, errors: [err] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const login = async (req: Request, res: Response) => {
|
||||||
|
try {
|
||||||
|
//check if we have an email or an username, and if we are note already logged in
|
||||||
|
if (req.session.uid)
|
||||||
|
return res.redirect("account")
|
||||||
|
|
||||||
|
let type = "name"
|
||||||
|
|
||||||
|
if (req.body.email)
|
||||||
|
type = "email"
|
||||||
|
|
||||||
|
const { password } = req.body
|
||||||
|
const data = req.body[(type == "name") ? "name" : type]
|
||||||
|
|
||||||
|
const doc = await User.findOne({ [data]: req.body[data] })
|
||||||
|
const uid = doc.uid
|
||||||
|
|
||||||
|
//check if the password is good
|
||||||
|
const passwordHash = await Passsord.findOne({ uid })
|
||||||
|
const match = await compare(password, passwordHash.password)
|
||||||
|
|
||||||
|
//return result
|
||||||
|
if (!match)
|
||||||
|
return res.json({
|
||||||
|
succes: false,
|
||||||
|
errors: ["wrong password"],
|
||||||
|
data: {
|
||||||
|
uid,
|
||||||
|
hash: passwordHash.password,
|
||||||
|
password,
|
||||||
|
[data]: req.body[data]
|
||||||
|
}
|
||||||
|
}).status(400)
|
||||||
|
|
||||||
|
//update the session ond save it
|
||||||
|
req.session.uid = uid
|
||||||
|
req.session.save(() => { })
|
||||||
|
|
||||||
|
//send it to the clinet
|
||||||
|
return res.json({ uid })
|
||||||
|
}
|
||||||
|
catch (errors) {
|
||||||
|
return res.json({ errors })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const logout = async (req: Request, res: Response) => {
|
||||||
|
//clear the uid
|
||||||
|
req.session.uid = undefined
|
||||||
|
|
||||||
|
//save it to the db
|
||||||
|
req.session.save(() => { })
|
||||||
|
|
||||||
|
res.send({ succes: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
router.use("*", validator())
|
||||||
|
|
||||||
|
router
|
||||||
|
.post("/", authHandler)
|
||||||
|
.post("/login", login)
|
||||||
|
.get("/account", account)
|
||||||
|
.get("/logout", logout)
|
||||||
|
.get("/uid", (req, res) => {
|
||||||
|
res.send(req.session.uid)
|
||||||
|
})
|
||||||
|
.get("/test/uid", async (req, res) => {
|
||||||
|
res.send(await generateUid())
|
||||||
|
})
|
||||||
|
|
||||||
|
export const auth = router
|
2
typescript/multiplayer-backend/src/routes/auth/index.ts
Normal file
2
typescript/multiplayer-backend/src/routes/auth/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./auth"
|
||||||
|
export * from "./token"
|
30
typescript/multiplayer-backend/src/routes/auth/token.ts
Normal file
30
typescript/multiplayer-backend/src/routes/auth/token.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { Router, Response, Request } from "express"
|
||||||
|
import { randomBytes } from "crypto"
|
||||||
|
import { SessionData,SessionDataDoc } from "../../models/SessionData";
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
|
||||||
|
const getToken = async (req: Request, res: Response) => {
|
||||||
|
//generate token
|
||||||
|
const token = randomBytes(16).toString("hex")
|
||||||
|
|
||||||
|
//save token into db
|
||||||
|
const data = new SessionData({
|
||||||
|
token,
|
||||||
|
data:"{}"
|
||||||
|
} as SessionDataDoc)
|
||||||
|
|
||||||
|
await data.save()
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
succes:true,
|
||||||
|
data:{
|
||||||
|
token
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get("/", getToken)
|
||||||
|
|
||||||
|
export const token = router
|
9
typescript/multiplayer-backend/src/routes/index.ts
Normal file
9
typescript/multiplayer-backend/src/routes/index.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { auth, token } from "./auth"
|
||||||
|
import { logs } from "./logging"
|
||||||
|
import { Router } from "express";
|
||||||
|
|
||||||
|
export const routes:{[key:string]:Router} = {
|
||||||
|
auth,
|
||||||
|
logs,
|
||||||
|
token
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./logs"
|
|
@ -0,0 +1,10 @@
|
||||||
|
export interface log{
|
||||||
|
title:string;
|
||||||
|
body:string;
|
||||||
|
time:Date;
|
||||||
|
elapsed?:number;
|
||||||
|
}
|
||||||
|
export interface shortConsole{
|
||||||
|
logs:log[];
|
||||||
|
log:(name:string,body:string) => any;
|
||||||
|
}
|
14
typescript/multiplayer-backend/src/routes/logging/logs.ts
Normal file
14
typescript/multiplayer-backend/src/routes/logging/logs.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { Router, Response, Request } from "express"
|
||||||
|
import { shortLogger } from "./shortLog";
|
||||||
|
import { reddirect } from "../../middleware/reddirect";
|
||||||
|
|
||||||
|
const router = Router()
|
||||||
|
|
||||||
|
const getShortLogs = (req: Request, res: Response) => {
|
||||||
|
res.json(shortLogger.logs)
|
||||||
|
}
|
||||||
|
|
||||||
|
router.get("/", getShortLogs)
|
||||||
|
router.use("/*", reddirect("/logs"))
|
||||||
|
|
||||||
|
export const logs = router
|
|
@ -0,0 +1,32 @@
|
||||||
|
import { performance } from "perf_hooks"
|
||||||
|
import { config } from "dotenv";
|
||||||
|
import { shortConsole } from "./interfaces";
|
||||||
|
config()
|
||||||
|
|
||||||
|
//clear the console
|
||||||
|
if (process.env.MODE == "DEV")
|
||||||
|
console.clear()
|
||||||
|
|
||||||
|
//used to log things
|
||||||
|
const shortLogger: shortConsole = {
|
||||||
|
|
||||||
|
//holds all the logs
|
||||||
|
logs: [],
|
||||||
|
|
||||||
|
//log a new message
|
||||||
|
log: (title: string, body: string) => {
|
||||||
|
//push the logs to the log array
|
||||||
|
shortLogger.logs.push({
|
||||||
|
title,
|
||||||
|
body,
|
||||||
|
time: new Date(),
|
||||||
|
elapsed: Math.floor(performance.now())
|
||||||
|
})
|
||||||
|
|
||||||
|
//if we are in dev mode log it
|
||||||
|
if (process.env.MODE == "DEV")
|
||||||
|
console.log(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { shortLogger }
|
45
typescript/multiplayer-backend/src/services/auth/signup.ts
Normal file
45
typescript/multiplayer-backend/src/services/auth/signup.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import * as bcrypt from "bcryptjs"
|
||||||
|
import { promisify } from "util";
|
||||||
|
import { randomBytes } from "crypto";
|
||||||
|
import { Passsord, PasswordDoc } from "../../models/Password";
|
||||||
|
import { User } from "../../models/User";
|
||||||
|
|
||||||
|
//promisify functions
|
||||||
|
const hash = promisify(bcrypt.hash)
|
||||||
|
|
||||||
|
|
||||||
|
export async function generateUid(): Promise<string> {
|
||||||
|
//generate uid
|
||||||
|
const uid = randomBytes(16).toString("hex")
|
||||||
|
|
||||||
|
//check if document exists
|
||||||
|
const doc = await User.findOne({ uid })
|
||||||
|
|
||||||
|
//if theres already an user with the same id, regenerate
|
||||||
|
if (doc)
|
||||||
|
return generateUid()
|
||||||
|
|
||||||
|
//then return the uid
|
||||||
|
return uid
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encodePassword(password: string): Promise<string> {
|
||||||
|
return hash(password, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function savePassword(uid: string, password: string) {
|
||||||
|
const passwordInstance = new Passsord({
|
||||||
|
password, uid
|
||||||
|
} as PasswordDoc)
|
||||||
|
|
||||||
|
return passwordInstance.save()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPassword(uid: string) {
|
||||||
|
//get doc
|
||||||
|
// const doc = await database.doc(`passwords/${uid}`).get()
|
||||||
|
|
||||||
|
//return result
|
||||||
|
// return doc.data()
|
||||||
|
return "train"
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./mongo"
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { config } from "dotenv"
|
||||||
|
import { connect, model, connection } from "mongoose"
|
||||||
|
|
||||||
|
config()
|
||||||
|
connect(process.env.DATABASE, { useNewUrlParser: true })
|
||||||
|
|
||||||
|
export const connected = new Promise((res, rej) => {
|
||||||
|
connection.on("open", (...args: any[]) => {
|
||||||
|
res(...args)
|
||||||
|
})
|
||||||
|
connection.on("error", (...args: any[]) => {
|
||||||
|
rej(...args)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
export { connection }
|
33
typescript/multiplayer-backend/tsconfig.json
Normal file
33
typescript/multiplayer-backend/tsconfig.json
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"*": [
|
||||||
|
"types/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"module": "commonjs",
|
||||||
|
"removeComments": true,
|
||||||
|
"lib": [
|
||||||
|
"es2015",
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"target": "ESNext",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"jsx": "preserve"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist",
|
||||||
|
"old_client"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue