Skip to content

Commit

Permalink
Add new backend functionalities (e.g. changed session flow, reset pas…
Browse files Browse the repository at this point in the history
…sword, confirm email) and start cleaning up the project a bit.
  • Loading branch information
carlkuesters committed Dec 10, 2023
1 parent ae5bcb5 commit 026a56a
Show file tree
Hide file tree
Showing 94 changed files with 1,256 additions and 518 deletions.
22 changes: 9 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@
"@ngrx/effects": "^17.0.1",
"@ngrx/entity": "^17.0.1",
"@ngrx/store": "^17.0.1",
"@ngrx/store-devtools": "^17.0.1",
"@ngx-translate/core": "^15.0.0",
"@ngx-translate/http-loader": "^8.0.0",
"bcryptjs": "^2.4.3",
"electron-is-dev": "^2.0.0",
"electron-updater": "^6.1.7",
"jwt-decode": "^4.0.0",
"rxjs": "^7.8.1",
"tslib": "^2.6.2",
"zone.js": "~0.14.2"
Expand Down
17 changes: 16 additions & 1 deletion src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { AuthenticationComponent } from './pages/authentication/authentication.component';
import { ConfirmEmailComponent } from './pages/authentication/confirm-email/confirm-email.component';
import { ForgotPasswordComponent } from './pages/authentication/forgot-password/forgot-password.component';
import { LoginComponent } from './pages/authentication/login/login.component';
import { RegistrationComponent } from './pages/authentication/registration/registration.component';
import { ResetPasswordComponent } from './pages/authentication/reset-password/reset-password.component';
import { HomeComponent } from './pages/home/home.component';
import { LibraryComponent } from './pages/library/library.component';
import { OfflineComponent } from './pages/offline/offline.component';
Expand All @@ -11,7 +16,17 @@ import { StoreAppComponent } from './pages/store-app/store-app.component';

const routes: Routes = [
{ path: 'update', component: SelfUpdateComponent },
{ path: 'authentication', component: AuthenticationComponent },
{
path: 'authentication',
component: AuthenticationComponent,
children: [
{ path: 'registration', component: RegistrationComponent },
{ path: 'login', component: LoginComponent },
{ path: 'confirmEmail', component: ConfirmEmailComponent },
{ path: 'forgotPassword', component: ForgotPasswordComponent },
{ path: 'resetPassword', component: ResetPasswordComponent },
],
},
{ path: 'offline', component: OfflineComponent },
{ path: 'home', component: HomeComponent },
{ path: 'store', component: StoreComponent },
Expand Down
6 changes: 2 additions & 4 deletions src/app/core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { NgModule } from '@angular/core';

import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

Expand All @@ -27,7 +26,7 @@ import { selfUpdateReducer } from '../store/reducers/self-update.reducers';
import { userReducer } from '../store/reducers/user.reducers';
import { HeaderComponent } from './components/header/header.component';
import { WindowControlsComponent } from './components/window-controls/window-controls.component';
import { SessionIdInterceptor } from './interceptors/session-id.interceptor';
import { AuthTokenInterceptor } from './interceptors/auth-token.interceptor';
import { AppHttpService } from './services/app-http.service';
import { BackgroundService } from './services/background.service';
import { ConfigHttpService } from './services/config-http.service';
Expand Down Expand Up @@ -60,7 +59,6 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
SelfUpdateEffects,
UserEffects,
]),
StoreDevtoolsModule.instrument({ maxAge: 50 }),

TranslateModule.forRoot({
loader: {
Expand All @@ -82,7 +80,7 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
UserHttpService,
{
provide: HTTP_INTERCEPTORS,
useClass: SessionIdInterceptor,
useClass: AuthTokenInterceptor,
multi: true,
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';
import { first, mergeMap } from 'rxjs/operators';

import { getSessionId } from '../../store/selectors/user.selectors';
import { getAuthToken } from '../../store/selectors/user.selectors';

@Injectable()
export class SessionIdInterceptor implements HttpInterceptor {
export class AuthTokenInterceptor implements HttpInterceptor {
constructor(public store: Store) {}

intercept(
request: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
return this.store.select(getSessionId).pipe(
return this.store.select(getAuthToken).pipe(
first(),
mergeMap((sessionId) => {
if (sessionId != null) {
mergeMap((authToken) => {
if (authToken != null) {
request = request.clone({
setHeaders: {
sessionId,
Authorization: 'Bearer ' + authToken,
},
});
}
Expand Down
10 changes: 6 additions & 4 deletions src/app/core/services/app-http.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Inject, Injectable } from '@angular/core';

import { Observable } from 'rxjs';

import { App } from '../../model/app.model';
import { AppFilesResponse } from '../../model/app-files-response.model';
import { App } from '../../interfaces/app.interface';
import { AppFilesResponse } from '../../interfaces/app-files-response.interface';
import { MASTERSERVER_URL } from '../injection-tokens';

@Injectable()
Expand All @@ -19,14 +19,16 @@ export class AppHttpService {
}

addToAccount(appId: number): Observable<void> {
return this.httpClient.get<void>(
return this.httpClient.post<void>(
this.masterserverUrl + '/apps/' + appId + '/addToAccount',
null,
);
}

removeFromAccount(appId: number): Observable<void> {
return this.httpClient.get<void>(
return this.httpClient.post<void>(
this.masterserverUrl + '/apps/' + appId + '/removeFromAccount',
null,
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/core/services/background.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';

import { App } from '../../model/app.model';
import { App } from '../.././interfaces/app.interface';

@Injectable()
export class BackgroundService {
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/services/config-http.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Inject, Injectable } from '@angular/core';

import { Observable } from 'rxjs';

import { Configs } from '../../model/configs.model';
import { Configs } from '../.././interfaces/configs.interface';
import { MASTERSERVER_URL } from '../injection-tokens';

@Injectable()
Expand Down
2 changes: 1 addition & 1 deletion src/app/core/services/news-http.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Inject, Injectable } from '@angular/core';

import { Observable } from 'rxjs';

import { News } from '../../model/news.model';
import { News } from '../.././interfaces/news.interface';
import { MASTERSERVER_URL } from '../injection-tokens';

@Injectable()
Expand Down
72 changes: 56 additions & 16 deletions src/app/core/services/user-http.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { Inject, Injectable } from '@angular/core';

import { Observable } from 'rxjs';

import { Registration } from '../../model/registration.model';
import { SafeCredentials } from '../../model/safe-credentials.model';
import { User } from '../../model/user.model';
import { LoginDto } from '../../interfaces/login.dto.interface';
import { RegistrationDto } from '../../interfaces/registration.dto.interface';
import { ResetPasswordDto } from '../../interfaces/reset-password.dto.interface';
import { User } from '../../interfaces/user.interface';
import { MASTERSERVER_URL } from '../injection-tokens';

@Injectable()
Expand All @@ -15,36 +16,75 @@ export class UserHttpService {
@Inject(MASTERSERVER_URL) private masterserverUrl: string,
) {}

register(registration: Registration): Observable<void> {
register(registrationDto: RegistrationDto): Observable<void> {
return this.httpClient.post<void>(
this.masterserverUrl + '/users/register',
registration,
registrationDto,
);
}

getSaltClient(login: string): Observable<string> {
return this.httpClient.post(
this.masterserverUrl + '/users/saltClient',
login,
return this.httpClient.get(
this.masterserverUrl +
'/users/' +
encodeURIComponent(login) +
'/saltClient',
{ responseType: 'text' },
);
}

login(safeCredentials: SafeCredentials): Observable<string> {
login(loginDto: LoginDto): Observable<string> {
return this.httpClient.post(
this.masterserverUrl + '/users/login',
safeCredentials,
loginDto,
{ responseType: 'text' },
);
}

getUser(): Observable<User> {
return this.httpClient.get<User>(this.masterserverUrl + '/users/bySession');
sendEmailConfirmationEmail(login: string): Observable<void> {
return this.httpClient.post<void>(
this.masterserverUrl +
'/users/' +
encodeURIComponent(login) +
'/sendEmailConfirmationEmail',
null,
);
}

confirmEmail(login: string, emailSecret: string): Observable<void> {
return this.httpClient.post<void>(
this.masterserverUrl +
'/users/' +
encodeURIComponent(login) +
'/confirmEmail',
emailSecret,
);
}

sendPasswordResetEmail(login: string): Observable<void> {
return this.httpClient.post<void>(
this.masterserverUrl +
'/users/' +
encodeURIComponent(login) +
'/sendPasswordResetEmail',
null,
);
}

resetPassword(
login: string,
resetPasswordDto: ResetPasswordDto,
): Observable<void> {
return this.httpClient.post<void>(
this.masterserverUrl +
'/users/' +
encodeURIComponent(login) +
'/resetPassword',
resetPasswordDto,
);
}

getAuthToken(): Observable<string> {
return this.httpClient.get(this.masterserverUrl + '/authToken', {
responseType: 'text',
});
getUser(userId: number): Observable<User> {
return this.httpClient.get<User>(this.masterserverUrl + '/users/' + userId);
}
}
6 changes: 3 additions & 3 deletions src/app/core/util/app.util.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { App } from '../../model/app.model';
import { AppFile } from '../../model/app-file.model';
import { LocalApp } from '../../model/local-app.model';
import { App } from '../.././interfaces/app.interface';
import { AppFile } from '../.././interfaces/app-file.interface';
import { LocalApp } from '../.././interfaces/local-app.interface';

export function getApp(apps: App[], id: number): App {
return apps.find((app) => app.id === id);
Expand Down
22 changes: 22 additions & 0 deletions src/app/core/util/error.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ErrorCode } from '../../interfaces/error-code.enum';

export function getErrorMessage(error: any): string {
const errorCode = getErrorCode(error);
return errorCode || 'AN_UNEXPECTED_ERROR_OCCURRED';
}

export function getErrorCode(error: any): ErrorCode {
if (error.error) {
try {
// Errors from backend currently come sometimes as string, sometimes as object
const errorObject =
typeof error.error === 'string' ? JSON.parse(error.error) : error.error;
if (errorObject.type === 'destrostudios') {
return errorObject.code;
}
} catch (e) {
// Ignore
}
}
return null;
}
9 changes: 9 additions & 0 deletions src/app/core/util/hash.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as bcrypt from 'bcryptjs';

export function generateSalt(): string {
return bcrypt.genSaltSync(10);
}

export function hashSecret(secret: string, salt: string): string {
return bcrypt.hashSync(secret, salt);
}
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppFile } from './app-file.model';
import { AppFile } from './app-file.interface';

export interface AppFilesResponse {
readonly files: AppFile[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Developer } from './developer.model';
import { Genre } from './genre.model';
import { Developer } from './developer.interface';
import { Genre } from './genre.interface';

export interface App {
readonly id: number;
Expand Down
File renamed without changes.
File renamed without changes.
14 changes: 14 additions & 0 deletions src/app/interfaces/error-code.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export enum ErrorCode {
APP_ALREADY_ADDED = 'APP_ALREADY_ADDED',
APP_FILE_NOT_FOUND = 'APP_FILE_NOT_FOUND',
APP_NOT_ADDED = 'APP_NOT_ADDED',
APP_NOT_FOUND = 'APP_NOT_FOUND',
BAD_REQUEST = 'BAD_REQUEST',
EMAIL_ALREADY_EXISTS = 'EMAIL_ALREADY_EXISTS',
EMAIL_NOT_CONFIRMED = 'EMAIL_NOT_CONFIRMED',
LOGIN_ALREADY_EXISTS = 'LOGIN_ALREADY_EXISTS',
TOO_MANY_EMAIL_REQUESTS = 'TOO_MANY_EMAIL_REQUESTS',
USER_NOT_FOUND = 'USER_NOT_FOUND',
WRONG_EMAIL_SECRET = 'WRONG_EMAIL_SECRET',
WRONG_PASSWORD = 'WRONG_PASSWORD',
}
Loading

0 comments on commit 026a56a

Please sign in to comment.