Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 48 additions & 0 deletions .github/workflows/build-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build docker

on:
workflow_dispatch:
push:
branches:
- 'version-2-dev'
paths:
- '**'
- '!.github/**'
- '.github/workflows/build-docker.yml'
- '!docs/**'
- '!README.md'
- '!LICENSE'

env:
DOCKER_OWNER: ${{ github.repository_owner }}
DOCKER_CONTAINER: Open-Report-Analyzer

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # 4.0.0

- name: Set up QEMU
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0

- name: Fix Docker environment variables
run: |
# Make lowercase
echo "DOCKER_OWNER=$(echo $DOCKER_OWNER | tr '[A-Z]' '[a-z]')" >> $GITHUB_ENV
echo "DOCKER_CONTAINER=$(echo $DOCKER_CONTAINER | tr '[A-Z]' '[a-z]')" >> $GITHUB_ENV

- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin

- name: Build and push
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
platforms: linux/amd64,linux/arm64
push: true
tags: ghcr.io/${{ env.DOCKER_OWNER }}/${{ env.DOCKER_CONTAINER }}:latest
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM composer:lts as composer

FROM php:8.2-apache

# Install package dependencies
RUN apt-get update -y \
&& apt-get install -y git libpq-dev

# Copy in composer
COPY --from=composer /usr/bin/composer /usr/bin/composer

# Copy in the tool and config file
COPY . /var/www/html/
COPY config.php.pub-docker /var/www/html/config.php
WORKDIR /var/www/html/

# Install php dependencies
RUN composer require kevinoo/phpwhois:^6.3
RUN composer require maxmind-db/reader:~1.0

# Enable php modules
RUN docker-php-ext-install pdo pdo_mysql pdo_pgsql

# Setup to use the stock php production config
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ Optionally, a [zip file of the latest release](https://github.com/userjack6880/O

Once downloaded and installed in a desired directory, install either jsmitty12's phpWhois package or the MaxMind DB Reader package through composer. Rename `config.php.pub` to `config.php` and edit the configuration for your environment (see the next section on **Configuration Options** for details). Finally, run `install.php` to create the database view used by this software package.

```sh
ALLOW_INSTALL=1 php install.php
```

`install.php` should remove itself and `mysql.sql` once complete. If permissions aren't given, `install.php` may not delete those files. It is recommended to manually delete these.

# Configuration Options
Expand Down Expand Up @@ -105,6 +109,15 @@ Defines the standard starting date range for data presented. All pages where dat

Valid date signifiers are `m`, `w`, and `d` for "month", "week", and "day".

# Docker
A docker image is provided for ease of deployment. The image is based on the official PHP 8.2 image, and is configured to use Apache 2.4.

The image is available on [GitHub Container Registry](https://github.com/userjack6880/Open-DMARC-Analyzer/pkgs/container/open-dmarc-parser).

All config options are available as environment variables. Along with `ALLOW_INSTALL` which needs to be set to `1` to allow the install.php script to run when requested inside the container.

There is also a pre-built `docker-compose.yml` file that can be used to deploy the container and its requirements. It is recommended to use this file as a template, and modify it to your needs.

# Latest Changes

## 2-α1
Expand Down
66 changes: 66 additions & 0 deletions config.php.pub-docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/* ----------------------------------------------------------------------------

Open Report Analyzer
Copyright (C) 2023 - John Bradley (userjack6880)

config.php
configuration file

Available at: https://github.com/userjack6880/Open-Report-Analyzer

-------------------------------------------------------------------------------

This file is part of Open Report Analyzer.

Open Report Analyzer is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.

---------------------------------------------------------------------------- */

// Env
$env = getenv();

// Database Settings

define('DB_HOST', isset($env['DB_HOST']) ? $env['DB_HOST'] : 'localhost');
define('DB_USER', isset($env['DB_USER']) ? $env['DB_USER'] : 'openreport');
define('DB_PASS', isset($env['DB_PASS']) ? $env['DB_PASS'] : 'password');
define('DB_NAME', isset($env['DB_NAME']) ? $env['DB_NAME'] : 'openreport');
define('DB_PORT', isset($env['DB_PORT']) ? $env['DB_PORT'] : '3306'); // default port 3306, 5432 for pgsql
define('DB_TYPE', isset($env['DB_TYPE']) ? $env['DB_TYPE'] : 'mysql'); // supported mysql and pgsql

// Report Type Settings
define('REPORT_TYPE', isset($env['REPORT_TYPE']) ? $env['REPORT_TYPE'] : 'dmarc'); // supported dmarc, tls, all

// Debug Settings

define('DEBUG', isset($env['DEBUG']) ? intval($env['DEBUG']) : 1);

// Template Settings

define('TEMPLATE', isset($env['TEMPLATE']) ? $env['TEMPLATE'] : 'openda');

// Package Loader

define('AUTO_LOADER', isset($env['AUTO_LOADER']) ? $env['AUTO_LOADER'] : 'vendor/autoload.php'); // autoloader for composer installed libraries

// GeoIP2 Settings

define('GEO_ENABLE', isset($env['GEO_ENABLE']) ? intval($env['GEO_ENABLE']) : 1); // 0 - disable GeoIP2, 1 - enable GeoIP2
define('GEO_DB', isset($env['GEO_DB']) ? $env['GEO_DB'] : 'includes/geolite2.mmdb'); // location of GeoIP2 database

// Date Range

define('DATE_RANGE', isset($env['DATE_RANGE']) ? $env['DATE_RANGE'] : '-1w');

?>
53 changes: 53 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
version: "3.8"
services:
mariadb:
image: mariadb:latest
restart: unless-stopped
healthcheck:
test: [ "CMD", "healthcheck.sh", "--su-mysql", "--connect", "--innodb_initialized" ]
interval: 10s
timeout: 5s
retries: 5
volumes:
- /opt/dmarc/mysql/:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: superlongpasswordforroot
MARIADB_DATABASE: dmarc
MARIADB_USER: dmarc
MARIADB_PASSWORD: dmarc
parser:
image: ghcr.io/userjack6880/open-report-parser:latest
depends_on:
mariadb:
condition: service_healthy
restart: unless-stopped
tty: true
environment:
DBHOST: mariadb
DBUSER: dmarc
DBPASS: dmarc
DBNAME: dmarc
IMAPAUTH: simple
IMAPSERVER: email.example.com
IMAPUSER: [email protected]
IMAPPASS: yourpasswordhere
IMAPPORT: 993
IMAPSSL: 1
IMAPDMARCFOLDER: INBOX
IMAPDMARCPROC: INBOX/Processed
IMAPDMARCERR: INBOX/Not Processed
IMAPIGNOREERROR: 1
analyzer:
image: ghcr.io/userjack6880/open-dmarc-analyzer:latest
depends_on:
mariadb:
condition: service_healthy
restart: unless-stopped
ports:
- 8080:80
environment:
DB_HOST: mariadb
DB_USER: dmarc
DB_PASS: dmarc
DB_NAME: dmarc
GEO_ENABLE: 0
10 changes: 9 additions & 1 deletion includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ function getArg($arg,$default) {
}
}

// Replacement for array_map('htmlspecialchars', $array)
function htmlspecialchars_array($array) {
foreach ($array as $key => $value) {
$array[$key] = is_string($value) ? htmlspecialchars($value) : $value;
}
return $array;
}

// Page Functions -------------------------------------------------------------

// Dashboard ------------------------------------
Expand Down Expand Up @@ -405,7 +413,7 @@ function getDomains($dateRange) {
$domains = dbQuery($pdo, $statement, $params);

foreach ($domains as $key => $domain) {
$domain = array_map('htmlspecialchars', $domain);
$domain = htmlspecialchars_array($domain);
$domains[$key] = $domain;
}

Expand Down
20 changes: 10 additions & 10 deletions includes/template.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ function overview_bar($d_stats, $t_stats, $domain) {
if ($domain == "all") {
$domain_count = 0;
foreach ($d_stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
$total = $total+$stat['total_messages'];
if ($stat['none'] > 0) { $dmarc_none = $dmarc_none+$stat['none']; }
if ($stat['quarantine'] > 0) { $dmarc_quar = $dmarc_quar+$stat['quarantine']; }
Expand All @@ -195,7 +195,7 @@ function overview_bar($d_stats, $t_stats, $domain) {
}
}
else {
$d_stats[0] = array_map('htmlspecialchars',$d_stats[0]);
$d_stats[0] = htmlspecialchars_array($d_stats[0]);
// $total = $d_stats[0]['total_messages'];
$policy = ucfirst($d_stats[0]['policy_p']);
$policy_pct = $d_stats[0]['policy_pct'];
Expand Down Expand Up @@ -236,7 +236,7 @@ function overview_bar($d_stats, $t_stats, $domain) {
$tls_total = 0;

foreach ($t_stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
// this should pick up the latest policy mode
if ($stat['policy_mode'] != '') { $tls_mode = $stat['policy_mode']; }
if ($stat['summary_success'] > 0) { $tls_success = $tls_success+$stat['summary_success']; }
Expand Down Expand Up @@ -388,7 +388,7 @@ function domain_overview($d_stats, $t_stats, $dateRange) {

// dmarc data processing
foreach ($d_stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
$domain = $stat['domain'];

// extract stats
Expand Down Expand Up @@ -440,7 +440,7 @@ function domain_overview($d_stats, $t_stats, $dateRange) {

// tls data processing
foreach ($t_stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
$domain = $stat['domain'];

// extract stats
Expand Down Expand Up @@ -582,7 +582,7 @@ function domain_details($d_stats, $t_stats, $domain, $dateRange) {
echo "<br>";
// do summations here
foreach ($t_stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
if ($stat['recv_mx'] == '') { $stat['recv_mx'] = 'unknown'; }
if (!isset($t_success[$stat['recv_mx']]) && !isset($t_failure[$stat['recv_mx']])) {
$t_success[$stat['recv_mx']] = 0;
Expand Down Expand Up @@ -691,7 +691,7 @@ function domain_details($d_stats, $t_stats, $domain, $dateRange) {

// extract stats - this'll be sorted by senderIP
$ip = get_ip($stat['ip'], $stat['ip6']);
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
$messages = $stat['messages'];
if ($stat['compliant'] > 0) { $compliant = $stat['compliant']; }
if ($stat['none'] > 0) { $none = $stat['none']; }
Expand Down Expand Up @@ -869,7 +869,7 @@ function sender_details($geo_data, $stats, $domain, $dateRange, $ip) {
}

foreach ($stats as $stat) {
$stat = array_map('htmlspecialchars',$stat);
$stat = htmlspecialchars_array($stat);
$dkimresult = $stat['dkimresult'] ?: 'unknown';
$dkim_align = $stat['dkim_align'] ?: 'unknown';
$spfresult = $stat['spfresult'] ?: 'unknown';
Expand Down Expand Up @@ -912,7 +912,7 @@ function sender_details($geo_data, $stats, $domain, $dateRange, $ip) {
function report_details($data, $report) {

if ($data[0]['ip6'] != '') { $ip = $data[0]['ip6']; }
$data[0] = array_map('htmlspecialchars',$data[0]);
$data[0] = htmlspecialchars_array($data[0]);
if ($data[0]['ip6'] != '') { $data[0]['ip6'] = $ip; }

if ($data[0]['policy_adkim'] == 'r') { $dkim_policy = 'Relaxed'; }
Expand Down Expand Up @@ -974,7 +974,7 @@ function report_details($data, $report) {

foreach ($data as $row) {
$ip = get_ip($row['ip'],$row['ip6']);
$row = array_map('htmlspecialchars',$row);
$row = htmlspecialchars_array($row);
$dkimresult = $row['dkimresult'] ?: 'unknown';
$dkim_align = $row['dkim_align'] ?: 'unknown';
$spfresult = $row['spfresult'] ?: 'unknown';
Expand Down
5 changes: 5 additions & 0 deletions install.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@

---------------------------------------------------------------------------- */

// Install protection
if (getenv("ALLOW_INSTALL") != 1) {
die("Installation is not allowed. Please set ALLOW_INSTALL=1 in your environment to enable installation.");
}

// Includes
include_once 'includes.php';

Expand Down