Added demo access
This commit is contained in:
+65
-1
@@ -100,6 +100,9 @@ const databaseUrl =
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000';
|
||||
const apiBaseUrl = process.env.API_BASE_URL || 'http://localhost:5000/api';
|
||||
const allowRegistration = (process.env.ALLOW_REGISTRATION ?? 'true').toLowerCase() !== 'false';
|
||||
const allowDemoAccount = (process.env.ALLOW_DEMO_ACCOUNT ?? 'false').toLowerCase() === 'true';
|
||||
const demoAccountPassword = process.env.DEMO_ACCOUNT_PASSWORD ?? 'demo1234';
|
||||
const demoAccountName = process.env.DEMO_ACCOUNT_NAME ?? 'Demo User';
|
||||
const { Pool } = pg;
|
||||
const pool = new Pool({ connectionString: databaseUrl });
|
||||
|
||||
@@ -152,6 +155,7 @@ const getNumber = (value: unknown, fieldName: string): number => {
|
||||
};
|
||||
|
||||
const normalizeEmail = (email: string) => email.trim().toLowerCase();
|
||||
const demoAccountEmail = normalizeEmail(process.env.DEMO_ACCOUNT_EMAIL ?? 'demo@arsenaliq.local');
|
||||
const hashToken = (token: string) => crypto.createHash('sha256').update(token).digest('hex');
|
||||
const createSessionToken = () => crypto.randomBytes(32).toString('hex');
|
||||
const isUuid = (value: string) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
||||
@@ -414,6 +418,35 @@ const ensureDefaultProfile = async (userId: string, userName: string) => {
|
||||
return created.rows[0];
|
||||
};
|
||||
|
||||
const ensureDemoAccount = async () => {
|
||||
if (!allowDemoAccount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const passwordHash = await bcrypt.hash(demoAccountPassword, 10);
|
||||
const existing = await pool.query<UserRow>('SELECT id, email, name FROM users WHERE email = $1', [demoAccountEmail]);
|
||||
|
||||
let user: UserRow;
|
||||
|
||||
if ((existing.rowCount ?? 0) > 0) {
|
||||
user = existing.rows[0];
|
||||
await pool.query('UPDATE users SET name = $2, password_hash = $3 WHERE id = $1', [
|
||||
user.id,
|
||||
demoAccountName,
|
||||
passwordHash,
|
||||
]);
|
||||
} else {
|
||||
const created = await pool.query<UserRow>(
|
||||
'INSERT INTO users (email, password_hash, name) VALUES ($1, $2, $3) RETURNING id, email, name',
|
||||
[demoAccountEmail, passwordHash, demoAccountName],
|
||||
);
|
||||
user = created.rows[0];
|
||||
}
|
||||
|
||||
const profile = await ensureDefaultProfile(user.id, demoAccountName);
|
||||
return { user, profile };
|
||||
};
|
||||
|
||||
const createSession = async (userId: string, activeProfileId: string) => {
|
||||
const token = createSessionToken();
|
||||
const tokenHash = hashToken(token);
|
||||
@@ -628,6 +661,7 @@ app.get('/api', (_req, res) => {
|
||||
name: 'Arsenal IQ API',
|
||||
version: '3.0.0',
|
||||
allowRegistration,
|
||||
allowDemoAccount,
|
||||
resources: [
|
||||
'/api/auth/login',
|
||||
'/api/auth/register',
|
||||
@@ -639,6 +673,35 @@ app.get('/api', (_req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/api/auth/demo', async (_req, res, next) => {
|
||||
try {
|
||||
if (!allowDemoAccount) {
|
||||
res.status(403).json({ error: 'Demo account is disabled' });
|
||||
return;
|
||||
}
|
||||
|
||||
const demoAccount = await ensureDemoAccount();
|
||||
|
||||
if (!demoAccount) {
|
||||
res.status(500).json({ error: 'Demo account is unavailable' });
|
||||
return;
|
||||
}
|
||||
|
||||
const { user, profile } = demoAccount;
|
||||
const { token, session } = await createSession(user.id, profile.id);
|
||||
const profiles = await getUserProfiles(user.id);
|
||||
|
||||
res.json({
|
||||
token,
|
||||
user,
|
||||
profiles,
|
||||
activeProfileId: session.active_profile_id,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/auth/providers', async (_req, res, next) => {
|
||||
try {
|
||||
const result = await pool.query<ProviderConfigRow>(
|
||||
@@ -1268,7 +1331,8 @@ app.use((error: Error, _req: express.Request, res: express.Response, _next: expr
|
||||
});
|
||||
|
||||
void ensureSchema()
|
||||
.then(() => {
|
||||
.then(async () => {
|
||||
await ensureDemoAccount();
|
||||
app.listen(port, () => {
|
||||
console.log(`Arsenal IQ API listening on http://localhost:${port}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user