-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(updater): Stop expiring secret prematurely #49578
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ | |
use OCP\BackgroundJob\TimedJob; | ||
use OCP\IAppConfig; | ||
use OCP\IConfig; | ||
use Psr\Log\LoggerInterface; | ||
|
||
/** | ||
* Deletes the updater secret after if it is older than 48h | ||
|
@@ -26,24 +27,31 @@ public function __construct( | |
ITimeFactory $time, | ||
private IConfig $config, | ||
private IAppConfig $appConfig, | ||
private LoggerInterface $logger, | ||
) { | ||
parent::__construct($time); | ||
// Run all 10 minutes | ||
parent::setInterval(60 * 10); | ||
// Run once an hour | ||
parent::setInterval(60 * 60); | ||
} | ||
|
||
/** | ||
* @param $argument | ||
*/ | ||
protected function run($argument) { | ||
if ($this->config->getSystemValueBool('config_is_read_only')) { | ||
$this->logger->debug('Skipping `updater.secret` reset since config_is_read_only is set', ['app' => 'updatenotification']); | ||
return; | ||
} | ||
|
||
$secretCreated = $this->appConfig->getValueInt('core', 'updater.secret.created', $this->time->getTime()); | ||
// Delete old tokens after 2 days | ||
if ($secretCreated >= 172800) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What an oversight 🙈 |
||
$secretCreatedDiff = $this->time->getTime() - $secretCreated; | ||
if ($secretCreatedDiff >= 172800) { | ||
$this->config->deleteSystemValue('updater.secret'); | ||
$this->appConfig->deleteKey('core', 'updater.secret.created'); | ||
$this->logger->warning('Cleared old `updater.secret` that was created ' . $secretCreatedDiff . ' seconds ago', ['app' => 'updatenotification']); | ||
} else { | ||
$this->logger->debug('Keeping existing `updater.secret` that was created ' . $secretCreatedDiff . ' seconds ago', ['app' => 'updatenotification']); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -13,35 +13,40 @@ | |||||
use OCP\IAppConfig; | ||||||
use OCP\IConfig; | ||||||
use PHPUnit\Framework\MockObject\MockObject; | ||||||
use Psr\Log\LoggerInterface; | ||||||
use Test\TestCase; | ||||||
|
||||||
class ResetTokenTest extends TestCase { | ||||||
private ITimeFactory|MockObject $timeFactory; | ||||||
private IConfig|MockObject $config; | ||||||
private IAppConfig|MockObject $appConfig; | ||||||
private ITimeFactory|MockObject $timeFactory; | ||||||
private LoggerInterface|MockObject $logger; | ||||||
private BackgroundJobResetToken $resetTokenBackgroundJob; | ||||||
|
||||||
protected function setUp(): void { | ||||||
parent::setUp(); | ||||||
$this->appConfig = $this->createMock(IAppConfig::class); | ||||||
$this->config = $this->createMock(IConfig::class); | ||||||
$this->timeFactory = $this->createMock(ITimeFactory::class); | ||||||
$this->config = $this->createMock(IConfig::class); | ||||||
$this->appConfig = $this->createMock(IAppConfig::class); | ||||||
$this->logger = $this->createMock(LoggerInterface::class); | ||||||
$this->resetTokenBackgroundJob = new BackgroundJobResetToken( | ||||||
$this->timeFactory, | ||||||
$this->config, | ||||||
$this->appConfig, | ||||||
$this->logger, | ||||||
); | ||||||
} | ||||||
|
||||||
public function testRunWithNotExpiredToken(): void { | ||||||
public function testRunWithNotExpiredToken(): void { // Affirm if updater.secret.created <48 hours ago then `updater.secret` is left alone | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make the comment part of the function name, so the failing test explains it right away without diving into test code, |
||||||
$this->timeFactory | ||||||
->expects($this->atLeastOnce()) | ||||||
->method('getTime') | ||||||
->willReturn(123); | ||||||
->willReturn(1733069649); // "Sun, 01 Dec 2024 16:14:09 +0000" | ||||||
$this->appConfig | ||||||
->expects($this->once()) | ||||||
->method('getValueInt') | ||||||
->with('core', 'updater.secret.created', 123); | ||||||
->with('core', 'updater.secret.created', 1733069649) | ||||||
->willReturn(1733069649 - 1 * 24 * 60 * 60); // 24h prior: "Sat, 30 Nov 2024 16:14:09 +0000" | ||||||
$this->config | ||||||
->expects($this->once()) | ||||||
->method('getSystemValueBool') | ||||||
|
@@ -50,29 +55,53 @@ public function testRunWithNotExpiredToken(): void { | |||||
$this->config | ||||||
->expects($this->never()) | ||||||
->method('deleteSystemValue'); | ||||||
$this->appConfig | ||||||
->expects($this->never()) | ||||||
->method('deleteKey'); | ||||||
$this->logger | ||||||
->expects($this->never()) | ||||||
->method('warning'); | ||||||
$this->logger | ||||||
->expects($this->once()) | ||||||
->method('debug'); | ||||||
|
||||||
static::invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
$this->invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Static is the correct/new stuff. Ref ffb3a3e |
||||||
} | ||||||
|
||||||
public function testRunWithExpiredToken(): void { | ||||||
public function testRunWithExpiredToken(): void { // Affirm if updater.secret.created >48 hours ago then `updater.secret` is removed | ||||||
$this->timeFactory | ||||||
->expects($this->once()) | ||||||
->expects($this->atLeastOnce()) | ||||||
->method('getTime') | ||||||
->willReturn(1455045234); | ||||||
->willReturn(1455045234); // "Tue, 09 Feb 2016 19:13:54 +0000" | ||||||
$this->appConfig | ||||||
->expects($this->once()) | ||||||
->method('getValueInt') | ||||||
->with('core', 'updater.secret.created', 1455045234) | ||||||
->willReturn(2 * 24 * 60 * 60 + 1); // over 2 days | ||||||
->willReturn(1455045234 - 3 * 24 * 60 * 60); // 72h prior: "Sat, 06 Feb 2016 19:13:54 +0000" | ||||||
$this->config | ||||||
->expects($this->once()) | ||||||
->method('getSystemValueBool') | ||||||
->with('config_is_read_only') | ||||||
->willReturn(false); | ||||||
$this->config | ||||||
->expects($this->once()) | ||||||
->method('deleteSystemValue') | ||||||
->with('updater.secret'); | ||||||
$this->appConfig | ||||||
->expects($this->once()) | ||||||
->method('deleteKey') | ||||||
->with('core', 'updater.secret.created'); | ||||||
$this->logger | ||||||
->expects($this->once()) | ||||||
->method('warning'); | ||||||
$this->logger | ||||||
->expects($this->never()) | ||||||
->method('debug'); | ||||||
|
||||||
static::invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
$this->invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
} | ||||||
|
||||||
public function testRunWithExpiredTokenAndReadOnlyConfigFile(): void { | ||||||
public function testRunWithExpiredTokenAndReadOnlyConfigFile(): void { // Affirm if config_is_read_only is set that the secret is never reset | ||||||
$this->timeFactory | ||||||
->expects($this->never()) | ||||||
->method('getTime'); | ||||||
|
@@ -87,7 +116,16 @@ public function testRunWithExpiredTokenAndReadOnlyConfigFile(): void { | |||||
$this->config | ||||||
->expects($this->never()) | ||||||
->method('deleteSystemValue'); | ||||||
$this->appConfig | ||||||
->expects($this->never()) | ||||||
->method('deleteKey'); | ||||||
$this->logger | ||||||
->expects($this->never()) | ||||||
->method('warning'); | ||||||
$this->logger | ||||||
->expects($this->once()) | ||||||
->method('debug'); | ||||||
|
||||||
static::invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
$this->invokePrivate($this->resetTokenBackgroundJob, 'run', [null]); | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should handle the "does not even exist" case.
Or should we even always try the delete of the
updater.secret
, when the timestamp is missing?