Added in a password field for login. need to add encryption sometime
This commit is contained in:
parent
ab2e91ec12
commit
d11837e449
@ -163,6 +163,18 @@
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Enter your password"
|
||||
required
|
||||
autocomplete="current-password"
|
||||
>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="login-button" id="login-button">
|
||||
Sign In
|
||||
</button>
|
||||
@ -180,6 +192,7 @@
|
||||
e.preventDefault();
|
||||
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
const button = document.getElementById('login-button');
|
||||
const errorMessage = document.getElementById('error-message');
|
||||
const successMessage = document.getElementById('success-message');
|
||||
@ -198,7 +211,7 @@
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email }),
|
||||
body: JSON.stringify({ email, password }),
|
||||
credentials: 'include'
|
||||
});
|
||||
|
||||
|
||||
@ -311,12 +311,12 @@ app.post('/api/auth/login', authLimiter, async (req, res) => {
|
||||
userAgent: req.headers['user-agent']
|
||||
});
|
||||
|
||||
const { email } = req.body;
|
||||
const { email, password } = req.body;
|
||||
|
||||
if (!email) {
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Email is required'
|
||||
error: 'Email and password are required'
|
||||
});
|
||||
}
|
||||
|
||||
@ -338,7 +338,7 @@ app.post('/api/auth/login', authLimiter, async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch authorized emails from NocoDB
|
||||
// Fetch user from NocoDB
|
||||
const url = `${process.env.NOCODB_API_URL}/db/data/v1/${process.env.NOCODB_PROJECT_ID}/${LOGIN_SHEET_ID}`;
|
||||
|
||||
logger.info(`Checking authentication for email: ${email}`);
|
||||
@ -350,23 +350,55 @@ app.post('/api/auth/login', authLimiter, async (req, res) => {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
params: {
|
||||
limit: 1000 // Adjust if you have more authorized users
|
||||
where: `(Email,eq,${email})`,
|
||||
limit: 1
|
||||
}
|
||||
});
|
||||
|
||||
const users = response.data.list || [];
|
||||
|
||||
// Check if email exists in the authorized users list
|
||||
const authorizedUser = users.find(user =>
|
||||
user.Email && user.Email.toLowerCase() === email.toLowerCase()
|
||||
);
|
||||
if (users.length === 0) {
|
||||
logger.warn(`No user found with email: ${email}`);
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid email or password'
|
||||
});
|
||||
}
|
||||
|
||||
const user = users[0];
|
||||
|
||||
// Check password (plain text comparison for now)
|
||||
if (user.Password !== password && user.password !== password) {
|
||||
logger.warn(`Invalid password for email: ${email}`);
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: 'Invalid email or password'
|
||||
});
|
||||
}
|
||||
|
||||
// Update last login time
|
||||
try {
|
||||
const updateUrl = `${process.env.NOCODB_API_URL}/db/data/v1/${process.env.NOCODB_PROJECT_ID}/${LOGIN_SHEET_ID}/${user.Id || user.id || user.ID}`;
|
||||
await axios.patch(updateUrl, {
|
||||
'Last Login': new Date().toISOString(),
|
||||
last_login: new Date().toISOString()
|
||||
}, {
|
||||
headers: {
|
||||
'xc-token': process.env.NOCODB_API_TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
} catch (updateError) {
|
||||
logger.warn('Failed to update last login time:', updateError.message);
|
||||
// Don't fail the login if we can't update last login time
|
||||
}
|
||||
|
||||
if (authorizedUser) {
|
||||
// Set session including admin status
|
||||
req.session.authenticated = true;
|
||||
req.session.userEmail = email;
|
||||
req.session.userName = authorizedUser.Name || email;
|
||||
req.session.isAdmin = authorizedUser.Admin === true || authorizedUser.Admin === 1;
|
||||
req.session.userName = user.Name || user.name || email;
|
||||
req.session.isAdmin = user.Admin === true || user.Admin === 1 || user.admin === true || user.admin === 1;
|
||||
req.session.userId = user.Id || user.id || user.ID;
|
||||
|
||||
// Force session save before sending response
|
||||
req.session.save((err) => {
|
||||
@ -390,13 +422,6 @@ app.post('/api/auth/login', authLimiter, async (req, res) => {
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
logger.warn(`Authentication failed for email: ${email}`);
|
||||
res.status(401).json({
|
||||
success: false,
|
||||
error: 'Email not authorized. Please contact an administrator.'
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Login error:', error.message);
|
||||
@ -1823,6 +1848,172 @@ app.get('/api/debug/walk-sheet-raw', requireAdmin, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Admin user management endpoints
|
||||
app.get('/api/admin/users', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
if (!LOGIN_SHEET_ID) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Login sheet not configured'
|
||||
});
|
||||
}
|
||||
|
||||
const url = `${process.env.NOCODB_API_URL}/db/data/v1/${process.env.NOCODB_PROJECT_ID}/${LOGIN_SHEET_ID}`;
|
||||
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
'xc-token': process.env.NOCODB_API_TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
params: {
|
||||
limit: 100,
|
||||
sort: '-created_at'
|
||||
}
|
||||
});
|
||||
|
||||
const users = response.data.list || [];
|
||||
|
||||
// Remove password field from response for security
|
||||
const safeUsers = users.map(user => {
|
||||
const { Password, password, ...safeUser } = user;
|
||||
return safeUser;
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
users: safeUsers
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Error fetching users:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch users'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/admin/users', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const { email, password, name, admin } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Email and password are required'
|
||||
});
|
||||
}
|
||||
|
||||
if (!LOGIN_SHEET_ID) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Login sheet not configured'
|
||||
});
|
||||
}
|
||||
|
||||
// Check if user already exists
|
||||
const checkUrl = `${process.env.NOCODB_API_URL}/db/data/v1/${process.env.NOCODB_PROJECT_ID}/${LOGIN_SHEET_ID}`;
|
||||
|
||||
const checkResponse = await axios.get(checkUrl, {
|
||||
headers: {
|
||||
'xc-token': process.env.NOCODB_API_TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
params: {
|
||||
where: `(Email,eq,${email})`,
|
||||
limit: 1
|
||||
}
|
||||
});
|
||||
|
||||
if (checkResponse.data.list && checkResponse.data.list.length > 0) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'User with this email already exists'
|
||||
});
|
||||
}
|
||||
|
||||
// Create new user
|
||||
const userData = {
|
||||
Email: email,
|
||||
email: email,
|
||||
Password: password,
|
||||
password: password,
|
||||
Name: name || '',
|
||||
name: name || '',
|
||||
Admin: admin === true,
|
||||
admin: admin === true,
|
||||
'Created At': new Date().toISOString(),
|
||||
created_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
const response = await axios.post(checkUrl, userData, {
|
||||
headers: {
|
||||
'xc-token': process.env.NOCODB_API_TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: 'User created successfully',
|
||||
user: {
|
||||
id: response.data.Id || response.data.id || response.data.ID,
|
||||
email: email,
|
||||
name: name,
|
||||
admin: admin
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Error creating user:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to create user'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/admin/users/:id', requireAdmin, async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
|
||||
if (!LOGIN_SHEET_ID) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'Login sheet not configured'
|
||||
});
|
||||
}
|
||||
|
||||
// Don't allow admins to delete themselves
|
||||
if (userId === req.session.userId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Cannot delete your own account'
|
||||
});
|
||||
}
|
||||
|
||||
const url = `${process.env.NOCODB_API_URL}/db/data/v1/${process.env.NOCODB_PROJECT_ID}/${LOGIN_SHEET_ID}/${userId}`;
|
||||
|
||||
await axios.delete(url, {
|
||||
headers: {
|
||||
'xc-token': process.env.NOCODB_API_TOKEN
|
||||
}
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'User deleted successfully'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Error deleting user:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to delete user'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Error handling middleware
|
||||
app.use((err, req, res, next) => {
|
||||
logger.error('Unhandled error:', err);
|
||||
|
||||
@ -411,6 +411,12 @@ create_login_table() {
|
||||
"uidt": "Email",
|
||||
"rqd": true
|
||||
},
|
||||
{
|
||||
"column_name": "password",
|
||||
"title": "Password",
|
||||
"uidt": "SingleLineText",
|
||||
"rqd": true
|
||||
},
|
||||
{
|
||||
"column_name": "name",
|
||||
"title": "Name",
|
||||
@ -566,6 +572,7 @@ create_default_admin() {
|
||||
|
||||
local admin_data='{
|
||||
"email": "admin@thebunkerops.ca",
|
||||
"password": "admin123",
|
||||
"name": "Administrator",
|
||||
"admin": true,
|
||||
"created_at": "'"$(date -u +"%Y-%m-%d %H:%M:%S")"'"
|
||||
@ -663,8 +670,15 @@ main() {
|
||||
print_status " - NOCODB_VIEW_URL (for locations table)"
|
||||
print_status " - NOCODB_LOGIN_SHEET (for login table)"
|
||||
print_status " - NOCODB_SETTINGS_SHEET (for settings table)"
|
||||
print_status "4. The default admin user is: admin@thebunkerops.ca"
|
||||
print_status "5. Start adding your location data!"
|
||||
print_status "4. The default admin user is: admin@thebunkerops.ca with password: admin123"
|
||||
print_status "5. IMPORTANT: Change the default password after first login!"
|
||||
print_status "6. Start adding your location data!"
|
||||
|
||||
print_warning ""
|
||||
print_warning "IMPORTANT: This script created a NEW base. Your existing data was NOT modified."
|
||||
print_warning "Please update your .env file with the new table URLs from the newly created base."
|
||||
print_warning "SECURITY: Change the default admin password immediately after first login!"
|
||||
|
||||
|
||||
print_warning ""
|
||||
print_warning "IMPORTANT: This script created a NEW base. Your existing data was NOT modified."
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user