<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program 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/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\library;
use seekquarry\yioop\configs as C;
/**
* Persists the long-lived ACME account key so the same account is
* reused across issuances, and keeps the directory the account key
* and any issuance scratch live in. The account key is the
* credential for the ACME account, so it is written private (mode
* 0600) under a directory that is not web served.
*
* @author Chris Pollett chris@pollett.org
*/
class AcmeKeyStore
{
/**
* Directory holding the account key and issuance scratch.
* @var string
*/
private $dir;
/**
* @param string $dir directory for ACME account material;
* defaults to an acme directory under WORK_DIRECTORY
*/
public function __construct($dir = null)
{
$this->dir = ($dir === null)
? C\WORK_DIRECTORY . "/acme" : $dir;
}
/**
* Ensures the account directory exists.
*
* @return bool true if the directory exists or was created
*/
private function ensureDir()
{
if (is_dir($this->dir)) {
return true;
}
return @mkdir($this->dir, 0700, true) || is_dir($this->dir);
}
/**
* Path of the account key file.
*
* @return string the account key path
*/
private function accountKeyPath()
{
return $this->dir . "/account.key";
}
/**
* Returns the stored account key PEM, generating and storing a
* fresh one on first use so a caller always gets a usable key.
* Returns null only if the key cannot be created or written.
*
* @param int $bits RSA size for a newly generated key
* @return string|null the account key PEM, or null on failure
*/
public function accountKey($bits = 2048)
{
$path = $this->accountKeyPath();
if (is_file($path)) {
$pem = @file_get_contents($path);
if ($pem !== false && $pem !== "") {
return $pem;
}
}
if (!$this->ensureDir()) {
return null;
}
$pem = AcmeClient::generateAccountKey($bits);
$temp = @tempnam($this->dir, "key");
if ($temp === false) {
return null;
}
if (@file_put_contents($temp, $pem) === false) {
@unlink($temp);
return null;
}
@chmod($temp, 0600);
if (!@rename($temp, $path)) {
@unlink($temp);
return null;
}
return $pem;
}
}