176 lines
6.3 KiB
PHP
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();
|
|
}
|
|
}
|