Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d21d7dd
allow public access to crime reports map endpoint
iSiRaH Jan 31, 2026
b52e34a
deleted unneccssary call analysis files and refactored service to use…
JinethBosilu Jan 31, 2026
c3a8d73
remove unnessary files
JinethBosilu Jan 31, 2026
4838a14
modified the database schema to include new tables for storing facial…
JinethBosilu Feb 1, 2026
b413aad
Merge pull request #14 from arosha-w/arosha
iSiRaH Feb 1, 2026
20c8c2b
implemented hybrid architecture for frontend API calls through Spring…
JinethBosilu Feb 1, 2026
608b04d
Update CodeQL workflow for Java 21 analysis
iSiRaH Feb 2, 2026
9f0f05c
Add Dependabot configuration for dependency updates
iSiRaH Feb 2, 2026
cadc5c4
Merge pull request #16 from arosha-w/iSiRaH-patch-1
arosha-w Feb 3, 2026
ccd6b4e
Bump actions/checkout from 4 to 6
dependabot[bot] Feb 3, 2026
7be13c7
Bump the spring group with 2 updates
dependabot[bot] Feb 3, 2026
4c93961
Enhance refresh token handling and validation logic
iSiRaH Feb 5, 2026
8b11b94
Merge pull request #17 from arosha-w/dependabot/github_actions/action…
LPK98 Feb 8, 2026
3e5a077
Bump actions/setup-java from 4 to 5
dependabot[bot] Feb 8, 2026
9f62b90
Merge pull request #18 from arosha-w/dependabot/github_actions/action…
LPK98 Feb 8, 2026
b8234c0
Implement location tracking features with bulk upload and history ret…
iSiRaH Feb 10, 2026
cc01854
Change meta column data type string to jsonb
iSiRaH Feb 10, 2026
1c718f2
Added debugging enpoints and make duty locations fetching from backend
iSiRaH Feb 13, 2026
56b36cf
Merge branch 'main' into isira
iSiRaH Feb 13, 2026
f782bb7
Merge pull request #22 from arosha-w/isira
arosha-w Feb 14, 2026
a7804e3
Merge pull request #19 from arosha-w/dependabot/maven/spring-94c7bc8383
arosha-w Feb 14, 2026
3887f4e
Resolve version conflict problems (#23)
iSiRaH Feb 15, 2026
4ae9f12
Merge facial_recognitionService: integrate call analysis and facial r…
JinethBosilu Feb 15, 2026
041fd7b
Security Fixes
JinethBosilu Feb 15, 2026
8e1ec45
ecurity: Fix log injection vulnerabilities
JinethBosilu Feb 15, 2026
d41d971
Refactor logging to use LogSanitizer for safe output and add LogSanit…
JinethBosilu Feb 28, 2026
ef74b74
Merge pull request #28 from arosha-w/merge-tets
arosha-w Feb 28, 2026
65388bc
Added crime evidence files uploading to supabase storage
iSiRaH Mar 2, 2026
2c823a2
Added crime evidence to upload to supabase storage
iSiRaH Mar 3, 2026
88a7018
FIXED downloading evidence files
iSiRaH Mar 4, 2026
b035ca7
Merge branch 'main' into isira
iSiRaH Mar 4, 2026
615d4c8
Added crime evidence files uploading to supabase storage
iSiRaH Mar 2, 2026
398fa9b
Added crime evidence files uploading to supabase storage
iSiRaH Mar 2, 2026
868697a
Resolve merge error
iSiRaH Mar 4, 2026
d3b1785
Merge pull request #30 from arosha-w/isira
arosha-w Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ DB_PASSWORD=your-password

# Server Configuration
SERVER_PORT=8080

# JWT Configuration
JWT_SECRET=secret_key
JWT_EXPIRATION=
REFRESH_TOKEN_EXPIRATION=

# Supabase Configurations
SUPABASE_URL=
SUPABASE_SERVICE_KEY=
55 changes: 55 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
version: 2

updates:
# Maven / Spring Boot dependencies
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "09:00"
open-pull-requests-limit: 10
rebase-strategy: "auto"

# Group updates to reduce noise in dev
groups:
spring:
patterns:
- "org.springframework*"
- "org.springframework.boot*"
testing:
patterns:
- "org.junit*"
- "org.mockito*"
- "org.assertj*"
- "org.testcontainers*"
build-plugins:
patterns:
- "org.apache.maven.plugins*"
- "io.spring.javaformat*"
- "com.diffplug.spotless*"
- "org.sonarsource.scanner.maven*"
misc:
patterns:
- "*"

# Avoid risky breaking changes automatically (you upgrade these intentionally)
ignore:
- dependency-name: "org.springframework.boot"
update-types: ["version-update:semver-major"]
- dependency-name: "org.springframework"
update-types: ["version-update:semver-major"]
- dependency-name: "org.springframework.security"
update-types: ["version-update:semver-major"]
- dependency-name: "org.hibernate.orm"
update-types: ["version-update:semver-major"]

# GitHub Actions used in workflows
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "09:00"
open-pull-requests-limit: 5
rebase-strategy: "auto"
57 changes: 57 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "CodeQL"

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
schedule:
- cron: "33 19 * * 4"

jobs:
analyze:
name: Analyze (Java 21)
runs-on: ubuntu-latest

permissions:
security-events: write
actions: read
contents: read
packages: read

steps:
- name: Checkout repository
uses: actions/checkout@v6

- name: Set up JDK 21
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "21"
cache: maven

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: java-kotlin
build-mode: manual
queries: security-extended,security-and-quality

# Maven (Spring Initializr usually uses Maven)
- name: Build with Maven
if: hashFiles('pom.xml') != ''
run: |
chmod +x mvnw || true
./mvnw -B -DskipTests clean package || mvn -B -DskipTests clean package

# Gradle (only runs if Gradle files exist)
- name: Build with Gradle
if: hashFiles('build.gradle', 'build.gradle.kts') != ''
run: |
chmod +x gradlew || true
./gradlew build -x test

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:java-kotlin"
267 changes: 267 additions & 0 deletions database/facial_recognition_tables.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
-- ====================================================================
-- Facial Recognition System - Database Schema
-- ====================================================================
-- This schema supports the facial recognition feature for CrimeLinkAnalyzer
-- Created: December 11, 2025
-- ====================================================================

-- Enable required PostgreSQL extension for EXCLUDE constraints
-- The btree_gist extension is required for using EXCLUDE constraints with equality operators
-- This allows us to enforce "one primary photo per criminal" at the database level
CREATE EXTENSION IF NOT EXISTS btree_gist;

-- Drop existing tables if they exist (for clean setup)
DROP TABLE IF EXISTS facial_recognition_logs CASCADE;
DROP TABLE IF EXISTS suspect_photos CASCADE;
DROP TABLE IF EXISTS criminals CASCADE;

-- ====================================================================
-- CRIMINALS TABLE
-- ====================================================================
-- Stores criminal records with biometric data
CREATE TABLE criminals (
criminal_id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
nic VARCHAR(20) UNIQUE,
alias VARCHAR(255),
date_of_birth DATE,
gender VARCHAR(10) CHECK (gender IN ('Male', 'Female', 'Other')),
address TEXT,
nationality VARCHAR(100) DEFAULT 'Sri Lankan',

-- Crime information stored as JSONB for flexibility
crime_history JSONB DEFAULT '[]'::jsonb,

-- Primary photo reference
primary_photo_url VARCHAR(500),

-- Face embedding - stored as BYTEA (binary)
-- This is the average embedding from all photos
face_embedding BYTEA,
embedding_model VARCHAR(50) DEFAULT 'buffalo_sc',
embedding_dimension INTEGER DEFAULT 512,

-- Status tracking
status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'inactive', 'archived')),
risk_level VARCHAR(20) DEFAULT 'medium' CHECK (risk_level IN ('low', 'medium', 'high', 'critical')),

-- Audit fields
created_by INTEGER, -- User ID who created this record
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

-- Metadata
notes TEXT,
last_seen_location VARCHAR(255),
last_seen_date DATE
);

-- ====================================================================
-- SUSPECT_PHOTOS TABLE
-- ====================================================================
-- Stores multiple photos per criminal for better accuracy
CREATE TABLE suspect_photos (
photo_id SERIAL PRIMARY KEY,
criminal_id INTEGER NOT NULL REFERENCES criminals(criminal_id) ON DELETE CASCADE,

-- Photo storage
photo_url VARCHAR(500) NOT NULL,
photo_hash VARCHAR(64) UNIQUE, -- SHA-256 hash to prevent duplicates
file_size_bytes INTEGER,

-- Face detection metadata
face_embedding BYTEA NOT NULL, -- Individual photo embedding
face_confidence DECIMAL(5,2), -- Detection confidence (0-100)
face_bbox JSONB, -- Bounding box coordinates {x, y, width, height}

-- Photo metadata
is_primary BOOLEAN DEFAULT FALSE,
photo_quality VARCHAR(20) CHECK (photo_quality IN ('low', 'medium', 'high', 'excellent')),
image_width INTEGER,
image_height INTEGER,

-- Source tracking
source VARCHAR(100), -- e.g., 'manual_upload', 'cctv', 'arrest_record'
source_date DATE,

-- Audit
uploaded_by INTEGER, -- User ID
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

-- Constraints
CONSTRAINT only_one_primary_per_criminal
EXCLUDE USING gist (criminal_id WITH =)
WHERE (is_primary = true)
);

-- ====================================================================
-- FACIAL_RECOGNITION_LOGS TABLE
-- ====================================================================
-- Audit trail for all facial recognition requests
CREATE TABLE facial_recognition_logs (
log_id SERIAL PRIMARY KEY,

-- Request details
analysis_type VARCHAR(50) DEFAULT 'suspect_match', -- 'suspect_match', 'criminal_registration'
uploaded_image_url VARCHAR(500),
uploaded_image_hash VARCHAR(64),

-- Face detection results
face_detected BOOLEAN DEFAULT FALSE,
face_count INTEGER DEFAULT 0,
face_quality VARCHAR(20),

-- Matching results
matches_found INTEGER DEFAULT 0,
best_match_criminal_id INTEGER REFERENCES criminals(criminal_id),
best_match_similarity DECIMAL(5,2), -- Percentage (0-100)
match_threshold DECIMAL(5,2) DEFAULT 75.00,

-- All matches stored as JSONB for detailed analysis
all_matches JSONB DEFAULT '[]'::jsonb,

-- Performance metrics
processing_time_ms INTEGER,
model_version VARCHAR(50),

-- Security & Audit
requested_by INTEGER, -- User ID
user_role VARCHAR(50),
ip_address INET,
user_agent TEXT,

-- Timestamps
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

-- Investigation reference
case_id VARCHAR(100),
investigation_notes TEXT
);

-- ====================================================================
-- INDEXES FOR PERFORMANCE
-- ====================================================================

-- Criminal table indexes
CREATE INDEX idx_criminal_nic ON criminals(nic);
CREATE INDEX idx_criminal_name ON criminals USING gin(to_tsvector('english', name));
CREATE INDEX idx_criminal_status ON criminals(status) WHERE status = 'active';
CREATE INDEX idx_criminal_risk_level ON criminals(risk_level);
CREATE INDEX idx_criminal_created_at ON criminals(created_at DESC);

-- Suspect photos indexes
CREATE INDEX idx_suspect_photos_criminal_id ON suspect_photos(criminal_id);
CREATE INDEX idx_suspect_photos_primary ON suspect_photos(criminal_id, is_primary) WHERE is_primary = true;
CREATE INDEX idx_suspect_photos_hash ON suspect_photos(photo_hash);

-- Facial recognition logs indexes
CREATE INDEX idx_fr_logs_created_at ON facial_recognition_logs(created_at DESC);
CREATE INDEX idx_fr_logs_user ON facial_recognition_logs(requested_by);
CREATE INDEX idx_fr_logs_best_match ON facial_recognition_logs(best_match_criminal_id) WHERE best_match_criminal_id IS NOT NULL;
CREATE INDEX idx_fr_logs_case_id ON facial_recognition_logs(case_id) WHERE case_id IS NOT NULL;

-- ====================================================================
-- TRIGGERS FOR AUTO-UPDATE
-- ====================================================================

-- Automatically update updated_at timestamp
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER update_criminals_updated_at
BEFORE UPDATE ON criminals
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();

-- ====================================================================
-- UTILITY FUNCTIONS
-- ====================================================================

-- Function to calculate average embedding from multiple photos
CREATE OR REPLACE FUNCTION calculate_average_embedding(p_criminal_id INTEGER)
RETURNS BYTEA AS $$
DECLARE
avg_embedding BYTEA;
BEGIN
-- This will be called from Python after uploading multiple photos
-- Python will handle the actual embedding averaging logic
-- This function is a placeholder for future stored procedure implementation
RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- Function to search similar faces (placeholder - actual search done in Python)
CREATE OR REPLACE FUNCTION search_similar_faces(
p_embedding BYTEA,
p_threshold DECIMAL DEFAULT 0.75,
p_limit INTEGER DEFAULT 10
)
RETURNS TABLE (
criminal_id INTEGER,
name VARCHAR,
similarity DECIMAL
) AS $$
BEGIN
-- Actual similarity search is performed in Python using numpy
-- This is a placeholder for documentation
RETURN QUERY SELECT NULL::INTEGER, NULL::VARCHAR, NULL::DECIMAL LIMIT 0;
END;
$$ LANGUAGE plpgsql;

-- ====================================================================
-- INITIAL DATA / SEED DATA
-- ====================================================================

-- Insert sample criminal record for testing
INSERT INTO criminals (
name,
nic,
date_of_birth,
gender,
crime_history,
status,
risk_level,
notes
) VALUES (
'Test Suspect One',
'199012345678',
'1990-05-15',
'Male',
'[{"crime_type": "Theft", "date": "2023-03-10", "status": "Convicted", "sentence": "2 years"}]'::jsonb,
'active',
'medium',
'Sample criminal record for testing facial recognition system'
);

-- ====================================================================
-- PERMISSIONS & SECURITY
-- ====================================================================

-- Grant appropriate permissions (adjust based on your user roles)
-- GRANT SELECT, INSERT, UPDATE ON criminals TO crimelink_app_user;
-- GRANT SELECT, INSERT ON suspect_photos TO crimelink_app_user;
-- GRANT INSERT ON facial_recognition_logs TO crimelink_app_user;

-- ====================================================================
-- COMMENTS FOR DOCUMENTATION
-- ====================================================================

COMMENT ON TABLE criminals IS 'Stores criminal records with biometric face embeddings for facial recognition';
COMMENT ON COLUMN criminals.face_embedding IS 'Average face embedding vector stored as binary data (512-dimensional float32 array)';
COMMENT ON COLUMN criminals.crime_history IS 'JSON array of crime records: [{crime_type, date, status, sentence}]';

COMMENT ON TABLE suspect_photos IS 'Multiple photos per criminal for improved recognition accuracy';
COMMENT ON COLUMN suspect_photos.face_embedding IS 'Individual face embedding for this specific photo';
COMMENT ON COLUMN suspect_photos.photo_hash IS 'SHA-256 hash to prevent duplicate photo uploads';

COMMENT ON TABLE facial_recognition_logs IS 'Audit trail for all facial recognition analysis requests';
COMMENT ON COLUMN facial_recognition_logs.all_matches IS 'JSON array of all matches: [{criminal_id, similarity, confidence}]';

-- ====================================================================
-- END OF SCHEMA
-- ====================================================================
Loading
Loading