diff --git a/quartz-manager-api/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java b/quartz-manager-api/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java index cc51e3d..b7f24d7 100644 --- a/quartz-manager-api/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java +++ b/quartz-manager-api/src/main/java/it/fabioformosa/quartzmanager/security/helpers/impl/JwtTokenHelper.java @@ -150,6 +150,9 @@ public class JwtTokenHelper { return authHeader.substring(7); } + if(request.getParameter("access_token") != null) + return request.getParameter("access_token"); + return null; } diff --git a/quartz-manager-frontend/angular.json b/quartz-manager-frontend/angular.json index 7cd6f33..563894f 100644 --- a/quartz-manager-frontend/angular.json +++ b/quartz-manager-frontend/angular.json @@ -11,6 +11,7 @@ "build": { "builder": "@angular-devkit/build-angular:browser", "options": { + "aot": true, "outputPath": "../server/src/main/resources/static", "index": "src/index.html", "main": "src/main.ts", @@ -27,6 +28,12 @@ }, "configurations": { "production": { + "budgets": [ + { + "type": "anyComponentStyle", + "maximumWarning": "6kb" + } + ], "optimization": true, "outputHashing": "all", "sourceMap": false, @@ -119,7 +126,7 @@ "schematics": { "@schematics/angular:component": { "prefix": "app", - "styleext": "css" + "style": "css" }, "@schematics/angular:directive": { "prefix": "app" diff --git a/quartz-manager-frontend/browserslist b/quartz-manager-frontend/browserslist new file mode 100644 index 0000000..8084853 --- /dev/null +++ b/quartz-manager-frontend/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/quartz-manager-frontend/package.json b/quartz-manager-frontend/package.json index 47d93ab..d442d69 100644 --- a/quartz-manager-frontend/package.json +++ b/quartz-manager-frontend/package.json @@ -12,19 +12,19 @@ }, "private": true, "dependencies": { - "@angular/animations": "7.2.13", - "@angular/cdk": "7.3.7", - "@angular/common": "7.2.13", - "@angular/compiler": "7.2.13", - "@angular/core": "7.2.13", - "@angular/flex-layout": "7.0.0-beta.24", - "@angular/forms": "7.2.13", - "@angular/http": "7.2.13", - "@angular/material": "7.3.7", - "@angular/platform-browser": "7.2.13", - "@angular/platform-browser-dynamic": "7.2.13", - "@angular/platform-server": "7.2.13", - "@angular/router": "7.2.13", + "@angular/animations": "9.1.4", + "@angular/cdk": "9.2.1", + "@angular/common": "9.1.4", + "@angular/compiler": "9.1.4", + "@angular/core": "9.1.4", + "@angular/flex-layout": "9.0.0-beta.29", + "@angular/forms": "9.1.4", + "@angular/material": "9.2.1", + "@angular/platform-browser": "9.1.4", + "@angular/platform-browser-dynamic": "9.1.4", + "@angular/platform-server": "9.1.4", + "@angular/router": "9.1.4", + "@auth0/angular-jwt": "^4.0.0", "@fortawesome/fontawesome": "^1.1.4", "@fortawesome/fontawesome-free-regular": "^5.0.8", "@fortawesome/fontawesome-free-solid": "^5.0.8", @@ -32,22 +32,22 @@ "core-js": "2.5.1", "hammerjs": "2.0.8", "net": "^1.0.2", - "rxjs": "6.4.0", + "rxjs": "6.5.5", "stompjs": "^2.3.3", - "tslib": "^1.9.0", - "zone.js": "0.8.18" + "tslib": "^1.10.0", + "zone.js": "~0.10.2" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.13.0", - "@angular-devkit/core": "^0.2.0", - "@angular/cli": "7.3.7", - "@angular/compiler-cli": "7.2.13", - "@angular/language-service": "7.2.13", + "@angular-devkit/build-angular": "~0.901.4", + "@angular-devkit/core": "^9.1.4", + "@angular/cli": "9.1.4", + "@angular/compiler-cli": "9.1.4", + "@angular/language-service": "9.1.4", "@types/hammerjs": "2.0.34", "@types/jasmine": "2.5.54", "@types/jasminewd2": "2.0.3", - "@types/node": "6.0.90", - "codelyzer": "4.2.1", + "@types/node": "^12.11.1", + "codelyzer": "^5.1.2", "jasmine-core": "2.6.4", "jasmine-spec-reporter": "4.1.1", "karma": "1.7.1", @@ -59,6 +59,6 @@ "protractor": "5.1.2", "ts-node": "3.0.6", "tslint": "5.7.0", - "typescript": "3.2.4" + "typescript": "3.8.3" } } diff --git a/quartz-manager-frontend/src/app/app.module.ts b/quartz-manager-frontend/src/app/app.module.ts index 72f2901..90e0d34 100644 --- a/quartz-manager-frontend/src/app/app.module.ts +++ b/quartz-manager-frontend/src/app/app.module.ts @@ -1,22 +1,23 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule, APP_INITIALIZER} from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { HttpModule } from '@angular/http'; import { HttpClientModule } from '@angular/common/http'; + +import {JWT_OPTIONS, JwtModule} from "@auth0/angular-jwt"; + // material -import { - MatButtonModule, - MatMenuModule, - MatIconModule, - MatToolbarModule, - MatTooltipModule, - MatCardModule, - MatChipsModule, - MatInputModule, - MatIconRegistry, - MatProgressSpinnerModule, - MatProgressBarModule, -} from '@angular/material'; +import {MatIconRegistry} from '@angular/material/icon'; +import {MatInputModule} from '@angular/material/input'; +import {MatChipsModule} from '@angular/material/chips'; +import {MatTooltipModule} from '@angular/material/tooltip'; +import {MatProgressBarModule} from '@angular/material/progress-bar'; +import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; +import {MatMenuModule} from '@angular/material/menu'; +import {MatToolbarModule} from '@angular/material/toolbar'; +import {MatIconModule} from '@angular/material/icon'; +import {MatButtonModule} from '@angular/material/button'; +import {MatCardModule} from '@angular/material/card'; + import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { FlexLayoutModule } from '@angular/flex-layout'; import { AppComponent } from './app.component'; @@ -77,6 +78,15 @@ export function initUserFactory(userService: UserService) { // debug: true // }; +export function jwtOptionsFactory(apiService: ApiService) { + return { + tokenGetter: () => { + return apiService.getToken(); + }, + whitelistedDomains: ['localhost:8080', 'localhost:4200'] + } +} + @NgModule({ declarations: [ AppComponent, @@ -99,9 +109,15 @@ export function initUserFactory(userService: UserService) { BrowserModule, FormsModule, ReactiveFormsModule, - HttpModule, HttpClientModule, AppRoutingModule, + JwtModule.forRoot({ + jwtOptionsProvider: { + provide: JWT_OPTIONS, + useFactory: jwtOptionsFactory, + deps: [ApiService] + } + }), MatMenuModule, MatTooltipModule, MatButtonModule, diff --git a/quartz-manager-frontend/src/app/components/header/header.component.scss b/quartz-manager-frontend/src/app/components/header/header.component.scss index 122b0bd..eb2bb4c 100644 --- a/quartz-manager-frontend/src/app/components/header/header.component.scss +++ b/quartz-manager-frontend/src/app/components/header/header.component.scss @@ -32,7 +32,7 @@ } -/deep/ { +::ng-deep { .app-header-accountMenu.mat-menu-panel { border-radius: 3px; max-width: initial; diff --git a/quartz-manager-frontend/src/app/model/SocketOption.model.ts b/quartz-manager-frontend/src/app/model/SocketOption.model.ts index 20d8fe3..529da9d 100644 --- a/quartz-manager-frontend/src/app/model/SocketOption.model.ts +++ b/quartz-manager-frontend/src/app/model/SocketOption.model.ts @@ -4,11 +4,14 @@ export class SocketOption{ brokerName : string; reconnectionTimeout : number = 30000 - constructor(socketUrl : string, topicName : string, brokerName : string = null, reconnectionTimeout : number = 30000){ + getAccessToken: Function = () => null; + + constructor(socketUrl : string, topicName : string, getAccessToken?: Function, brokerName : string = null, reconnectionTimeout : number = 30000){ this.socketUrl = socketUrl; this.topicName = topicName; this.brokerName = brokerName; this.reconnectionTimeout = reconnectionTimeout; + this.getAccessToken = getAccessToken || (() => null); } } \ No newline at end of file diff --git a/quartz-manager-frontend/src/app/services/api.service.ts b/quartz-manager-frontend/src/app/services/api.service.ts index 6760f30..bf84c6f 100644 --- a/quartz-manager-frontend/src/app/services/api.service.ts +++ b/quartz-manager-frontend/src/app/services/api.service.ts @@ -41,6 +41,8 @@ export class ApiService { this.jwtToken = token; } + getToken = () => this.jwtToken; + get(path: string, args?: any): Observable { const options = { headers: this.headers, @@ -50,8 +52,8 @@ export class ApiService { if (args) options['params'] = serialize(args); - if(this.jwtToken) - options.headers = options.headers.set('Authorization', `Bearer ${this.jwtToken}`); + // if(this.jwtToken) + // options.headers = options.headers.set('Authorization', `Bearer ${this.jwtToken}`); return this.http.get(path, options) .pipe(catchError(this.checkError.bind(this))); @@ -75,8 +77,8 @@ export class ApiService { withCredentials: true } - if(this.jwtToken) - options.headers = options.headers.append('Authorization', `Bearer ${this.jwtToken}`); + // if(this.jwtToken) + // options.headers = options.headers.append('Authorization', `Bearer ${this.jwtToken}`); const req = new HttpRequest(method, path, body, options); diff --git a/quartz-manager-frontend/src/app/services/logs.websocket.service.ts b/quartz-manager-frontend/src/app/services/logs.websocket.service.ts index 76664cc..fe2cd06 100644 --- a/quartz-manager-frontend/src/app/services/logs.websocket.service.ts +++ b/quartz-manager-frontend/src/app/services/logs.websocket.service.ts @@ -1,12 +1,12 @@ import { Injectable, OnInit } from '@angular/core'; -import { WebsocketService } from '.'; +import { WebsocketService, ApiService } from '.'; import { SocketOption } from '../model/SocketOption.model'; -Injectable() +@Injectable() export class LogsWebsocketService extends WebsocketService { - constructor(){ - super(new SocketOption('/quartz-manager/logs', '/topic/logs')) + constructor(private apiService: ApiService){ + super(new SocketOption('/quartz-manager/logs', '/topic/logs', apiService.getToken)) } } \ No newline at end of file diff --git a/quartz-manager-frontend/src/app/services/progress.websocket.service.ts b/quartz-manager-frontend/src/app/services/progress.websocket.service.ts index 378b7d2..173428b 100644 --- a/quartz-manager-frontend/src/app/services/progress.websocket.service.ts +++ b/quartz-manager-frontend/src/app/services/progress.websocket.service.ts @@ -1,12 +1,12 @@ import { Injectable, OnInit } from '@angular/core'; -import { WebsocketService } from '.'; +import { WebsocketService, ApiService } from '.'; import { SocketOption } from '../model/SocketOption.model'; -Injectable() +@Injectable() export class ProgressWebsocketService extends WebsocketService { - constructor(){ - super(new SocketOption('/quartz-manager/progress', '/topic/progress')) + constructor(private apiService: ApiService){ + super(new SocketOption('/quartz-manager/progress', '/topic/progress', apiService.getToken)) } } \ No newline at end of file diff --git a/quartz-manager-frontend/src/app/services/scheduler.service.ts b/quartz-manager-frontend/src/app/services/scheduler.service.ts index 2da0a1f..f2b351b 100644 --- a/quartz-manager-frontend/src/app/services/scheduler.service.ts +++ b/quartz-manager-frontend/src/app/services/scheduler.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Headers } from '@angular/http'; import { ApiService } from './api.service'; @Injectable() diff --git a/quartz-manager-frontend/src/app/services/user.service.ts b/quartz-manager-frontend/src/app/services/user.service.ts index 310eb49..351653a 100644 --- a/quartz-manager-frontend/src/app/services/user.service.ts +++ b/quartz-manager-frontend/src/app/services/user.service.ts @@ -1,5 +1,4 @@ import { Injectable } from '@angular/core'; -import { Headers } from '@angular/http'; import { ApiService } from './api.service'; import { ConfigService } from './config.service'; diff --git a/quartz-manager-frontend/src/app/services/websocket.service.ts b/quartz-manager-frontend/src/app/services/websocket.service.ts index a9fa640..e1eda64 100644 --- a/quartz-manager-frontend/src/app/services/websocket.service.ts +++ b/quartz-manager-frontend/src/app/services/websocket.service.ts @@ -1,10 +1,4 @@ -import { Injectable, OnInit } from '@angular/core'; -import { Headers } from '@angular/http'; - import { Observable } from 'rxjs'; - -import { ApiService } from './api.service'; - import { SocketEndpoint } from '../model/SocketEndpoint.model' @@ -39,10 +33,7 @@ export class WebsocketService { this.observableStompConnection = new Observable((observer) => { const subscriberIndex = this.subscriberIndex++; this.addToSubscribers({ index: subscriberIndex, observer }); - return () => { - const index = subscriberIndex; - this.removeFromSubscribers(index); - }; + return () => this.removeFromSubscribers(subscriberIndex); }); } @@ -51,13 +42,9 @@ export class WebsocketService { } removeFromSubscribers = (index) => { - let subscribeFromIndex; - for (let i=0 ; i < this.subscribers.length; i++) - if(i === index){ - subscribeFromIndex = this.subscribers[i]; - this.subscribers.splice(i, 1); - break; - } + if(index > this.subscribers.length) + throw new Error(`Unexpected error removing subscriber from websocket, because index ${index} is greater than subscriber length ${this.subscribers.length}`); + this.subscribers.splice(index, 1); } getObservable = () => { @@ -71,7 +58,7 @@ export class WebsocketService { out.headers = {}; out.headers.messageId = data.headers["message-id"]; - let messageIdIndex = this._messageIds.indexOf( out.headers.messageId); + let messageIdIndex = this._messageIds.indexOf(out.headers.messageId); if ( messageIdIndex > -1) { out.self = true; this._messageIds = this._messageIds.splice(messageIdIndex, 1); @@ -81,24 +68,20 @@ export class WebsocketService { _socketListener = (frame) => { console.log('Connected: ' + frame); - this._socket.stomp.subscribe(this._options.topicName, (data) => { - this.subscribers.forEach(subscriber => { - subscriber.observer.next(this.getMessage(data)); - }) - }) + this._socket.stomp.subscribe( + this._options.topicName, + data => this.subscribers.forEach(subscriber => subscriber.observer.next(this.getMessage(data))) + ); } _onSocketError = (errorMsg) => { let out: any = {}; out.type = 'ERROR'; out.message = errorMsg; - this.subscribers.forEach(subscriber => { - subscriber.observer.error(out); - }) + this.subscribers.forEach(subscriber => subscriber.observer.error(out)); this.scheduleReconnection(); } - scheduleReconnection = () => { this.reconnectionPromise = setTimeout(() => { console.log("Socket reconnecting... (if it fails, next attempt in " + this._options.reconnectionTimeout + " msec)"); @@ -126,7 +109,12 @@ export class WebsocketService { connect = () => { const headers = {}; - this._socket.client = new SockJS(this._options.socketUrl); + + let socketUrl = this._options.socketUrl; + if(this._options.getAccessToken()) + socketUrl += `?access_token=${this._options.getAccessToken()}` + + this._socket.client = new SockJS(socketUrl); this._socket.stomp = Stomp.over(this._socket.client); this._socket.stomp.connect(headers, this._socketListener, this._onSocketError); this._socket.stomp.onclose = this.scheduleReconnection; diff --git a/quartz-manager-frontend/src/tsconfig.app.json b/quartz-manager-frontend/src/tsconfig.app.json index 5e2507d..26227d8 100644 --- a/quartz-manager-frontend/src/tsconfig.app.json +++ b/quartz-manager-frontend/src/tsconfig.app.json @@ -2,12 +2,14 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/app", - "module": "es2015", "baseUrl": "", "types": [] }, - "exclude": [ - "test.ts", - "**/*.spec.ts" + "files": [ + "main.ts", + "polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" ] } diff --git a/quartz-manager-frontend/src/tsconfig.spec.json b/quartz-manager-frontend/src/tsconfig.spec.json index 15458ed..9c56a51 100644 --- a/quartz-manager-frontend/src/tsconfig.spec.json +++ b/quartz-manager-frontend/src/tsconfig.spec.json @@ -2,8 +2,6 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", - "module": "commonjs", - "target": "es5", "baseUrl": "", "types": [ "jasmine", diff --git a/quartz-manager-frontend/tsconfig.json b/quartz-manager-frontend/tsconfig.json index ab228cc..3a709a3 100644 --- a/quartz-manager-frontend/tsconfig.json +++ b/quartz-manager-frontend/tsconfig.json @@ -1,6 +1,7 @@ { "compileOnSave": false, "compilerOptions": { + "downlevelIteration": true, "importHelpers": true, "outDir": "./dist/out-tsc", "baseUrl": "src", @@ -9,7 +10,7 @@ "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es5", + "target": "es2015", "typeRoots": [ "node_modules/@types" ], @@ -17,6 +18,6 @@ "es2016", "dom" ], - "module": "es2015" + "module": "esnext" } } \ No newline at end of file diff --git a/quartz-manager-frontend/tslint.json b/quartz-manager-frontend/tslint.json index bb84fcf..1701630 100644 --- a/quartz-manager-frontend/tslint.json +++ b/quartz-manager-frontend/tslint.json @@ -100,12 +100,12 @@ "directive-selector": [true, "attribute", "app", "camelCase"], "component-selector": [true, "element", "app", "kebab-case"], - "use-input-property-decorator": true, - "use-output-property-decorator": true, - "use-host-property-decorator": true, + "no-inputs-metadata-property": true, + "no-outputs-metadata-property": true, + "no-host-metadata-property": true, "no-input-rename": true, "no-output-rename": true, - "use-life-cycle-interface": true, + "use-lifecycle-interface": true, "use-pipe-transform-interface": true, "component-class-suffix": true, "directive-class-suffix": true,