Verschlüsselung korrigiert
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { sequelize } from '../../utils/sequelize.js';
|
import { sequelize } from '../../utils/sequelize.js';
|
||||||
import { DataTypes } from 'sequelize';
|
import { DataTypes } from 'sequelize';
|
||||||
import bcrypt from 'bcrypt';
|
import bcrypt from 'bcrypt';
|
||||||
|
import { encrypt, generateIv } from '../../utils/encryption.js';
|
||||||
|
|
||||||
const User = sequelize.define('user', {
|
const User = sequelize.define('user', {
|
||||||
email: {
|
email: {
|
||||||
@@ -8,9 +9,17 @@ const User = sequelize.define('user', {
|
|||||||
allowNull: false,
|
allowNull: false,
|
||||||
unique: true,
|
unique: true,
|
||||||
set(value) {
|
set(value) {
|
||||||
this.setDataValue('email', bcrypt.hashSync(value, 10));
|
if (value) {
|
||||||
|
const iv = generateIv();
|
||||||
|
this.setDataValue('iv', iv.toString('hex'));
|
||||||
|
this.setDataValue('email', encrypt(value, iv));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
iv: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false
|
||||||
|
},
|
||||||
username: {
|
username: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
@@ -19,6 +28,9 @@ const User = sequelize.define('user', {
|
|||||||
password: {
|
password: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
set(value) {
|
||||||
|
this.setDataValue('password', bcrypt.hashSync(value, 10));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
registrationDate: {
|
registrationDate: {
|
||||||
type: DataTypes.DATE,
|
type: DataTypes.DATE,
|
||||||
@@ -40,7 +52,7 @@ const User = sequelize.define('user', {
|
|||||||
}, {
|
}, {
|
||||||
tableName: 'user',
|
tableName: 'user',
|
||||||
schema: 'community',
|
schema: 'community',
|
||||||
underscored: true,
|
underscored: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export default User;
|
export default User;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { sequelize } from '../../utils/sequelize.js';
|
|||||||
import { DataTypes } from 'sequelize';
|
import { DataTypes } from 'sequelize';
|
||||||
import User from './user.js';
|
import User from './user.js';
|
||||||
import UserParamType from '../type/user_param.js';
|
import UserParamType from '../type/user_param.js';
|
||||||
|
import { encrypt, decrypt, generateIv } from '../../utils/encryption.js';
|
||||||
|
|
||||||
const UserParam = sequelize.define('user_param', {
|
const UserParam = sequelize.define('user_param', {
|
||||||
userId: {
|
userId: {
|
||||||
@@ -18,20 +19,52 @@ const UserParam = sequelize.define('user_param', {
|
|||||||
references: {
|
references: {
|
||||||
model: UserParamType,
|
model: UserParamType,
|
||||||
key: 'id'
|
key: 'id'
|
||||||
},
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
allowNull: false,
|
||||||
|
set(value) {
|
||||||
|
if (value) {
|
||||||
|
const iv = generateIv();
|
||||||
|
this.setDataValue('iv', iv.toString('hex'));
|
||||||
|
this.setDataValue('value', encrypt(value, iv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
iv: {
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
allowNull: false
|
allowNull: false
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
tableName: 'user_param',
|
tableName: 'user_param',
|
||||||
schema: 'community',
|
schema: 'community',
|
||||||
underscored: true
|
underscored: true,
|
||||||
|
hooks: {
|
||||||
|
beforeSave: (userParam) => {
|
||||||
|
if (userParam.value && !userParam.iv) {
|
||||||
|
const iv = generateIv();
|
||||||
|
userParam.iv = iv.toString('hex');
|
||||||
|
userParam.value = encrypt(userParam.value, iv);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
afterFind: (userParams) => {
|
||||||
|
if (userParams) {
|
||||||
|
if (Array.isArray(userParams)) {
|
||||||
|
userParams.forEach((userParam) => {
|
||||||
|
const iv = Buffer.from(userParam.iv, 'hex');
|
||||||
|
userParam.value = decrypt(userParam.value, iv);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const iv = Buffer.from(userParams.iv, 'hex');
|
||||||
|
userParams.value = decrypt(userParams.value, iv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
UserParam.belongsTo(User, { foreignKey: 'userId' });
|
UserParam.belongsTo(User, { foreignKey: 'userId' });
|
||||||
UserParam.belongsTo(UserParamType, { foreignKey: 'param_type_id' });
|
UserParam.belongsTo(UserParamType, { foreignKey: 'paramTypeId' });
|
||||||
|
|
||||||
export default UserParam;
|
export default UserParam;
|
||||||
|
|||||||
@@ -8,31 +8,40 @@ import { sendAccountActivationEmail, sendPasswordResetEmail } from './emailServi
|
|||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
|
|
||||||
export const registerUser = async ({ email, username, password, language }) => {
|
export const registerUser = async ({ email, username, password, language }) => {
|
||||||
|
const [results] = await sequelize.query(
|
||||||
|
'SELECT * FROM "community"."user" WHERE pgp_sym_decrypt("email", :key) = :email',
|
||||||
|
{
|
||||||
|
replacements: { key: process.env.SECRET_KEY, email },
|
||||||
|
type: sequelize.QueryTypes.SELECT
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (results.length > 0) {
|
||||||
|
throw new Error('Email already in use');
|
||||||
|
}
|
||||||
|
const iv = generateIv();
|
||||||
|
const encryptedEmail = encrypt(email, iv);
|
||||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||||
const resetToken = uuidv4();
|
const resetToken = uuidv4();
|
||||||
const user = await User.create({
|
const user = await User.create({
|
||||||
email,
|
email: encryptedEmail,
|
||||||
|
iv: iv.toString('hex'),
|
||||||
username,
|
username,
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
resetToken: resetToken,
|
resetToken: resetToken,
|
||||||
active: false,
|
active: false,
|
||||||
registration_date: new Date()
|
registration_date: new Date()
|
||||||
});
|
});
|
||||||
|
|
||||||
const languageType = await UserParamType.findOne({ where: { description: 'language' } });
|
const languageType = await UserParamType.findOne({ where: { description: 'language' } });
|
||||||
if (!languageType) {
|
if (!languageType) {
|
||||||
throw new Error('Language type not found');
|
throw new Error('Language type not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await UserParam.create({
|
await UserParam.create({
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
paramTypeId: languageType.id,
|
paramTypeId: languageType.id,
|
||||||
value: language
|
value: language
|
||||||
});
|
});
|
||||||
|
|
||||||
const activationLink = `${process.env.FRONTEND_URL}/activate?token=${resetToken}`;
|
const activationLink = `${process.env.FRONTEND_URL}/activate?token=${resetToken}`;
|
||||||
await sendAccountActivationEmail(email, activationLink, username, resetToken, language);
|
await sendAccountActivationEmail(email, activationLink, username, resetToken, language);
|
||||||
|
|
||||||
return { id: user.hashedId, username: user.username, active: user.active };
|
return { id: user.hashedId, username: user.username, active: user.active };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
32
backend/utils/encryption.js
Normal file
32
backend/utils/encryption.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import crypto from 'crypto';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
|
dotenv.config(); // Laden der Umgebungsvariablen
|
||||||
|
|
||||||
|
const algorithm = 'aes-256-cbc';
|
||||||
|
const secretKey = process.env.SECRET_KEY;
|
||||||
|
|
||||||
|
if (!secretKey || secretKey.length !== 32) {
|
||||||
|
throw new Error('SECRET_KEY length must be 32 bytes');
|
||||||
|
}
|
||||||
|
|
||||||
|
const encrypt = (text, iv) => {
|
||||||
|
const cipher = crypto.createCipheriv(algorithm, Buffer.from(secretKey, 'utf-8'), iv);
|
||||||
|
let encrypted = cipher.update(text);
|
||||||
|
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||||
|
return encrypted.toString('hex');
|
||||||
|
};
|
||||||
|
|
||||||
|
const decrypt = (encryptedText, iv) => {
|
||||||
|
const encryptedBuffer = Buffer.from(encryptedText, 'hex');
|
||||||
|
const decipher = crypto.createDecipheriv(algorithm, Buffer.from(secretKey, 'utf-8'), iv);
|
||||||
|
let decrypted = decipher.update(encryptedBuffer);
|
||||||
|
decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||||
|
return decrypted.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateIv = () => {
|
||||||
|
return crypto.randomBytes(16);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { encrypt, decrypt, generateIv };
|
||||||
Reference in New Issue
Block a user