<?php

declare(strict_types=1);

namespace SiteFort\Modules\Firewall\SafeNetwork;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

final class SafeNetworkFeedVerifier {
	private const PUBLIC_KEYS_B64 = [
		'1' => 'YlnqXTm5VKoSKOaLcBfGtnhig3Gn9lQbC1bEs/wpBlc=',
		'2' => 'JacIfic0T6/+LHfLVXOgOn/UQlkvGmZSnZa7UecshdI=',
	];

	public static function verify_response_body( string $body, string $signature_b64, string $key_id ): bool {
		$keys   = self::public_keys();
		$key_id = trim( $key_id );

		if ( $keys === [] || $body === '' || $signature_b64 === '' || $key_id === '' || ! isset( $keys[ $key_id ] ) ) {
			return false;
		}

		if ( ! function_exists( 'sodium_crypto_sign_verify_detached' ) ) {
			return false;
		}

		$sig = base64_decode( trim( $signature_b64 ), true );
		$pub = base64_decode( $keys[ $key_id ], true );
		if ( false === $sig || strlen( $sig ) !== 64 || false === $pub || strlen( $pub ) !== 32 ) {
			return false;
		}

		return sodium_crypto_sign_verify_detached( $sig, $body, $pub );
	}

	private static function public_keys(): array {
		$keys = self::PUBLIC_KEYS_B64;

		if ( defined( 'SITEFORT_SAFE_NETWORK_FEED_PUBLIC_KEYS' ) && is_array( SITEFORT_SAFE_NETWORK_FEED_PUBLIC_KEYS ) ) {
			foreach ( SITEFORT_SAFE_NETWORK_FEED_PUBLIC_KEYS as $key_id => $key ) {
				self::add_public_key( $keys, (string) $key_id, $key );
			}
		}

		if (
			defined( 'SITEFORT_SAFE_NETWORK_FEED_KEY_ID' )
			&& defined( 'SITEFORT_SAFE_NETWORK_FEED_PUBLIC_KEY_B64' )
		) {
			self::add_public_key(
				$keys,
				(string) SITEFORT_SAFE_NETWORK_FEED_KEY_ID,
				SITEFORT_SAFE_NETWORK_FEED_PUBLIC_KEY_B64
			);
		}

		return $keys;
	}

	private static function add_public_key( array &$keys, string $key_id, $key ): void {
		$key_id = trim( $key_id );
		if ( $key_id === '' || isset( self::PUBLIC_KEYS_B64[ $key_id ] ) || ! is_string( $key ) ) {
			return;
		}

		$key = trim( $key );
		$raw = base64_decode( $key, true );
		if ( false === $raw || strlen( $raw ) !== 32 ) {
			return;
		}

		if ( ! isset( $keys[ $key_id ] ) ) {
			$keys[ $key_id ] = $key;
		}
	}
}
