diff --git a/AI_CONTRIBUTING_RULES.md b/AI_CONTRIBUTING_RULES.md new file mode 100644 index 0000000..cee8d7e --- /dev/null +++ b/AI_CONTRIBUTING_RULES.md @@ -0,0 +1,13 @@ +# Global AI Agent Instructions (Jules) + +**1. The "Living Wiki" Mandate:** +This repository maintains its documentation as a living wiki. The primary sources of truth are the `SYSTEM_ARCHITECTURE.md` and `SECURITY_ARCHITECTURE.md` files. + +**2. Mandatory PR Checklist:** +For *every single Pull Request* you generate, regardless of the specific issue assigned to you, you MUST perform the following checks before committing: +* **Diff Review:** Analyze your proposed code changes. +* **Wiki Sync:** If your code alters the network flow, port configurations, authentication methods, database schemas, or deployment commands, you MUST open `SYSTEM_ARCHITECTURE.md` (and create it if it doesn't exist) to update the relevant sections to reflect your exact code changes. +* **Commit Inclusion:** The documentation updates must be included in the same commit/PR as the code changes. Do not submit a PR where the code and the architecture wiki are out of sync. + +**3. Global Build Constraint:** +Whenever generating or modifying Dockerfiles for this project, you MUST ensure the font package is explicitly set to `fonts-freefont-ttf` to prevent downstream rendering failures. diff --git a/README.md b/README.md index d586e32..e332b48 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ This repository combines all the OSH modules and dependencies to deploy the OSH - [Java 21](https://www.oracle.com/java/technologies/downloads/#java21) - [Oakridge Build Node Repository](https://github.com/Botts-Innovative-Research/osh-oakridge-buildnode) - Node v22 +- [Docker](https://docs.docker.com/get-docker/) (Required to run the PostGIS database system) ## Installation Clone the repository and update all submodules recursively @@ -44,26 +45,47 @@ After the build completes, it can be located in `build/distributions/` Option 1: Command Line ```bash - unzip build/distributions/osh-node-oscar-1.0.zip - cd osh-node-oscar-1.0/osh-node-oscar-1.0 + # Note: Replace with the current version, e.g. 3.0.0 + unzip build/distributions/osh-node-oscar-.zip + cd osh-node-oscar-/osh-node-oscar- ``` ```bash - tar -xf build/distributions/osh-node-oscar-1.0.zip - cd osh-node-oscar-1.0/osh-node-oscar-1.0 + # Note: Replace with the current version, e.g. 3.0.0 + tar -xf build/distributions/osh-node-oscar-.zip + cd osh-node-oscar-/osh-node-oscar- ``` Option 2: Use File Explorer 1. Navigate to `path/to/osh-oakridge-buildnode/build/distributions/` - 2. Right-click `osh-node-oscar-1.0.zip`. + 2. Right-click `osh-node-oscar-.zip` (where `` is the current release version, e.g. `3.0.0`). 3. Select **Extract All..** 4. Choose your destination, (or leave the default) and extract. -1. Launch the OSH node: - Run the launch script, "launch.sh" for linux/mac and "launch.bat" for windows. +1. Launch the OSH node and PostGIS Database: + The database management system is handled through Docker. The default launch scripts automatically build and run a PostGIS container using the `Dockerfile` located in `dist/release/postgis`, and then start the OSH node. + Run the launch script, `launch-all.sh` (or `launch.sh` within the `osh-node-oscar` folder directly if the database is already running) for linux, `launch-all-arm.sh` (or `launch-arm.sh` if it exists) for mac, and `launch-all.bat` (or `launch.bat`) for windows. 2. Access the OSH Node - Remote: **[ip-address]:8282/sensorhub/admin** - Locally: **http://localhost:8282/sensorhub/admin** The default credentials to access the OSH Node are admin:admin. This can be changed in the Security section of the admin page. +**Language Selection** +The user can select different languages for the Admin UI by using the language drop-down menu located in the top right corner of the Admin UI toolbar. Selecting a new language will instantly switch the UI localization. + +**Two-Factor Authentication (2FA)** +2FA can be configured for users to add an extra layer of security. To set this up: +1. Log in to the Admin UI. +2. Navigate to the **Security** section. +3. Edit the user profile and set up Two-Factor Authentication. A popup window will appear with a QR code. +4. Scan the QR code with an authenticator app (like Google Authenticator or Authy) to complete the setup. + +**Importing/Exporting Lane Configurations via CSV** +Configurations for Lane Systems can be bulk managed via spreadsheet (CSV). +1. Log in to the Admin UI. +2. Navigate to **Services -> OSCAR Service**. +3. Within the configuration form for the OSCAR service, locate the property for spreadsheet configuration (`spreadsheetConfigPath`). +4. To export, click the download button to retrieve the current configurations as a CSV file. +5. To import, upload your modified CSV file through the provided upload mechanism in the service configuration to apply new or updated lane setups. + For documentation on configuring a Lane System on the OSH Admin panel, please refer to the OSCAR Documentation provided in the Google Drive documentation folder. ## Deploy the Client diff --git a/SECURITY_ARCHITECTURE.md b/SECURITY_ARCHITECTURE.md new file mode 100644 index 0000000..6435601 --- /dev/null +++ b/SECURITY_ARCHITECTURE.md @@ -0,0 +1,30 @@ +# OSCAR Security Hardening Architecture + +**Critical Domain Context:** +This project is an Open Source Central Alarm Station (OSCAR) monitoring radiation portal monitors. The application runs cross-platform on Windows, macOS, and Linux. The primary critical threat is the unauthorized suppression, modification, or spoofing of alarms. Note this specific nomenclature: +* **G Alarm:** Gamma Alarm. +* **N Alarm:** Neutron Alarm. +* **G-N:** Gamma Neutron Alarm. + +**OpenSensorHub (OSH) Ecosystem Constraint:** +OSCAR is built on the OpenSensorHub framework. **Under no circumstances may any code modifications break compatibility with the larger OSH ecosystem.** * Standard OGC SWE, SOS, and SPS API endpoints must remain fully compliant. +* Sensor drivers (e.g., video processing, hardware interfaces mapped in `config.csv`) must not be prevented from initializing or communicating. +* Machine-to-machine API routes cannot rely on human-interactive authentication (like 302 redirects to a TOTP login). + +**Global Build Constraint:** +Whenever generating or modifying Dockerfiles for this project, you MUST ensure the font package is explicitly set to `fonts-freefont-ttf`. This is strictly required to prevent downstream rendering failures in the application's graphical reporting components. + +## Database Security Implementation + +### SCRAM-SHA-256 Authentication +PostgreSQL is configured to enforce `scram-sha-256` authentication for all database users. This is initialized during the PostGIS container setup via `POSTGRES_INITDB_ARGS`. + +### Docker Secrets for Database Credentials +The system uses Docker Secrets (via bind mounts) to manage database passwords. +- **Injected Secret Path**: `/run/secrets/db_password` within the container. +- **Environment Variable**: `POSTGRES_PASSWORD_FILE` points to this secret path. +- **Backend Priority**: The OSH Java backend is architected to prioritize the `POSTGRES_PASSWORD_FILE` environment variable during initialization, overriding any plaintext credentials in `config.json`. + +### Configurable Networking and TLS +- **DB Host**: The database host is configurable via the `DB_HOST` environment variable (default: `localhost`), enabling secure deployment on separate LAN machines. +- **TLS Enforcement**: All connections from the OSH backend to PostGIS are secured over TLS. This is enforced by using `sslmode=require` in the JDBC connection string in the `ConnectionManager`. diff --git a/SYSTEM_ARCHITECTURE.md b/SYSTEM_ARCHITECTURE.md new file mode 100644 index 0000000..c9f7252 --- /dev/null +++ b/SYSTEM_ARCHITECTURE.md @@ -0,0 +1,42 @@ +# OSCAR System Architecture + +## Overview +OSCAR (Open Source Central Alarm Station) is a monitoring system for radiation portal monitors based on the OpenSensorHub (OSH) framework. + +## Component Network Flow and Ports + +### Components: +- **OSH Backend**: Java-based core application. +- **PostGIS Database**: PostgreSQL with PostGIS extensions for persistent storage. +- **Client Web UI**: React/Frontend viewer. + +### Default Port Configuration: +- **OSH Backend API (HTTP)**: `8282` +- **OSH Backend Admin UI**: `8282` +- **PostGIS Database**: `5432` +- **MQTT Server (HiveMQ)**: WebSockets on `/mqtt` (via proxy on port `8282`) + +### Network Flows: +- **Client to OSH**: Clients interact with OSH through its REST API and Web UI on port `8282`. +- **OSH to PostGIS**: The OSH backend connects to the PostGIS database over the network (local or LAN) on port `5432`. This connection is secured via TLS and authenticated with SCRAM-SHA-256. + +## Deployment and Lifecycle Commands + +### Main Launch Scripts: +Located in `dist/release/`: +- `launch-all.sh`: Starts the PostGIS container and the OSH backend (Linux/macOS). +- `launch-all-arm.sh`: Starts the PostGIS container and the OSH backend (ARM64, e.g., Mac M1/M2/M3). +- `launch-all.bat`: Starts the PostGIS container and the OSH backend (Windows). + +### Standalone Database Scripts: +Located in `dist/release/postgis/`: +- `run-postgis.sh`: Starts the PostGIS container independently (Linux/macOS). +- `run-postgis-arm.sh`: Starts the PostGIS container independently (ARM64). +- `run-postgis.bat`: Starts the PostGIS container independently (Windows). + +## Database Utilities +Cross-platform scripts are provided in the repository root for maintenance: +- `backup.sh/bat`: Safely creates a database dump. +- `restore.sh/bat`: Restores the database from a dump. + +These utilities respect the `DB_HOST` and `POSTGRES_PASSWORD_FILE` environment variables. diff --git a/backup.bat b/backup.bat new file mode 100644 index 0000000..8c62a77 --- /dev/null +++ b/backup.bat @@ -0,0 +1,32 @@ +@echo off +setlocal enabledelayedexpansion + +if "%DB_HOST%"=="" (set DB_HOST=localhost) +set DB_NAME=gis +set DB_USER=postgres + +if "%POSTGRES_PASSWORD_FILE%"=="" ( + echo Error: POSTGRES_PASSWORD_FILE environment variable is not set. + exit /b 1 +) + +if not exist "%POSTGRES_PASSWORD_FILE%" ( + echo Error: Password file %POSTGRES_PASSWORD_FILE% does not exist. + exit /b 1 +) + +set /p PGPASSWORD=<"%POSTGRES_PASSWORD_FILE%" + +set TIMESTAMP=%date:~10,4%%date:~4,2%%date:~7,2%_%time:~0,2%%time:~3,2%%time:~6,2% +set TIMESTAMP=%TIMESTAMP: =0% +set BACKUP_FILE=backup_%TIMESTAMP%.dump + +echo Backing up database %DB_NAME% from %DB_HOST%... +pg_dump -h %DB_HOST% -U %DB_USER% -d %DB_NAME% -F c -f "%BACKUP_FILE%" + +if %errorlevel% equ 0 ( + echo Backup completed successfully: %BACKUP_FILE% +) else ( + echo Backup failed. + exit /b 1 +) diff --git a/backup.sh b/backup.sh new file mode 100755 index 0000000..cf8f55e --- /dev/null +++ b/backup.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +DB_HOST="${DB_HOST:-localhost}" +DB_NAME="gis" +DB_USER="postgres" + +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + echo "Error: POSTGRES_PASSWORD_FILE environment variable is not set." + exit 1 +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Error: Password file $POSTGRES_PASSWORD_FILE does not exist." + exit 1 +fi + +export PGPASSWORD=$(cat "$POSTGRES_PASSWORD_FILE") + +echo "Backing up database $DB_NAME from $DB_HOST..." +pg_dump -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -F c -f "backup_$(date +%Y%m%d_%H%M%S).dump" + +if [ $? -eq 0 ]; then + echo "Backup completed successfully." +else + echo "Backup failed." + exit 1 +fi diff --git a/build.gradle b/build.gradle index 3f4a802..20aad5e 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply from: gradle.oshCoreDir + '/common.gradle' description = '' allprojects { - version = "3.0.0-rc.5" + version = "3.0.0" } subprojects { diff --git a/changelog.md b/changelog.md index 4564fab..8696d47 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,14 @@ # OSCAR Build Node Change Log All notable changes to this project will be documented in this file. +## 3.0.0 2026-02-04 +This is the official first release of 3.0.0 +### Changes +- Data from database is purged regularly with "daily files" exported at midnight +- Added internationalization (i18n) to the frontend +- Sorted lanes by alphanumeric order in the frontend dashboard +- Use server-side filters in frontend tables +### Fixed +- Fixed issue where database is queried everytime Admin UI is loaded ## 3.0.0-rc.5 2025-12-11 ### Changes diff --git a/dist/config/standard/config.json b/dist/config/standard/config.json index a88eea6..3fc7a6e 100644 --- a/dist/config/standard/config.json +++ b/dist/config/standard/config.json @@ -94,7 +94,7 @@ "uiClass": "com.botts.ui.oscar.forms.OSCARServiceForm" } ], - "deploymentName": "OSCAR 3.0.0-rc.5", + "deploymentName": "OSCAR 3.0.0", "enableLandingPage": false, "id": "5cb05c9c-9123-4fa1-8731-ffaa51489678", "autoStart": true, @@ -158,7 +158,8 @@ "initialBuckets": [ "sitemap", "reports", - "videos" + "videos", + "adjudication" ], "fileStoreRootDir": "files", "endPoint": "/buckets", @@ -174,7 +175,7 @@ "url": "localhost:5432", "dbName": "gis", "login": "postgres", - "password": "postgres", + "password": "", "idProviderType": "SEQUENTIAL", "autoCommitPeriod": 10, "useBatch": false, diff --git a/dist/release/launch-all-arm.sh b/dist/release/launch-all-arm.sh index 96c1cc5..a14b151 100755 --- a/dist/release/launch-all-arm.sh +++ b/dist/release/launch-all-arm.sh @@ -1,6 +1,6 @@ #!/bin/bash -HOST=localhost +HOST="${DB_HOST:-localhost}" DB_NAME=gis DB_USER=postgres RETRY_MAX=20 @@ -8,6 +8,16 @@ RETRY_INTERVAL=5 PROJECT_DIR="$(pwd)" # Store the original directory CONTAINER_NAME=oscar-postgis-container +# Set up DB password secret +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + export POSTGRES_PASSWORD_FILE="${PROJECT_DIR}/.db_password" +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Generating new database password..." + openssl rand -base64 32 > "$POSTGRES_PASSWORD_FILE" +fi + #sudo docker rm -f "$CONTAINER_NAME" 2>/dev/null || true # Create pgdata directory if needed @@ -48,10 +58,11 @@ else --name $CONTAINER_NAME \ -e POSTGRES_DB=$DB_NAME \ -e POSTGRES_USER=$DB_USER \ - -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_PASS=$(cat "$POSTGRES_PASSWORD_FILE") \ -e DATADIR=/var/lib/postgresql/data \ -p 5432:5432 \ -v "$(pwd)/pgdata:/var/lib/postgresql/data" \ + -v "$POSTGRES_PASSWORD_FILE:/run/secrets/db_password" \ -d \ oscar-postgis-arm || { echo "Failed to start PostGIS container"; exit 1; } fi @@ -60,16 +71,24 @@ fi echo "Waiting for PostGIS ARM64 (PostgreSQL) to be ready..." RETRY_COUNT=0 -export PGPASSWORD=postgres # Needed for pg_isready with password - -until docker exec "$CONTAINER_NAME" pg_isready -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; do +until docker exec -u "$DB_USER" "$CONTAINER_NAME" pg_isready -d "$DB_NAME" > /dev/null 2>&1; do echo "PostGIS not ready yet, retrying..." sleep "${RETRY_INTERVAL}" done echo "PostGIS (PostgreSQL) is ready! Please wait for OpenSensorHub to start..." -sleep 10 +sleep 30 + +# Final check +until docker exec -u "$DB_USER" "$CONTAINER_NAME" pg_isready -d "$DB_NAME" > /dev/null 2>&1; do + echo "PostGIS still restarting, waiting..." + sleep 5 +done + +# Export for OSH backend +export DB_HOST="$HOST" +export POSTGRES_PASSWORD_FILE="$POSTGRES_PASSWORD_FILE" # Launch osh-node-oscar cd "$PROJECT_DIR/osh-node-oscar" || { echo "Error: osh-node-oscar not found"; exit 1; } diff --git a/dist/release/launch-all.bat b/dist/release/launch-all.bat index 5c93081..1daae2e 100755 --- a/dist/release/launch-all.bat +++ b/dist/release/launch-all.bat @@ -2,7 +2,7 @@ setlocal enabledelayedexpansion REM ==== CONFIG ==== -set HOST=localhost +if "%DB_HOST%"=="" (set HOST=localhost) else (set HOST=%DB_HOST%) set PORT=5432 set DB_NAME=gis set USER=postgres @@ -14,6 +14,16 @@ set IMAGE_NAME=oscar-postgis echo PROJECT_DIR is: %PROJECT_DIR% +REM Set up DB password secret +if "%POSTGRES_PASSWORD_FILE%"=="" (set "POSTGRES_PASSWORD_FILE=%PROJECT_DIR%\.db_password") + +if not exist "%POSTGRES_PASSWORD_FILE%" ( + echo Generating new database password... + powershell -Command "$p = New-Object byte[] 32; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($p); $pwd = [Convert]::ToBase64String($p); [System.IO.File]::WriteAllText(\"%POSTGRES_PASSWORD_FILE:\=\\%\", $pwd)" +) + +set /p DB_PASSWORD=<"%POSTGRES_PASSWORD_FILE%" + where docker >nul 2>&1 if %errorlevel% neq 0 ( echo ERROR: Docker is not installed or not in PATH. @@ -61,9 +71,10 @@ if defined CONTAINER_EXISTS ( --name %CONTAINER_NAME% ^ -e POSTGRES_DB=%DB_NAME% ^ -e POSTGRES_USER=%USER% ^ - -e POSTGRES_PASSWORD=postgres ^ + -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password ^ -p %PORT%:5432 ^ -v "%PROJECT_DIR%\pgdata:/var/lib/postgresql/data" ^ + -v "%POSTGRES_PASSWORD_FILE%:/run/secrets/db_password" ^ -d ^ %IMAGE_NAME% @@ -78,7 +89,7 @@ echo Waiting for PostGIS database to become ready... set RETRY_COUNT=0 :wait_loop -docker exec %CONTAINER_NAME% pg_isready -U %USER% -d %DB_NAME% >nul 2>&1 +docker exec -u %USER% %CONTAINER_NAME% pg_isready -d %DB_NAME% >nul 2>&1 if %errorlevel% equ 0 ( echo Received OK from PostGIS. Please wait for initialization... goto after_wait @@ -97,10 +108,25 @@ goto wait_loop :after_wait -timeout /t 10 >nul +timeout /t 30 >nul + +:final_wait_loop +docker exec -u %USER% %CONTAINER_NAME% pg_isready -d %DB_NAME% >nul 2>&1 +if %errorlevel% equ 0 ( + goto after_final_wait +) +echo PostGIS still restarting, waiting... +timeout /t 5 >nul +goto final_wait_loop + +:after_final_wait echo PostGIS database is ready! +REM Export for OSH backend +set DB_HOST=%HOST% +set POSTGRES_PASSWORD_FILE=%POSTGRES_PASSWORD_FILE% + cd "%PROJECT_DIR%\osh-node-oscar" if %errorlevel% neq 0 ( echo ERROR: osh-node-oscar directory not found. diff --git a/dist/release/launch-all.sh b/dist/release/launch-all.sh index 5716c7c..9ca8e4f 100755 --- a/dist/release/launch-all.sh +++ b/dist/release/launch-all.sh @@ -1,6 +1,6 @@ #!/bin/bash -HOST="localhost" +HOST="${DB_HOST:-localhost}" PORT="5432" DB_NAME="gis" DB_USER="postgres" @@ -9,6 +9,16 @@ RETRY_INTERVAL=5 PROJECT_DIR="$(pwd)" # Store the original directory CONTAINER_NAME="oscar-postgis-container" +# Set up DB password secret +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + export POSTGRES_PASSWORD_FILE="${PROJECT_DIR}/.db_password" +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Generating new database password..." + openssl rand -base64 32 > "$POSTGRES_PASSWORD_FILE" +fi + #docker rm -f "$CONTAINER_NAME" 2>/dev/null || true # Create pgdata directory if needed @@ -51,9 +61,10 @@ else --name "$CONTAINER_NAME" \ -e POSTGRES_DB="$DB_NAME" \ -e POSTGRES_USER="$DB_USER" \ - -e POSTGRES_PASSWORD="postgres" \ + -e POSTGRES_PASSWORD_FILE="/run/secrets/db_password" \ -p $PORT:5432 \ -v "${PROJECT_DIR}/pgdata:/var/lib/postgresql/data" \ + -v "$POSTGRES_PASSWORD_FILE:/run/secrets/db_password" \ -d \ oscar-postgis || { echo "Failed to start PostGIS container"; exit 1; } fi @@ -62,16 +73,24 @@ fi echo "Waiting for PostGIS (PostgreSQL) to be ready..." RETRY_COUNT=0 -export PGPASSWORD=postgres # Needed for pg_isready with password - -until docker exec "$CONTAINER_NAME" pg_isready -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; do +until docker exec -u "$DB_USER" "$CONTAINER_NAME" pg_isready -d "$DB_NAME" > /dev/null 2>&1; do echo "PostGIS not ready yet, retrying..." sleep "${RETRY_INTERVAL}" done echo "PostGIS (PostgreSQL) is ready! Please wait for OpenSensorHub to start..." -sleep 10 +sleep 30 + +# Final check +until docker exec -u "$DB_USER" "$CONTAINER_NAME" pg_isready -d "$DB_NAME" > /dev/null 2>&1; do + echo "PostGIS still restarting, waiting..." + sleep 5 +done + +# Export for OSH backend +export DB_HOST="$HOST" +export POSTGRES_PASSWORD_FILE="$POSTGRES_PASSWORD_FILE" # Launch osh-node-oscar cd "$PROJECT_DIR/osh-node-oscar" || { echo "Error: osh-node-oscar not found"; exit 1; } diff --git a/dist/release/postgis/Dockerfile b/dist/release/postgis/Dockerfile index ce645c7..090489a 100644 --- a/dist/release/postgis/Dockerfile +++ b/dist/release/postgis/Dockerfile @@ -1,5 +1,14 @@ FROM postgis/postgis:16-3.4 +# Install fonts as required by AI_CONTRIBUTING_RULES.md +RUN apt-get update && apt-get install -y fonts-freefont-ttf && rm -rf /var/lib/apt/lists/* + COPY init-extensions.sql /docker-entrypoint-initdb.d/init-extensions.sql -ENV POSTGRES_INITDB_ARGS="-c max_parallel_workers_per_gather=0 -c max_parallel_workers=0" \ No newline at end of file +# Generate self-signed certificate for SSL support +RUN openssl req -new -x509 -days 365 -nodes -text -out /var/lib/postgresql/server.crt \ + -keyout /var/lib/postgresql/server.key -subj "/CN=oscar-postgis" \ + && chmod 600 /var/lib/postgresql/server.key \ + && chown postgres:postgres /var/lib/postgresql/server.key /var/lib/postgresql/server.crt + +ENV POSTGRES_INITDB_ARGS="--auth-local=trust --auth-host=scram-sha-256 -c max_parallel_workers_per_gather=0 -c max_parallel_workers=0 -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key" \ No newline at end of file diff --git a/dist/release/postgis/Dockerfile-arm64 b/dist/release/postgis/Dockerfile-arm64 index becfa20..4efddd7 100644 --- a/dist/release/postgis/Dockerfile-arm64 +++ b/dist/release/postgis/Dockerfile-arm64 @@ -1,7 +1,14 @@ FROM kartoza/postgis:16-3.4 -RUN echo "host all all all md5" >> /etc/postgresql/16/main/pg_hba.conf +# Install fonts as required by AI_CONTRIBUTING_RULES.md +RUN apt-get update && apt-get install -y fonts-freefont-ttf && rm -rf /var/lib/apt/lists/* COPY init-extensions.sql /docker-entrypoint-initdb.d/init-extensions.sql -ENV POSTGRES_INITDB_ARGS="-c max_parallel_workers_per_gather=0 -c max_parallel_workers=0" \ No newline at end of file +# Generate self-signed certificate for SSL support +RUN openssl req -new -x509 -days 365 -nodes -text -out /var/lib/postgresql/server.crt \ + -keyout /var/lib/postgresql/server.key -subj "/CN=oscar-postgis" \ + && chmod 600 /var/lib/postgresql/server.key \ + && chown postgres:postgres /var/lib/postgresql/server.key /var/lib/postgresql/server.crt + +ENV POSTGRES_INITDB_ARGS="--auth-local=trust --auth-host=scram-sha-256 -c max_parallel_workers_per_gather=0 -c max_parallel_workers=0 -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key" \ No newline at end of file diff --git a/dist/release/postgis/init-extensions.sql b/dist/release/postgis/init-extensions.sql index 796b363..50f33ee 100644 --- a/dist/release/postgis/init-extensions.sql +++ b/dist/release/postgis/init-extensions.sql @@ -1,4 +1,8 @@ ALTER SYSTEM SET max_connections = 1024; +ALTER SYSTEM SET ssl = 'on'; +ALTER SYSTEM SET ssl_cert_file = '/var/lib/postgresql/server.crt'; +ALTER SYSTEM SET ssl_key_file = '/var/lib/postgresql/server.key'; + \connect gis; CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION IF NOT EXISTS btree_gist; diff --git a/dist/release/postgis/run-postgis-arm.sh b/dist/release/postgis/run-postgis-arm.sh index 62ff5b6..987aa40 100755 --- a/dist/release/postgis/run-postgis-arm.sh +++ b/dist/release/postgis/run-postgis-arm.sh @@ -5,13 +5,26 @@ if [ ! -d "$(pwd)/pgdata" ]; then mkdir -p "$(pwd)/pgdata" fi +# Set up DB password secret +PROJECT_DIR="$(pwd)" +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + export POSTGRES_PASSWORD_FILE="${PROJECT_DIR}/.db_password" +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Generating new database password..." + openssl rand -base64 32 > "$POSTGRES_PASSWORD_FILE" +fi + docker build . --file=Dockerfile-arm64 --tag=oscar-postgis-arm docker run \ -e PG_MAX_CONNECTIONS=500 \ -e POSTGRES_DB=gis \ -e POSTGRES_USER=postgres \ - -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_PASS=$(cat "$POSTGRES_PASSWORD_FILE") \ -e DATADIR=/var/lib/postgresql/data \ -p 5432:5432 \ -v "$(pwd)/pgdata:/var/lib/postgresql/data" \ + -v "$POSTGRES_PASSWORD_FILE:/run/secrets/db_password" \ + -d \ oscar-postgis-arm \ No newline at end of file diff --git a/dist/release/postgis/run-postgis.bat b/dist/release/postgis/run-postgis.bat index f7ae6ad..d09ddb6 100644 --- a/dist/release/postgis/run-postgis.bat +++ b/dist/release/postgis/run-postgis.bat @@ -5,6 +5,14 @@ if not exist "%cd%\pgdata" ( mkdir "%cd%\pgdata" ) +# Set up DB password secret +if "%POSTGRES_PASSWORD_FILE%"=="" (set POSTGRES_PASSWORD_FILE=%cd%\.db_password) + +if not exist "%POSTGRES_PASSWORD_FILE%" ( + echo Generating new database password... + powershell -Command "$p = New-Object byte[] 32; (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($p); $pwd = [Convert]::ToBase64String($p); [System.IO.File]::WriteAllText('%POSTGRES_PASSWORD_FILE%', $pwd)" +) + docker build . --tag=oscar-postgis docker run ^ @@ -13,7 +21,9 @@ docker run ^ -e PG_MAX_CONNECTIONS=500 ^ -e POSTGRES_DB=gis ^ -e POSTGRES_USER=postgres ^ - -e POSTGRES_PASSWORD=postgres ^ + -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password ^ -p 5432:5432 ^ -v "%cd%\pgdata:/var/lib/postgresql/data" ^ + -v "%POSTGRES_PASSWORD_FILE%:/run/secrets/db_password" ^ + -d ^ oscar-postgis \ No newline at end of file diff --git a/dist/release/postgis/run-postgis.sh b/dist/release/postgis/run-postgis.sh index 4b47008..4ff1726 100755 --- a/dist/release/postgis/run-postgis.sh +++ b/dist/release/postgis/run-postgis.sh @@ -5,12 +5,25 @@ if [ ! -d "$(pwd)/pgdata" ]; then mkdir -p "$(pwd)/pgdata" fi +# Set up DB password secret +PROJECT_DIR="$(pwd)" +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + export POSTGRES_PASSWORD_FILE="${PROJECT_DIR}/.db_password" +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Generating new database password..." + openssl rand -base64 32 > "$POSTGRES_PASSWORD_FILE" +fi + docker build . --file=Dockerfile --tag=oscar-postgis docker run \ -e PG_MAX_CONNECTIONS=1024 \ -e POSTGRES_DB=gis \ -e POSTGRES_USER=postgres \ - -e POSTGRES_PASSWORD=postgres \ + -e POSTGRES_PASSWORD_FILE="/run/secrets/db_password" \ -p 5432:5432 \ -v "$(pwd)/pgdata:/var/lib/postgresql/data" \ + -v "$POSTGRES_PASSWORD_FILE:/run/secrets/db_password" \ + -d \ oscar-postgis diff --git a/dist/scripts/standard/launch.bat b/dist/scripts/standard/launch.bat index 52eb997..1d9d00e 100755 --- a/dist/scripts/standard/launch.bat +++ b/dist/scripts/standard/launch.bat @@ -15,6 +15,17 @@ set TRUSTSTORE_PASSWORD=changeit set INITIAL_ADMIN_PASSWORD_FILE=.\.s +REM Database configuration +if "%DB_HOST%"=="" (set DB_HOST=localhost) +if "%POSTGRES_PASSWORD_FILE%"=="" ( + if exist "..\.db_password" ( + for %%i in ("..\.db_password") do set POSTGRES_PASSWORD_FILE=%%~fi + ) else ( + if exist ".\.db_password" ( + for %%i in (".\.db_password") do set POSTGRES_PASSWORD_FILE=%%~fi + ) + ) +) REM Check if INITIAL_ADMIN_PASSWORD_FILE and INITIAL_ADMIN_PASSWORD are empty REM Set default password if neither is provided diff --git a/dist/scripts/standard/launch.sh b/dist/scripts/standard/launch.sh index 856b549..932a60f 100755 --- a/dist/scripts/standard/launch.sh +++ b/dist/scripts/standard/launch.sh @@ -13,6 +13,16 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) export TRUSTSTORE_PASSWORD="changeit" export INITIAL_ADMIN_PASSWORD_FILE="./.s" +# Database configuration +export DB_HOST="${DB_HOST:-localhost}" +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + # Check for password file in parent directory (standard for release) or current + if [ -f "../.db_password" ]; then + export POSTGRES_PASSWORD_FILE="$(cd .. && pwd)/.db_password" + elif [ -f "./.db_password" ]; then + export POSTGRES_PASSWORD_FILE="$(pwd)/.db_password" + fi +fi # After copying the default configuration file, also look to see if they # specified what they want the initial admin user's password to be, either diff --git a/docs/ADDING_NEW_RADIATION_PORTAL_MONITOR.md b/docs/ADDING_NEW_RADIATION_PORTAL_MONITOR.md new file mode 100644 index 0000000..1dea20e --- /dev/null +++ b/docs/ADDING_NEW_RADIATION_PORTAL_MONITOR.md @@ -0,0 +1,45 @@ +# Adding a New Radiation Portal Monitor System + +This document provides the correct process for adding a new radiation portal monitor system using the Lane Systems sensor. + +## Step 1: Add a New Module +1. Navigate to the admin panel at [localhost:8282/sensorhub/admin](http://localhost:8282/sensorhub/admin). +2. Right-click in the **Sensors** area. +3. Click **Add New Module**. +4. Select the **Lane Systems** module. + +## Step 2: Configure Location and Manufacturer +1. Enter the required **Location Information**. +2. Go to the tab that allows you to enter the radiation portal monitor manufacturer (Rapiscan or Aspect). +3. If you select **Rapiscan**, enter the **IP address** and the **communication port**. + +## Step 3: Add Camera Systems +Add the camera system of your choice by selecting the appropriate option: **Sony**, **Axis**, or **Generic**. + +### Sony or Axis Cameras +- If a Sony or Axis camera is selected, you will be presented with options to enter the **username**, **password**, and **IP address** for the camera. +- **Sony** cameras will additionally have the ability to choose between the **MJPG** and **H.264** video streams. + +### Generic Cameras +- If a Generic camera is selected, you will have the option to enter the **username**, **password**, **IP address**, **port number**, and the **stream URL** (this consists of the information that follows the initial IP address of the camera). + +*Note: More than one camera may be added by selecting to add additional cameras.* + +## Step 4: Save Changes +**Important: The save buttons must be clicked in the specific order described below.** + +1. **Session Save:** After all information has been entered for the radiation portal monitor system, save your changes by clicking the appropriate button on the **right side** of the upper corner of the screen. + *(Note: Saving only via the button on the right side saves the changes **only during the current session** that the node is running in.)* +2. **Persistent Save:** Next, save the changes by clicking the save icon on the **left side** of the screen. + *(Note: Clicking the save icon on the upper left-hand portion of the screen actually saves the configuration into the configuration file, ensuring they will persist after the node is restarted.)* + +## Step 5: Start the Module +1. Right-click on the newly created module in the Sensors area and select **Start**. +2. The module may go through an initial initialization phase where communication is established between the node and each of the sensors. +3. After initialization, the module will start. + *(Note: Modules can also be configured to auto-start when the node is started.)* + +## Step 6: Verify in OSCAR Viewer +Once the module has been successfully added and started: +1. Switch to the Oscar Viewer Dashboard at [localhost:8282](http://localhost:8282). +2. You will often need to **refresh this page** to make the newly added sensors appear. diff --git a/include/osh-addons b/include/osh-addons index ce66c7f..a5c6c7d 160000 --- a/include/osh-addons +++ b/include/osh-addons @@ -1 +1 @@ -Subproject commit ce66c7f8aabddbff05ed07c9bbe07fd0c436d24e +Subproject commit a5c6c7d9092142f6cdb66075b5ad6d7d3ab6ee23 diff --git a/include/osh-core b/include/osh-core index 7af3a11..d5e7f74 160000 --- a/include/osh-core +++ b/include/osh-core @@ -1 +1 @@ -Subproject commit 7af3a119dde5241e19fd94ae459aac192780fc3d +Subproject commit d5e7f747b0c5e8104691a3a960403998df5d5b58 diff --git a/include/osh-oakridge-modules b/include/osh-oakridge-modules index e3b15fc..907d282 160000 --- a/include/osh-oakridge-modules +++ b/include/osh-oakridge-modules @@ -1 +1 @@ -Subproject commit e3b15fce02cd9eeb1d3a4a365ae6451bf03bcf17 +Subproject commit 907d28284125d805141f58a857d9ec7cc6c9142d diff --git a/restore.bat b/restore.bat new file mode 100644 index 0000000..51eb88e --- /dev/null +++ b/restore.bat @@ -0,0 +1,34 @@ +@echo off +setlocal enabledelayedexpansion + +if "%DB_HOST%"=="" (set DB_HOST=localhost) +set DB_NAME=gis +set DB_USER=postgres + +if "%POSTGRES_PASSWORD_FILE%"=="" ( + echo Error: POSTGRES_PASSWORD_FILE environment variable is not set. + exit /b 1 +) + +if not exist "%POSTGRES_PASSWORD_FILE%" ( + echo Error: Password file %POSTGRES_PASSWORD_FILE% does not exist. + exit /b 1 +) + +if "%~1"=="" ( + echo Usage: %0 ^ + exit /b 1 +) + +set BACKUP_FILE=%~1 +set /p PGPASSWORD=<"%POSTGRES_PASSWORD_FILE%" + +echo Restoring database %DB_NAME% to %DB_HOST% from %BACKUP_FILE%... +pg_restore -h %DB_HOST% -U %DB_USER% -d %DB_NAME% -v "%BACKUP_FILE%" + +if %errorlevel% equ 0 ( + echo Restore completed successfully. +) else ( + echo Restore failed. + exit /b 1 +) diff --git a/restore.sh b/restore.sh new file mode 100755 index 0000000..5946c96 --- /dev/null +++ b/restore.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +DB_HOST="${DB_HOST:-localhost}" +DB_NAME="gis" +DB_USER="postgres" + +if [ -z "$POSTGRES_PASSWORD_FILE" ]; then + echo "Error: POSTGRES_PASSWORD_FILE environment variable is not set." + exit 1 +fi + +if [ ! -f "$POSTGRES_PASSWORD_FILE" ]; then + echo "Error: Password file $POSTGRES_PASSWORD_FILE does not exist." + exit 1 +fi + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 1 +fi + +BACKUP_FILE="$1" +export PGPASSWORD=$(cat "$POSTGRES_PASSWORD_FILE") + +echo "Restoring database $DB_NAME to $DB_HOST from $BACKUP_FILE..." +pg_restore -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" -v "$BACKUP_FILE" + +if [ $? -eq 0 ]; then + echo "Restore completed successfully." +else + echo "Restore failed." + exit 1 +fi diff --git a/tools/sensorhub-test/src/main/resources/config.json b/tools/sensorhub-test/src/main/resources/config.json index a6fc3df..66b84a4 100644 --- a/tools/sensorhub-test/src/main/resources/config.json +++ b/tools/sensorhub-test/src/main/resources/config.json @@ -170,7 +170,7 @@ "url": "localhost:5432", "dbName": "gis", "login": "postgres", - "password": "postgres", + "password": "", "idProviderType": "SEQUENTIAL", "autoCommitPeriod": 10, "useBatch": false, diff --git a/web/oscar-viewer b/web/oscar-viewer index 5cbddb7..9c0ac7f 160000 --- a/web/oscar-viewer +++ b/web/oscar-viewer @@ -1 +1 @@ -Subproject commit 5cbddb7dec77fbea96cfb3c6e8e9a0fe14df2310 +Subproject commit 9c0ac7f330fc9fec79838cd1c4ce09376c9e8969