Skip to content

Commit

Permalink
Merge pull request Open-Cap-Stack#83 from anushac14/main
Browse files Browse the repository at this point in the history
Add new user authentication feature
  • Loading branch information
urbantech authored Aug 23, 2024
2 parents 617c386 + 34c9720 commit 4221e93
Show file tree
Hide file tree
Showing 8 changed files with 959 additions and 25 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ jobs:
node-version: '14'

- name: Install dependencies
run: npm i
run: npm install [email protected]

- name: Install dependencies
run: npm install

- name: Install dev dependencies
run: npm install --save-dev jest chai supertest mongoose sinon dotenv chai-http
Expand All @@ -50,4 +53,4 @@ jobs:
run: docker pull mongo:latest

- name: Print Docker logs
run: docker logs $(docker ps -q --filter "ancestor=mongo:latest")
run: docker logs $(docker ps -q --filter "ancestor=mongo:latest")
4 changes: 3 additions & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ const investmentRoutes = require('./routes/investmentTrackerRoutes');
const adminRoutes = require('./routes/adminRoutes');
const documentAccessRoutes = require('./routes/documentAccessRoutes');
const investorRoutes = require('./routes/investorRoutes');
const companyRoutes = require('./routes/Company'); // Correctly link to the Company routes
const companyRoutes = require('./routes/Company');
const taxCalculatorRoutes = require('./routes/TaxCalculator');
const authRoutes = require('./routes/authRoutes');

const app = express();
app.use(express.json());
Expand All @@ -37,5 +38,6 @@ app.use('/api/documentAccesses', documentAccessRoutes);
app.use('/api/investors', investorRoutes);
app.use('/api/taxCalculations', taxCalculatorRoutes);
app.use('/api/companies', companyRoutes);
app.use('/auth', authRoutes);

module.exports = app;
114 changes: 114 additions & 0 deletions controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
const User = require('../models/userModel');
const bcrypt = require('bcrypt');
const mongoose = require('mongoose');
const jwt = require('jsonwebtoken');

const { OAuth2Client } = require('google-auth-library'); // For Google OAuth (example)

const googleClient = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);

// Register a new user with username and password
exports.registerUser = async (req, res) => {
const { username, email, password, roles } = req.body;
try {
// Check if email or username already exists
const existingUser = await User.findOne({ $or: [{ username }, { email }] });
if (existingUser) {
return res.status(400).json({ message: 'User already exists' });
}

const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({
userId: new mongoose.Types.ObjectId().toString(),
username,
email,
password: hashedPassword, // Assign hashedPassword here
UserRoles: roles,
Permissions: 'Standard', // You can customize this
AuthenticationMethods: 'UsernamePassword',
});

await user.save();
res.status(201).json({ message: 'User registered successfully' });
} catch (error) {
console.error('Error during user registration:', error.message);
res.status(500).json({ message: 'Internal server error' });
}
};


// User login with username and password
exports.loginUser = async (req, res) => {
const { username, password } = req.body;
try {
// Log the incoming request for debugging
console.log('Login attempt:', { username, passwordProvided: !!password });

// Check if the user exists
const user = await User.findOne({ username });
if (!user) {
console.log('User not found');
return res.status(404).json({ message: 'User not found' });
}

// Check if the password field is provided and the user has a password
if (!password || !user.password) {
console.log('Password not provided or user has no password');
return res.status(400).json({ message: 'Password is required' });
}

// Compare the provided password with the stored hashed password
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
console.log('Invalid credentials');
return res.status(400).json({ message: 'Invalid credentials' });
}

// Generate a JWT token
const token = jwt.sign(
{ userId: user.userId, roles: user.UserRoles },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
); // Add the semicolon here

// Log successful login
console.log('Login successful:', { userId: user.userId, roles: user.UserRoles });

// Send the token as the response
res.json({ token });
} catch (error) {
console.error('Error during login:', error.message);
res.status(500).json({ message: 'Internal server error' });
}
};

// OAuth login (e.g., Google OAuth)
exports.oauthLogin = async (req, res) => {
const { token } = req.body;
try {
const ticket = await googleClient.verifyIdToken({
idToken: token,
audience: process.env.GOOGLE_CLIENT_ID,
});
const { email, name } = ticket.getPayload();

let user = await User.findOne({ email });
if (!user) {
user = new User({
userId: new mongoose.Types.ObjectId().toString(),
username: name,
email,
UserRoles: ['Viewer'], // Default role for OAuth users
Permissions: 'Standard',
AuthenticationMethods: 'OAuth',
});
await user.save();
}

const jwtToken = jwt.sign({ userId: user.userId, roles: user.UserRoles }, process.env.JWT_SECRET, { expiresIn: '1h' });
res.json({ token: jwtToken });
} catch (error) {
console.error('Error during OAuth login:', error.message);
res.status(500).json({ message: 'Internal server error' });
}
};
45 changes: 45 additions & 0 deletions models/userModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const mongoose = require('mongoose');
const { Schema } = mongoose;

const userSchema = new Schema({
userId: {
type: String,
unique: true,
required: true,
},
username: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: false,
},
UserRoles: {
type: [String],
enum: ['Admin', 'Editor', 'Viewer'],
required: true,
},
Permissions: {
type: String,
required: true,
},
AuditLogs: {
type: [String],
default: [],
},
AuthenticationMethods: {
type: String,
enum: ['OAuth', 'UsernamePassword'],
default: 'UsernamePassword',
},
}, {
timestamps: true,
});


module.exports = mongoose.model('userModel', userSchema);
Loading

0 comments on commit 4221e93

Please sign in to comment.