GSecrets::getRefreshToken()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\Google;
5
6
/**
7
 * Helper class for the maintenance of the oauth client data and tokens.
8
 *
9
 * > **Note:** <br/>
10
 * > This class ofers the functionality to save tokens in files on the server.
11
 * > This 'mode' was implemented for development purposes:
12
 * > - for easier read the tokens returned by the google API
13
 * > - to work on a local development environment where the development server
14
 * >   is NOT the localhost but the redirectURI  also is not accessible from
15
 * >   outside. In that case, only the login have to be made directly on the
16
 * >   machine where the webserver runs - all subsequent calls to the API uses
17
 * >   the tokens from the files created after the oauth-login has called the
18
 * >   redirectURI.
19
 * >
20
 * > **For  security issues DO NOT USE THIS MODE for public environments!!!**
21
 *
22
 * @author Stefanius <[email protected]>
23
 * @copyright MIT License - see the LICENSE file for details
24
 */
25
class GSecrets
26
{
27
    /** refreshtoken are saved in cookies   */
28
    public const TOKEN_COOKIE = 0;
29
    /** refreshtoken are saved in files on the server   */
30
    public const TOKEN_FILE = 1;
31
32
    /** Filename to save access token     */
33
    protected const ACCESS_TOKEN = 'google_access_token';
34
    /** Filename to save refresh token     */
35
    protected const REFRESH_TOKEN = 'google_refresh_token';
36
37
    /** @var int where to save the access- and refreshtoken     */
38
    protected int $iSaveTokensAt = self::TOKEN_COOKIE;
39
    /** @var int time, how long the login is valid (-> how long is the refreshToken saved)    */
40
    protected int $iKeepLoggedIn = 0;
41
    /** @var string the path, where the secrets can be found     */
42
    protected string $strSecretsPath = './secrets/';
43
    /** @var string the path, where the secrets can be found     */
44
    protected string $strSecretsFilename = 'google_secrets.json';
45
46
    /**
47
     * Create an instance of the class.
48
     * **DO NOT USE `$iSaveTokensAt = self::TOKEN_FILE` IN PUBLIC ENVIRONMENT** <br/>
49
     * In 'self::TOKEN_FILE - Mode' the `$iKeepLoggedIn` param is ignored since the tokens
50
     * saved in files that never expires unless they are deleted manually...
51
     * @param int $iKeepLoggedIn    0 (default) -> session only, -1 -> 'forever', other value -> days to keep the login
52
     * @param int $iSaveTokensAt    `self::TOKEN_COOKIE` (default) or `self::TOKEN_FILE`
53
     */
54
    public function __construct(int $iKeepLoggedIn = 0, int $iSaveTokensAt = self::TOKEN_COOKIE)
55
    {
56
        $this->iSaveTokensAt = $iSaveTokensAt;
57
        $this->iKeepLoggedIn = ($iKeepLoggedIn * 86400);
58
        if ($iKeepLoggedIn < 0) {
59
            // -1 means nearly 'forever' ... with the following value login expires in about 20 years
60
            $this->iKeepLoggedIn = 630720000;
61
        }
62
    }
63
64
    /**
65
     * Set the path where the secrets- and token files are located.
66
     * The directory must not be write-protected and should be protected
67
     * agains access from outside (.htacces: `deny from all`).
68
     * @param string $strSecretsPath
69
     */
70
    public function setSecretsPath(string $strSecretsPath) : void
71
    {
72
        $this->strSecretsPath = rtrim($strSecretsPath, '/') . '/';
73
    }
74
75
    /**
76
     * Sets the filename of the google oauth client configuration file.
77
     * @param string $strSecretsFilename
78
     */
79
    public function setSecretsFilename(string $strSecretsFilename) : void
80
    {
81
        $this->strSecretsFilename = $strSecretsFilename;
82
    }
83
84
    /**
85
     * Get full path and filename of the oauth client configuration file.
86
     * @return string
87
     */
88
    public function getClientSecrets() : string
89
    {
90
        return $this->strSecretsPath . $this->strSecretsFilename;
91
    }
92
93
    /**
94
     * Gets the last saved accesToken.
95
     * @return array<mixed>
96
     */
97
    public function getAccessToken() : array
98
    {
99
        $aToken = [];
100
        if (isset($_COOKIE[self::ACCESS_TOKEN])) {
101
            $aToken = json_decode($_COOKIE[self::ACCESS_TOKEN], true);
102
            if ($aToken === false) {
103
                $aToken = [];
104
            }
105
        }
106
        return $aToken;
107
    }
108
109
    /**
110
     * Save accessToken.
111
     * @param array<mixed> $aToken
112
     */
113
    public function saveAccessToken(array $aToken) : void
114
    {
115
        $strToken = json_encode($aToken);
116
        if ($strToken !== false) {
117
            // the access token has a limited validity anyway, we set the lifetime of this
118
            // cookie to the session
119
            $this->setCookie(self::ACCESS_TOKEN, $strToken);
120
            if ($this->iSaveTokensAt == self::TOKEN_FILE) {
121
                // since self::TOKEN_FILE only should be used in debug/local environment
122
                // we just save the accesToken to file to get easier access to its value...
123
                file_put_contents($this->strSecretsPath . self::ACCESS_TOKEN . '.json', $strToken);
124
            }
125
        }
126
    }
127
128
    /**
129
     * Gets the last saved refreshToken.
130
     * @return string
131
     */
132
    public function getRefreshToken() : string
133
    {
134
        $strRefreshToken = '';
135
        if ($this->iSaveTokensAt == self::TOKEN_COOKIE) {
136
            $strRefreshToken = $_COOKIE[self::REFRESH_TOKEN] ?? '';
137
        } else if (file_exists($this->strSecretsPath . self::REFRESH_TOKEN . '.txt')) {
138
            $strRefreshToken = file_get_contents($this->strSecretsPath . self::REFRESH_TOKEN . '.txt');
139
        }
140
        return $strRefreshToken;
141
    }
142
143
    /**
144
     * Save the refreshToken.
145
     * @param string $strRefreshToken
146
     */
147
    public function saveRefreshToken(string $strRefreshToken) : void
148
    {
149
        if ($this->iSaveTokensAt == self::TOKEN_COOKIE) {
150
            $iExpires = ($this->iKeepLoggedIn > 0) ?  time() + $this->iKeepLoggedIn : 0;
151
            $this->setCookie(self::REFRESH_TOKEN, $strRefreshToken, $iExpires);
152
        } else {
153
            file_put_contents($this->strSecretsPath . self::REFRESH_TOKEN . '.txt', $strRefreshToken);
154
        }
155
    }
156
157
    /**
158
     * Logout from the google account.
159
     * Deletes a saved access- and refreshToken.
160
     */
161
    public function logout() : void
162
    {
163
        $this->setCookie(self::ACCESS_TOKEN, '');
164
        if ($this->iSaveTokensAt == self::TOKEN_COOKIE) {
165
            $this->setCookie(self::REFRESH_TOKEN, '');
166
        } else {
167
            /** @scrutinizer ignore-unhandled */
168
            @unlink($this->strSecretsPath . self::REFRESH_TOKEN . '.txt');
169
            /** @scrutinizer ignore-unhandled */
170
            @unlink($this->strSecretsPath . self::ACCESS_TOKEN . '.json');
171
        }
172
    }
173
174
    /**
175
     * Sets the specified cookie.
176
     * @param string $strCookie
177
     * @param string $strValue
178
     * @param int $iExpires
179
     */
180
    private function setCookie(string $strCookie, string $strValue, int $iExpires = 0) : void
181
    {
182
        setcookie($strCookie, $strValue, [
183
            'expires' => $iExpires,
184
            'path' => '/',
185
            'domain' => '',
186
            'secure' => false,
187
            'httponly' => false,
188
            'samesite' => 'Lax'
189
        ]);
190
    }
191
}