mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-06 09:41:51 +01:00
feat: started with proper E2EE ;)
This commit is contained in:
parent
e3b5c59949
commit
18d019d8b3
13 changed files with 380 additions and 1 deletions
|
|
@ -54,6 +54,11 @@ const messageSchema = mongoose.Schema(
|
|||
type: String,
|
||||
meiliIndex: true,
|
||||
},
|
||||
// If the message is encrypted (and stored in 'text'),
|
||||
// then this field should hold the IV used during encryption.
|
||||
messageEncryptionIV: {
|
||||
type: String,
|
||||
},
|
||||
summary: {
|
||||
type: String,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@ const shareSchema = mongoose.Schema(
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// --- Field for re-encrypting the conversation key for the forked user ---
|
||||
encryptionKeys: [
|
||||
{
|
||||
user: { type: String, index: true },
|
||||
encryptedKey: { type: String },
|
||||
},
|
||||
],
|
||||
},
|
||||
{ timestamps: true },
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ const { SystemRoles } = require('librechat-data-provider');
|
|||
* @property {Array} [plugins=[]] - List of plugins used by the user
|
||||
* @property {Array.<MongoSession>} [refreshToken] - List of sessions with refresh tokens
|
||||
* @property {Date} [expiresAt] - Optional expiration date of the file
|
||||
* @property {string} [encryptionPublicKey] - The user's public key for E2EE (client-generated)
|
||||
* @property {string} [encryptedPrivateKey] - The user's private key encrypted with a user-defined passphrase
|
||||
* @property {string} [encryptionSalt] - The salt used for PBKDF2 during encryption
|
||||
* @property {string} [encryptionIV] - The initialization vector used for encryption (AES-GCM)
|
||||
* @property {Date} [createdAt] - Date when the user was created (added by timestamps)
|
||||
* @property {Date} [updatedAt] - Date when the user was last updated (added by timestamps)
|
||||
*/
|
||||
|
|
@ -132,6 +136,27 @@ const userSchema = mongoose.Schema(
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// --- New Fields for E2EE ---
|
||||
encryptionPublicKey: {
|
||||
type: String,
|
||||
required: false,
|
||||
// Provided by the client after key generation.
|
||||
},
|
||||
encryptedPrivateKey: {
|
||||
type: String,
|
||||
required: false,
|
||||
// The private key encrypted on the client with the user’s encryption passphrase.
|
||||
},
|
||||
encryptionSalt: {
|
||||
type: String,
|
||||
required: false,
|
||||
// Salt used for PBKDF2 when encrypting the private key.
|
||||
},
|
||||
encryptionIV: {
|
||||
type: String,
|
||||
required: false,
|
||||
// IV used for AES-GCM encryption of the private key.
|
||||
},
|
||||
},
|
||||
|
||||
{ timestamps: true },
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const {
|
|||
deleteMessages,
|
||||
deleteUserById,
|
||||
deleteAllUserSessions,
|
||||
updateUser,
|
||||
} = require('~/models');
|
||||
const User = require('~/models/User');
|
||||
const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService');
|
||||
|
|
@ -162,6 +163,34 @@ const resendVerificationController = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
const updateUserEncryptionController = async (req, res) => {
|
||||
try {
|
||||
const { encryptionPublicKey, encryptedPrivateKey, encryptionSalt, encryptionIV } = req.body;
|
||||
|
||||
// Validate required parameters
|
||||
if (!encryptionPublicKey || !encryptedPrivateKey || !encryptionSalt || !encryptionIV) {
|
||||
return res.status(400).json({ message: 'Missing encryption parameters.' });
|
||||
}
|
||||
|
||||
// Use the helper function to update the user.
|
||||
const updatedUser = await updateUser(req.user.id, {
|
||||
encryptionPublicKey,
|
||||
encryptedPrivateKey,
|
||||
encryptionSalt,
|
||||
encryptionIV,
|
||||
});
|
||||
|
||||
if (!updatedUser) {
|
||||
return res.status(404).json({ message: 'User not found.' });
|
||||
}
|
||||
|
||||
res.status(200).json({ success: true });
|
||||
} catch (error) {
|
||||
logger.error('[updateUserEncryptionController]', error);
|
||||
res.status(500).json({ message: 'Something went wrong updating encryption keys.' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getUserController,
|
||||
getTermsStatusController,
|
||||
|
|
@ -170,4 +199,5 @@ module.exports = {
|
|||
verifyEmailController,
|
||||
updateUserPluginsController,
|
||||
resendVerificationController,
|
||||
updateUserEncryptionController,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ const {
|
|||
resendVerificationController,
|
||||
getTermsStatusController,
|
||||
acceptTermsController,
|
||||
updateUserEncryptionController,
|
||||
} = require('~/server/controllers/UserController');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', requireJwtAuth, getUserController);
|
||||
router.get('/terms', requireJwtAuth, getTermsStatusController);
|
||||
router.put('/encryption', requireJwtAuth, updateUserEncryptionController);
|
||||
router.post('/terms/accept', requireJwtAuth, acceptTermsController);
|
||||
router.post('/plugins', requireJwtAuth, updateUserPluginsController);
|
||||
router.delete('/delete', requireJwtAuth, canDeleteAccount, deleteUserController);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue