Remove all "FileHasObject" edge reads and writes
[phabricator.git] / src / applications / auth / constants / PhabricatorCookies.php
blob2573bf3ec68664a169724fe5f21821319dd8d5f9
1 <?php
3 /**
4 * Consolidates Phabricator application cookies, including registration
5 * and session management.
7 * @task clientid Client ID Cookie
8 * @task next Next URI Cookie
9 */
10 final class PhabricatorCookies extends Phobject {
12 /**
13 * Stores the login username for password authentication. This is just a
14 * display value for convenience, used to prefill the login form. It is not
15 * authoritative.
17 const COOKIE_USERNAME = 'phusr';
20 /**
21 * Stores the user's current session ID. This is authoritative and establishes
22 * the user's identity.
24 const COOKIE_SESSION = 'phsid';
27 /**
28 * Stores a secret used during new account registration to prevent an attacker
29 * from tricking a victim into registering an account which is linked to
30 * credentials the attacker controls.
32 const COOKIE_REGISTRATION = 'phreg';
35 /**
36 * Stores a secret used during OAuth2 handshakes to prevent various attacks
37 * where an attacker hands a victim a URI corresponding to the middle of an
38 * OAuth2 workflow and we might otherwise do something sketchy. Particularly,
39 * this corresponds to the OAuth2 "code".
41 const COOKIE_CLIENTID = 'phcid';
44 /**
45 * Stores the URI to redirect the user to after login. This allows users to
46 * visit a path like `/feed/`, be prompted to login, and then be redirected
47 * back to `/feed/` after the workflow completes.
49 const COOKIE_NEXTURI = 'next_uri';
52 /**
53 * Stores a hint that the user should be moved directly into high security
54 * after upgrading a partial login session. This is used during password
55 * recovery to avoid a double-prompt.
57 const COOKIE_HISEC = 'jump_to_hisec';
60 /**
61 * Stores an invite code.
63 const COOKIE_INVITE = 'invite';
66 /**
67 * Stores a workflow completion across a redirect-after-POST following a
68 * form submission. This can be used to show "Changes Saved" messages.
70 const COOKIE_SUBMIT = 'phfrm';
73 /* -( Client ID Cookie )--------------------------------------------------- */
76 /**
77 * Set the client ID cookie. This is a random cookie used like a CSRF value
78 * during authentication workflows.
80 * @param AphrontRequest Request to modify.
81 * @return void
82 * @task clientid
84 public static function setClientIDCookie(AphrontRequest $request) {
86 // NOTE: See T3471 for some discussion. Some browsers and browser extensions
87 // can make duplicate requests, so we overwrite this cookie only if it is
88 // not present in the request. The cookie lifetime is limited by making it
89 // temporary and clearing it when users log out.
91 $value = $request->getCookie(self::COOKIE_CLIENTID);
92 if (!strlen($value)) {
93 $request->setTemporaryCookie(
94 self::COOKIE_CLIENTID,
95 Filesystem::readRandomCharacters(16));
100 /* -( Next URI Cookie )---------------------------------------------------- */
104 * Set the Next URI cookie. We only write the cookie if it wasn't recently
105 * written, to avoid writing over a real URI with a bunch of "humans.txt"
106 * stuff. See T3793 for discussion.
108 * @param AphrontRequest Request to write to.
109 * @param string URI to write.
110 * @param bool Write this cookie even if we have a fresh
111 * cookie already.
112 * @return void
114 * @task next
116 public static function setNextURICookie(
117 AphrontRequest $request,
118 $next_uri,
119 $force = false) {
121 if (!$force) {
122 $cookie_value = $request->getCookie(self::COOKIE_NEXTURI);
123 list($set_at, $current_uri) = self::parseNextURICookie($cookie_value);
125 // If the cookie was set within the last 2 minutes, don't overwrite it.
126 // Primarily, this prevents browser requests for resources which do not
127 // exist (like "humans.txt" and various icons) from overwriting a normal
128 // URI like "/feed/".
129 if ($set_at > (time() - 120)) {
130 return;
134 $new_value = time().','.$next_uri;
135 $request->setTemporaryCookie(self::COOKIE_NEXTURI, $new_value);
140 * Read the URI out of the Next URI cookie.
142 * @param AphrontRequest Request to examine.
143 * @return string|null Next URI cookie's URI value.
145 * @task next
147 public static function getNextURICookie(AphrontRequest $request) {
148 $cookie_value = $request->getCookie(self::COOKIE_NEXTURI);
149 list($set_at, $next_uri) = self::parseNextURICookie($cookie_value);
151 return $next_uri;
156 * Parse a Next URI cookie into its components.
158 * @param string Raw cookie value.
159 * @return list<string> List of timestamp and URI.
161 * @task next
163 private static function parseNextURICookie($cookie) {
164 // Old cookies look like: /uri
165 // New cookies look like: timestamp,/uri
167 if (!strlen($cookie)) {
168 return null;
171 if (strpos($cookie, ',') !== false) {
172 list($timestamp, $uri) = explode(',', $cookie, 2);
173 return array((int)$timestamp, $uri);
176 return array(0, $cookie);