Skip to content

Commit

Permalink
add authentication by user vs client user
Browse files Browse the repository at this point in the history
  • Loading branch information
EnricoSchw committed Nov 2, 2024
1 parent e2796cc commit 734b481
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 64 deletions.
5 changes: 5 additions & 0 deletions projects/core/src/lib/entities/account.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface Account {
user: string,
email: string,
password: string,
}
5 changes: 5 additions & 0 deletions projects/core/src/lib/entities/client-user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface ClientUser {
id: string,
name: string,
token: string,
}
4 changes: 4 additions & 0 deletions projects/core/src/lib/entities/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './account';
export * from './channel.msg';
export * from './client-user';
export * from './constraints';
export * from './device-settings';
export * from './lobby-media.event';
Expand All @@ -7,6 +9,7 @@ export * from './lobby-media-muted';
export * from './lobby-media-purpose';
export * from './lobby-media-stream';
export * from './media-devices';
export * from './token';
export * from './sdp-media-info';
export * from './sdp-media-line';
export * from './space';
Expand All @@ -18,3 +21,4 @@ export * from './user';




1 change: 0 additions & 1 deletion projects/core/src/lib/entities/lobby-media-stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import {User} from './user';
import {LobbyMedia} from './lobby-media';
import {LobbyMediaPurpose} from './lobby-media-purpose';

Expand Down
3 changes: 3 additions & 0 deletions projects/core/src/lib/entities/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Token {
jwt: string
}
5 changes: 2 additions & 3 deletions projects/core/src/lib/entities/user.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export interface User {
id: string,
name: string,
token: string,
name: string,
domain: string,
}
4 changes: 2 additions & 2 deletions projects/core/src/lib/interceptors/auth.interceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ export class AuthInterceptor implements HttpInterceptor {
.pipe(
map(isActive => {
if (isActive) {
const token = this.session.getToken();
const token = this.session.getAuthenticationToken();
request = request.clone({
setHeaders: {
Authorization: token,
Authorization: `Bearer ${token}`,
},
});
}
Expand Down
82 changes: 82 additions & 0 deletions projects/core/src/lib/provider/auth.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {Injectable} from '@angular/core';
import {Account, Token, User} from '../entities';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {ParameterService} from './parameter.service';
import {catchError, lastValueFrom, map, mergeMap, Observable, tap} from 'rxjs';
import {handleError} from './error.handler';
import {SessionService} from './session.service';

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

httpOptions = {
headers: new HttpHeaders({'Content-Type': 'application/json', 'Accept': 'application/json'}),
};

constructor(private http: HttpClient, private params: ParameterService, private session: SessionService) {
}

login(email: string, pass: string): Observable<void> {
const loginUrl = `${this.params.API_PREFIX}/auth/login`;
const body = {email, pass};
// returns 200 || 403
return this.http.post<Token>(loginUrl, body, this.httpOptions).pipe(
tap((token: Token) => this.session.setAuthenticationToken(token.jwt)),
mergeMap(() => this.getUser()),
map((user) => this.session.setUser(user))
);
}

registerAccount(account: Account): Observable<void> {
const url = `${this.params.API_PREFIX}/auth/register`;
// returns 201 || 400
return this.http.post<void>(url, account, this.httpOptions);
}

verifyAccount(token: String): Observable<void> {
const url = `${this.params.API_PREFIX}/auth/verify`;
// returns 200 || 400
return this.http.put<void>(url, {token}, this.httpOptions);
}

forgetPassword(email: string) {
const url = `${this.params.API_PREFIX}/auth/forgotPassword`;
const body = {email};

return lastValueFrom(this.http.post(url, body, this.httpOptions).pipe(
tap(a => console.log('Forgot Password Finish', a)),
catchError(handleError<string>('forgot password', ''))
)
);
}

newPassword(password: string, token: string) {
const url = `${this.params.API_PREFIX}/auth/newPassword`;
const body = {password, token};

return lastValueFrom(this.http.post(url, body, this.httpOptions).pipe(
tap(a => console.log('New Password Finish', a)),
catchError(handleError<string>('new password', ''))
)
);
}

deleteAccount(email: string) {
const url = `${this.params.API_PREFIX}/auth/deleteAccount`;
const body = {email};

return lastValueFrom(this.http.post(url, body, this.httpOptions).pipe(
tap(a => console.log('Delete Account', a)),
catchError(handleError<string>('delete account', ''))
)
);
}

private getUser(): Observable<User> {
const userUrl = `${this.params.API_PREFIX}/auth/user`;
// returns 200 || 403
return this.http.get<User>(userUrl, this.httpOptions);
}
}
24 changes: 24 additions & 0 deletions projects/core/src/lib/provider/error.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {Observable, of} from 'rxjs';


/**
* Handle Http operation that failed.
* Let the app continue.
*
* @param operation - name of the operation that failed
* @param result - optional value to return as the observable result
*/
export const handleError = <T>(operation = 'operation', result?: T): (error: any) => Observable<T> => {

return (error: any): Observable<T> => {

// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead

// TODO: better job of transforming error for user consumption
console.log(`${operation} failed: ${error.message}`);

// Let the app keep running by returning an empty result.
return of(result as T);
};
};
1 change: 1 addition & 0 deletions projects/core/src/lib/provider/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './auth.service';
export * from './channel-messenger';
export * from './lobby.service';
export * from './message.service';
Expand Down
81 changes: 25 additions & 56 deletions projects/core/src/lib/provider/session.service.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,58 @@
import {Injectable} from '@angular/core';
import {BehaviorSubject, Observable, of, Subject} from 'rxjs';
import {User} from '../entities';
import {ClientUser} from '../entities';
import {User} from '../entities/user';

const USER_NAME_KEY = 'user-name';
const USER_DOMAIN_KEY = 'user-domain';
const SESSION_TOKEN_KEY = 'jwt';

@Injectable({
providedIn: 'root'
})
export class SessionService {
private readonly users: User[] = [
{id: 'root@localhost:9000', name: 'root@localhost:9000', token: token1},
{id: 'user123@localhost:9000', name: 'user123@localhost:9000', token: token2},
{id: 'guest-2', name: 'Guest 2', token: token3},
{id: 'guest-3', name: 'Guest 3', token: token4},
{id: 'guest-4', name: 'Guest 4', token: token5},
];

private readonly userName$: Subject<string>;
private readonly anonymous = 'anonymous';

private authToken: string | undefined;

constructor() {
const user = localStorage.getItem('user');
const user = window.localStorage.getItem(USER_NAME_KEY);
this.userName$ = new BehaviorSubject<string>(user === null ? this.anonymous : user);
}

setAuthenticationToken(token: string) {
this.authToken = token;
public setAuthenticationToken(token: string) {
window.localStorage.setItem(SESSION_TOKEN_KEY, token);
}

public getAuthenticationToken(): string | null {
return window.localStorage.getItem(SESSION_TOKEN_KEY);
}

isActive(): Observable<boolean> {
if (this.authToken !== undefined) {
if (this.getAuthenticationToken() !== null) {
return of(true);
}
const user = localStorage.getItem('user');
return of(user !== null);
return of(false)
}

getUserName(): Observable<string> {
return this.userName$;
}

setUserName(user: User): boolean {
const found = this.users.find((list) => list.id === user.id);
if (found === undefined) {
return false;
}
localStorage.setItem('user', user.name);
this.userName$.next(user.name);
return true;
}

getUsers(): User[] {
return this.users;
}

public removeUser(key: string) {
localStorage.removeItem('user');
this.userName$.next(this.anonymous);
}

public clearData() {
localStorage.clear();
window.localStorage.clear();
this.userName$.next(this.anonymous);
}

public getToken(): string {
if (this.authToken !== undefined) {
return this.authToken;
}

let userName = localStorage.getItem('user');
if (userName === null) {
return '';
}
const user = this.users.find(items => items.name === userName);
if (user === undefined) {
return '';
}
public setUser(user: User) {
window.localStorage.setItem(USER_NAME_KEY, user.name);
window.localStorage.setItem(USER_DOMAIN_KEY, user.domain);
this.userName$.next(user.name);
}

return `Bearer ${user.token}`;
public removeUser(key: string) {
window.localStorage.removeItem(USER_NAME_KEY);
window.localStorage.removeItem(USER_DOMAIN_KEY);
this.userName$.next(this.anonymous);
}
}

const token1 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJ1dWlkIjoiMWY1NjA2NmYtYjA1Yi00NDhhLWI3NjUtYjhkYzJiZTU1OTY3In0.GV0ptLGhnA0gwJC5zlKPY5z94KfLYUEpDraQmXPAR4o';
const token2 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJ1dWlkIjoiOGRhMGNkYzItZTVmMS00ZmZiLWIwYTktYWYxODI0MzI5OTQ0In0.CVk4I_9BP5yQuFS4X6XNZsvQ7tFStn3eGXGtNVYvSjY';
const token3 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJ1dWlkIjoiNzBiZTg2ODItNzk5Yy00MjdmLWI3MjgtZmQwMDhjNTYzYWFjIn0.mLT7DRp50QP6OqqxBQmf4VSx02i3cA0jk89UMdXLhBY';
const token4 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJ1dWlkIjoiMjhiYmYzNTctYTFmNy00NDkwLWIxZjItYTYzN2E0YWU5YmFlIn0.wMfmkJ0VBj86tW5NfQnnV91j2YT-mUZeM_E9qbt_bjg';
const token5 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJ1dWlkIjoiZmUwMjI2NDgtYTBlOS00NDQ0LTlkNGQtYTRjMGQ5ZWZiNmQ3In0.HgWacVwFeEgYBG6iDJYlQ25VTymM0xHpnppjWGrzOp4';
4 changes: 2 additions & 2 deletions projects/core/src/lib/shig-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import {
} from './component';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import '@material/web/switch/switch';
import '@material/web/chips/filter-chip';
// import '@material/web/common';



@NgModule({ declarations: [
Expand Down

0 comments on commit 734b481

Please sign in to comment.