Add typescript/multiplayer-backend
This commit is contained in:
commit
7908f1221e
|
@ -1,6 +1,6 @@
|
|||
# Javascript
|
||||
|
||||
| Name | Description |
|
||||
| -------------------------------------- | -------------------------------------------------- |
|
||||
| [clever-dots](./clever-dots/) | Half broken genetic algorithm implementation in js |
|
||||
| [linear-regression](linear-regression) | Basic linear regression implementation |
|
||||
| Name | Description |
|
||||
| ---------------------------------------- | -------------------------------------------------- |
|
||||
| [clever-dots](./clever-dots/) | Half broken genetic algorithm implementation in js |
|
||||
| [linear-regression](./linear-regression) | Basic linear regression implementation |
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
# Typescript
|
||||
|
||||
| Name | Description |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [lunardash](./lunardash/) | Rhythm game I dropped super early into development |
|
||||
| [option](./option/) | Typescript implementation of the `Maybe` monad |
|
||||
| [wave38](./wave38/) | Remake of [wave37](https://github.com/Mateiadrielrafael/wave37) I dropped super early into development. |
|
||||
| [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/) |
|
||||
| [monadic](./monadic) | Custom web framework inspired by [halogen](https://github.com/purescript-halogen/purescript-halogen) |
|
||||
| [og-website](./og-website) | My first ever personal website |
|
||||
| Name | Description |
|
||||
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [lunardash](./lunardash/) | Rhythm game I dropped super early into development |
|
||||
| [monadic](./monadic) | Custom web framework inspired by [halogen](https://github.com/purescript-halogen/purescript-halogen) |
|
||||
| [multiplayer-backend](./multiplayer-backend) | Unfinished server for some multiplayer game. Later rebranded into `pleix-backend` |
|
||||
| [og-website](./og-website) | My first ever personal website |
|
||||
| [option](./option/) | Typescript implementation of the `Maybe` monad |
|
||||
| [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