Merge pull request #5403 from tsiegleauq/blacklist-browsers
Catch unsupported browsers
This commit is contained in:
commit
f590994875
@ -63,6 +63,7 @@
|
||||
"moment": "^2.24.0",
|
||||
"ng2-charts": "^2.3.0",
|
||||
"ng2-pdf-viewer": "^6.1.2",
|
||||
"ngx-device-detector": "^1.4.4",
|
||||
"ngx-file-drop": "^8.0.8",
|
||||
"ngx-mat-select-search": "^2.1.2",
|
||||
"ngx-material-timepicker": "^5.5.1",
|
||||
|
@ -7,6 +7,7 @@ import { LoginPrivacyPolicyComponent } from './site/login/components/login-priva
|
||||
import { LoginWrapperComponent } from './site/login/components/login-wrapper/login-wrapper.component';
|
||||
import { ResetPasswordConfirmComponent } from './site/login/components/reset-password-confirm/reset-password-confirm.component';
|
||||
import { ResetPasswordComponent } from './site/login/components/reset-password/reset-password.component';
|
||||
import { UnsupportedBrowserComponent } from './site/login/components/unsupported-browser/unsupported-browser.component';
|
||||
|
||||
/**
|
||||
* Global app routing
|
||||
@ -20,7 +21,8 @@ const routes: Routes = [
|
||||
{ path: 'reset-password', component: ResetPasswordComponent },
|
||||
{ path: 'reset-password-confirm', component: ResetPasswordConfirmComponent },
|
||||
{ path: 'legalnotice', component: LoginLegalNoticeComponent },
|
||||
{ path: 'privacypolicy', component: LoginPrivacyPolicyComponent }
|
||||
{ path: 'privacypolicy', component: LoginPrivacyPolicyComponent },
|
||||
{ path: 'unsupported-browser', component: UnsupportedBrowserComponent }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -6,6 +6,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
import { AuthService } from 'app/core/core-services/auth.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
@ -14,6 +15,7 @@ import { OverlayService } from 'app/core/ui-services/overlay.service';
|
||||
import { UserAuthType } from 'app/shared/models/users/user';
|
||||
import { ParentErrorStateMatcher } from 'app/shared/parent-error-state-matcher';
|
||||
import { BaseViewComponent } from 'app/site/base/base-view';
|
||||
import { BrowserSupportService } from '../../services/browser-support.service';
|
||||
|
||||
/**
|
||||
* Login mask component.
|
||||
@ -31,6 +33,8 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
|
||||
*/
|
||||
public hide: boolean;
|
||||
|
||||
private checkBrowser = true;
|
||||
|
||||
/**
|
||||
* Reference to the SnackBarEntry for the installation notice send by the server.
|
||||
*/
|
||||
@ -82,7 +86,8 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
|
||||
private route: ActivatedRoute,
|
||||
private formBuilder: FormBuilder,
|
||||
private loginDataService: LoginDataService,
|
||||
private overlayService: OverlayService
|
||||
private overlayService: OverlayService,
|
||||
private browserSupport: BrowserSupportService
|
||||
) {
|
||||
super(title, translate, matSnackBar);
|
||||
// Hide the spinner if the user is at `login-mask`
|
||||
@ -113,6 +118,14 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
|
||||
this.authService.redirectUser(user.id);
|
||||
}
|
||||
});
|
||||
|
||||
this.route.queryParams.pipe(filter(params => params.checkBrowser)).subscribe(params => {
|
||||
this.checkBrowser = params.checkBrowser === 'true';
|
||||
});
|
||||
|
||||
if (this.checkBrowser) {
|
||||
this.checkDevice();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,6 +135,12 @@ export class LoginMaskComponent extends BaseViewComponent implements OnInit, OnD
|
||||
this.clearOperatorSubscription();
|
||||
}
|
||||
|
||||
private checkDevice(): void {
|
||||
if (!this.browserSupport.isBrowserSupported()) {
|
||||
this.router.navigate(['./unsupported-browser'], { relativeTo: this.route });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the subscription to the operator.
|
||||
*/
|
||||
|
@ -1,7 +1,9 @@
|
||||
<!-- The actual form -->
|
||||
<header>
|
||||
<mat-toolbar class="login-logo-bar" color="primary">
|
||||
<a routerLink="/login"><img src="assets/img/openslides-logo-dark.svg" alt="OpenSlides-logo" /></a>
|
||||
<a routerLink="/login" [queryParams]="{ checkBrowser: false }"
|
||||
><img src="assets/img/openslides-logo-dark.svg" alt="OpenSlides-logo"
|
||||
/></a>
|
||||
</mat-toolbar>
|
||||
</header>
|
||||
|
||||
|
@ -0,0 +1,37 @@
|
||||
<main>
|
||||
<h1 class="center spacer-top-20" *ngIf="!supported">
|
||||
{{ 'Your browser is not supported by OpenSlides' | translate }}
|
||||
</h1>
|
||||
<h1 class="center spacer-top-20" *ngIf="supported">
|
||||
{{ 'Congratuations! Your browser is supported by OpenSlides' | translate }}
|
||||
</h1>
|
||||
|
||||
<mat-card class="os-card">
|
||||
<div>
|
||||
<span>
|
||||
{{ 'Your browser' | translate }}: {{ currentBrowser }} ({{ 'version' | translate }}:
|
||||
{{ browserVersion }})
|
||||
</span>
|
||||
<br />
|
||||
<span *ngIf="!!supportedVersion">{{ 'Minimal required version for your browser' | translate }}: {{ supportedVersion }}</span>
|
||||
</div>
|
||||
|
||||
<div class="spacer-top-20" *ngIf="!supported">
|
||||
<span>{{
|
||||
'Please update your browser or contact your system administration to have your browser updated for you.'
|
||||
| translate
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div class="spacer-top-20">
|
||||
<span>
|
||||
{{ 'OpenSlides recommends:' | translate }}
|
||||
<ul>
|
||||
<li *ngFor="let browser of recommendedBrowsers">
|
||||
<a [href]="browser.url">{{ browser.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</mat-card>
|
||||
</main>
|
@ -0,0 +1,27 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { UnsupportedBrowserComponent } from './unsupported-browser.component';
|
||||
|
||||
describe('UnsupportedBrowserComponent', () => {
|
||||
let component: UnsupportedBrowserComponent;
|
||||
let fixture: ComponentFixture<UnsupportedBrowserComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [UnsupportedBrowserComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(UnsupportedBrowserComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { BrowserRecommendation, BrowserSupportService } from '../../services/browser-support.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-unsupported-browser',
|
||||
templateUrl: './unsupported-browser.component.html'
|
||||
})
|
||||
export class UnsupportedBrowserComponent implements OnInit {
|
||||
public supported: boolean;
|
||||
public currentBrowser: string;
|
||||
public browserVersion: string;
|
||||
public supportedVersion: number;
|
||||
|
||||
public get recommendedBrowsers(): BrowserRecommendation[] {
|
||||
return this.browserSupprt.recommendedBrowsers;
|
||||
}
|
||||
|
||||
public constructor(private browserSupprt: BrowserSupportService) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
const deviceInfo = this.browserSupprt.getDeviceInfo();
|
||||
this.supported = this.browserSupprt.isBrowserSupported();
|
||||
this.currentBrowser = deviceInfo.browser;
|
||||
this.browserVersion = deviceInfo.browser_version;
|
||||
this.supportedVersion = this.browserSupprt.getSupportedVersion(deviceInfo);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { DeviceDetectorModule } from 'ngx-device-detector';
|
||||
|
||||
import { LoginLegalNoticeComponent } from './components/login-legal-notice/login-legal-notice.component';
|
||||
import { LoginMaskComponent } from './components/login-mask/login-mask.component';
|
||||
import { LoginPrivacyPolicyComponent } from './components/login-privacy-policy/login-privacy-policy.component';
|
||||
@ -9,16 +11,18 @@ import { LoginWrapperComponent } from './components/login-wrapper/login-wrapper.
|
||||
import { ResetPasswordConfirmComponent } from './components/reset-password-confirm/reset-password-confirm.component';
|
||||
import { ResetPasswordComponent } from './components/reset-password/reset-password.component';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
import { UnsupportedBrowserComponent } from './components/unsupported-browser/unsupported-browser.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, RouterModule, SharedModule],
|
||||
imports: [CommonModule, RouterModule, SharedModule, DeviceDetectorModule],
|
||||
declarations: [
|
||||
LoginWrapperComponent,
|
||||
ResetPasswordComponent,
|
||||
ResetPasswordConfirmComponent,
|
||||
LoginMaskComponent,
|
||||
LoginLegalNoticeComponent,
|
||||
LoginPrivacyPolicyComponent
|
||||
LoginPrivacyPolicyComponent,
|
||||
UnsupportedBrowserComponent
|
||||
]
|
||||
})
|
||||
export class LoginModule {}
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { BrowserSupportService } from './browser-support.service';
|
||||
|
||||
describe('BrowserSupportService', () => {
|
||||
let service: BrowserSupportService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(BrowserSupportService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,63 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { DeviceDetectorService, DeviceInfo } from 'ngx-device-detector';
|
||||
|
||||
const SmallestSupportedBrowserVersion = {
|
||||
Chrome: 81,
|
||||
Safari: 13,
|
||||
Firefox: 68,
|
||||
Opera: 66,
|
||||
'MS-Edge': 81,
|
||||
'MS-Edge-Chromium': 81
|
||||
};
|
||||
|
||||
const BrowserBlacklist = ['IE'];
|
||||
|
||||
export interface BrowserRecommendation {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class BrowserSupportService {
|
||||
public readonly recommendedBrowsers: BrowserRecommendation[] = [
|
||||
{
|
||||
name: 'Google Chrome',
|
||||
url: 'https://www.google.com/chrome/'
|
||||
},
|
||||
{
|
||||
name: 'Mozilla Firefox',
|
||||
url: 'https://www.mozilla.org/firefox/'
|
||||
}
|
||||
];
|
||||
|
||||
public constructor(private deviceService: DeviceDetectorService) {}
|
||||
|
||||
public getDeviceInfo(): DeviceInfo {
|
||||
return this.deviceService.getDeviceInfo();
|
||||
}
|
||||
|
||||
public getSupportedVersion(info: DeviceInfo): number {
|
||||
return SmallestSupportedBrowserVersion[info.browser];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the browser version and forward to an error page if the browser was too old
|
||||
*/
|
||||
public isBrowserSupported(): boolean {
|
||||
const deviceInfo = this.deviceService.getDeviceInfo();
|
||||
const browser = deviceInfo.browser;
|
||||
const version = parseInt(deviceInfo.browser_version, 10);
|
||||
|
||||
if (BrowserBlacklist.includes(browser)) {
|
||||
return false;
|
||||
} else if (!SmallestSupportedBrowserVersion[browser]) {
|
||||
// if we don't know the browser, let's assume they are working
|
||||
return true;
|
||||
} else {
|
||||
return version >= this.getSupportedVersion(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user