From a9c30a6f78aa5fe70d89898261094d18d35bf0a6 Mon Sep 17 00:00:00 2001 From: Luis Vilca Flores Date: Wed, 8 Apr 2020 22:59:22 -0500 Subject: [PATCH] feat(login) login now returns jwt --- .env | 3 +- .stignore | 4 ++ .vscode/settings.json | 2 + Dockerfile | 20 ++++++ Makefile | 4 ++ bashrc | 5 ++ k8s.yml | 33 +++++++++ okteto.yml | 12 ++++ package-lock.json | 91 +++++++++++++++++++++++++ package.json | 1 + src/app.module.ts | 4 +- src/modules/auth/auth.module.ts | 1 - src/modules/auth/auth.service.ts | 101 +++++++++++++--------------- src/modules/auth/utils/jwt.ts | 10 +++ src/modules/auth/utils/puppetter.ts | 17 +++++ src/modules/user/user.entity.ts | 7 ++ src/modules/user/user.service.ts | 11 +++ 17 files changed, 268 insertions(+), 58 deletions(-) create mode 100644 .stignore create mode 100644 .vscode/settings.json create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 bashrc create mode 100644 k8s.yml create mode 100644 okteto.yml create mode 100644 src/modules/auth/utils/jwt.ts create mode 100644 src/modules/auth/utils/puppetter.ts diff --git a/.env b/.env index de78a08..33b72f0 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -MONGO_SRV = 'mongodb+srv://SRN:123456789123@cubiculospool-oxewp.mongodb.net/CubiculosPoolDev?retryWrites=true&w=majority' \ No newline at end of file +MONGO_SRV = 'mongodb+srv://SRN:123456789123@cubiculospool-oxewp.mongodb.net/CubiculosPoolDev?retryWrites=true&w=majority' +JWT_SECRET = 'hArDT0D3C0D3PAZZW0RD' \ No newline at end of file diff --git a/.stignore b/.stignore new file mode 100644 index 0000000..2df3aed --- /dev/null +++ b/.stignore @@ -0,0 +1,4 @@ +/.git +/node_modules +/.vscode +/images \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7a73a41 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,2 @@ +{ +} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1e13215 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM node:13 AS base + +WORKDIR /app +RUN npm install +RUN npm run build +COPY dist/main.js dist/main.js + +################################# + +FROM base AS dev + +COPY bashrc /root/.bashrc +RUN npm install -g nodemon + +################################# + +FROM base AS prod + +EXPOSE 8080 +CMD node app.js diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..055b481 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: push +push: + okteto build -t okteto/upc-pool:node-dev --target dev . + okteto build -t okteto/upc-pool:node . diff --git a/bashrc b/bashrc new file mode 100644 index 0000000..aa1ea1f --- /dev/null +++ b/bashrc @@ -0,0 +1,5 @@ +cat << EOF +Welcome to your development environment. Happy coding! +EOF + +export PS1="\[\e[32m\]okteto\[\e[m\]> " diff --git a/k8s.yml b/k8s.yml new file mode 100644 index 0000000..d7c095e --- /dev/null +++ b/k8s.yml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: upc-pool +spec: + replicas: 1 + selector: + matchLabels: + app: upc-pool + template: + metadata: + labels: + app: upc-pool + spec: + containers: + - image: node + name: upc-pool + +--- + +apiVersion: v1 +kind: Service +metadata: + name: upc-pool + annotations: + dev.okteto.com/auto-ingress: "true" +spec: + type: ClusterIP + ports: + - name: "upc-pool" + port: 3000 + selector: + app: upc-pool diff --git a/okteto.yml b/okteto.yml new file mode 100644 index 0000000..a07fa5b --- /dev/null +++ b/okteto.yml @@ -0,0 +1,12 @@ +name: upc-pool +image: okteto/node +command: ["npm","install"] +workdir: /usr/ +environment: + - MONGO_SRV=mongodb+srv://SRN:123456789123@cubiculospool-oxewp.mongodb.net/CubiculosPoolDev?retryWrites=true&w=majority + - environment=development +forward: + - 3000:8000 + - 9229:9229 +persistentVolume: + enabled: false \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 19cb242..7d9db8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2524,6 +2524,11 @@ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -3363,6 +3368,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "elliptic": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", @@ -6897,6 +6910,30 @@ "graceful-fs": "^4.1.6" } }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -6909,6 +6946,25 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kareem": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", @@ -7041,12 +7097,47 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", diff --git a/package.json b/package.json index 8d8c188..b9e7a25 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "class-transformer": "^0.2.3", "class-validator": "^0.11.1", "dotenv": "^8.2.0", + "jsonwebtoken": "^8.5.1", "lightning-pool": "^2.1.3", "mongoose": "^5.9.7", "puppeteer": "^2.1.1", diff --git a/src/app.module.ts b/src/app.module.ts index c5bcc8d..0cf696a 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -4,11 +4,11 @@ import { AppService } from './app.service'; import { UserModule } from './modules/user/user.module'; import { AuthModule } from './modules/auth/auth.module'; import { MongooseModule } from '@nestjs/mongoose'; -require('dotenv').config() +require('dotenv').config() @Module({ imports: [MongooseModule.forRoot(process.env.MONGO_SRV,{useNewUrlParser: true,useUnifiedTopology: true}),UserModule, AuthModule], controllers: [AppController], - providers: [AppService], + providers: [AppService] }) export class AppModule {} diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts index 34ed42d..4f7f832 100644 --- a/src/modules/auth/auth.module.ts +++ b/src/modules/auth/auth.module.ts @@ -2,7 +2,6 @@ import { Module } from '@nestjs/common'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; import { UserModule } from '../user/user.module'; -import { UserService } from '../user/user.service'; @Module({ imports:[UserModule], diff --git a/src/modules/auth/auth.service.ts b/src/modules/auth/auth.service.ts index bdb7b68..70cbf06 100644 --- a/src/modules/auth/auth.service.ts +++ b/src/modules/auth/auth.service.ts @@ -4,18 +4,62 @@ import { async } from 'rxjs/internal/scheduler/async'; import { AuthDto } from './auth.entity'; import { UserService } from '../user/user.service'; import { User } from '../user/user.entity'; -const { Pool } = require('lightning-pool'); +import { Pool } from 'lightning-pool'; +import { puppetterLogin } from './utils/puppetter'; +import { JWTsign } from './utils/jwt'; // const puppeteer = require('puppeteer'); +/* eslint-disable prefer-const*/ @Injectable() export class AuthService { puppeteerInstance: Browser puppeteerPage: Page puppeteerPool - constructor(private userService: UserService) { + constructor(private readonly userService: UserService) { this.createFactory() } + async upbWebTestPool(userCode, password) { + let page: Page = await this.puppeteerPool.acquire() + try { + let response = await puppetterLogin(page,userCode,password) + this.puppeteerPool.release(page) + if (response) + throw new BadRequestException(response); + return { + status:200 + } + } catch (error) { + this.puppeteerPool.release(page) + throw error + } + } + + async createUser(userCode,password){ + let user:User = new User({userCode,password}) + let response = await this.userService.saveNewUser(user) + return response + } + + async loginUser() { + return + } + async loginUserExp(body:AuthDto) { + try { + let response = await this.upbWebTestPool(body.userCode, body.password) + if(response.status== 200){ + let createUser = await this.createUser(body.userCode,body.password) + console.log(createUser) + let jwt = JWTsign(createUser) + return jwt + } + } catch (error) { + console.error(this.loginUserExp.name,error); + throw error + } + + } + createFactory() { const factory = { create: async function (opts) { @@ -35,13 +79,10 @@ export class AuthService { reset: function (client: Page) { console.debug('Reseting Instance') return client.goto('https://aulavirtual.upc.edu.pe/',{ timeout:6000}) - }, - validate: function (client) { - } }; - var opts = { + const opts = { max: 3, min: 1, minIdle: 2 @@ -50,52 +91,4 @@ export class AuthService { this.puppeteerPool = new Pool(factory, opts) } - async upbWebTestPool(username, password) { - let page: Page = await this.puppeteerPool.acquire() - try { - await page.focus('#user_id'); - await page.keyboard.type(username); - await page.focus('#password'); - await page.keyboard.type(password); - await page.click('#entry-login'); - await page.waitFor(200); - let response = await page.evaluate(() => { - try { - return document.getElementById('loginErrorMessage').textContent; - } catch (e) { - return null; - } - }); - console.log('resp', response); - this.puppeteerPool.release(page) - if (response) - throw new BadRequestException(response); - return { - statusCode: 200, - message: 'Ok' - } - } catch (error) { - this.puppeteerPool.release(page) - throw error - } - } - - upcApi() { - - } - - async loginUser() { - - let response = await this.upcApi() - return - } - async loginUserExp(body:AuthDto) { - let response = await this.upbWebTestPool(body.userCode, body.password) - if(response.statusCode == 200){ - let user = new User() - //this.userService.saveNewUser() - } - return response - } - } diff --git a/src/modules/auth/utils/jwt.ts b/src/modules/auth/utils/jwt.ts new file mode 100644 index 0000000..7abeba7 --- /dev/null +++ b/src/modules/auth/utils/jwt.ts @@ -0,0 +1,10 @@ + +import * as jwt from 'jsonwebtoken' + +export async function JWTvalidate(token) { + return jwt.verify(token, process.env.JWT_SECRET, {expiresIn: '90d'}) +} + +export async function JWTsign(obj) { + return jwt.sign({ _id: obj._id }, process.env.JWT_SECRET); +} \ No newline at end of file diff --git a/src/modules/auth/utils/puppetter.ts b/src/modules/auth/utils/puppetter.ts new file mode 100644 index 0000000..5358fe9 --- /dev/null +++ b/src/modules/auth/utils/puppetter.ts @@ -0,0 +1,17 @@ + + +export async function puppetterLogin(page, username, password) { + await page.focus('#user_id'); + await page.keyboard.type(username); + await page.focus('#password'); + await page.keyboard.type(password); + await page.click('#entry-login'); + await page.waitFor(200); + return await page.evaluate(() => { + try { + return document.getElementById('loginErrorMessage').textContent; + } catch (e) { + return null; + } + }); +} diff --git a/src/modules/user/user.entity.ts b/src/modules/user/user.entity.ts index ab9833d..3855113 100644 --- a/src/modules/user/user.entity.ts +++ b/src/modules/user/user.entity.ts @@ -9,6 +9,13 @@ class HoursLeft { } export class User { + constructor(obj){ + this.name= obj.name + this.userCode= obj.userCode ?? obj.username + this.userCode = this.userCode.toUpperCase() + this.email= `${this.userCode}@upc.edu.pe` + } + @IsEmail() @IsNotEmpty() email: string; diff --git a/src/modules/user/user.service.ts b/src/modules/user/user.service.ts index 3d0a261..c8b1972 100644 --- a/src/modules/user/user.service.ts +++ b/src/modules/user/user.service.ts @@ -6,6 +6,7 @@ import { validate } from 'class-validator'; @Injectable() export class UserService { + private number = 0 constructor(@InjectModel('users') private userModel: Model) { } getHello(): string { @@ -14,6 +15,16 @@ export class UserService { async saveNewUser(user: User) { try { + user.inRoom =false + user.hoursLeft ={ + todayHours:2, + tomorrowHours:2 + } + user.secondaryHoursLeft = 2 + user.points = 0 + user.inRoom = false + user.name = `Usuario ${++this.number}` + const createdUser = new this.userModel(user) return await createdUser.save() } catch (error) {