From 158053a8ff7881d1223b08dd285e7f4c466f7bbe Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 18 Jul 2026 17:18:42 +0200 Subject: [PATCH] Restrict symbol data endpoint to authenticated users --- apps/api/src/app/info/info.module.ts | 2 + apps/api/src/app/info/info.service.ts | 10 +++++ apps/api/src/app/symbol/symbol.controller.ts | 1 + .../home-market/home-market.component.ts | 43 ++----------------- .../components/home-market/home-market.html | 19 +------- .../src/lib/interfaces/info-item.interface.ts | 1 + 6 files changed, 19 insertions(+), 57 deletions(-) diff --git a/apps/api/src/app/info/info.module.ts b/apps/api/src/app/info/info.module.ts index e33c5e0c2e..06b7249095 100644 --- a/apps/api/src/app/info/info.module.ts +++ b/apps/api/src/app/info/info.module.ts @@ -7,6 +7,7 @@ import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.mo import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; +import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { DataGatheringQueueModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; @@ -29,6 +30,7 @@ import { InfoService } from './info.service'; secret: process.env.JWT_SECRET_KEY, signOptions: { expiresIn: '30 days' } }), + MarketDataModule, PlatformModule, PropertyModule, RedisCacheModule, diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index 10836f7b8f..2752795672 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -6,9 +6,11 @@ import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.s import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { DEFAULT_CURRENCY, + ghostfolioFearAndGreedIndexSymbolStocks, PROPERTY_COUNTRIES_OF_SUBSCRIBERS, PROPERTY_DEMO_USER_ID, PROPERTY_DOCKER_HUB_PULLS, @@ -36,6 +38,7 @@ export class InfoService { private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly jwtService: JwtService, + private readonly marketDataService: MarketDataService, private readonly propertyService: PropertyService, private readonly redisCacheService: RedisCacheService, private readonly subscriptionService: SubscriptionService, @@ -72,6 +75,13 @@ export class InfoService { info.fearAndGreedDataSource = fearAndGreedIndexDataSource; } + const latestMarketData = await this.marketDataService.getLatest({ + dataSource: fearAndGreedIndexDataSource, + symbol: ghostfolioFearAndGreedIndexSymbolStocks + }); + + info.fearAndGreedMarketPrice = latestMarketData?.marketPrice; + globalPermissions.push(permissions.enableFearAndGreedIndex); } diff --git a/apps/api/src/app/symbol/symbol.controller.ts b/apps/api/src/app/symbol/symbol.controller.ts index d94ffb4dcf..a1351dbed2 100644 --- a/apps/api/src/app/symbol/symbol.controller.ts +++ b/apps/api/src/app/symbol/symbol.controller.ts @@ -65,6 +65,7 @@ export class SymbolController { * Must be after /lookup */ @Get(':dataSource/:symbol') + @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getSymbolData( diff --git a/apps/client/src/app/components/home-market/home-market.component.ts b/apps/client/src/app/components/home-market/home-market.component.ts index 6bf99b31d1..d22f3b9749 100644 --- a/apps/client/src/app/components/home-market/home-market.component.ts +++ b/apps/client/src/app/components/home-market/home-market.component.ts @@ -1,16 +1,8 @@ import { GfFearAndGreedIndexComponent } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.component'; import { UserService } from '@ghostfolio/client/services/user/user.service'; -import { ghostfolioFearAndGreedIndexSymbolStocks } from '@ghostfolio/common/config'; -import { resetHours } from '@ghostfolio/common/helper'; -import { - Benchmark, - HistoricalDataItem, - InfoItem, - User -} from '@ghostfolio/common/interfaces'; +import { Benchmark, InfoItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; -import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { DataService } from '@ghostfolio/ui/services'; import { @@ -29,11 +21,7 @@ import { DeviceDetectorService } from 'ngx-device-detector'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, - imports: [ - GfBenchmarkComponent, - GfFearAndGreedIndexComponent, - GfLineChartComponent - ], + imports: [GfBenchmarkComponent, GfFearAndGreedIndexComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-home-market', styleUrls: ['./home-market.scss'], @@ -45,11 +33,7 @@ export class GfHomeMarketComponent implements OnInit { () => this.deviceDetectorService.deviceInfo().deviceType ); protected readonly fearAndGreedIndex = signal(undefined); - protected readonly fearLabel = $localize`Fear`; - protected readonly greedLabel = $localize`Greed`; protected hasPermissionToAccessFearAndGreedIndex: boolean; - protected readonly historicalDataItems = signal([]); - protected readonly numberOfDays = 365; protected user: User; private readonly info: InfoItem; @@ -80,27 +64,8 @@ export class GfHomeMarketComponent implements OnInit { permissions.enableFearAndGreedIndex ); - if ( - this.hasPermissionToAccessFearAndGreedIndex && - this.info.fearAndGreedDataSource - ) { - this.dataService - .fetchSymbolItem({ - dataSource: this.info.fearAndGreedDataSource, - includeHistoricalData: this.numberOfDays, - symbol: ghostfolioFearAndGreedIndexSymbolStocks - }) - .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(({ historicalData, marketPrice }) => { - this.fearAndGreedIndex.set(marketPrice); - this.historicalDataItems.set([ - ...historicalData, - { - date: resetHours(new Date()).toISOString(), - value: marketPrice - } - ]); - }); + if (this.hasPermissionToAccessFearAndGreedIndex) { + this.fearAndGreedIndex.set(this.info.fearAndGreedMarketPrice); } this.dataService diff --git a/apps/client/src/app/components/home-market/home-market.html b/apps/client/src/app/components/home-market/home-market.html index a782526eee..6d344d74f1 100644 --- a/apps/client/src/app/components/home-market/home-market.html +++ b/apps/client/src/app/components/home-market/home-market.html @@ -1,25 +1,8 @@

Markets

@if (hasPermissionToAccessFearAndGreedIndex) { -
+
-
- Last {{ numberOfDays }} Days -
-