Fossil SCM
Re-added SameSite=strict cookie flag and update user.cexpire even for session cookies, otherwise non-anonymous session-only logins do not "stick" past the login process.
Commit
5c84a729077d9e01cd5bb548a775ad025657fd00bb5589d48b579cf3b248d66d
Parent
80025e706d03ad6…
2 files changed
+3
-2
+16
-14
+3
-2
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -255,15 +255,16 @@ | ||
| 255 | 255 | zSecure = " secure;"; |
| 256 | 256 | } |
| 257 | 257 | if( lifetime!=0 ){ |
| 258 | 258 | blob_appendf(&extraHeader, |
| 259 | 259 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| 260 | - "%s Version=1\r\n", | |
| 260 | + "SameSite=strict; %s Version=1\r\n", | |
| 261 | 261 | zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure); |
| 262 | 262 | }else{ |
| 263 | 263 | blob_appendf(&extraHeader, |
| 264 | - "Set-Cookie: %s=%t; Path=%s; HttpOnly; %s Version=1\r\n", | |
| 264 | + "Set-Cookie: %s=%t; Path=%s; HttpOnly; SameSite=strict; " | |
| 265 | + "%s Version=1\r\n", | |
| 265 | 266 | zName, zValue, zPath, zSecure); |
| 266 | 267 | } |
| 267 | 268 | } |
| 268 | 269 | |
| 269 | 270 | |
| 270 | 271 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -255,15 +255,16 @@ | |
| 255 | zSecure = " secure;"; |
| 256 | } |
| 257 | if( lifetime!=0 ){ |
| 258 | blob_appendf(&extraHeader, |
| 259 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| 260 | "%s Version=1\r\n", |
| 261 | zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure); |
| 262 | }else{ |
| 263 | blob_appendf(&extraHeader, |
| 264 | "Set-Cookie: %s=%t; Path=%s; HttpOnly; %s Version=1\r\n", |
| 265 | zName, zValue, zPath, zSecure); |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | |
| 270 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -255,15 +255,16 @@ | |
| 255 | zSecure = " secure;"; |
| 256 | } |
| 257 | if( lifetime!=0 ){ |
| 258 | blob_appendf(&extraHeader, |
| 259 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| 260 | "SameSite=strict; %s Version=1\r\n", |
| 261 | zName, lifetime>0 ? zValue : "null", zPath, lifetime, zSecure); |
| 262 | }else{ |
| 263 | blob_appendf(&extraHeader, |
| 264 | "Set-Cookie: %s=%t; Path=%s; HttpOnly; SameSite=strict; " |
| 265 | "%s Version=1\r\n", |
| 266 | zName, zValue, zPath, zSecure); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | |
| 271 |
+16
-14
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -273,34 +273,35 @@ | ||
| 273 | 273 | int uid, /* User's ID */ |
| 274 | 274 | char **zDest, /* Optional: store generated cookie value. */ |
| 275 | 275 | int bSessionCookie /* True for session-only cookie */ |
| 276 | 276 | ){ |
| 277 | 277 | const char *zCookieName = login_cookie_name(); |
| 278 | - const char *zExpire = bSessionCookie ? 0 : db_get("cookie-expire","8766"); | |
| 279 | - int expires = bSessionCookie ? 0 : atoi(zExpire)*3600; | |
| 278 | + const char *zExpire = db_get("cookie-expire","8766"); | |
| 279 | + const int expires = atoi(zExpire)*3600 | |
| 280 | + /* the expiry time for session cookies is a bit of a hack. If we | |
| 281 | + don't update user.cexpire for session-only cookies then | |
| 282 | + session-only logins for non-anonymous users do not survive past | |
| 283 | + the login step. */; | |
| 280 | 284 | char *zHash = 0; |
| 281 | 285 | char *zCookie; |
| 282 | 286 | const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */ |
| 283 | 287 | |
| 284 | 288 | assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data."); |
| 285 | - if(bSessionCookie==0){ | |
| 286 | - zHash = db_text(0, | |
| 289 | + zHash = db_text(0, | |
| 287 | 290 | "SELECT cookie FROM user" |
| 288 | 291 | " WHERE uid=%d" |
| 289 | 292 | " AND cexpire>julianday('now')" |
| 290 | 293 | " AND length(cookie)>30", |
| 291 | 294 | uid); |
| 292 | - } | |
| 293 | 295 | if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); |
| 294 | 296 | zCookie = login_gen_user_cookie_value(zUsername, zHash); |
| 295 | - cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires); | |
| 297 | + cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), | |
| 298 | + bSessionCookie ? 0 : expires); | |
| 296 | 299 | record_login_attempt(zUsername, zIpAddr, 1); |
| 297 | - if(bSessionCookie==0){ | |
| 298 | - db_multi_exec("UPDATE user SET cookie=%Q," | |
| 299 | - " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", | |
| 300 | - zHash, expires, uid); | |
| 301 | - } | |
| 300 | + db_multi_exec("UPDATE user SET cookie=%Q," | |
| 301 | + " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", | |
| 302 | + zHash, expires, uid); | |
| 302 | 303 | fossil_free(zHash); |
| 303 | 304 | if( zDest ){ |
| 304 | 305 | *zDest = zCookie; |
| 305 | 306 | }else{ |
| 306 | 307 | free(zCookie); |
| @@ -726,13 +727,14 @@ | ||
| 726 | 727 | } |
| 727 | 728 | @ <tr> |
| 728 | 729 | @ <td></td> |
| 729 | 730 | @ <td><input type="submit" name="in" value="Login"> |
| 730 | 731 | @ <input type="checkbox" name="remember" value="1" \ |
| 731 | - @ %s(rememberMe ? "checked=\"checked\"" : "")>Remember me? | |
| 732 | - @ (If checked, login will use a persistent cookie, else it | |
| 733 | - @ will use a session cookie.)</td> | |
| 732 | + @ id="remember-me" %s(rememberMe ? "checked=\"checked\"" : "")> | |
| 733 | + @ <label for="remember-me">Remember me?</label> | |
| 734 | + @ (If checked, login will use a persistent cookie, else it | |
| 735 | + @ will use a session cookie.)</td> | |
| 734 | 736 | @ </tr> |
| 735 | 737 | if( !noAnon && login_self_register_available(0) ){ |
| 736 | 738 | @ <tr> |
| 737 | 739 | @ <td></td> |
| 738 | 740 | @ <td><input type="submit" name="self" value="Create A New Account"> |
| 739 | 741 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -273,34 +273,35 @@ | |
| 273 | int uid, /* User's ID */ |
| 274 | char **zDest, /* Optional: store generated cookie value. */ |
| 275 | int bSessionCookie /* True for session-only cookie */ |
| 276 | ){ |
| 277 | const char *zCookieName = login_cookie_name(); |
| 278 | const char *zExpire = bSessionCookie ? 0 : db_get("cookie-expire","8766"); |
| 279 | int expires = bSessionCookie ? 0 : atoi(zExpire)*3600; |
| 280 | char *zHash = 0; |
| 281 | char *zCookie; |
| 282 | const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */ |
| 283 | |
| 284 | assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data."); |
| 285 | if(bSessionCookie==0){ |
| 286 | zHash = db_text(0, |
| 287 | "SELECT cookie FROM user" |
| 288 | " WHERE uid=%d" |
| 289 | " AND cexpire>julianday('now')" |
| 290 | " AND length(cookie)>30", |
| 291 | uid); |
| 292 | } |
| 293 | if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); |
| 294 | zCookie = login_gen_user_cookie_value(zUsername, zHash); |
| 295 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires); |
| 296 | record_login_attempt(zUsername, zIpAddr, 1); |
| 297 | if(bSessionCookie==0){ |
| 298 | db_multi_exec("UPDATE user SET cookie=%Q," |
| 299 | " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", |
| 300 | zHash, expires, uid); |
| 301 | } |
| 302 | fossil_free(zHash); |
| 303 | if( zDest ){ |
| 304 | *zDest = zCookie; |
| 305 | }else{ |
| 306 | free(zCookie); |
| @@ -726,13 +727,14 @@ | |
| 726 | } |
| 727 | @ <tr> |
| 728 | @ <td></td> |
| 729 | @ <td><input type="submit" name="in" value="Login"> |
| 730 | @ <input type="checkbox" name="remember" value="1" \ |
| 731 | @ %s(rememberMe ? "checked=\"checked\"" : "")>Remember me? |
| 732 | @ (If checked, login will use a persistent cookie, else it |
| 733 | @ will use a session cookie.)</td> |
| 734 | @ </tr> |
| 735 | if( !noAnon && login_self_register_available(0) ){ |
| 736 | @ <tr> |
| 737 | @ <td></td> |
| 738 | @ <td><input type="submit" name="self" value="Create A New Account"> |
| 739 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -273,34 +273,35 @@ | |
| 273 | int uid, /* User's ID */ |
| 274 | char **zDest, /* Optional: store generated cookie value. */ |
| 275 | int bSessionCookie /* True for session-only cookie */ |
| 276 | ){ |
| 277 | const char *zCookieName = login_cookie_name(); |
| 278 | const char *zExpire = db_get("cookie-expire","8766"); |
| 279 | const int expires = atoi(zExpire)*3600 |
| 280 | /* the expiry time for session cookies is a bit of a hack. If we |
| 281 | don't update user.cexpire for session-only cookies then |
| 282 | session-only logins for non-anonymous users do not survive past |
| 283 | the login step. */; |
| 284 | char *zHash = 0; |
| 285 | char *zCookie; |
| 286 | const char *zIpAddr = PD("REMOTE_ADDR","nil"); /* IP address of user */ |
| 287 | |
| 288 | assert((zUsername && *zUsername) && (uid > 0) && "Invalid user data."); |
| 289 | zHash = db_text(0, |
| 290 | "SELECT cookie FROM user" |
| 291 | " WHERE uid=%d" |
| 292 | " AND cexpire>julianday('now')" |
| 293 | " AND length(cookie)>30", |
| 294 | uid); |
| 295 | if( zHash==0 ) zHash = db_text(0, "SELECT hex(randomblob(25))"); |
| 296 | zCookie = login_gen_user_cookie_value(zUsername, zHash); |
| 297 | cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), |
| 298 | bSessionCookie ? 0 : expires); |
| 299 | record_login_attempt(zUsername, zIpAddr, 1); |
| 300 | db_multi_exec("UPDATE user SET cookie=%Q," |
| 301 | " cexpire=julianday('now')+%d/86400.0 WHERE uid=%d", |
| 302 | zHash, expires, uid); |
| 303 | fossil_free(zHash); |
| 304 | if( zDest ){ |
| 305 | *zDest = zCookie; |
| 306 | }else{ |
| 307 | free(zCookie); |
| @@ -726,13 +727,14 @@ | |
| 727 | } |
| 728 | @ <tr> |
| 729 | @ <td></td> |
| 730 | @ <td><input type="submit" name="in" value="Login"> |
| 731 | @ <input type="checkbox" name="remember" value="1" \ |
| 732 | @ id="remember-me" %s(rememberMe ? "checked=\"checked\"" : "")> |
| 733 | @ <label for="remember-me">Remember me?</label> |
| 734 | @ (If checked, login will use a persistent cookie, else it |
| 735 | @ will use a session cookie.)</td> |
| 736 | @ </tr> |
| 737 | if( !noAnon && login_self_register_available(0) ){ |
| 738 | @ <tr> |
| 739 | @ <td></td> |
| 740 | @ <td><input type="submit" name="self" value="Create A New Account"> |
| 741 |