Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
66.67% covered (warning)
66.67%
10 / 15
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
Transient_Data_Store
66.67% covered (warning)
66.67%
10 / 15
50.00% covered (danger)
50.00%
2 / 4
7.33
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 save
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 get_value_for_code
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 delete_expired_codes
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Saves the expiring autologin code as a WordPress transient.
4 *
5 * @link       https://BrianHenry.ie
6 * @since      1.2.1
7 *
8 * @package    bh-wp-autologin-urls
9 */
10
11namespace BrianHenryIE\WP_Autologin_URLs\API\Data_Stores;
12
13use BrianHenryIE\WP_Autologin_URLs\API\Data_Store_Interface;
14use DateTimeInterface;
15use Psr\Log\LoggerAwareTrait;
16use Psr\Log\LoggerInterface;
17
18/**
19 * Deprecated class that uses WordPress transients for storage. Less reliable than a custom database table,
20 * but potentially useful for many use cases.
21 */
22class Transient_Data_Store implements Data_Store_Interface {
23    use LoggerAwareTrait;
24
25    /**
26     * Constructor.
27     *
28     * @param LoggerInterface $logger A PSR logger.
29     */
30    public function __construct( LoggerInterface $logger ) {
31        $this->setLogger( $logger );
32    }
33
34    public const TRANSIENT_PREFIX = 'bh_autologin_';
35
36    /**
37     * Save the hashed password and hashed value of user_id and password as a WordPress transient.
38     *
39     * @param int    $user_id The user id for the password being saved.
40     * @param string $code The unhashed password.
41     * @param int    $expires_in Number of seconds until the password should expire.
42     */
43    public function save( int $user_id, string $code, int $expires_in ): void {
44
45        // In the unlikely event there is a collision, someone won't get to log in. Oh well.
46        $transient_name = self::TRANSIENT_PREFIX . hash( 'sha256', $code );
47
48        // Concatenate $user_id and $password so the database cannot be searched by username.
49        $value = hash( 'sha256', $user_id . $code );
50
51        // This could return false if not set.
52        set_transient( $transient_name, $value, $expires_in );
53    }
54
55    /**
56     * Return the hashed value corresponding to the inputted autologin code, or null if none is found.
57     *
58     * Deletes the transient when found, so autologin codes can only be used once.
59     *
60     * @param string $code The code as supplied to the user, which has never been saved by us.
61     * @param bool   $delete Should the code be expiried immediately after use.
62     *
63     * @return string|null
64     */
65    public function get_value_for_code( string $code, bool $delete = true ): ?string {
66
67        $transient_name = self::TRANSIENT_PREFIX . hash( 'sha256', $code );
68
69        $value = get_transient( $transient_name );
70
71        if ( false === $value ) {
72            return null;
73        }
74
75        if ( $delete ) {
76            delete_transient( $transient_name );
77        }
78
79        return $value;
80    }
81
82    /**
83     * Delete codes that are no longer valid.
84     *
85     * @param DateTimeInterface $before The date from which to purge old codes.
86     *
87     * @return array{deleted_count:int|null}
88     */
89    public function delete_expired_codes( DateTimeInterface $before ): array {
90        return array(
91            'deleted_count' => null,
92            'message'       => 'Transients auto-delete',
93        );
94    }
95}