first commit
This commit is contained in:
60
config/database.js
Normal file
60
config/database.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import mongoose from "mongoose";
|
||||
import { config } from "./index.js";
|
||||
|
||||
let isConnected = false;
|
||||
|
||||
export const connectDatabase = async () => {
|
||||
if (isConnected) {
|
||||
console.log("📦 Using existing database connection");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const options = {
|
||||
maxPoolSize: 10,
|
||||
serverSelectionTimeoutMS: 5000,
|
||||
socketTimeoutMS: 45000,
|
||||
};
|
||||
|
||||
await mongoose.connect(config.mongodb.uri, options);
|
||||
|
||||
isConnected = true;
|
||||
|
||||
console.log("✅ MongoDB connected successfully");
|
||||
|
||||
mongoose.connection.on("error", (err) => {
|
||||
console.error("❌ MongoDB connection error:", err);
|
||||
isConnected = false;
|
||||
});
|
||||
|
||||
mongoose.connection.on("disconnected", () => {
|
||||
console.warn("⚠️ MongoDB disconnected");
|
||||
isConnected = false;
|
||||
});
|
||||
|
||||
process.on("SIGINT", async () => {
|
||||
await mongoose.connection.close();
|
||||
console.log("🔌 MongoDB connection closed through app termination");
|
||||
process.exit(0);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("❌ Error connecting to MongoDB:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
export const disconnectDatabase = async () => {
|
||||
if (!isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await mongoose.connection.close();
|
||||
isConnected = false;
|
||||
console.log("🔌 MongoDB disconnected");
|
||||
} catch (error) {
|
||||
console.error("❌ Error disconnecting from MongoDB:", error);
|
||||
}
|
||||
};
|
||||
|
||||
export default { connectDatabase, disconnectDatabase };
|
||||
79
config/index.js
Normal file
79
config/index.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
export const config = {
|
||||
// Server
|
||||
nodeEnv: process.env.NODE_ENV || "development",
|
||||
port: parseInt(process.env.PORT, 10) || 3000,
|
||||
host: process.env.HOST || "0.0.0.0",
|
||||
|
||||
// Database
|
||||
mongodb: {
|
||||
uri: process.env.MONGODB_URI || "mongodb://localhost:27017/turbotrades",
|
||||
},
|
||||
|
||||
// Session
|
||||
session: {
|
||||
secret: process.env.SESSION_SECRET || "your-super-secret-session-key",
|
||||
cookieName: "sessionId",
|
||||
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
|
||||
},
|
||||
|
||||
// JWT
|
||||
jwt: {
|
||||
accessSecret: process.env.JWT_ACCESS_SECRET || "your-jwt-access-secret",
|
||||
refreshSecret: process.env.JWT_REFRESH_SECRET || "your-jwt-refresh-secret",
|
||||
accessExpiry: process.env.JWT_ACCESS_EXPIRY || "15m",
|
||||
refreshExpiry: process.env.JWT_REFRESH_EXPIRY || "7d",
|
||||
},
|
||||
|
||||
// Steam
|
||||
steam: {
|
||||
apiKey: process.env.STEAM_API_KEY,
|
||||
realm: process.env.STEAM_REALM || "http://localhost:3000",
|
||||
returnURL:
|
||||
process.env.STEAM_RETURN_URL || "http://localhost:3000/auth/steam/return",
|
||||
},
|
||||
|
||||
// Cookies
|
||||
cookie: {
|
||||
domain: process.env.COOKIE_DOMAIN || "localhost",
|
||||
secure: process.env.COOKIE_SECURE === "true",
|
||||
sameSite: process.env.COOKIE_SAME_SITE || "lax",
|
||||
httpOnly: true,
|
||||
},
|
||||
|
||||
// CORS
|
||||
cors: {
|
||||
origin: process.env.CORS_ORIGIN || "http://localhost:5173",
|
||||
credentials: true,
|
||||
},
|
||||
|
||||
// Rate Limiting
|
||||
rateLimit: {
|
||||
max: parseInt(process.env.RATE_LIMIT_MAX, 10) || 100,
|
||||
timeWindow: parseInt(process.env.RATE_LIMIT_TIMEWINDOW, 10) || 60000,
|
||||
},
|
||||
|
||||
// Email (for future implementation)
|
||||
email: {
|
||||
host: process.env.SMTP_HOST,
|
||||
port: parseInt(process.env.SMTP_PORT, 10) || 587,
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS,
|
||||
from: process.env.EMAIL_FROM || "noreply@turbotrades.com",
|
||||
},
|
||||
|
||||
// WebSocket
|
||||
websocket: {
|
||||
pingInterval: parseInt(process.env.WS_PING_INTERVAL, 10) || 30000,
|
||||
maxPayload: parseInt(process.env.WS_MAX_PAYLOAD, 10) || 1048576,
|
||||
},
|
||||
|
||||
// Security
|
||||
isDevelopment: process.env.NODE_ENV !== "production",
|
||||
isProduction: process.env.NODE_ENV === "production",
|
||||
};
|
||||
|
||||
export default config;
|
||||
136
config/passport.js
Normal file
136
config/passport.js
Normal file
@@ -0,0 +1,136 @@
|
||||
import passport from "passport";
|
||||
import SteamStrategy from "passport-steam";
|
||||
import { config } from "./index.js";
|
||||
import User from "../models/User.js";
|
||||
|
||||
// Configure HTTP agent with timeout for Steam OpenID
|
||||
import https from "https";
|
||||
import http from "http";
|
||||
|
||||
const httpAgent = new http.Agent({
|
||||
timeout: 10000, // 10 second timeout
|
||||
keepAlive: true,
|
||||
});
|
||||
|
||||
const httpsAgent = new https.Agent({
|
||||
timeout: 10000, // 10 second timeout
|
||||
keepAlive: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* Configure Passport with Steam Strategy
|
||||
*/
|
||||
export const configurePassport = () => {
|
||||
// Serialize user to session
|
||||
passport.serializeUser((user, done) => {
|
||||
done(null, user._id.toString());
|
||||
});
|
||||
|
||||
// Deserialize user from session
|
||||
passport.deserializeUser(async (id, done) => {
|
||||
try {
|
||||
const user = await User.findById(id);
|
||||
done(null, user);
|
||||
} catch (error) {
|
||||
done(error, null);
|
||||
}
|
||||
});
|
||||
|
||||
console.log("🔧 Configuring Steam Strategy...");
|
||||
console.log("Steam Realm:", config.steam.realm);
|
||||
console.log("Steam Return URL:", config.steam.returnURL);
|
||||
console.log(
|
||||
"Steam API Key:",
|
||||
config.steam.apiKey
|
||||
? "Set (length: " + config.steam.apiKey.length + ")"
|
||||
: "Not Set"
|
||||
);
|
||||
|
||||
// Configure Steam Strategy with options
|
||||
try {
|
||||
passport.use(
|
||||
new SteamStrategy(
|
||||
{
|
||||
returnURL: config.steam.returnURL,
|
||||
realm: config.steam.realm,
|
||||
apiKey: config.steam.apiKey,
|
||||
// Add HTTP agents for timeout control
|
||||
agent: httpAgent,
|
||||
profile: true,
|
||||
},
|
||||
async (identifier, profile, done) => {
|
||||
try {
|
||||
const steamId = profile.id;
|
||||
|
||||
// Find or create user
|
||||
let user = await User.findOne({ steamId });
|
||||
|
||||
if (user) {
|
||||
// Update existing user profile
|
||||
user.username = profile.displayName;
|
||||
user.avatar =
|
||||
profile.photos?.[2]?.value ||
|
||||
profile.photos?.[0]?.value ||
|
||||
null;
|
||||
user.communityvisibilitystate =
|
||||
profile._json?.communityvisibilitystate || 1;
|
||||
|
||||
await user.save();
|
||||
|
||||
console.log(
|
||||
`✅ Existing user logged in: ${user.username} (${steamId})`
|
||||
);
|
||||
} else {
|
||||
// Create new user
|
||||
user = new User({
|
||||
username: profile.displayName,
|
||||
steamId: steamId,
|
||||
avatar:
|
||||
profile.photos?.[2]?.value ||
|
||||
profile.photos?.[0]?.value ||
|
||||
null,
|
||||
account_creation:
|
||||
profile._json?.timecreated || Math.floor(Date.now() / 1000),
|
||||
communityvisibilitystate:
|
||||
profile._json?.communityvisibilitystate || 1,
|
||||
balance: 0,
|
||||
staffLevel: 0,
|
||||
});
|
||||
|
||||
await user.save();
|
||||
|
||||
console.log(
|
||||
`✅ New user registered: ${user.username} (${steamId})`
|
||||
);
|
||||
}
|
||||
|
||||
return done(null, user);
|
||||
} catch (error) {
|
||||
console.error("❌ Steam authentication error:", error);
|
||||
return done(error, null);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
console.log("✅ Steam Strategy registered successfully");
|
||||
} catch (error) {
|
||||
console.error("❌ Failed to configure Steam Strategy:", error.message);
|
||||
console.error("This may be due to network issues or invalid configuration");
|
||||
}
|
||||
|
||||
console.log("🔐 Passport configured with Steam strategy");
|
||||
console.log(`📍 Steam Realm: ${config.steam.realm}`);
|
||||
console.log(`🔙 Return URL: ${config.steam.returnURL}`);
|
||||
console.log(`🔑 API Key: ${config.steam.apiKey ? "✅ Set" : "❌ Not Set"}`);
|
||||
|
||||
// Important note about Steam OpenID
|
||||
console.log("\n💡 Note: Steam OpenID discovery can sometimes fail due to:");
|
||||
console.log(" - Network/firewall blocking Steam's OpenID endpoint");
|
||||
console.log(" - Steam's service being temporarily unavailable");
|
||||
console.log(" - DNS resolution issues");
|
||||
console.log(
|
||||
" If /auth/steam fails, try: curl -v https://steamcommunity.com/openid"
|
||||
);
|
||||
};
|
||||
|
||||
export default configurePassport;
|
||||
Reference in New Issue
Block a user