diff --git a/server/controllers/session.controller.js b/server/controllers/session.controller.js index 211b8a46..4b4e3025 100644 --- a/server/controllers/session.controller.js +++ b/server/controllers/session.controller.js @@ -13,6 +13,7 @@ export function createSession(req, res, next) { email: req.user.email, username: req.user.username, preferences: req.user.preferences, + apiKeys: req.user.apiKeys, verified: req.user.verified, id: req.user._id }); @@ -26,6 +27,7 @@ export function getSession(req, res) { email: req.user.email, username: req.user.username, preferences: req.user.preferences, + apiKeys: req.user.apiKeys, verified: req.user.verified, id: req.user._id }); diff --git a/server/controllers/user.controller.js b/server/controllers/user.controller.js index 00f3f022..d22b19ae 100644 --- a/server/controllers/user.controller.js +++ b/server/controllers/user.controller.js @@ -352,3 +352,42 @@ export function updateSettings(req, res) { } }); } + +export function addApiKey(req, res) { + User.findById(req.user.id, (err, user) => { + if (err) { + res.status(500).json({ error: err }); + return; + } + if (!user) { + res.status(404).json({ error: 'User not found' }); + return; + } + if (!req.body.label || !req.body.hashedKey) { + res.status(400).json({ error: 'Expected field \'label\' or \'hashedKey\' was not present in request body' }); + return; + } + user.apiKeys.push(req.body); + saveUser(res, user); + }); +} + +export function removeApiKey(req, res) { + User.findById(req.user.id, (err, user) => { + if (err) { + res.status(500).json({ error: err }); + return; + } + if (!user) { + res.status(404).json({ error: 'User not found' }); + return; + } + const keyToDelete = user.apiKeys.find(key => key.id === req.params.keyId); + if (!keyToDelete) { + res.status(404).json({ error: 'Key does not exist for user' }); + return; + } + user.apiKeys.pull({ _id: req.params.keyId }); + saveUser(res, user); + }); +} diff --git a/server/models/user.js b/server/models/user.js index 5cbf12be..d15a8930 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -10,6 +10,20 @@ const EmailConfirmationStates = { const { Schema } = mongoose; +const apiKeySchema = new Schema({ + label: { type: String, default: 'API Key' }, + lastUsedAt: { type: Date, required: true, default: Date.now }, + hashedKey: { type: String, required: true }, +}, { timestamps: true, _id: true }); + +apiKeySchema.virtual('id').get(function getApiKeyId() { + return this._id.toHexString(); +}); + +apiKeySchema.set('toJSON', { + virtuals: true +}); + const userSchema = new Schema({ name: { type: String, default: '' }, username: { type: String, required: true, unique: true }, @@ -22,6 +36,7 @@ const userSchema = new Schema({ github: { type: String }, email: { type: String, unique: true }, tokens: Array, + apiKeys: { type: [apiKeySchema] }, preferences: { fontSize: { type: Number, default: 18 }, indentationAmount: { type: Number, default: 2 }, diff --git a/server/routes/user.routes.js b/server/routes/user.routes.js index 427e0705..49b09a94 100644 --- a/server/routes/user.routes.js +++ b/server/routes/user.routes.js @@ -18,6 +18,10 @@ router.post('/reset-password/:token', UserController.updatePassword); router.put('/account', isAuthenticated, UserController.updateSettings); +router.put('/account/api-keys', isAuthenticated, UserController.addApiKey); + +router.delete('/account/api-keys/:keyId', isAuthenticated, UserController.removeApiKey); + router.post('/verify/send', UserController.emailVerificationInitiate); router.get('/verify', UserController.verifyEmail);