use https

This commit is contained in:
Will Bradley 2025-07-16 19:01:15 -07:00
parent ea3bfc8b8f
commit e432d43376
2 changed files with 92 additions and 50 deletions

View File

@ -14,3 +14,4 @@ DATABASE_URL=./water_stations.db
# Server configuration # Server configuration
PORT=3000 PORT=3000
FORCE_HTTPS=false

View File

@ -15,6 +15,7 @@ require('dotenv').config();
const app = express(); const app = express();
const HOST = process.env.HOST || "0.0.0.0"; const HOST = process.env.HOST || "0.0.0.0";
const PORT = process.env.PORT || 3000; const PORT = process.env.PORT || 3000;
const FORCE_HTTPS = process.env.FORCE_HTTPS === 'true';
// Database setup // Database setup
const db = new sqlite3.Database('./water_stations.db'); const db = new sqlite3.Database('./water_stations.db');
@ -91,6 +92,17 @@ app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public'))); app.use(express.static(path.join(__dirname, 'public')));
// HTTPS enforcement middleware
if (FORCE_HTTPS) {
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});
}
app.use(session({ app.use(session({
store: new SQLiteStore({ store: new SQLiteStore({
db: 'water_stations.db', db: 'water_stations.db',
@ -100,7 +112,7 @@ app.use(session({
resave: false, resave: false,
saveUninitialized: false, saveUninitialized: false,
cookie: { cookie: {
secure: false, // Set to true in production with HTTPS secure: FORCE_HTTPS, // Use secure cookies when HTTPS is forced
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
} }
})); }));
@ -108,6 +120,13 @@ app.use(session({
app.use(passport.initialize()); app.use(passport.initialize());
app.use(passport.session()); app.use(passport.session());
// Helper function to get base URL
function getBaseUrl(req) {
const protocol = FORCE_HTTPS || req.secure || req.header('x-forwarded-proto') === 'https' ? 'https' : 'http';
const host = req.header('host');
return `${protocol}://${host}`;
}
// Passport configuration // Passport configuration
passport.use(new LocalStrategy( passport.use(new LocalStrategy(
{ usernameField: 'username' }, { usernameField: 'username' },
@ -124,10 +143,17 @@ passport.use(new LocalStrategy(
} }
)); ));
// Initialize OAuth strategies with dynamic callback URLs
function initializeOAuthStrategies(baseUrl = '') {
// Clear existing strategies
passport.unuse('google');
passport.unuse('instagram');
// Google OAuth Strategy
passport.use(new GoogleStrategy({ passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID, clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET, clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback" callbackURL: `${baseUrl}/auth/google/callback`
}, (accessToken, refreshToken, profile, done) => { }, (accessToken, refreshToken, profile, done) => {
db.get('SELECT * FROM users WHERE google_id = ?', [profile.id], (err, user) => { db.get('SELECT * FROM users WHERE google_id = ?', [profile.id], (err, user) => {
if (err) return done(err); if (err) return done(err);
@ -149,10 +175,11 @@ passport.use(new GoogleStrategy({
}); });
})); }));
// Instagram OAuth Strategy
passport.use(new InstagramStrategy({ passport.use(new InstagramStrategy({
clientID: process.env.INSTAGRAM_CLIENT_ID, clientID: process.env.INSTAGRAM_CLIENT_ID,
clientSecret: process.env.INSTAGRAM_CLIENT_SECRET, clientSecret: process.env.INSTAGRAM_CLIENT_SECRET,
callbackURL: "/auth/instagram/callback" callbackURL: `${baseUrl}/auth/instagram/callback`
}, (accessToken, refreshToken, profile, done) => { }, (accessToken, refreshToken, profile, done) => {
db.get('SELECT * FROM users WHERE instagram_id = ?', [profile.id], (err, user) => { db.get('SELECT * FROM users WHERE instagram_id = ?', [profile.id], (err, user) => {
if (err) return done(err); if (err) return done(err);
@ -173,6 +200,10 @@ passport.use(new InstagramStrategy({
} }
}); });
})); }));
}
// Initialize OAuth strategies with empty base URL (will be updated per request)
initializeOAuthStrategies();
passport.serializeUser((user, done) => { passport.serializeUser((user, done) => {
done(null, user.id); done(null, user.id);
@ -198,6 +229,11 @@ app.get('/auth/google', (req, res, next) => {
if (req.query.redirect) { if (req.query.redirect) {
req.session.redirectUrl = req.query.redirect; req.session.redirectUrl = req.query.redirect;
} }
// Reinitialize strategies with current request's base URL
const baseUrl = getBaseUrl(req);
initializeOAuthStrategies(baseUrl);
passport.authenticate('google', { scope: ['profile', 'email'] })(req, res, next); passport.authenticate('google', { scope: ['profile', 'email'] })(req, res, next);
}); });
@ -214,6 +250,11 @@ app.get('/auth/instagram', (req, res, next) => {
if (req.query.redirect) { if (req.query.redirect) {
req.session.redirectUrl = req.query.redirect; req.session.redirectUrl = req.query.redirect;
} }
// Reinitialize strategies with current request's base URL
const baseUrl = getBaseUrl(req);
initializeOAuthStrategies(baseUrl);
passport.authenticate('instagram')(req, res, next); passport.authenticate('instagram')(req, res, next);
}); });