• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / auth / 25551603694

08 May 2026 10:49AM UTC coverage: 71.592% (+12.6%) from 59.035%
25551603694

push

github

daycry
tests: bring coverage from 58% to 71% with 180 new tests

Adds 22 new test files covering services, models, filters, traits, commands,
exceptions, and password validators. Test count goes from 732 to 912.

Bug fixes uncovered while writing tests:
- Totp2FA::verifyCodeForUser: was passing the encrypted+base64 secret to
  TOTP::verify, which then tried to base32-decode binary garbage. Now uses
  the user's getTotpSecret() so the decrypted base32 secret reaches verify.
- HasAccessTokens trait: accessTokens() and revokeAllAccessTokens() called
  non-existent plural method names on UserIdentityModel; refactored the
  trait to delegate to AccessTokenRepository (the architectural direction).
- PasswordChangeRecorder::stampChangedAt: silently dropped the timestamp
  because password_changed_at isn't in UserModel::$allowedFields. Switched
  to a direct query builder update.
- Five admin commands (audit, sessions, tokens, totp, gdpr): used the static
  CLI::write/error/getOption helpers, which bypass the MockInputOutput
  interceptor used by tests. Switched to instance helpers and \$params.

Baseline regenerated to absorb the new (and legitimate) deprecated-method
and internal-helper warnings raised by tests that intentionally exercise
deprecated APIs and the BaseCommand setInputOutput hook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

59 of 69 new or added lines in 8 files covered. (85.51%)

1 existing line in 1 file now uncovered.

4453 of 6220 relevant lines covered (71.59%)

62.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.67
/src/Commands/TokensCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Auth.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Auth\Commands;
15

16
use CodeIgniter\CLI\CLI;
17
use Daycry\Auth\Enums\IdentityType;
18
use Daycry\Auth\Models\AccessTokenRepository;
19
use Daycry\Auth\Models\UserIdentityModel;
20
use Daycry\Auth\Models\UserModel;
21
use Throwable;
22

23
/**
24
 * Admin CLI to soft-revoke a user's access / JWT-refresh tokens.
25
 *
26
 * Usage:
27
 *   php spark auth:tokens revoke -e user@example.com
28
 *   php spark auth:tokens revoke -e user@example.com --type=access_token
29
 *   php spark auth:tokens revoke -e user@example.com --type=jwt_refresh
30
 *   php spark auth:tokens revoke -e user@example.com --type=all
31
 */
32
class TokensCommand extends BaseCommand
33
{
34
    /**
35
     * Command's name
36
     *
37
     * @var string
38
     */
39
    protected $name = 'auth:tokens';
40

41
    /**
42
     * Command's short description
43
     *
44
     * @var string
45
     */
46
    protected $description = 'Soft-revoke access / refresh tokens for a user.';
47

48
    /**
49
     * Command's usage
50
     *
51
     * @var string
52
     */
53
    protected $usage = <<<'EOL'
54
        auth:tokens revoke -e <email> [--type=access_token|jwt_refresh|all]
55
        EOL;
56

57
    /**
58
     * Command's Arguments
59
     *
60
     * @var array<string, string>
61
     */
62
    protected $arguments = [
63
        'action' => 'Currently only `revoke` is supported.',
64
    ];
65

66
    /**
67
     * Command's Options
68
     *
69
     * @var array<string, string>
70
     */
71
    protected $options = [
72
        '-e'     => 'Target user email.',
73
        '-i'     => 'Target user id (alternative to -e).',
74
        '--type' => 'Token type to revoke: access_token | jwt_refresh | all (default: all).',
75
    ];
76

77
    public function run(array $params): int
7✔
78
    {
79
        $action = $params[0] ?? '';
7✔
80

81
        if ($action !== 'revoke') {
7✔
82
            $this->error('Unsupported action. Supported: revoke.');
1✔
83

84
            return 1;
1✔
85
        }
86

87
        $email = (string) ($params['e'] ?? '');
6✔
88
        $id    = (string) ($params['i'] ?? '');
6✔
89
        $type  = (string) ($params['type'] ?? 'all');
6✔
90

91
        if ($email === '' && $id === '') {
6✔
92
            $this->error('Specify -e <email> or -i <id>.');
1✔
93

94
            return 1;
1✔
95
        }
96

97
        /** @var UserModel $userModel */
98
        $userModel = model(UserModel::class);
5✔
99
        $user      = $id !== ''
5✔
100
            ? $userModel->findById((int) $id)
1✔
101
            : $userModel->findByCredentials(['email' => $email]);
4✔
102

103
        if ($user === null) {
5✔
104
            $this->error('User not found.');
1✔
105

106
            return 1;
1✔
107
        }
108

109
        try {
110
            if ($type === 'all' || $type === 'access_token') {
4✔
111
                $repo = new AccessTokenRepository(model(UserIdentityModel::class));
2✔
112
                $repo->softRevokeAllAccessTokens($user);
2✔
113
                $this->write('Revoked all access tokens for user ' . $user->id, 'green');
2✔
114
            }
115

116
            if ($type === 'all' || $type === 'jwt_refresh') {
4✔
117
                /** @var UserIdentityModel $identityModel */
118
                $identityModel = model(UserIdentityModel::class);
3✔
119
                $identityModel->revokeIdentitiesByUserAndType(
3✔
120
                    (int) $user->id,
3✔
121
                    IdentityType::JWT_REFRESH->value,
3✔
122
                );
3✔
123
                $this->write('Revoked all JWT refresh tokens for user ' . $user->id, 'green');
3✔
124
            }
125

126
            // Sanity check on the type argument
127
            if (! in_array($type, ['all', 'access_token', 'jwt_refresh'], true)) {
4✔
128
                $this->error('Unknown --type. Use: access_token | jwt_refresh | all.');
1✔
129

130
                return 1;
4✔
131
            }
132
        } catch (Throwable $e) {
×
NEW
133
            $this->error('Token revocation failed: ' . $e->getMessage());
×
134

135
            return 1;
×
136
        }
137

138
        return 0;
3✔
139
    }
140
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc