From f464c5c91edd4f1071e48e87a42ceb2c1f636183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20G=C3=B3mez=20Garc=C3=ADa?= Date: Sun, 15 Jan 2023 17:08:40 +0100 Subject: [PATCH] Enforced strict mode for typescript --- .hintrc | 1 - .../gui/components/filter/filter.component.ts | 12 +++++-- .../components/service/service.component.ts | 35 +++++-------------- .../services-group.component.ts | 10 +++--- src/app/gui/modal/modal.component.ts | 26 +++++--------- src/app/gui/navbar/navbar.component.ts | 19 ++++++---- src/app/gui/safe-html.pipe.ts | 2 +- src/app/gui/uds-gui.service.ts | 2 -- src/app/helpers/plugin.ts | 23 +++++++----- .../pages/downloads/downloads.component.ts | 4 +-- src/app/pages/error/error.component.ts | 20 +++++------ src/app/pages/login/login.component.ts | 2 +- src/app/pages/services/services.component.ts | 4 +-- src/app/uds-api.service.ts | 3 +- tsconfig.json | 1 + 15 files changed, 75 insertions(+), 89 deletions(-) diff --git a/.hintrc b/.hintrc index 5030cd6..cda7829 100644 --- a/.hintrc +++ b/.hintrc @@ -6,7 +6,6 @@ "axe/forms": "off", "axe/text-alternatives": "off", "button-type": "off", - "typescript-config/strict": "off", "typescript-config/consistent-casing": "off" } } \ No newline at end of file diff --git a/src/app/gui/components/filter/filter.component.ts b/src/app/gui/components/filter/filter.component.ts index dcf0a70..bceadf6 100644 --- a/src/app/gui/components/filter/filter.component.ts +++ b/src/app/gui/components/filter/filter.component.ts @@ -12,17 +12,23 @@ export class FilterComponent implements AfterViewInit { @Output() updateEvent = new EventEmitter(); - @ViewChild('input', {static: true}) input: ElementRef; + @ViewChild('input', {static: true}) input: ElementRef|undefined = undefined; constructor() { } ngAfterViewInit() { - fromEvent(this.input.nativeElement, 'keyup') + // if input is not set, this will fail + if(this.input === undefined) { + throw new Error('input atrribute is not provided'); + } + const input = this.input; + + fromEvent(input.nativeElement, 'keyup') .pipe( filter(Boolean), debounceTime(600), distinctUntilChanged(), - tap(() => this.update(this.input.nativeElement.value)) + tap(() => this.update(input.nativeElement.value)) ).subscribe(); } diff --git a/src/app/gui/components/service/service.component.ts b/src/app/gui/components/service/service.component.ts index d8507cb..16b2e0f 100644 --- a/src/app/gui/components/service/service.component.ts +++ b/src/app/gui/components/service/service.component.ts @@ -12,7 +12,7 @@ const MAX_NAME_LENGTH = 32; styleUrls: ['./service.component.scss'], }) export class ServiceComponent implements OnInit { - @Input() service: JSONService; + @Input() service: JSONService = {} as JSONService; constructor(private api: UDSApiService) {} @@ -62,10 +62,7 @@ export class ServiceComponent implements OnInit { get serviceNameClass() { const klass = []; - const len = Math.min( - Math.floor((this.service.visual_name.length - 1) / 4) * 4, - 28 - ); + const len = Math.min(Math.floor((this.service.visual_name.length - 1) / 4) * 4, 28); if (len >= 16) { klass.push('small-' + len.toString()); } @@ -95,27 +92,18 @@ export class ServiceComponent implements OnInit { } notifyNotLaunching(message: string) { - this.api.gui.alert( - '

' + django.gettext('Launcher') + '

', - message - ); + this.api.gui.alert('

' + django.gettext('Launcher') + '

', message); } - launch(transport: JSONTransport) { + launch(transport: JSONTransport|null) { if (this.service.maintenance) { - this.notifyNotLaunching( - django.gettext('Service is in maintenance and cannot be launched') - ); + this.notifyNotLaunching(django.gettext('Service is in maintenance and cannot be launched')); } else if (this.service.not_accesible) { - const calendarDeniedText = - this.service.custom_calendar_text || - this.api.config.messages.calendarDenied; + const calendarDeniedText = this.service.custom_calendar_text || this.api.config.messages.calendarDenied; this.notifyNotLaunching( '

' + - django.gettext( - 'This service is currently not accesible due to schedule restrictions.' - ) + + django.gettext('This service is currently not accesible due to schedule restrictions.') + '

' + calendarDeniedText + '

' + @@ -132,15 +120,10 @@ export class ServiceComponent implements OnInit { action(type: string) { const title = - (type === 'release' - ? django.gettext('Release service: ') - : django.gettext('Reset service: ')) + + (type === 'release' ? django.gettext('Release service: ') : django.gettext('Reset service: ')) + ' ' + this.serviceName; - const action = - type === 'release' - ? django.gettext('Service released') - : django.gettext('Service reseted'); + const action = type === 'release' ? django.gettext('Service released') : django.gettext('Service reseted'); this.api.gui.yesno(title, django.gettext('Are you sure?')).then((val) => { if (val) { this.api.action(type, this.service.id).then((service) => { diff --git a/src/app/gui/components/services-group/services-group.component.ts b/src/app/gui/components/services-group/services-group.component.ts index b34b81a..f750fef 100644 --- a/src/app/gui/components/services-group/services-group.component.ts +++ b/src/app/gui/components/services-group/services-group.component.ts @@ -9,15 +9,12 @@ import { UDSApiService } from '../../../uds-api.service'; }) export class ServicesGroupComponent implements OnInit { - @Input() services: JSONService[]; - @Input() group: JSONGroup; + @Input() services: JSONService[] = []; + @Input() group: JSONGroup = {} as JSONGroup; @Input() expanded = false; constructor(private api: UDSApiService) { } - ngOnInit() { - } - get groupImage() { return this.api.galleryImageURL(this.group.imageUuid); } @@ -37,4 +34,7 @@ export class ServicesGroupComponent implements OnInit { }); } + ngOnInit() { + } + } diff --git a/src/app/gui/modal/modal.component.ts b/src/app/gui/modal/modal.component.ts index 1ec55ad..7bf38b7 100644 --- a/src/app/gui/modal/modal.component.ts +++ b/src/app/gui/modal/modal.component.ts @@ -15,7 +15,6 @@ export interface ModalData { title: string; body: string; autoclose?: number; - checkClose?: Promise; type: DialogType; username?: string; domain?: string; @@ -28,18 +27,16 @@ export interface ModalData { }) export class ModalComponent implements OnInit { - extra: string; - subscription: Subscription; - yesno: Promise; - resolver: (value: boolean) => void; + extra = ''; + subscription: Subscription | null = null; + yesno: Promise = new Promise((resolve) => this.resolver = resolve); constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: ModalData) { // Notifies on case of yes or not to subscriber - this.yesno = new Promise((resolve) => { - this.resolver = resolve; - }); } + resolver: (value: boolean) => void = () => {}; + close() { this.dialogRef.close(); } @@ -54,24 +51,19 @@ export class ModalComponent implements OnInit { } async initAlert(): Promise { - if (this.data.autoclose > 0) { + const autoclose = (this.data.autoclose || 0); + if (autoclose > 0) { this.dialogRef.afterClosed().subscribe(res => { this.close(); }); - this.setExtra(this.data.autoclose); + this.setExtra(autoclose); interval(1000).subscribe(n => { - const rem = this.data.autoclose - (n + 1) * 1000; + const rem = autoclose - (n + 1) * 1000; this.setExtra(rem); if (rem <= 0) { this.close(); } }); - /*window.setTimeout(() => { - this.dialogRef.close(); - }, this.data.autoclose);*/ - } else if (this.data.checkClose) { - await this.data.checkClose; - this.close(); } } diff --git a/src/app/gui/navbar/navbar.component.ts b/src/app/gui/navbar/navbar.component.ts index 44221e9..51183d3 100644 --- a/src/app/gui/navbar/navbar.component.ts +++ b/src/app/gui/navbar/navbar.component.ts @@ -8,8 +8,8 @@ import { Lang } from '../../types/config'; styleUrls: ['./navbar.component.css'] }) export class NavbarComponent implements OnInit { - lang: Lang; // Current language - langs: Lang[]; // Available languages + lang: Lang = {} as Lang; // Current language + langs: Lang[] = []; // Available languages style = ''; // Empty on start constructor(public api: UDSApiService) { @@ -30,13 +30,18 @@ export class NavbarComponent implements OnInit { return; } - changeLang(to: Lang): boolean { + changeLang(to: Lang): void { // alert(document.getElementById('form_language')); this.lang = to; - document.getElementById('id_language').attributes['value'].value = to.id; - // alert(document.getElementById('id_language').attributes['value'].value); - (document.getElementById('form_language') as HTMLFormElement).submit(); - return false; + const lang = document.getElementById('id_language'); + if (lang) { + lang.setAttribute('value', to.id); + } + // Submit form form_language + const form = document.getElementById('form_language'); + if (form) { + (form as HTMLFormElement).submit(); + } } admin(): void { diff --git a/src/app/gui/safe-html.pipe.ts b/src/app/gui/safe-html.pipe.ts index d5aa8c7..a064725 100644 --- a/src/app/gui/safe-html.pipe.ts +++ b/src/app/gui/safe-html.pipe.ts @@ -13,7 +13,7 @@ export class SafeHtmlPipe implements PipeTransform { // Remove if exists any javascript event // eslint-disable-next-line max-len value = value.replace(/onclick|onmouseover|onmouseout|onmousemove|onmouseenter|onmouseleave|onmouseup|onmousedown|onkeyup|onkeydown|onkeypress|onkeydown|onkeypress|onkeyup|onchange|onfocus|onblur|onload|onunload|onabort|onerror|onresize|onscroll/gi, ''); - // Remove if exists any javascript: + // Remove if exists any javascript: reference value = value.replace(/javascript\s*\:/gi, ''); return this.sanitizer.bypassSecurityTrustHtml(value); diff --git a/src/app/gui/uds-gui.service.ts b/src/app/gui/uds-gui.service.ts index fa0db49..a97d478 100644 --- a/src/app/gui/uds-gui.service.ts +++ b/src/app/gui/uds-gui.service.ts @@ -24,7 +24,6 @@ export class UDSGuiService { title: string, message: string, autoclose = 0, - checkClose: Promise = null ): Promise> { const width = window.innerWidth < 800 ? '80%' : '40%'; const dialogRef = this.dialog.open(ModalComponent, { @@ -33,7 +32,6 @@ export class UDSGuiService { title, body: message, autoclose, - checkClose, type: DialogType.alert, }, disableClose: true, diff --git a/src/app/helpers/plugin.ts b/src/app/helpers/plugin.ts index 889bfa5..00629b7 100644 --- a/src/app/helpers/plugin.ts +++ b/src/app/helpers/plugin.ts @@ -10,7 +10,7 @@ declare const django: any; */ export class Plugin { - static transportsWindow = {}; + static transportsWindow: any = {}; delay: number; constructor(private api: UDSApiServiceType) { @@ -29,7 +29,6 @@ export class Plugin { text: string, info: string, waitTime: number, - checker: Promise = null ) { return this.api.gui.alert( django.gettext('Launching service'), @@ -39,7 +38,6 @@ export class Plugin { info + '

', waitTime, - checker ); } @@ -62,6 +60,13 @@ export class Plugin { 'hiddenUdsLauncherIFrame' ) as HTMLIFrameElement; } + // Ensure all is ok + if (elem === null) { + throw new Error('Unable to create hidden iframe'); + } + if (elem.contentWindow === null) { + throw new Error('Unable to get content window'); + } elem.contentWindow.location.href = url; } @@ -215,14 +220,15 @@ export class Plugin { private async processCredentials( data: JSONTransportURLService ): Promise { - if (data.url.indexOf('&creds=') !== -1) { - const creds = data.url.split('&creds=')[1]; + const url = data.url || ''; + if (url.indexOf('&creds=') !== -1) { + const creds = url.split('&creds=')[1]; let username = ''; let domain = ''; - // Remove credentials from url - data.url = data.url.split('&creds=')[0]; + // Remove credentials from data.url input + data.url = url.split('&creds=')[0]; // From "data=..." extract ticket and scrambler that is ticket.scrambler - const values = data.url.split('data=')[1].split('&')[0].split('.'); + const values = url.split('data=')[1].split('&')[0].split('.'); const ticket = values[0]; const scrambler = values[1]; @@ -253,6 +259,7 @@ export class Plugin { if (location.indexOf('o_s_w=') !== -1) { const osw = /(.*)&o_s_w=.*/.exec(location); wnd = 'same'; + // @ts-ignore osw is something for sure, checked before location = osw[1]; } else { // If the url contains "o_n_w", will open the url on a new window ALWAYS diff --git a/src/app/pages/downloads/downloads.component.ts b/src/app/pages/downloads/downloads.component.ts index f37ab77..4887866 100644 --- a/src/app/pages/downloads/downloads.component.ts +++ b/src/app/pages/downloads/downloads.component.ts @@ -9,7 +9,7 @@ import { Downloadable } from '../../types/config'; }) export class DownloadsComponent implements OnInit { - actors: Downloadable[]; + actors: Downloadable[] = []; constructor(public api: UDSApiService) { } @@ -33,7 +33,7 @@ export class DownloadsComponent implements OnInit { } img(filename: string) { - const extension = filename.split('.').pop().toLowerCase(); + const extension = (filename.split('.').pop() || '').toLowerCase(); let image = 'Linux'; if (extension === 'exe') { image = 'Windows'; diff --git a/src/app/pages/error/error.component.ts b/src/app/pages/error/error.component.ts index ef9aab4..c611709 100644 --- a/src/app/pages/error/error.component.ts +++ b/src/app/pages/error/error.component.ts @@ -11,25 +11,21 @@ declare const udsData: any; styleUrls: ['./error.component.css'], }) export class ErrorComponent implements OnInit { - error: string; - returnUrl: string; + error = ''; + returnUrl = '/'; constructor(public api: UDSApiService, private route: ActivatedRoute) {} - ngOnInit() { - this.getError(); + async ngOnInit() { + await this.getError(); } - getError(): void { - const id = this.route.snapshot.paramMap.get('id'); - if (id === '19') { + async getError(): Promise { + const id = this.route.snapshot.paramMap.get('id') || '-1'; + if (id === '19') { // 19 is MFA error, return to MFA this.returnUrl = '/mfa'; } - this.error = ''; // Request error string from UDS - this.api.getErrorInformation(id).then((errInfo) => { - // Set error to errInfo.error + Hex code - this.error = errInfo.error; - }); + this.error = (await this.api.getErrorInformation(id)).error; } } diff --git a/src/app/pages/login/login.component.ts b/src/app/pages/login/login.component.ts index 051e963..1c5fc62 100644 --- a/src/app/pages/login/login.component.ts +++ b/src/app/pages/login/login.component.ts @@ -12,7 +12,7 @@ declare const django: any; }) export class LoginComponent implements OnInit { auths: Authenticator[]; - auth: HTMLInputElement; + auth: HTMLInputElement = {} as HTMLInputElement; title = 'UDS Enterprise'; constructor(public api: UDSApiService) { diff --git a/src/app/pages/services/services.component.ts b/src/app/pages/services/services.component.ts index 25503a8..2cd41e4 100644 --- a/src/app/pages/services/services.component.ts +++ b/src/app/pages/services/services.component.ts @@ -30,7 +30,7 @@ export class ServicesComponent implements OnInit { transports: '' }; - group: GroupedServices[]; + group: GroupedServices[] = []; constructor(public api: UDSApiService) {} @@ -96,7 +96,7 @@ export class ServicesComponent implements OnInit { // Fill up groupedServices this.group = []; - let current: GroupedServices = null; + let current: GroupedServices|null = null; this.servicesInformation.services .filter( (value) => diff --git a/src/app/uds-api.service.ts b/src/app/uds-api.service.ts index afaaaaa..117e430 100644 --- a/src/app/uds-api.service.ts +++ b/src/app/uds-api.service.ts @@ -34,7 +34,7 @@ const toPromise = (observable: Observable, wait?: number): Promise => { @Injectable() export class UDSApiService implements UDSApiServiceType { readonly user: User; - transportsWindow: Window; + transportsWindow: Window|null = null; plugin: Plugin; constructor( @@ -43,7 +43,6 @@ export class UDSApiService implements UDSApiServiceType { public router: Router ) { this.user = new User(udsData.profile); - this.transportsWindow = null; this.plugin = new Plugin(this); } /** diff --git a/tsconfig.json b/tsconfig.json index 5f889e2..f45e018 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ "strictTemplates": true, }, "compilerOptions": { + "strict": true, "downlevelIteration": true, "importHelpers": true, "outDir": "./dist/out-tsc",