Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Liquibase Only mode - PostgreSQL / test (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
- Implement DIP/MNRL lookup logs table, filtering, and detail review under reports. - Integrate DIP verification gating on client creation, allowing officers to record PROCEEDED/REJECTED decisions with reasons. - Upgrade Sanctions verification dialog to support comparing Name, DOB, and Nationality particulars. - Add Sanctions disposition recording (FALSE_POSITIVE / CONFIRMED_MATCH) awaiting Principal Officer approval. - Add sanctions-alert-review-dialog for reviewers to assess and escalate/clear flagged names. - Enforce strict screening reset logic on client name changes, preventing bypass of existing blocks. - Update routes and shell menu navigation to include DIP/MNRL Lookups and Sanctions Logs.
168 lines
5.4 KiB
JavaScript
168 lines
5.4 KiB
JavaScript
/*
|
|
* LOCAL TEST DIP/MNRL LOOKUP SERVICE — NOT A REAL DoT ENDPOINT.
|
|
*
|
|
* This stands in for the Department of Telecommunications Digital Intelligence Platform so the
|
|
* client-onboarding flow can be exercised end to end without a live DoT connection. It invents
|
|
* its answers. NOTHING HERE IS A REAL DIP OR MNRL CHECK.
|
|
*
|
|
* Mirrors scripts/mock-sms-gateway.js in intent: an unconfigured external provider gets a local
|
|
* stand-in rather than a dangling URL, and every response is stamped so it can never be mistaken
|
|
* for a genuine DoT result in the audit trail.
|
|
*
|
|
* Usage:
|
|
* node scripts/mock-dip-lookup-service.js # listens on 8090
|
|
* MOCK_DIP_PORT=9100 node scripts/mock-dip-lookup-service.js
|
|
*
|
|
* Point the backend at it:
|
|
* FINERACT_MOBILE_LOOKUP_BASE_URL=http://127.0.0.1:8090
|
|
*
|
|
* BEFORE PRODUCTION: point FINERACT_MOBILE_LOOKUP_BASE_URL at the real DIP/MNRL provider and do
|
|
* not run this. See the banner in application.properties.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const http = require('http');
|
|
const { URL } = require('url');
|
|
|
|
const PORT = Number(process.env.MOCK_DIP_PORT || 8090);
|
|
|
|
/** Stamped into every response so a mock lookup is identifiable in the stored raw JSON. */
|
|
const PROVIDER = 'MOCK_DIP_LOOKUP_TEST_ONLY';
|
|
|
|
/*
|
|
* Fixed verdicts for numbers used in demos and manual testing. Anything not listed here comes
|
|
* back CLEAN — the common case, so an ordinary test number does not trip the flagged-number gate.
|
|
*
|
|
* These overlap deliberately with DEMO_SUSPECTED_NUMBERS in MobileLookupServiceImpl: those are
|
|
* short-circuited before the HTTP call ever happens, so they are here only to keep the two lists
|
|
* telling the same story if that short-circuit is ever removed.
|
|
*/
|
|
const SUSPECTED = new Set([
|
|
'9827123456', '9827456789', '9826234567',
|
|
'9826987654', '9893123456', '9893765432'
|
|
]);
|
|
|
|
const DISCONNECTED = new Set([
|
|
'9000000001', '9000000002'
|
|
]);
|
|
|
|
const SUSPECTED_AND_DISCONNECTED = new Set([
|
|
'9000000003'
|
|
]);
|
|
|
|
/** Strips a leading country code so 919827123456 and 9827123456 resolve alike. */
|
|
function normalise(raw) {
|
|
const digits = String(raw || '').replace(/\D/g, '');
|
|
if (digits.length > 10 && digits.startsWith('91')) {
|
|
return digits.slice(2);
|
|
}
|
|
return digits;
|
|
}
|
|
|
|
function suspectedDetail() {
|
|
return {
|
|
dipStatus: 'active',
|
|
reason: 'Reported in cyber-fraud complaints (mock data)',
|
|
reportedBy: PROVIDER
|
|
};
|
|
}
|
|
|
|
function disconnectedDetail() {
|
|
return {
|
|
disconnectionReason: 'Number revoked and listed on MNRL (mock data)',
|
|
operator: 'MOCK TELECOM'
|
|
};
|
|
}
|
|
|
|
/*
|
|
* The backend parser reads suspectedDetail/disconnectedDetail unconditionally and only guards
|
|
* with isJsonNull(), so both keys must always be present — an absent key would NPE there rather
|
|
* than surface as a clean parse failure.
|
|
*/
|
|
function verdictFor(mobileNumber) {
|
|
const n = normalise(mobileNumber);
|
|
|
|
if (SUSPECTED_AND_DISCONNECTED.has(n)) {
|
|
return {
|
|
status: 'SUSPECTED_AND_DISCONNECTED',
|
|
suspected: true,
|
|
disconnected: true,
|
|
suspectedDetail: suspectedDetail(),
|
|
disconnectedDetail: disconnectedDetail(),
|
|
message: 'Number is SUSPECTED and DISCONNECTED — found in both DIP and MNRL records'
|
|
};
|
|
}
|
|
if (SUSPECTED.has(n)) {
|
|
return {
|
|
status: 'SUSPECTED',
|
|
suspected: true,
|
|
disconnected: false,
|
|
suspectedDetail: suspectedDetail(),
|
|
disconnectedDetail: null,
|
|
message: 'Number is SUSPECTED — found in DIP records'
|
|
};
|
|
}
|
|
if (DISCONNECTED.has(n)) {
|
|
return {
|
|
status: 'DISCONNECTED',
|
|
suspected: false,
|
|
disconnected: true,
|
|
suspectedDetail: null,
|
|
disconnectedDetail: disconnectedDetail(),
|
|
message: 'Number is DISCONNECTED — found in MNRL records'
|
|
};
|
|
}
|
|
return {
|
|
status: 'CLEAN',
|
|
suspected: false,
|
|
disconnected: false,
|
|
suspectedDetail: null,
|
|
disconnectedDetail: null,
|
|
message: 'Number is CLEAN — not found in DIP or MNRL records'
|
|
};
|
|
}
|
|
|
|
const server = http.createServer((req, res) => {
|
|
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
|
|
if (url.pathname !== '/api/v1/lookup/check') {
|
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ success: false, message: 'Not found', provider: PROVIDER }));
|
|
return;
|
|
}
|
|
|
|
const mobileNumber = url.searchParams.get('mobileNumber');
|
|
if (!mobileNumber || !mobileNumber.trim()) {
|
|
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify({ success: false, message: 'mobileNumber is required', provider: PROVIDER }));
|
|
return;
|
|
}
|
|
|
|
const verdict = verdictFor(mobileNumber);
|
|
const body = {
|
|
success: true,
|
|
message: verdict.message,
|
|
timestamp: new Date().toISOString(),
|
|
provider: PROVIDER,
|
|
data: {
|
|
mobileNumber: mobileNumber.trim(),
|
|
status: verdict.status,
|
|
suspected: verdict.suspected,
|
|
disconnected: verdict.disconnected,
|
|
suspectedDetail: verdict.suspectedDetail,
|
|
disconnectedDetail: verdict.disconnectedDetail
|
|
}
|
|
};
|
|
|
|
console.log(`[${PROVIDER}] ${mobileNumber} -> ${verdict.status}`);
|
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
res.end(JSON.stringify(body));
|
|
});
|
|
|
|
server.listen(PORT, '127.0.0.1', () => {
|
|
console.log(`${PROVIDER} listening on http://127.0.0.1:${PORT}`);
|
|
console.log('This is NOT a real DoT DIP/MNRL service. Responses are invented.');
|
|
console.log(`Set FINERACT_MOBILE_LOOKUP_BASE_URL=http://127.0.0.1:${PORT}`);
|
|
});
|