Skip to content

Commit c5c001a

Browse files
committed
feat: kill inactive access tokens
1 parent a695c9d commit c5c001a

File tree

5 files changed

+112
-1
lines changed

5 files changed

+112
-1
lines changed

extend.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
use Flarum\Api\Serializer\CurrentUserSerializer;
1818
use Flarum\Api\Serializer\ForumSerializer;
1919
use Flarum\Api\Serializer\GroupSerializer;
20+
use Flarum\Console\Schedule;
2021
use Flarum\Extend;
2122
use Flarum\Group\Event\Saving as GroupSaving;
2223
use Flarum\Group\Group;
2324
use Flarum\User\User;
2425
use IanM\TwoFactor\Api\Serializer\TwoFactorSerializer;
2526
use IanM\TwoFactor\Model\TwoFactor;
2627
use IanM\TwoFactor\OAuth\TwoFactorOAuthCheck;
28+
use Illuminate\Console\Scheduling\Event;
2729

2830
return [
2931
(new Extend\Frontend('forum'))
@@ -92,7 +94,14 @@
9294

9395
(new Extend\Settings())
9496
->default('ianm-twofactor.admin.settings.forum_logo_qr', true)
95-
->default('ianm-twofactor.admin.settings.forum_logo_qr_width', 100),
97+
->default('ianm-twofactor.admin.settings.forum_logo_qr_width', 100)
98+
->default('ianm-twofactor.kill_inactive_tokens', true)
99+
->default('ianm-twofactor.kill_inactive_tokens_age_days', 30)
100+
->default('ianm-twofactor.also_kill_developer_tokens', false),
101+
102+
(new Extend\Console())
103+
->command(Console\KillInactiveTokensCommand::class)
104+
->schedule(Console\KillInactiveTokensCommand::class, Console\InactiveTokensSchedule::class),
96105

97106
(new Extend\Conditional())
98107
->whenExtensionEnabled('fof-oauth', fn () => [

js/src/admin/components/SettingsPage.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ export default class SettingsPage extends ExtensionPage {
3232
help: app.translator.trans('ianm-twofactor.admin.settings.forum_logo_qr_width_help'),
3333
max: 200,
3434
})}
35+
<h3>{app.translator.trans('ianm-twofactor.admin.settings.tokens.heading')}</h3>
36+
<p className="helpText">{app.translator.trans('ianm-twofactor.admin.settings.tokens.help')}</p>
37+
{this.buildSettingComponent({
38+
setting: 'ianm-twofactor.kill_inactive_tokens',
39+
type: 'boolean',
40+
label: app.translator.trans('ianm-twofactor.admin.settings.tokens.kill_inactive_tokens'),
41+
help: app.translator.trans('ianm-twofactor.admin.settings.tokens.kill_inactive_tokens_help'),
42+
})}
43+
{this.buildSettingComponent({
44+
setting: 'ianm-twofactor.kill_inactive_tokens_age_days',
45+
type: 'number',
46+
min: 1,
47+
label: app.translator.trans('ianm-twofactor.admin.settings.tokens.kill_inactive_tokens_age_days'),
48+
help: app.translator.trans('ianm-twofactor.admin.settings.tokens.kill_inactive_tokens_age_days_help'),
49+
})}
50+
{this.buildSettingComponent({
51+
setting: 'ianm-twofactor.also_kill_developer_tokens',
52+
type: 'boolean',
53+
label: app.translator.trans('ianm-twofactor.admin.settings.tokens.also_kill_developer_tokens'),
54+
help: app.translator.trans('ianm-twofactor.admin.settings.tokens.also_kill_developer_tokens_help'),
55+
})}
3556
{this.submitButton()}
3657
</div>
3758
</div>

locale/en.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ ianm-twofactor:
1717
forum_logo_qr_width_help: The width of the forum logo embedded on the QR code displayed when enabling 2FA. Max 200.
1818
logo_qr: Logo on QR Code
1919
logo_qr_help: If logo has been uploaded, this logo will be embedded on the QR code. Leave blank to use the forum logo.
20+
tokens:
21+
heading: Access Tokens
22+
help: For extended security, you can manage additional behaviour here related to access tokens.
23+
kill_inactive_tokens: Kill Inactive Tokens
24+
kill_inactive_tokens_help: Automatically kill access tokens that have been inactive for a specified period of time.
25+
kill_inactive_tokens_age_days: Kill Inactive Tokens After (Days)
26+
kill_inactive_tokens_age_days_help: The number of days of inactivity after which access tokens will be deleted.
27+
also_kill_developer_tokens: Also Kill Developer Tokens
28+
also_kill_developer_tokens_help: Also kill developer access tokens that have been inactive for the specified period of time.
29+
2030

2131
forum:
2232
user_2fa.alert_message: You must enable 2FA to continue accessing your account.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace IanM\TwoFactor\Console;
4+
5+
use Flarum\Settings\SettingsRepositoryInterface;
6+
use Illuminate\Console\Scheduling\Event;
7+
8+
class InactiveTokensSchedule
9+
{
10+
public function __construct(
11+
protected SettingsRepositoryInterface $settings
12+
) { }
13+
14+
public function __invoke(Event $event)
15+
{
16+
if (! (bool) $this->settings->get('ianm-twofactor.kill_inactive_tokens')) {
17+
return;
18+
}
19+
20+
$event->twiceDaily();
21+
}
22+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace IanM\TwoFactor\Console;
4+
5+
use Carbon\Carbon;
6+
use Flarum\Http\AccessToken;
7+
use Flarum\Settings\SettingsRepositoryInterface;
8+
use Illuminate\Console\Command;
9+
10+
class KillInactiveTokensCommand extends Command
11+
{
12+
protected $signature = 'twofactor:kill-inactive-tokens';
13+
protected $description = 'Kill all inactive tokens';
14+
15+
public function __construct(
16+
protected SettingsRepositoryInterface $settings
17+
) {
18+
parent::__construct();
19+
}
20+
21+
public function handle(): void
22+
{
23+
$age = (int) $this->settings->get('ianm-twofactor.kill_inactive_tokens_age_days');
24+
$maxAge = Carbon::now()->subdays($age);
25+
26+
$query = AccessToken::query()
27+
->where('last_activity_at', '<', $maxAge);
28+
29+
if (! (bool) $this->settings->get('ianm-twofactor.also_kill_developer_tokens')) {
30+
$this->info('Not deleting any developer tokens.');
31+
$query->where('type', '!=', 'developer');
32+
}
33+
34+
$count = $query->count();
35+
36+
if ($count === 0) {
37+
$this->info("No tokens found which have not been used in $age+ days.");
38+
return;
39+
}
40+
41+
$this->info("Found $count tokens which have not been used in $age+ days. Deleting...");
42+
43+
$this->output->progressStart($count);
44+
45+
$query->delete();
46+
47+
$this->output->progressFinish();
48+
}
49+
}

0 commit comments

Comments
 (0)