mince/src/Authorisations.php
2024-02-21 16:08:45 +00:00

176 lines
6.3 KiB
PHP

<?php
namespace Mince;
use InvalidArgumentException;
use RuntimeException;
use Index\Data\{DbStatementCache,IDbConnection};
use Index\Net\IPAddress;
use Ramsey\Uuid\UuidInterface;
class Authorisations {
private IDbConnection $dbConn;
private DbStatementCache $cache;
public function __construct(IDbConnection $dbConn) {
$this->dbConn = $dbConn;
$this->cache = new DbStatementCache($dbConn);
}
public function prune(): void {
$this->dbConn->execute('DELETE FROM authorisations WHERE (auth_requested < NOW() - INTERVAL 1 HOUR AND auth_granted IS NULL) OR (auth_used < NOW() - INTERVAL 1 WEEK AND auth_granted IS NOT NULL)');
}
public function getAuthorisations(
AccountLinkInfo|UuidInterface|string $uuid
): iterable {
if($uuid instanceof AccountLinkInfo)
$uuid = $uuid->getUUIDRaw();
elseif($uuid instanceof UuidInterface)
$uuid = $uuid->getBytes();
$stmt = $this->cache->get('SELECT auth_id, auth_uuid, INET6_NTOA(auth_addr), UNIX_TIMESTAMP(auth_requested), UNIX_TIMESTAMP(auth_granted), UNIX_TIMESTAMP(auth_used) FROM authorisations WHERE auth_uuid = ? ORDER BY auth_granted IS NULL DESC, auth_granted DESC, auth_requested DESC');
$stmt->addParameter(1, $uuid);
$stmt->execute();
return $stmt->getResult()->getIterator(AuthorisationInfo::fromResult(...));
}
public function getAuthorisation(
?string $authId = null,
AccountLinkInfo|UuidInterface|string|null $uuid = null,
IPAddress|string|null $remoteAddr = null
): AuthorisationInfo {
$hasAuthId = $authId !== null;
$hasUuid = $uuid !== null;
$hasRemoteAddr = $remoteAddr !== null;
$values = [];
$query = 'SELECT auth_id, auth_uuid, INET6_NTOA(auth_addr), UNIX_TIMESTAMP(auth_requested), UNIX_TIMESTAMP(auth_granted), UNIX_TIMESTAMP(auth_used) FROM authorisations';
if($hasAuthId) {
$query .= ' WHERE auth_id = ?';
$values[] = $authId;
} else {
$args = 0;
if($hasUuid) {
if($uuid instanceof AccountLinkInfo)
$uuid = $uuid->getUUIDRaw();
elseif($uuid instanceof UuidInterface)
$uuid = $uuid->getBytes();
++$args;
$query .= ' WHERE auth_uuid = ?';
$values[] = $uuid;
}
if($hasRemoteAddr) {
if($remoteAddr instanceof IPAddress)
$remoteAddr = (string)$remoteAddr;
$query .= sprintf(' %s auth_addr = INET6_ATON(?)', ++$args > 1 ? 'AND' : 'WHERE');
$values[] = $remoteAddr;
}
}
if(empty($values))
throw new InvalidArgumentException('At least one argument must be specified.');
$args = 0;
$stmt = $this->cache->get($query);
foreach($values as $value)
$stmt->addParameter(++$args, $value);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('Authorisation info not found.');
return AuthorisationInfo::fromResult($result);
}
public function createAuthorisation(
AccountLinkInfo|VerificationInfo|UuidInterface|string $uuid,
IPAddress|string|null $remoteAddr = null,
bool $grant = false
): void {
if($uuid instanceof VerificationInfo) {
$remoteAddr = $uuid->getAddressRaw();
$uuid = $uuid->getUUIDRaw();
} else {
if($remoteAddr === null)
throw new InvalidArgumentException('$remoteAddr may not be null (unless $uuid is a valid VerificationInfo instance)');
if($uuid instanceof AccountLinkInfo)
$uuid = $uuid->getUUIDRaw();
elseif($uuid instanceof UuidInterface)
$uuid = $uuid->getBytes();
if($remoteAddr instanceof IPAddress)
$remoteAddr = (string)$remoteAddr;
}
$stmt = $this->cache->get(sprintf(
'INSERT INTO authorisations (auth_uuid, auth_addr, auth_granted) VALUES (?, INET6_ATON(?), %s)',
$grant ? 'NOW()' : 'NULL'
));
$stmt->addParameter(1, $uuid);
$stmt->addParameter(2, $remoteAddr);
$stmt->execute();
}
public function setAuthorisationGranted(AuthorisationInfo|string $authInfo): void {
if($authInfo instanceof AuthorisationInfo)
$authInfo = $authInfo->getId();
$stmt = $this->cache->get('UPDATE authorisations SET auth_granted = COALESCE(auth_granted, NOW()) WHERE auth_id = ?');
$stmt->addParameter(1, $authInfo);
$stmt->execute();
}
public function markAuthorisationUsed(AuthorisationInfo|string $authInfo): void {
if($authInfo instanceof AuthorisationInfo)
$authInfo = $authInfo->getId();
$stmt = $this->cache->get('UPDATE authorisations SET auth_used = NOW() WHERE auth_id = ?');
$stmt->addParameter(1, $authInfo);
$stmt->execute();
}
public function deleteAuthorisations(
AuthorisationInfo|string|null $authInfo = null,
AccountLinkInfo|UuidInterface|string|null $uuid = null,
?bool $pending = null
): void {
$hasAuthInfo = $authInfo !== null;
$hasUuid = $uuid !== null;
$hasPending = $pending !== null;
if(!$hasAuthInfo && !$hasUuid)
throw new InvalidArgumentException('$authInfo or $uuid must be specified.');
$value = null;
$query = 'DELETE FROM authorisations';
if($hasAuthInfo) {
if($authInfo instanceof AuthorisationInfo)
$authInfo = $authInfo->getId();
$query .= ' WHERE auth_id = ?';
$value = $authInfo;
} elseif($hasUuid) {
if($uuid instanceof AccountLinkInfo)
$uuid = $uuid->getUUIDRaw();
elseif($uuid instanceof UuidInterface)
$uuid = $uuid->getBytes();
$query .= ' WHERE auth_uuid = ?';
$value = $uuid;
if($hasPending)
$query .= sprintf(' AND auth_granted %s NULL', $pending ? 'IS' : 'IS NOT');
}
$stmt = $this->cache->get($query);
$stmt->addParameter(1, $value);
$stmt->execute();
}
}