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(); } }