Skip to content

Commit

Permalink
Merge pull request #102 from sinfo/feature/company-infos
Browse files Browse the repository at this point in the history
Feature: Deck2
  • Loading branch information
PMax5 authored Sep 18, 2023
2 parents 7e7f9d6 + 3bf6bd3 commit 3054770
Show file tree
Hide file tree
Showing 19 changed files with 9,474 additions and 12,069 deletions.
21,090 changes: 9,201 additions & 11,889 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
"@ng-bootstrap/ng-bootstrap": "^3.2.0",
"@ngx-translate/core": "^11.0.1",
"@ngx-translate/http-loader": "^4.0.0",
"@types/google-one-tap": "^1.2.2",
"@types/google.accounts": "^0.0.9",
"core-js": "^2.5.4",
"ng-lazyload-image": "^4.0.0",
"ng-lazyload-image": "4.0.0",
"ngx-clipboard": "^11.1.7",
"rxjs": "^6.3.3",
"rxjs": "6.0.0",
"zone.js": "~0.8.26"
},
"devDependencies": {
Expand Down
23 changes: 7 additions & 16 deletions src/app/admin/links/links.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,37 @@ import { Subscription } from 'rxjs/internal/Subscription';

import { environment } from 'src/environments/environment';
import { StorageService } from '../../storage.service';
import { Credentials } from '../login/credentials';

import { DeckService } from 'src/app/deck/deck.service';

import { Link, LinkForm, LinkEdit } from './link/link';
import { Companies } from './link/companies';
import { Company } from 'src/app/deck/company';
import { Event } from 'src/app/deck/event';
import { LoginService } from '../login/login.service';

@Injectable({
providedIn: 'root'
})
export class LinksService {

private corlief = `${environment.corlief}/link`;
private credentials: Credentials;

private companiesSubject: ReplaySubject<Companies> = new ReplaySubject<Companies>();
private headers: HttpHeaders;
companies: Companies;

event: Event;

eventSubscription: Subscription;
deckCompaniesSubscription: Subscription;

private companiesSubject: ReplaySubject<Companies> = new ReplaySubject<Companies>();

private headers: HttpHeaders;
deckCompaniesSubscription: Subscription;s

constructor(
private http: HttpClient,
private storage: StorageService,
private deckService: DeckService
private deckService: DeckService,
private loginService: LoginService
) {
this.companies = new Companies();

const credentials = <Credentials>this.storage.getItem('credentials');
this.credentials = credentials;

this.headers = new HttpHeaders({
'Authorization': `${credentials.user} ${credentials.token}`,
'Authorization': `Bearer ${this.loginService.getToken()}`,
'Content-Type': 'application/json'
});

Expand Down
123 changes: 123 additions & 0 deletions src/app/admin/login/jwt.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { Injectable } from '@angular/core'

/**
* This code was taken from: https://github.com/auth0/angular2-jwt
* We only need the basic functionality to decode and check if token is expired
*/
@Injectable()
export class JwtService {

constructor () {}

public urlBase64Decode (str: string): string {
let output = str.replace(/-/g, '+').replace(/_/g, '/')
switch (output.length % 4) {
case 0: {
break
}
case 2: {
output += '=='
break
}
case 3: {
output += '='
break
}
default: {
throw new Error('Illegal base64url string!')
}
}
return this.b64DecodeUnicode(output)
}

// credits for decoder goes to https://github.com/atk
private b64decode (str: string): string {
let chars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
let output = ''

str = String(str).replace(/=+$/, '')

if (str.length % 4 === 1) {
throw new Error(
"'atob' failed: The string to be decoded is not correctly encoded."
)
}

for (
// initialize result and counters
// tslint:disable-next-line:one-variable-per-declaration
let bc = 0, bs: any, buffer: any, idx = 0;
// get next character
// tslint:disable-next-line:no-conditional-assignment
(buffer = str.charAt(idx++));
// character found in table? initialize bit storage and add its ascii value;
// tslint:disable-next-line:no-bitwise
~buffer &&
(
// tslint:disable-next-line:no-conditional-assignment
(bs = bc % 4 ? bs * 64 + buffer : buffer),
// and if not first of each 4 characters,
// convert the first 8 bits to one ascii character
bc++ % 4
)
// tslint:disable-next-line:no-bitwise
? (output += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6))))
: 0
) {
// try to find character in table (0-63, not found => -1)
buffer = chars.indexOf(buffer)
}
return output
}

private b64DecodeUnicode (str: any) {
return decodeURIComponent(
Array.prototype.map
.call(this.b64decode(str), (c: any) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
})
.join('')
)
}

public decodeToken (token: string): any {
let parts = token.split('.')

if (parts.length !== 3) {
throw new Error('The inspected token doesn\'t appear to be a JWT.')
}

let decoded = this.urlBase64Decode(parts[1])
if (!decoded) {
throw new Error('Cannot decode the token.')
}

return JSON.parse(decoded)
}

public getTokenExpirationDate (token: string): Date {
let decoded: any
decoded = this.decodeToken(token)

if (!decoded.hasOwnProperty('exp')) {
return null
}

const date = new Date(0)
date.setUTCSeconds(decoded.exp)

return date
}

public isTokenExpired (token: string, offsetSeconds?: number): boolean {
let date = this.getTokenExpirationDate(token)
offsetSeconds = offsetSeconds || 0

if (date === null) {
return false
}

return !(date.valueOf() > new Date().valueOf() + offsetSeconds * 1000)
}
}
1 change: 1 addition & 0 deletions src/app/admin/login/login.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
.card-body {
display: flex;
flex-direction: column;
align-items: center;
}

.input-group-prepend {
Expand Down
30 changes: 2 additions & 28 deletions src/app/admin/login/login.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,11 @@
<div class="card">

<div class="card-header">
SINFO's login
SINFO Authentication
</div>

<div class="card-body">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">User</span>
</div>
<input [(ngModel)]="user" placeholder="user">
</div>

<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">Token</span>
</div>
<input [(ngModel)]="token" placeholder="token" type="password">
</div>

<span class="footer" [ngClass]="error ? 'with-message' : 'without-message'">

<span class="errorMessage" [hidden]="error === undefined">
<h6>{{error}}</h6>
</span>

<button class="btn" [ngClass]="loading ? 'btn-warning': 'btn-primary'" (click)="login()">
<fa-icon [icon]="['fas', 'sync']" [spin]="true" [hidden]="!loading"></fa-icon>
Login
</button>

</span>

<div id="google-button"></div>
</div>
</div>
</span>
99 changes: 70 additions & 29 deletions src/app/admin/login/login.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, AfterViewInit, NgZone, HostListener } from '@angular/core';
import { LoginService } from 'src/app/admin/login/login.service';
import { Credentials } from './credentials';
import { environment } from "../../../environments/environment";
import { Router } from '@angular/router';
import { JwtService } from './jwt.service';

declare let google: any;

@Component({
selector: 'app-login',
Expand All @@ -10,42 +13,80 @@ import { Router } from '@angular/router';
})
export class LoginComponent implements OnInit {

user: String;
token: String;
loading = false;
error: String;
private isLoggedIn = false;
private isGoogleActive = false;

constructor(private loginService: LoginService, private router: Router) { }
constructor(
private loginService: LoginService,
private jwtService: JwtService,
private zone: NgZone,
private router: Router) { }

ngOnInit() {
this.isLoggedIn = this.loginService.isLoggedIn();

if (this.isLoggedIn) {
this.router.navigate(['/admin']);
}

this.isGoogleActive = typeof google !== "undefined" && google !== null;
}

@HostListener('window:resize', ['$event'])
onWindowResize() {
this.renderGoogleButton();
}

changeLoading() {
this.loading = !this.loading;
ngAfterViewInit() {
this.initSocialSDKs();
}

login() {
this.changeLoading();
this.loginService.login(this.user, this.token)
.subscribe(
(credentials: Credentials) => {
this.changeLoading();
this.error = undefined;
this.loginService.saveCredentials(credentials);
this.router.navigate(['admin/reservations']);
},
error => {
this.changeLoading();

if (error.status === 401) {
this.error = 'Invalid credentials';
} else if (error.status === 0) {
this.error = 'Server down. Please contact the administrator';
} else {
this.error = 'Unknown error';
}

initSocialSDKs() {
google.accounts.id.initialize({
client_id: environment.google.clientId,
callback: this.handleGoogleCredentialResponse.bind(this),
auto_select: false,
cancel_on_tap_outside: true,
ux_mode: "popup",
});
this.renderGoogleButton();
}

private renderGoogleButton() {
if (this.isGoogleActive) {
google.accounts.id.renderButton(
document.getElementById("google-button"),
{
theme: "outline",
size: "medium",
type: "standard",
shape: "rectangular",
text: "signin_with",
logo_alignment: "center",
locale: "en_US",
width: 280
}
);
}
}

async handleGoogleCredentialResponse(response: any) {
let userInfo = this.jwtService.decodeToken(response.credential);

let userId = userInfo.sub;
let token = response.credential;
this.loginService.login(userId, token).subscribe(
(corliefCredentials) => {
this.loginService.saveToken(corliefCredentials);
this.zone.run(() =>
this.router.navigate(['/admin'])
);
},
(error) => {
console.error(error);
this.zone.run(() => this.router.navigate(["/login"]));
}
);
}
}
Loading

0 comments on commit 3054770

Please sign in to comment.