From 642c5231ed2024c826728f06ee6d83f6e543b8a5 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 9 Jun 2026 09:31:37 +0200 Subject: [PATCH 1/4] feat(gs): add email to userDataId lookup to debug tooling The /gs/debug SQL endpoint blocks the user_data.mail column (PII), so an email address cannot be resolved to a userDataId via SQL. Add a dedicated POST /gs/debug/user endpoint (DEBUG role) that returns only non-PII identifiers, plus a -u/--user flag in scripts/db-debug.sh. --- scripts/db-debug.sh | 33 ++++++++++ .../generic/gs/__tests__/gs.service.spec.ts | 63 ++++++++++++++++++- .../generic/gs/dto/debug-user-query.dto.ts | 22 +++++++ src/subdomains/generic/gs/gs.controller.ts | 9 +++ src/subdomains/generic/gs/gs.service.ts | 20 ++++++ 5 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/subdomains/generic/gs/dto/debug-user-query.dto.ts diff --git a/scripts/db-debug.sh b/scripts/db-debug.sh index 07a5d34076..4e27add3b2 100755 --- a/scripts/db-debug.sh +++ b/scripts/db-debug.sh @@ -67,6 +67,7 @@ if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then echo " Show complete referral chain for user" echo " -T, --referral-tree " echo " Show complete referral tree (all branches)" + echo " -u, --user Resolve an email address to userDataId(s)" echo "" echo "Examples:" echo " ./scripts/db-debug.sh --anomalies 50" @@ -76,6 +77,7 @@ if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then echo " ./scripts/db-debug.sh --asset-history MaerkiBaumann/CHF 10" echo " ./scripts/db-debug.sh --referral-chain 370625" echo " ./scripts/db-debug.sh --referral-tree 370625" + echo " ./scripts/db-debug.sh --user user@example.com" echo " ./scripts/db-debug.sh \"SELECT * FROM asset LIMIT 10\"" exit 0 fi @@ -109,6 +111,8 @@ ASSET_LIMIT="10" REFERRAL_CHAIN_MODE="" REFERRAL_TREE_MODE="" TARGET_USER_ID="" +USER_LOOKUP_MODE="" +LOOKUP_MAIL="" case "${1:-}" in -a|--anomalies) @@ -153,6 +157,15 @@ case "${1:-}" in REFERRAL_TREE_MODE="1" TARGET_USER_ID="$2" ;; + -u|--user) + if [ -z "${2:-}" ]; then + echo "Error: --user requires an email address" + echo "Usage: ./scripts/db-debug.sh --user " + exit 1 + fi + USER_LOOKUP_MODE="1" + LOOKUP_MAIL="$2" + ;; *) SQL="${1:-SELECT id, name, blockchain FROM asset ORDER BY id DESC LIMIT 5}" ;; @@ -198,6 +211,26 @@ ROLE=$(echo "$TOKEN" | cut -d'.' -f2 | base64 -d 2>/dev/null | jq -r '.role' 2>/ echo "Authenticated with role: $ROLE" echo "" +# --- User lookup mode (email -> userDataId) --- +if [ -n "$USER_LOOKUP_MODE" ]; then + echo "=== Resolving userDataId for: $LOOKUP_MAIL ===" + echo "" + + PAYLOAD=$(jq -n --arg mail "$LOOKUP_MAIL" '{"mail": $mail}') + RESULT=$(curl -s -X POST "$API_URL/gs/debug/user" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$PAYLOAD") + + if command -v jq &> /dev/null; then + echo "$RESULT" | jq . + else + echo "$RESULT" + fi + + exit 0 +fi + # --- Referral chain mode --- if [ -n "$REFERRAL_CHAIN_MODE" ]; then if ! command -v jq &> /dev/null; then diff --git a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts index 331ded6eef..ab08359ab0 100644 --- a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts +++ b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts @@ -26,19 +26,24 @@ import { LimitRequestService } from 'src/subdomains/supporting/support-issue/ser import { SupportIssueService } from 'src/subdomains/supporting/support-issue/services/support-issue.service'; import { SwapService } from 'src/subdomains/core/buy-crypto/routes/swap/swap.service'; import { VirtualIbanService } from 'src/subdomains/supporting/bank/virtual-iban/virtual-iban.service'; +import { UserData } from '../../user/models/user-data/user-data.entity'; +import { AccountType } from '../../user/models/user-data/account-type.enum'; +import { KycLevel, KycType, UserDataStatus } from '../../user/models/user-data/user-data.enum'; describe('GsService', () => { let service: GsService; let dataSource: DataSource; let appInsightsQueryService: AppInsightsQueryService; + let userDataService: UserDataService; beforeEach(() => { dataSource = createMock(); appInsightsQueryService = createMock(); + userDataService = createMock(); service = new GsService( appInsightsQueryService, - createMock(), + userDataService, createMock(), createMock(), createMock(), @@ -220,4 +225,60 @@ describe('GsService', () => { verboseSpy.mockRestore(); }); }); + + describe('resolveDebugUser', () => { + it('returns only non-PII fields for matching accounts', async () => { + jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([ + { + id: 123, + accountType: AccountType.PERSONAL, + kycLevel: KycLevel.LEVEL_20, + kycType: KycType.DFX, + status: UserDataStatus.NA, + created: new Date('2026-01-01T00:00:00.000Z'), + wallet: { name: 'TestWallet' }, + } as UserData, + ]); + + const result = await service.resolveDebugUser('user@example.com', 'test-user'); + + expect(result).toEqual([ + { + userDataId: 123, + accountType: AccountType.PERSONAL, + kycLevel: KycLevel.LEVEL_20, + kycType: KycType.DFX, + status: UserDataStatus.NA, + wallet: 'TestWallet', + created: new Date('2026-01-01T00:00:00.000Z'), + }, + ]); + }); + + it('includes every status (onlyValidUser=false) and tolerates a missing wallet or accountType', async () => { + const spy = jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([ + { + id: 456, + kycLevel: KycLevel.LEVEL_0, + kycType: KycType.DFX, + status: UserDataStatus.MERGED, + created: new Date('2026-02-02T00:00:00.000Z'), + } as UserData, + ]); + + const result = await service.resolveDebugUser('merged@example.com', 'test-user'); + + expect(spy).toHaveBeenCalledWith('merged@example.com', false); + expect(result[0].wallet).toBeNull(); + expect(result[0].accountType).toBeNull(); + }); + + it('returns an empty list when no account matches', async () => { + jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([]); + + const result = await service.resolveDebugUser('missing@example.com', 'test-user'); + + expect(result).toEqual([]); + }); + }); }); diff --git a/src/subdomains/generic/gs/dto/debug-user-query.dto.ts b/src/subdomains/generic/gs/dto/debug-user-query.dto.ts new file mode 100644 index 0000000000..32a9eae239 --- /dev/null +++ b/src/subdomains/generic/gs/dto/debug-user-query.dto.ts @@ -0,0 +1,22 @@ +import { IsNotEmpty, IsString, MaxLength } from 'class-validator'; +import { AccountType } from 'src/subdomains/generic/user/models/user-data/account-type.enum'; +import { KycLevel, KycType, UserDataStatus } from 'src/subdomains/generic/user/models/user-data/user-data.enum'; + +export class DebugUserQueryDto { + @IsNotEmpty() + @IsString() + @MaxLength(256) + mail: string; +} + +// Only non-PII fields: enough to identify and disambiguate accounts (a mail can map to +// several user_data rows through test aliases or merges) without exposing personal data. +export interface DebugUserResult { + userDataId: number; + accountType: AccountType | null; + kycLevel: KycLevel; + kycType: KycType; + status: UserDataStatus; + wallet: string | null; + created: Date; +} diff --git a/src/subdomains/generic/gs/gs.controller.ts b/src/subdomains/generic/gs/gs.controller.ts index 15f11227fb..7ef35d3c10 100644 --- a/src/subdomains/generic/gs/gs.controller.ts +++ b/src/subdomains/generic/gs/gs.controller.ts @@ -9,6 +9,7 @@ import { UserRole } from 'src/shared/auth/user-role.enum'; import { DfxLogger } from 'src/shared/services/dfx-logger'; import { DbQueryBaseDto, DbQueryDto, DbReturnData } from './dto/db-query.dto'; import { DebugQueryDto } from './dto/debug-query.dto'; +import { DebugUserQueryDto, DebugUserResult } from './dto/debug-user-query.dto'; import { LogQueryDto, LogQueryResult } from './dto/log-query.dto'; import { SupportDataQuery, SupportReturnData } from './dto/support-data.dto'; import { GsService } from './gs.service'; @@ -63,4 +64,12 @@ export class GsController { async executeLogQuery(@GetJwt() jwt: JwtPayload, @Body() dto: LogQueryDto): Promise { return this.gsService.executeLogQuery(dto, jwt.address ?? `account:${jwt.account}`); } + + @Post('debug/user') + @ApiBearerAuth() + @ApiExcludeEndpoint() + @UseGuards(AuthGuard(), RoleGuard(UserRole.DEBUG), UserActiveGuard()) + async resolveDebugUser(@GetJwt() jwt: JwtPayload, @Body() dto: DebugUserQueryDto): Promise { + return this.gsService.resolveDebugUser(dto.mail, jwt.address ?? `account:${jwt.account}`); + } } diff --git a/src/subdomains/generic/gs/gs.service.ts b/src/subdomains/generic/gs/gs.service.ts index ccf2610590..77e089a95a 100644 --- a/src/subdomains/generic/gs/gs.service.ts +++ b/src/subdomains/generic/gs/gs.service.ts @@ -29,6 +29,7 @@ import { UserData } from '../user/models/user-data/user-data.entity'; import { UserDataService } from '../user/models/user-data/user-data.service'; import { UserService } from '../user/models/user/user.service'; import { DbQueryBaseDto, DbQueryDto, DbReturnData } from './dto/db-query.dto'; +import { DebugUserResult } from './dto/debug-user-query.dto'; import { DebugBlockedCols, DebugBlockedSchemas, @@ -192,6 +193,25 @@ export class GsService { }; } + // Sanctioned reverse lookup for the DEBUG tooling: the /gs/debug SQL endpoint blocks the + // user_data.mail column (PII), so an email cannot be resolved to a userDataId via SQL. This + // returns only non-PII identifiers, never the mail or any other personal data. + async resolveDebugUser(mail: string, userIdentifier: string): Promise { + this.logger.verbose(`Debug user lookup by ${userIdentifier}`); + + const userDataList = await this.userDataService.getUsersByMail(mail, false); + + return userDataList.map((userData) => ({ + userDataId: userData.id, + accountType: userData.accountType ?? null, + kycLevel: userData.kycLevel, + kycType: userData.kycType, + status: userData.status, + wallet: userData.wallet?.name ?? null, + created: userData.created, + })); + } + async executeDebugQuery(sql: string, userIdentifier: string): Promise[]> { // 1. Parse SQL to AST for robust validation let ast; From f197a6972cdbfd3cde02292580f8945ac2f43e2a Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:08:41 +0200 Subject: [PATCH 2/4] refactor(gs): return only userDataIds from debug user lookup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror the compliance search result shape ({ type, userDataIds }) and return solely non-PII userDataIds (deduplicated, sorted) — never name, mail or other personal data. --- .../generic/gs/__tests__/gs.service.spec.ts | 55 +++++-------------- .../generic/gs/dto/debug-user-query.dto.ts | 15 ++--- src/subdomains/generic/gs/gs.controller.ts | 2 +- src/subdomains/generic/gs/gs.service.ts | 17 +++--- 4 files changed, 27 insertions(+), 62 deletions(-) diff --git a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts index ab08359ab0..e5866ee2cf 100644 --- a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts +++ b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts @@ -27,8 +27,7 @@ import { SupportIssueService } from 'src/subdomains/supporting/support-issue/ser import { SwapService } from 'src/subdomains/core/buy-crypto/routes/swap/swap.service'; import { VirtualIbanService } from 'src/subdomains/supporting/bank/virtual-iban/virtual-iban.service'; import { UserData } from '../../user/models/user-data/user-data.entity'; -import { AccountType } from '../../user/models/user-data/account-type.enum'; -import { KycLevel, KycType, UserDataStatus } from '../../user/models/user-data/user-data.enum'; +import { ComplianceSearchType } from '../../support/dto/user-data-support.dto'; describe('GsService', () => { let service: GsService; @@ -227,58 +226,34 @@ describe('GsService', () => { }); describe('resolveDebugUser', () => { - it('returns only non-PII fields for matching accounts', async () => { - jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([ - { - id: 123, - accountType: AccountType.PERSONAL, - kycLevel: KycLevel.LEVEL_20, - kycType: KycType.DFX, - status: UserDataStatus.NA, - created: new Date('2026-01-01T00:00:00.000Z'), - wallet: { name: 'TestWallet' }, - } as UserData, - ]); + it('returns deduplicated, sorted userDataIds with the Mail search type and no PII', async () => { + jest + .spyOn(userDataService, 'getUsersByMail') + .mockResolvedValue([ + { id: 102, firstname: 'Jane', surname: 'Doe' } as UserData, + { id: 101, firstname: 'John', surname: 'Doe' } as UserData, + { id: 101 } as UserData, + ]); const result = await service.resolveDebugUser('user@example.com', 'test-user'); - expect(result).toEqual([ - { - userDataId: 123, - accountType: AccountType.PERSONAL, - kycLevel: KycLevel.LEVEL_20, - kycType: KycType.DFX, - status: UserDataStatus.NA, - wallet: 'TestWallet', - created: new Date('2026-01-01T00:00:00.000Z'), - }, - ]); + expect(result).toEqual({ type: ComplianceSearchType.MAIL, userDataIds: [101, 102] }); }); - it('includes every status (onlyValidUser=false) and tolerates a missing wallet or accountType', async () => { - const spy = jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([ - { - id: 456, - kycLevel: KycLevel.LEVEL_0, - kycType: KycType.DFX, - status: UserDataStatus.MERGED, - created: new Date('2026-02-02T00:00:00.000Z'), - } as UserData, - ]); + it('resolves the mail with onlyValidUser=false (same resolution as the compliance search)', async () => { + const spy = jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([{ id: 1 } as UserData]); - const result = await service.resolveDebugUser('merged@example.com', 'test-user'); + await service.resolveDebugUser('merged@example.com', 'test-user'); expect(spy).toHaveBeenCalledWith('merged@example.com', false); - expect(result[0].wallet).toBeNull(); - expect(result[0].accountType).toBeNull(); }); - it('returns an empty list when no account matches', async () => { + it('returns an empty id list when no account matches', async () => { jest.spyOn(userDataService, 'getUsersByMail').mockResolvedValue([]); const result = await service.resolveDebugUser('missing@example.com', 'test-user'); - expect(result).toEqual([]); + expect(result).toEqual({ type: ComplianceSearchType.MAIL, userDataIds: [] }); }); }); }); diff --git a/src/subdomains/generic/gs/dto/debug-user-query.dto.ts b/src/subdomains/generic/gs/dto/debug-user-query.dto.ts index 32a9eae239..eb28226c19 100644 --- a/src/subdomains/generic/gs/dto/debug-user-query.dto.ts +++ b/src/subdomains/generic/gs/dto/debug-user-query.dto.ts @@ -1,6 +1,5 @@ import { IsNotEmpty, IsString, MaxLength } from 'class-validator'; -import { AccountType } from 'src/subdomains/generic/user/models/user-data/account-type.enum'; -import { KycLevel, KycType, UserDataStatus } from 'src/subdomains/generic/user/models/user-data/user-data.enum'; +import { ComplianceSearchType } from 'src/subdomains/generic/support/dto/user-data-support.dto'; export class DebugUserQueryDto { @IsNotEmpty() @@ -9,14 +8,8 @@ export class DebugUserQueryDto { mail: string; } -// Only non-PII fields: enough to identify and disambiguate accounts (a mail can map to -// several user_data rows through test aliases or merges) without exposing personal data. +// Mirrors the compliance search result shape, but exposes only non-PII userDataIds. export interface DebugUserResult { - userDataId: number; - accountType: AccountType | null; - kycLevel: KycLevel; - kycType: KycType; - status: UserDataStatus; - wallet: string | null; - created: Date; + type: ComplianceSearchType; + userDataIds: number[]; } diff --git a/src/subdomains/generic/gs/gs.controller.ts b/src/subdomains/generic/gs/gs.controller.ts index 7ef35d3c10..210be4752d 100644 --- a/src/subdomains/generic/gs/gs.controller.ts +++ b/src/subdomains/generic/gs/gs.controller.ts @@ -69,7 +69,7 @@ export class GsController { @ApiBearerAuth() @ApiExcludeEndpoint() @UseGuards(AuthGuard(), RoleGuard(UserRole.DEBUG), UserActiveGuard()) - async resolveDebugUser(@GetJwt() jwt: JwtPayload, @Body() dto: DebugUserQueryDto): Promise { + async resolveDebugUser(@GetJwt() jwt: JwtPayload, @Body() dto: DebugUserQueryDto): Promise { return this.gsService.resolveDebugUser(dto.mail, jwt.address ?? `account:${jwt.account}`); } } diff --git a/src/subdomains/generic/gs/gs.service.ts b/src/subdomains/generic/gs/gs.service.ts index 77e089a95a..69a7792f72 100644 --- a/src/subdomains/generic/gs/gs.service.ts +++ b/src/subdomains/generic/gs/gs.service.ts @@ -24,6 +24,7 @@ import { DataSource } from 'typeorm'; import { LimitRequestService } from '../../supporting/support-issue/services/limit-request.service'; import { KycDocumentService } from '../kyc/services/integration/kyc-document.service'; import { KycAdminService } from '../kyc/services/kyc-admin.service'; +import { ComplianceSearchType } from '../support/dto/user-data-support.dto'; import { BankDataService } from '../user/models/bank-data/bank-data.service'; import { UserData } from '../user/models/user-data/user-data.entity'; import { UserDataService } from '../user/models/user-data/user-data.service'; @@ -196,20 +197,16 @@ export class GsService { // Sanctioned reverse lookup for the DEBUG tooling: the /gs/debug SQL endpoint blocks the // user_data.mail column (PII), so an email cannot be resolved to a userDataId via SQL. This // returns only non-PII identifiers, never the mail or any other personal data. - async resolveDebugUser(mail: string, userIdentifier: string): Promise { + async resolveDebugUser(mail: string, userIdentifier: string): Promise { this.logger.verbose(`Debug user lookup by ${userIdentifier}`); + // Same resolution the compliance search uses for a mail; returns only userDataIds, no PII. const userDataList = await this.userDataService.getUsersByMail(mail, false); + const userDataIds = Util.toUniqueList(userDataList, 'id') + .map((userData) => userData.id) + .sort((a, b) => a - b); - return userDataList.map((userData) => ({ - userDataId: userData.id, - accountType: userData.accountType ?? null, - kycLevel: userData.kycLevel, - kycType: userData.kycType, - status: userData.status, - wallet: userData.wallet?.name ?? null, - created: userData.created, - })); + return { type: ComplianceSearchType.MAIL, userDataIds }; } async executeDebugQuery(sql: string, userIdentifier: string): Promise[]> { From ef4929a1cf110c35de7bb108a7b843c405d36158 Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:12:49 +0200 Subject: [PATCH 3/4] test(gs): assert debug user lookup never returns PII Make the no-PII guarantee explicit: feed records carrying firstname/surname and assert the serialized response contains only userDataIds. --- src/subdomains/generic/gs/__tests__/gs.service.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts index e5866ee2cf..8b5c846e65 100644 --- a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts +++ b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts @@ -227,6 +227,8 @@ describe('GsService', () => { describe('resolveDebugUser', () => { it('returns deduplicated, sorted userDataIds with the Mail search type and no PII', async () => { + // The resolved records intentionally carry PII (firstname/surname) to prove the DEBUG + // response strips it: only userDataIds may ever be returned, never personal data. jest .spyOn(userDataService, 'getUsersByMail') .mockResolvedValue([ @@ -238,6 +240,8 @@ describe('GsService', () => { const result = await service.resolveDebugUser('user@example.com', 'test-user'); expect(result).toEqual({ type: ComplianceSearchType.MAIL, userDataIds: [101, 102] }); + expect(JSON.stringify(result)).not.toContain('firstname'); + expect(JSON.stringify(result)).not.toContain('Doe'); }); it('resolves the mail with onlyValidUser=false (same resolution as the compliance search)', async () => { From 199a00c06006f457e4c68f6de43b91a576ab96ff Mon Sep 17 00:00:00 2001 From: TaprootFreak <142087526+TaprootFreak@users.noreply.github.com> Date: Tue, 9 Jun 2026 10:52:34 +0200 Subject: [PATCH 4/4] chore(gs): polish debug user lookup imports and query Use absolute import paths per the contribution guide and skip loading unused relations (only the id is read) in the mail resolution. --- src/subdomains/generic/gs/__tests__/gs.service.spec.ts | 6 +++--- src/subdomains/generic/gs/gs.service.ts | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts index 8b5c846e65..ce2ae5f47a 100644 --- a/src/subdomains/generic/gs/__tests__/gs.service.spec.ts +++ b/src/subdomains/generic/gs/__tests__/gs.service.spec.ts @@ -26,8 +26,8 @@ import { LimitRequestService } from 'src/subdomains/supporting/support-issue/ser import { SupportIssueService } from 'src/subdomains/supporting/support-issue/services/support-issue.service'; import { SwapService } from 'src/subdomains/core/buy-crypto/routes/swap/swap.service'; import { VirtualIbanService } from 'src/subdomains/supporting/bank/virtual-iban/virtual-iban.service'; -import { UserData } from '../../user/models/user-data/user-data.entity'; -import { ComplianceSearchType } from '../../support/dto/user-data-support.dto'; +import { UserData } from 'src/subdomains/generic/user/models/user-data/user-data.entity'; +import { ComplianceSearchType } from 'src/subdomains/generic/support/dto/user-data-support.dto'; describe('GsService', () => { let service: GsService; @@ -249,7 +249,7 @@ describe('GsService', () => { await service.resolveDebugUser('merged@example.com', 'test-user'); - expect(spy).toHaveBeenCalledWith('merged@example.com', false); + expect(spy).toHaveBeenCalledWith('merged@example.com', false, {}); }); it('returns an empty id list when no account matches', async () => { diff --git a/src/subdomains/generic/gs/gs.service.ts b/src/subdomains/generic/gs/gs.service.ts index 69a7792f72..9c5b213105 100644 --- a/src/subdomains/generic/gs/gs.service.ts +++ b/src/subdomains/generic/gs/gs.service.ts @@ -10,6 +10,7 @@ import { SwapService } from 'src/subdomains/core/buy-crypto/routes/swap/swap.ser import { RefRewardService } from 'src/subdomains/core/referral/reward/services/ref-reward.service'; import { BuyFiatService } from 'src/subdomains/core/sell-crypto/process/services/buy-fiat.service'; import { SellService } from 'src/subdomains/core/sell-crypto/route/sell.service'; +import { ComplianceSearchType } from 'src/subdomains/generic/support/dto/user-data-support.dto'; import { BankTxRepeatService } from 'src/subdomains/supporting/bank-tx/bank-tx-repeat/bank-tx-repeat.service'; import { BankTxType } from 'src/subdomains/supporting/bank-tx/bank-tx/entities/bank-tx.entity'; import { BankTxService } from 'src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service'; @@ -24,7 +25,6 @@ import { DataSource } from 'typeorm'; import { LimitRequestService } from '../../supporting/support-issue/services/limit-request.service'; import { KycDocumentService } from '../kyc/services/integration/kyc-document.service'; import { KycAdminService } from '../kyc/services/kyc-admin.service'; -import { ComplianceSearchType } from '../support/dto/user-data-support.dto'; import { BankDataService } from '../user/models/bank-data/bank-data.service'; import { UserData } from '../user/models/user-data/user-data.entity'; import { UserDataService } from '../user/models/user-data/user-data.service'; @@ -201,7 +201,8 @@ export class GsService { this.logger.verbose(`Debug user lookup by ${userIdentifier}`); // Same resolution the compliance search uses for a mail; returns only userDataIds, no PII. - const userDataList = await this.userDataService.getUsersByMail(mail, false); + // No relations needed — only the id is read. + const userDataList = await this.userDataService.getUsersByMail(mail, false, {}); const userDataIds = Util.toUniqueList(userDataList, 'id') .map((userData) => userData.id) .sort((a, b) => a - b);