2023-08-22 23:47:37 +00:00
< ? php
namespace Mince ;
use InvalidArgumentException ;
use RuntimeException ;
2024-02-21 16:08:45 +00:00
use Index\Data\ { DbStatementCache , IDbConnection };
2023-08-22 23:47:37 +00:00
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
2024-02-21 16:08:45 +00:00
) : iterable {
2023-08-22 23:47:37 +00:00
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 ();
2024-02-21 16:08:45 +00:00
return $stmt -> getResult () -> getIterator ( AuthorisationInfo :: fromResult ( ... ));
2023-08-22 23:47:37 +00:00
}
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.' );
2024-02-21 16:08:45 +00:00
return AuthorisationInfo :: fromResult ( $result );
2023-08-22 23:47:37 +00:00
}
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 ();
}
}