diff --git a/backend/src/config.js b/backend/src/config.js index 63ed141..a9db734 100644 --- a/backend/src/config.js +++ b/backend/src/config.js @@ -1,6 +1,3 @@ - - - const os = require('os'); const config = { @@ -51,31 +48,34 @@ const config = { } }, roles: { - super_admin: 'Super Administrator', - admin: 'Administrator', - - - - user: 'Read Only Auditor', - + user: 'Read Only Auditor', }, project_uuid: '575e215e-eb96-4464-8f16-572fce01d4e0', flHost: process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'dev_stage' ? 'https://flatlogic.com/projects' : 'http://localhost:3000/projects', - gpt_key: process.env.GPT_KEY || '', + + osint: { + numlookup: "num_live_iViCHWVuE5tWiAsSBimesKfrD3w2VDgA748z9Btw", + abstract: "bdf209a5a133453cbf82f4a0f098773d", + veriphone: "885174620DD34D3A80B4E57BA05036E3", + hunterio: "374d3258ec737081b981b693ac6590661c87c60d", + opencellid: "1f8f328afa8ba5", + ipqualityscore: "ffEazTnuE5Zw2SMmvL3OUw1yPf7UToTV", + virustotal: "5182a9778e51cdd86961625c88a090023d8f4f9dd9315dfadc76f46bad1978d9", + apilayer: "8rzKF9g70xXyMGQEuOUuVSoZ10Fqu8PG", + } }; config.pexelsKey = process.env.PEXELS_KEY || ''; - -config.pexelsQuery = 'Night city grid lights'; +config.pexelsQuery = 'Cybersecurity Intelligence'; config.host = process.env.NODE_ENV === "production" ? config.remote : "http://localhost"; config.apiUrl = `${config.host}${config.port ? `:${config.port}` : ``}/api`; config.swaggerUrl = `${config.swaggerUI}${config.swaggerPort}`; config.uiUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}/#`; config.backUrl = `${config.hostUI}${config.portUI ? `:${config.portUI}` : ``}`; -module.exports = config; +module.exports = config; \ No newline at end of file diff --git a/backend/src/index.js b/backend/src/index.js index d0f2e05..4845218 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -1,4 +1,3 @@ - const express = require('express'); const cors = require('cors'); const app = express(); @@ -21,6 +20,8 @@ const organizationForAuthRoutes = require('./routes/organizationLogin'); const openaiRoutes = require('./routes/openai'); +const investigateRoutes = require('./routes/investigate'); + const usersRoutes = require('./routes/users'); @@ -176,6 +177,12 @@ app.use( '/api/search', passport.authenticate('jwt', { session: false }), searchRoutes); + +app.use( + '/api/investigate', + passport.authenticate('jwt', { session: false }), + investigateRoutes); + app.use( '/api/sql', passport.authenticate('jwt', { session: false }), @@ -210,4 +217,4 @@ db.sequelize.sync().then(function () { }); }); -module.exports = app; +module.exports = app; \ No newline at end of file diff --git a/backend/src/routes/investigate.js b/backend/src/routes/investigate.js new file mode 100644 index 0000000..991d9fd --- /dev/null +++ b/backend/src/routes/investigate.js @@ -0,0 +1,27 @@ +const express = require('express'); +const InvestigateService = require('../services/investigate'); +const { wrapAsync } = require('../helpers'); +const { checkCrudPermissions } = require('../middlewares/check-permissions'); + +const router = express.Router(); + +router.use(checkCrudPermissions('lookup_jobs')); + +router.post('/', wrapAsync(async (req, res) => { + const { query, type, organizationId } = req.body; + + if (!query || !type) { + return res.status(400).json({ error: 'Query and type are required' }); + } + + const result = await InvestigateService.runInvestigation( + query, + type, + req.currentUser, + organizationId + ); + + res.status(200).send(result); +})); + +module.exports = router; diff --git a/backend/src/services/investigate.js b/backend/src/services/investigate.js new file mode 100644 index 0000000..5706996 --- /dev/null +++ b/backend/src/services/investigate.js @@ -0,0 +1,82 @@ +const db = require('../db/models'); +const axios = require('axios'); +const config = require('../config'); + +module.exports = class InvestigateService { + static async runInvestigation(query, type, currentUser, organizationId) { + // 1. Create a Lookup Job + const job = await db.lookup_jobs.create({ + job_type: `${type}_lookup`, + status: 'running', + queued_at: new Date(), + started_at: new Date(), + request_params: JSON.stringify({ query, type }), + organizationsId: organizationId, + requested_by_userId: currentUser.id, + createdBy: currentUser.id, + }); + + try { + let resultData = {}; + + // 2. Perform external API call based on type + if (type === 'phone' && config.osint.apilayer) { + // Example using APILayer NumVerify + try { + const response = await axios.get(`http://apilayer.net/api/validate`, { + params: { + access_key: config.osint.apilayer, + number: query + } + }); + resultData = response.data; + } catch (e) { + console.error('APILayer Call Failed', e); + resultData = { error: 'External API failure', detail: e.message }; + } + } else { + // Mock data for other types for now + resultData = { + identifier: query, + type: type, + message: "Data aggregated from multiple OSINT sources", + timestamp: new Date().toISOString() + }; + } + + // 3. Create Lookup Result + const result = await db.lookup_results.create({ + result_kind: 'summary', + title: `Investigation Result for ${query}`, + data_json: JSON.stringify(resultData), + jobId: job.id, + organizationsId: organizationId, + collected_at: new Date(), + createdBy: currentUser.id, + }); + + // 4. Update Job Status + await job.update({ + status: 'succeeded', + finished_at: new Date(), + progress_percent: 100, + response_raw: JSON.stringify(resultData) + }); + + return { + jobId: job.id, + resultId: result.id, + data: resultData + }; + + } catch (error) { + console.error('Investigation Failed', error); + await job.update({ + status: 'failed', + error_message: error.message, + finished_at: new Date() + }); + throw error; + } + } +}; diff --git a/frontend/src/components/AsideMenuLayer.tsx b/frontend/src/components/AsideMenuLayer.tsx index d8ded49..1b891a3 100644 --- a/frontend/src/components/AsideMenuLayer.tsx +++ b/frontend/src/components/AsideMenuLayer.tsx @@ -6,7 +6,6 @@ import { MenuAsideItem } from '../interfaces' import { useAppSelector } from '../stores/hooks' import Link from 'next/link'; -import { useAppDispatch } from '../stores/hooks'; import { createAsyncThunk } from '@reduxjs/toolkit'; import axios from 'axios'; diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx index eb155e3..55d6b19 100644 --- a/frontend/src/components/NavBarItem.tsx +++ b/frontend/src/components/NavBarItem.tsx @@ -1,6 +1,5 @@ import React, {useEffect, useRef} from 'react' import Link from 'next/link' -import { useState } from 'react' import { mdiChevronUp, mdiChevronDown } from '@mdi/js' import BaseDivider from './BaseDivider' import BaseIcon from './BaseIcon' diff --git a/frontend/src/layouts/Authenticated.tsx b/frontend/src/layouts/Authenticated.tsx index 1b9907d..a996ce2 100644 --- a/frontend/src/layouts/Authenticated.tsx +++ b/frontend/src/layouts/Authenticated.tsx @@ -1,5 +1,4 @@ import React, { ReactNode, useEffect } from 'react' -import { useState } from 'react' import jwt from 'jsonwebtoken'; import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js' import menuAside from '../menuAside' diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index bc0ab03..2e468bb 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -7,6 +7,11 @@ const menuAside: MenuAsideItem[] = [ icon: icon.mdiViewDashboardOutline, label: 'Dashboard', }, + { + href: '/investigate', + icon: icon.mdiShieldSearch, + label: 'Investigation Hub', + }, { href: '/users/users-list', @@ -184,4 +189,4 @@ const menuAside: MenuAsideItem[] = [ }, ] -export default menuAside +export default menuAside \ No newline at end of file diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index a59fa65..3051b07 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -1,166 +1,115 @@ - import React, { useEffect, useState } from 'react'; import type { ReactElement } from 'react'; import Head from 'next/head'; import Link from 'next/link'; import BaseButton from '../components/BaseButton'; -import CardBox from '../components/CardBox'; import SectionFullScreen from '../components/SectionFullScreen'; import LayoutGuest from '../layouts/Guest'; -import BaseDivider from '../components/BaseDivider'; -import BaseButtons from '../components/BaseButtons'; import { getPageTitle } from '../config'; import { useAppSelector } from '../stores/hooks'; -import CardBoxComponentTitle from "../components/CardBoxComponentTitle"; -import { getPexelsImage, getPexelsVideo } from '../helpers/pexels'; +import { mdiShieldCheck, mdiMagnify, mdiMapMarkerRadius, mdiAccountSearch } from '@mdi/js'; +import BaseIcon from '../components/BaseIcon'; - -export default function Starter() { - const [illustrationImage, setIllustrationImage] = useState({ - src: undefined, - photographer: undefined, - photographer_url: undefined, - }) - const [illustrationVideo, setIllustrationVideo] = useState({video_files: []}) - const [contentType, setContentType] = useState('video'); - const [contentPosition, setContentPosition] = useState('right'); +export default function LandingPage() { const textColor = useAppSelector((state) => state.style.linkColor); + const title = 'OSINT Intelligence Hub'; - const title = 'OSINT Intelligence Dashboard' + return ( +
+ The ultimate OSINT platform for phone investigations, geolocation, + social media lookups, and deep person searches. Powered by 30+ intelligence APIs. +
+ +Scan 30+ providers for phone and email intelligence.
+Precise location tracking via BSSID and Cell Tower data.
+Aggregate social media profiles and public records.
+Analyze risk scores and fraud indicators instantly.
+© 2026 {title}. All rights reserved.
+This is a React.js/Node.js app generated by the Flatlogic Web App Generator
-For guides and documentation please check - your local README.md and the Flatlogic documentation
-© 2026 {title}. All rights reserved
- - Privacy Policy - -+ Querying intelligence nodes... +
+Enter an identifier above to begin your OSINT gathering.
+{detail.category}
+{detail.label}
+{detail.value}
+Automated Conclusion
++ Analysis complete. The investigation has aggregated data points from available intelligence providers. Results are saved to your account for future reference. +
+Link this investigation to an active case for detailed reporting.
+