From 0e16c5f48319a95640730ed5e3b8d90608517a5b Mon Sep 17 00:00:00 2001 From: Jonny Ngo Luong <jonnynl@stud.ntnu.no> Date: Mon, 22 Feb 2021 01:17:40 +0100 Subject: [PATCH] feat: added jwt token as session and authentication token (#9) --- .gitignore | 5 + client/src/app/app.module.ts | 3 +- client/src/app/authentication/auth.module.ts | 12 + .../app/authentication/auth.service.spec.ts | 16 ++ client/src/app/authentication/auth.service.ts | 50 ++++ .../user-login-form.component.ts | 15 +- .../user-profile/user-profile.component.html | 3 + .../user-profile/user-profile.component.ts | 19 +- server/package-lock.json | 218 ++++++++++++++++++ server/package.json | 3 + server/src/config.ts | 11 +- .../src/controllers/userController/index.ts | 18 +- server/src/index.ts | 6 +- 13 files changed, 368 insertions(+), 11 deletions(-) create mode 100644 client/src/app/authentication/auth.module.ts create mode 100644 client/src/app/authentication/auth.service.spec.ts create mode 100644 client/src/app/authentication/auth.service.ts diff --git a/.gitignore b/.gitignore index 42b7fa6..3c05752 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,8 @@ yarn-error.log* .idea .vscode + +# keys and .env +jwtRS256.key +jwtRS256.key.pub +server/.env \ No newline at end of file diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 28a13e7..497c6e4 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -6,6 +6,7 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { PostModule } from './posts/post.module'; import { UserModule } from './users/user.module'; +import { AuthModule } from './authentication/auth.module'; import { SharedModule } from './shared/shared.module'; @@ -16,7 +17,7 @@ import { SharedModule } from './shared/shared.module'; imports: [ BrowserModule, UserModule, - + AuthModule, AppRoutingModule, PostModule, SharedModule, diff --git a/client/src/app/authentication/auth.module.ts b/client/src/app/authentication/auth.module.ts new file mode 100644 index 0000000..d2e4fae --- /dev/null +++ b/client/src/app/authentication/auth.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + + + +@NgModule({ + declarations: [], + imports: [ + CommonModule + ] +}) +export class AuthModule { } diff --git a/client/src/app/authentication/auth.service.spec.ts b/client/src/app/authentication/auth.service.spec.ts new file mode 100644 index 0000000..f1251ca --- /dev/null +++ b/client/src/app/authentication/auth.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthService } from './auth.service'; + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AuthService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/client/src/app/authentication/auth.service.ts b/client/src/app/authentication/auth.service.ts new file mode 100644 index 0000000..626aff1 --- /dev/null +++ b/client/src/app/authentication/auth.service.ts @@ -0,0 +1,50 @@ +import { HttpClient, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { User } from '../models/user.model'; +import { tap, shareReplay } from 'rxjs/operators'; + +interface IUserLogin { + username: string; + password: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + loginUrl = "api/user/login" + + constructor(private http: HttpClient) { } + + login(body: IUserLogin): Promise<string> { + return new Promise<string>( + (resolve, reject) => { + this.login_user(body).subscribe((data: any) => { + try { + resolve(data.token); + } catch (err: any) { + reject(err); + } + }, + (err: any) => { + console.log(err.message); + reject(err); + }); + } + ); + } + private login_user(body: IUserLogin) { + return this.http.post(this.loginUrl, body).pipe( + tap(res =>this.setSession(res)), + shareReplay());; + } + private setSession(authResult) { + console.log(authResult); + localStorage.setItem('token', authResult.token); + } + + logout() { + localStorage.removeItem("token"); + } + +} diff --git a/client/src/app/users/user-login-form/user-login-form.component.ts b/client/src/app/users/user-login-form/user-login-form.component.ts index 24057cb..328d380 100644 --- a/client/src/app/users/user-login-form/user-login-form.component.ts +++ b/client/src/app/users/user-login-form/user-login-form.component.ts @@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { User } from 'src/app/models/user.model'; import { UserService } from '../user.service'; +import { AuthService } from '../../authentication/auth.service'; @Component({ selector: 'app-user-login-form', @@ -14,7 +15,7 @@ export class UserLoginFormComponent implements OnInit { statusMessage: string = ""; - constructor(private userService: UserService, private router: Router) { } + constructor(private userService: UserService, private authService: AuthService, private router: Router) { } ngOnInit(): void { } @@ -46,13 +47,21 @@ export class UserLoginFormComponent implements OnInit { password: this.password, }; - // Adds user to database and changes page afterwards + // Login the user + this.authService.login(request).then(status => { + console.log("User login1: " + JSON.stringify(status)); + this.router.navigateByUrl("/"); + }).catch(error => { + console.log("Error user login: " + error); + }); + /* Old this.userService.login(request).then(status => { - console.log("User login: " + JSON.stringify(status)); + console.log("User login2: " + JSON.stringify(status)); this.router.navigateByUrl("/"); }).catch(error => { console.log("Error adding user: " + error); }); + */ } } diff --git a/client/src/app/users/user-profile/user-profile.component.html b/client/src/app/users/user-profile/user-profile.component.html index fedcb8b..9b8f350 100644 --- a/client/src/app/users/user-profile/user-profile.component.html +++ b/client/src/app/users/user-profile/user-profile.component.html @@ -1 +1,4 @@ <p>user-profile works!</p> +<p>Userid: {{user.getUserId}}</p> +<p>username: {{user.getUsername}}</p> +<p>email: {{user.getEmail}}</p> \ No newline at end of file diff --git a/client/src/app/users/user-profile/user-profile.component.ts b/client/src/app/users/user-profile/user-profile.component.ts index d7ff774..d818b70 100644 --- a/client/src/app/users/user-profile/user-profile.component.ts +++ b/client/src/app/users/user-profile/user-profile.component.ts @@ -1,4 +1,9 @@ import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { AuthService } from 'src/app/authentication/auth.service'; +import { User } from 'src/app/models/user.model'; +import { UserService } from '../user.service'; + @Component({ selector: 'app-user-profile', @@ -7,9 +12,21 @@ import { Component, OnInit } from '@angular/core'; }) export class UserProfileComponent implements OnInit { - constructor() { } + user: User = new User(); + constructor(private userService: UserService, private authService: AuthService, private router: Router) { } ngOnInit(): void { + const token = localStorage.getItem('token'); + if (!token) this.router.navigateByUrl("/"); + // Get user data from JWT token + const user_data = JSON.parse(atob(token.split(".")[1])).data[0]; + console.log(user_data) + // Gets all categories and displays them in dropdown + this.userService.getUser(user_data.userId).then(user => { + this.user = user; + }).catch (error => { + console.log("Error getting user: " + error); + }); } } diff --git a/server/package-lock.json b/server/package-lock.json index 4908b6d..95c60c7 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -15,14 +15,17 @@ "@types/supertest": "^2.0.10", "body-parser": "^1.19.0", "cors": "^2.8.5", + "dotenv": "^8.2.0", "express": "^4.17.1", "jest": "^26.6.3", + "jsonwebtoken": "^8.5.1", "mysql": "^2.18.1", "mysql2": "^2.2.5", "supertest": "^6.1.3", "ts-jest": "^26.5.1" }, "devDependencies": { + "@types/jsonwebtoken": "^8.5.0", "nodemon": "^2.0.7", "ts-node": "^9.1.1", "typescript": "^4.1.3" @@ -1062,6 +1065,15 @@ "pretty-format": "^26.0.0" } }, + "node_modules/@types/jsonwebtoken": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", + "integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -1697,6 +1709,11 @@ "node-int64": "^0.4.0" } }, + "node_modules/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=" + }, "node_modules/buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -2387,6 +2404,14 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, "node_modules/duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -2402,6 +2427,14 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/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==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4904,6 +4937,32 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "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" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -4918,6 +4977,25 @@ "verror": "1.10.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -4996,6 +5074,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -8997,6 +9110,15 @@ "pretty-format": "^26.0.0" } }, + "@types/jsonwebtoken": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz", + "integrity": "sha512-9bVao7LvyorRGZCw0VmH/dr7Og+NdjYSsKAxB43OQoComFbBgsEpoR9JW6+qSq/ogwVBg8GI2MfAlk4SYI4OLg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -9501,6 +9623,11 @@ "node-int64": "^0.4.0" } }, + "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", @@ -10039,6 +10166,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -10054,6 +10186,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" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -11928,6 +12068,30 @@ "minimist": "^1.2.5" } }, + "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.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -11939,6 +12103,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" + } + }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -11999,6 +12182,41 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "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.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/server/package.json b/server/package.json index ddee435..7b7e5cc 100644 --- a/server/package.json +++ b/server/package.json @@ -17,14 +17,17 @@ "@types/supertest": "^2.0.10", "body-parser": "^1.19.0", "cors": "^2.8.5", + "dotenv": "^8.2.0", "express": "^4.17.1", "jest": "^26.6.3", + "jsonwebtoken": "^8.5.1", "mysql": "^2.18.1", "mysql2": "^2.2.5", "supertest": "^6.1.3", "ts-jest": "^26.5.1" }, "devDependencies": { + "@types/jsonwebtoken": "^8.5.0", "nodemon": "^2.0.7", "ts-node": "^9.1.1", "typescript": "^4.1.3" diff --git a/server/src/config.ts b/server/src/config.ts index 3ca155c..f2dc97f 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -1,6 +1,8 @@ +const { config } = require('dotenv'); +config({ path: __dirname+'/../.env'}); const env = process.env; -const config = { +export default { db: { host: env.DB_HOST || 'mysql.stud.ntnu.no', user: env.DB_USER || 'jonnynl_tdt4140', @@ -12,6 +14,9 @@ const config = { debug: false }, listPerPage: 10, + JWT_KEY : env.JWT_KEY || "", + HOST: env.HOST || "localhost", + PORT: env.HTTPPORT || 3000, + ACCESS_TOKEN_SECRET: env.ACCESS_TOKEN_SECRET, + REFRESH_TOKEN_SECRET: env.REFRESH_TOKEN_SECRET, }; - -export default config; diff --git a/server/src/controllers/userController/index.ts b/server/src/controllers/userController/index.ts index f45e65b..6f2b01e 100644 --- a/server/src/controllers/userController/index.ts +++ b/server/src/controllers/userController/index.ts @@ -2,6 +2,8 @@ import { Response, Request } from "express"; import query from '../../services/db_query'; import express from 'express'; import IUser from '../../models/user'; +import * as jwt from 'jsonwebtoken'; +import config from '../../config'; const router = express.Router(); /* ============================= CREATE ============================= */ @@ -50,9 +52,23 @@ router.route('/login').post(async (request: Request, response: Response) => { const {username, password} = request.body; try { const input = "SELECT userId, username, email, create_time FROM user WHERE username=? AND password=?;" - response.status(200).json(await query(input,[username, password])); + const user = await query(input,[username, password]); + // Check if an user object is retrieved + const userObj = Object.values(JSON.parse(JSON.stringify(user.data)))[0]; + if (userObj) { + const jwt_token = jwt.sign({data: user.data}, config.JWT_KEY.replace(/\\n/gm, '\n'), { + algorithm: 'RS256', + expiresIn: 3600*24, // 24 hours + }); + response.status(200).json({ + token: jwt_token, + }); + } else { + response.status(403).send("Invalid combination of username and password given!"); + } } catch (error) { response.status(400).send("Bad Request"); + console.log(error); } }); diff --git a/server/src/index.ts b/server/src/index.ts index d4b4977..77bda9f 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,8 +1,10 @@ import app from './app'; +import config from './config'; // REST API config -const port = 3000; +const port = config.PORT; app.listen(port, () => { - console.log(`Listening on port ${port}!`) + const host = config.HOST; + console.log('[*] Server listening at http://%s:%s \n', host, port); }); \ No newline at end of file -- GitLab