Skip to content

Commit

Permalink
fix(push): Check last activity and last check for age
Browse files Browse the repository at this point in the history
Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Mar 3, 2025
1 parent 47adde9 commit 4e94f08
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 17 deletions.
69 changes: 52 additions & 17 deletions lib/Push.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use OCP\AppFramework\Http;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\Exceptions\InvalidTokenException;
use OCP\Authentication\Token\IToken;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Http\Client\IClientService;
use OCP\ICache;
Expand Down Expand Up @@ -593,27 +594,61 @@ protected function sendNotificationsToProxies(): void {

protected function validateToken(int $tokenId, int $maxAge): bool {
$age = $this->cache->get('t' . $tokenId);
if ($age !== null) {
return $age > $maxAge;

if ($age === null) {
try {
// Check if the token is still valid...
$token = $this->tokenProvider->getTokenById($tokenId);
$type = $this->callSafelyForToken($token, 'getType');
if ($type === IToken::WIPE_TOKEN) {
// Token does not exist any more, should drop the push device entry
$this->printInfo('Device token is marked for remote wipe');
$this->deletePushToken($tokenId);
$this->cache->set('t' . $tokenId, 0, 600);
return false;
}

$age = $token->getLastCheck();
$lastActivity = $this->callSafelyForToken($token, 'getLastActivity');
if ($lastActivity) {
$age = max($age, $lastActivity);
}
$this->cache->set('t' . $tokenId, $age, 600);
} catch (InvalidTokenException) {
// Token does not exist any more, should drop the push device entry
$this->printInfo('InvalidTokenException is thrown');
$this->deletePushToken($tokenId);
$this->cache->set('t' . $tokenId, 0, 600);
return false;
}
}

try {
// Check if the token is still valid...
$token = $this->tokenProvider->getTokenById($tokenId);
$this->cache->set('t' . $tokenId, $token->getLastCheck(), 600);
if ($token->getLastCheck() > $maxAge) {
$this->printInfo('Device token is valid');
} else {
$this->printInfo('Device token "last checked" is older than 60 days: ' . $token->getLastCheck());
if ($age > $maxAge) {
$this->printInfo('Device token is valid');
return true;
}

$this->printInfo('Device token "last checked" is older than 60 days: ' . $age);
return false;
}

/**
* The functions are not part of public API so we are a bit more careful
* @param IToken $token
* @param 'getLastActivity'|'getType' $method
* @return int|null
*/
protected function callSafelyForToken(IToken $token, string $method): ?int {
if (method_exists($token, $method) || method_exists($token, '__call')) {
try {
$result = $token->$method();
if (is_int($result)) {
return $result;
}
} catch (\BadFunctionCallException) {
}
return $token->getLastCheck() > $maxAge;
} catch (InvalidTokenException $e) {
// Token does not exist anymore, should drop the push device entry
$this->printInfo('InvalidTokenException is thrown');
$this->deletePushToken($tokenId);
$this->cache->set('t' . $tokenId, 0, 600);
return false;
}
return null;
}

/**
Expand Down
29 changes: 29 additions & 0 deletions tests/Unit/PushTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
use GuzzleHttp\Exception\ServerException;
use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Token\IProvider;
use OC\Authentication\Token\PublicKeyToken;
use OC\Security\IdentityProof\Key;
use OC\Security\IdentityProof\Manager;
use OCA\Notifications\Push;
use OCP\AppFramework\Http;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Authentication\Token\IToken as OCPIToken;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
Expand Down Expand Up @@ -847,4 +849,31 @@ public function testPushToDeviceTalkNotification(array $deviceTypes, $isTalkNoti

$push->pushToDevice(200718, $notification);
}

public static function dataValidateToken(): array {
return [
[1239999999, 1230000000, OCPIToken::WIPE_TOKEN, false],
[1230000000, 1239999999, OCPIToken::WIPE_TOKEN, false],
[1230000000, 1239999999, OCPIToken::PERMANENT_TOKEN, true],
[1239999999, 1230000000, OCPIToken::PERMANENT_TOKEN, true],
[1230000000, 1230000000, OCPIToken::PERMANENT_TOKEN, false],
];
}

/**
* @dataProvider dataValidateToken
*/
public function testValidateToken(int $lastCheck, int $lastActivity, int $type, bool $expected): void {
$token = PublicKeyToken::fromParams([
'lastCheck' => $lastCheck,
'lastActivity' => $lastActivity,
'type' => $type,
]);

$this->tokenProvider->method('getTokenById')
->willReturn($token);

$push = $this->getPush();
$this->assertSame($expected, self::invokePrivate($push, 'validateToken', [42, 1234567890]));
}
}

0 comments on commit 4e94f08

Please sign in to comment.