<?php

declare(strict_types=1);

/*
 * eduVPN - End-user friendly VPN.
 *
 * Copyright: 2014-2023, The Commons Conservancy eduVPN Programme
 * SPDX-License-Identifier: AGPL-3.0+
 */

namespace Vpn\Portal;

use Vpn\Portal\Cfg\StaticPermissionsConfig;
use Vpn\Portal\Http\Request;

class StaticPermissionsSource implements PermissionSourceInterface
{
    private StaticPermissionsConfig $staticPermissionsConfig;
    private Request $httpRequest;

    public function __construct(StaticPermissionsConfig $staticPermissionsConfig, Request $httpRequest)
    {
        $this->staticPermissionsConfig = $staticPermissionsConfig;
        $this->httpRequest = $httpRequest;
    }

    /**
     * Get current permissions for users directly from the source.
     *
     * If no permissions are available, or the user no longer exists, an empty
     * array is returned.
     *
     * @return array<string>
     */
    public function permissionsForUser(string $userId): array
    {
        $permissionsFile = $this->staticPermissionsConfig->permissionsFile();
        if (!FileIO::exists($permissionsFile)) {
            return [];
        }

        $permissionData = Json::decode(FileIO::read($permissionsFile));
        $permissionList = [];
        foreach ($permissionData as $permissionId => $userIdList) {
            if (!is_string($permissionId)) {
                continue;
            }
            if (!is_array($userIdList)) {
                continue;
            }
            if (false === strpos($permissionId, '!')) {
                $permissionId = sprintf('%s!%s', $this->staticPermissionsConfig->defaultAttributeName(), $permissionId);
            }
            if (in_array($userId, $userIdList, true)) {
                $permissionList[] = $permissionId;

                continue;
            }
            // check whether the permissions are IP prefixes that also result
            // in permissions
            $remoteAddr = Ip::fromIp($this->httpRequest->requireHeader('REMOTE_ADDR'));
            foreach ($userIdList as $ipPrefix) {
                if (0 !== strpos($ipPrefix, 'IP@')) {
                    continue;
                }
                $permissionAddr = Ip::fromIpPrefix(substr($ipPrefix, 3));
                if ($permissionAddr->contains($remoteAddr)) {
                    $permissionList[] = $permissionId;
                }
            }
        }

        return $permissionList;
    }
}
