. */ namespace SP\Services\Crypt; use Defuse\Crypto\Key; use SP\Core\Crypt\UUIDCookie; use SP\Core\Crypt\Vault; use SP\Http\Request; use SP\Services\Service; use SP\Services\ServiceException; use SP\Storage\File\FileCache; use SP\Storage\File\FileException; /** * Class SecureSessionService * * @package SP\Services\Crypt */ final class SecureSessionService extends Service { const CACHE_EXPIRE_TIME = 86400; const CACHE_PATH = CACHE_PATH . DIRECTORY_SEPARATOR . 'secure_session'; /** * @var FileCache */ protected $fileCache; /** * @var string */ protected $seed; /** * @var Request */ protected $request; /** * @var UUIDCookie */ protected $cookie; /** * @var string */ private $filename; /** * Returns the encryption key * * @param UUIDCookie $cookie * * @return Key|false */ public function getKey(UUIDCookie $cookie) { $this->cookie = $cookie; try { if ($this->fileCache->isExpired($this->getFileNameFromCookie(), self::CACHE_EXPIRE_TIME)) { debugLog('Session key expired or does not exist.'); return $this->saveKey(); } if (($vault = $this->fileCache->load($this->getFileNameFromCookie())) instanceof Vault) { return Key::loadFromAsciiSafeString($vault->getData($this->getCypher())); } } catch (FileException $e) { return $this->saveKey(); } catch (\Exception $e) { processException($e); } return false; } /** * Returns an unique filename from a browser cookie * * @return string * @throws ServiceException */ private function getFileNameFromCookie() { if (!$this->filename) { if (($uuid = $this->cookie->loadCookie($this->seed)) === false && ($uuid = $this->cookie->createCookie($this->seed)) === false ) { throw new ServiceException('Unable to get UUID for filename.'); } $this->filename = self::CACHE_PATH . DIRECTORY_SEPARATOR . $uuid; } return $this->filename; } /** * Saves the encryption key * * @return Key|false */ private function saveKey() { try { $securedKey = Key::createNewRandomKey(); $this->fileCache->save($this->getFileNameFromCookie(), (new Vault())->saveData($securedKey->saveToAsciiSafeString(), $this->getCypher())); debugLog('Saved session key.'); return $securedKey; } catch (\Exception $e) { processException($e); } return false; } /** * Returns the key to be used for encrypting the session data * * @return string */ private function getCypher() { return hash_pbkdf2('sha1', sha1($this->request->getHeader('User-Agent') . $this->request->getClientAddress()), $this->seed, 500, 32 ); } /** * @return string */ public function getFilename(): string { return $this->filename; } protected function initialize() { $this->fileCache = $this->dic->get(FileCache::class); $this->request = $this->dic->get(Request::class); $this->seed = $this->config->getConfigData()->getPasswordSalt(); } }