jdesboeufs / connect-mongo

MongoDB session store for Express
MIT License
1.96k stars 342 forks source link

Session consistency #460

Closed YC closed 2 years ago

YC commented 2 years ago

When connecting to a remote cluster on MongoDB Atlas, req.session appears to be occasionally inconsistent (in previous state), but becomes correct after re-visiting route (manual refresh of page). I was also able to reproduce this with a port-forwarded non-clustered db hosted remotely (ping around 103ms).

This behavior doesn't seem to be reproducible with a local database.

const express = require('express');
const session = require('express-session');
const MongoStore = require('connect-mongo');

const app = express();

app.use(session( {
    secret: 'hi',
    saveUninitialized: false,
    resave: false,
    store: MongoStore.create({ mongoUrl: 'mongodb+srv://app:<pass>@cluster0.hr0yf.mongodb.net/?retryWrites=true&w=3' })
} ))

app.get('/', (req, res) => {
    console.log(req.session)
    if (req.session?.whatever) {
        return res.send('<h1>Logged in</h1><form action="/logout" method="POST"><input id="logout" type="submit" /></form>')
    } else {
        return res.send('<h1>Logged out</h1><form action="/login" method="POST"><input id="login" type="submit" /></form>')
    }
});

app.post('/login', (req, res) => {
    req.session.whatever = 'hi';
    return res.redirect('/');
})

app.post('/logout', (req, res) => {
    req.session.whatever = null;
    return res.redirect('/');
})

app.listen(3000);
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

BASE_URL = "http://localhost:3000"

def d(driver):
    driver.get(BASE_URL)
    driver.delete_all_cookies()

    for _ in range(100):
        WebDriverWait(driver, 5).until(
            EC.text_to_be_present_in_element((By.TAG_NAME, "h1"), "Logged out"),
        )
        elem = driver.find_element(By.CSS_SELECTOR, 'input')
        elem.click()

        WebDriverWait(driver, 5).until(
            EC.text_to_be_present_in_element((By.TAG_NAME, "h1"), "Logged in"),
        )
        elem = driver.find_element(By.CSS_SELECTOR, 'input')
        elem.click()

    driver.close()
    driver.quit()

for _ in range(5):
    driver = webdriver.Chrome()
    d(driver)

    driver = webdriver.Firefox()
    d(driver)
YC commented 2 years ago

I realised that the above code is missing req.session.save, and therefore it's likely a bug for the package which consumed express-session.

req.session.save((err) => {
    return res.redirect('/');
})