From b91f195955eee68b510c99800a994f35f51650fb Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Mon, 1 Jul 2024 14:33:19 +0900
Subject: [PATCH 1/3] [footer] refresh auth state in real time
---
.../master-page/master-page.component.html | 2 +-
frontend/src/app/services/services-api.service.ts | 2 +-
.../global-footer/global-footer.component.html | 8 ++++----
.../global-footer/global-footer.component.ts | 15 +++++++++++----
4 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html
index 591a8730e..25843bb28 100644
--- a/frontend/src/app/components/master-page/master-page.component.html
+++ b/frontend/src/app/components/master-page/master-page.component.html
@@ -129,7 +129,7 @@
-
+
diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts
index 0dc58b957..546b38730 100644
--- a/frontend/src/app/services/services-api.service.ts
+++ b/frontend/src/app/services/services-api.service.ts
@@ -1,6 +1,6 @@
import { Router, NavigationStart } from '@angular/router';
import { Injectable } from '@angular/core';
-import { HttpClient, HttpParams } from '@angular/common/http';
+import { HttpClient } from '@angular/common/http';
import { StateService } from './state.service';
import { StorageService } from './storage.service';
import { MenuGroup } from '../interfaces/services.interface';
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.html b/frontend/src/app/shared/components/global-footer/global-footer.component.html
index 69fdf50e7..bd1783513 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.html
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.html
@@ -33,8 +33,8 @@
}
@if (!env.customize?.theme) {
@@ -44,8 +44,8 @@
}
@if (!enterpriseInfo?.footer_img) {
Explore the full Bitcoin ecosystem
diff --git a/frontend/src/app/shared/components/global-footer/global-footer.component.ts b/frontend/src/app/shared/components/global-footer/global-footer.component.ts
index 826172c4b..50f9a53d7 100644
--- a/frontend/src/app/shared/components/global-footer/global-footer.component.ts
+++ b/frontend/src/app/shared/components/global-footer/global-footer.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, Inject, LOCALE_ID, HostListener, OnDestroy } from '@angular/core';
+import { Input, ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, OnChanges, SimpleChanges, Inject, LOCALE_ID, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Observable, merge, of, Subject, Subscription } from 'rxjs';
import { tap, takeUntil } from 'rxjs/operators';
@@ -16,7 +16,9 @@ import { EnterpriseService } from '../../../services/enterprise.service';
styleUrls: ['./global-footer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class GlobalFooterComponent implements OnInit, OnDestroy {
+export class GlobalFooterComponent implements OnInit, OnDestroy, OnChanges {
+ @Input() user: any = undefined;
+
private destroy$: Subject = new Subject();
env: Env;
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
@@ -29,7 +31,6 @@ export class GlobalFooterComponent implements OnInit, OnDestroy {
network$: Observable;
networkPaths: { [network: string]: string };
currentNetwork = '';
- loggedIn = false;
urlSubscription: Subscription;
isServicesPage = false;
@@ -72,11 +73,17 @@ export class GlobalFooterComponent implements OnInit, OnDestroy {
});
this.urlSubscription = this.route.url.subscribe((url) => {
- this.loggedIn = this.storageService.getAuth() !== null;
+ this.user = this.storageService.getAuth();
this.cd.markForCheck();
})
}
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.user) {
+ this.user = this.storageService.getAuth();
+ }
+ }
+
ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.complete();
From 2d12d2e5ef9b20582749651bc2e2e27517056d6a Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Mon, 1 Jul 2024 15:30:39 +0900
Subject: [PATCH 2/3] [logout] fix redirection
---
frontend/src/app/components/menu/menu.component.ts | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/frontend/src/app/components/menu/menu.component.ts b/frontend/src/app/components/menu/menu.component.ts
index 7a2d8b6ed..fe9fd5f09 100644
--- a/frontend/src/app/components/menu/menu.component.ts
+++ b/frontend/src/app/components/menu/menu.component.ts
@@ -61,12 +61,18 @@ export class MenuComponent implements OnInit, OnDestroy {
this.loggedOut.emit(true);
if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) {
this.userMenuGroups$ = this.servicesApiServices.getUserMenuGroups$();
- this.router.navigateByUrl('/');
+ if (window.location.toString().includes('services')) {
+ this.router.navigateByUrl('/login');
+ }
}
});
}
onLinkClick(link) {
+ if (link === 'logout') {
+ this.toggleMenu(false);
+ return;
+ }
if (!this.isServicesPage || this.isSmallScreen()) {
this.toggleMenu(false);
}
From 5b93c8e875a93d54ac4099ab05e23691997ffd3a Mon Sep 17 00:00:00 2001
From: nymkappa <1612910616@pm.me>
Date: Mon, 1 Jul 2024 16:21:47 +0900
Subject: [PATCH 3/3] [accelerator] refresh auth state when logging out
---
.../accelerate-checkout.component.ts | 23 ++++--
.../src/app/components/menu/menu.component.ts | 5 +-
frontend/src/app/services/auth.service.ts | 71 +++++++++++++++++++
.../src/app/services/services-api.service.ts | 4 ++
4 files changed, 95 insertions(+), 8 deletions(-)
create mode 100644 frontend/src/app/services/auth.service.ts
diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts
index 8c0d35dd9..8fe16aad4 100644
--- a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts
+++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts
@@ -7,7 +7,7 @@ import { AudioService } from '../../services/audio.service';
import { ETA, EtaService } from '../../services/eta.service';
import { Transaction } from '../../interfaces/electrs.interface';
import { MiningStats } from '../../services/mining.service';
-import { StorageService } from '../../services/storage.service';
+import { IAuth, AuthServiceMempool } from '../../services/auth.service';
export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp';
@@ -72,7 +72,8 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
simpleMode: boolean = true;
paymentMethod: 'cashapp' | 'btcpay';
- user: any = undefined;
+ authSubscription$: Subscription;
+ auth: IAuth | null = null;
// accelerator stuff
square: { appId: string, locationId: string};
@@ -109,16 +110,22 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
constructor(
public stateService: StateService,
private servicesApiService: ServicesApiServices,
- private storageService: StorageService,
private etaService: EtaService,
private audioService: AudioService,
- private cd: ChangeDetectorRef
+ private cd: ChangeDetectorRef,
+ private authService: AuthServiceMempool
) {
this.accelerationUUID = window.crypto.randomUUID();
}
ngOnInit() {
- this.user = this.storageService.getAuth()?.user ?? null;
+ this.authSubscription$ = this.authService.getAuth$().subscribe((auth) => {
+ this.auth = auth;
+ this.estimate = null;
+ this.moveToStep('summary');
+ });
+ this.authService.refreshAuth$().subscribe();
+
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.get('cash_request_id')) { // Redirected from cashapp
this.moveToStep('processing');
@@ -140,6 +147,9 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
if (this.estimateSubscription) {
this.estimateSubscription.unsubscribe();
}
+ if (this.authSubscription$) {
+ this.authSubscription$.unsubscribe();
+ }
}
ngOnChanges(changes: SimpleChanges): void {
@@ -465,8 +475,7 @@ export class AccelerateCheckout implements OnInit, OnDestroy {
}
isLoggedIn(): boolean {
- const auth = this.storageService.getAuth();
- return auth !== null;
+ return this.auth !== null;
}
get step() {
diff --git a/frontend/src/app/components/menu/menu.component.ts b/frontend/src/app/components/menu/menu.component.ts
index fe9fd5f09..719495bb0 100644
--- a/frontend/src/app/components/menu/menu.component.ts
+++ b/frontend/src/app/components/menu/menu.component.ts
@@ -5,6 +5,7 @@ import { StorageService } from '../../services/storage.service';
import { Router, NavigationStart } from '@angular/router';
import { StateService } from '../../services/state.service';
import { IUser, ServicesApiServices } from '../../services/services-api.service';
+import { AuthServiceMempool } from '../../services/auth.service';
@Component({
selector: 'app-menu',
@@ -26,7 +27,8 @@ export class MenuComponent implements OnInit, OnDestroy {
private servicesApiServices: ServicesApiServices,
private storageService: StorageService,
private router: Router,
- private stateService: StateService
+ private stateService: StateService,
+ private authService: AuthServiceMempool
) {}
ngOnInit(): void {
@@ -61,6 +63,7 @@ export class MenuComponent implements OnInit, OnDestroy {
this.loggedOut.emit(true);
if (this.stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE) {
this.userMenuGroups$ = this.servicesApiServices.getUserMenuGroups$();
+ this.authService.logout();
if (window.location.toString().includes('services')) {
this.router.navigateByUrl('/login');
}
diff --git a/frontend/src/app/services/auth.service.ts b/frontend/src/app/services/auth.service.ts
new file mode 100644
index 000000000..7a4fcda24
--- /dev/null
+++ b/frontend/src/app/services/auth.service.ts
@@ -0,0 +1,71 @@
+import { Injectable } from '@angular/core';
+import { Router } from '@angular/router';
+import { map, Observable, ReplaySubject, switchMap, tap } from 'rxjs';
+import { ServicesApiServices } from './services-api.service';
+
+export interface IAuth {
+ token: string;
+ user: {
+ userId: number;
+ username: string;
+ }
+}
+
+@Injectable({
+ providedIn: 'root'
+})
+export class AuthServiceMempool {
+ private auth$: ReplaySubject = new ReplaySubject(1);
+
+ constructor(
+ private servicesApiService: ServicesApiServices,
+ private router: Router,
+ ) {
+ const localStorageAuth = localStorage.getItem('auth');
+ if (!localStorageAuth || localStorageAuth.length === 0) {
+ this.setAuth(null);
+ } else {
+ try {
+ this.setAuth(JSON.parse(localStorageAuth));
+ } catch (e) {
+ console.error(`Unable to parse 'auth' from localStorage`, e);
+ localStorage.removeItem('auth');
+ this.setAuth(null);
+ }
+ }
+ }
+
+ refreshAuth$(): Observable {
+ return this.servicesApiService.getJWT$()
+ .pipe(
+ tap((user) => {
+ this.setAuth(user);
+ }),
+ map((user) => {
+ return user;
+ })
+ );
+ }
+
+ logout() {
+ this.setAuth(null);
+ }
+
+ setAuth(auth: any) {
+ if (!auth) {
+ localStorage.removeItem('auth');
+ } else {
+ localStorage.setItem('auth', JSON.stringify(auth));
+ }
+ this.auth$.next(auth);
+ }
+
+ getAuth$(): Observable {
+ if (!localStorage.getItem('auth')) {
+ return this.refreshAuth$().pipe(
+ switchMap(() => this.auth$.asObservable())
+ );
+ }
+ return this.auth$.asObservable();
+ }
+}
diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts
index 546b38730..07e72e0b6 100644
--- a/frontend/src/app/services/services-api.service.ts
+++ b/frontend/src/app/services/services-api.service.ts
@@ -120,6 +120,10 @@ export class ServicesApiServices {
return this.httpClient.post(`${SERVICES_API_PREFIX}/auth/logout`, {});
}
+ getJWT$() {
+ return this.httpClient.get(`${SERVICES_API_PREFIX}/auth/getJWT`);
+ }
+
getServicesBackendInfo$(): Observable {
return this.httpClient.get(`${SERVICES_API_PREFIX}/version`);
}