Skip to content

Commit

Permalink
feat: email will be stored hashed now for all users (#8720)
Browse files Browse the repository at this point in the history
Adding email_hash column to users table.
We will update all existing users to have hashed email. 
All new users will also get the hash.

We are fine to use md5, because we just need uniqueness. We have emails
in events table stored anyways, so it is not sensitive.
  • Loading branch information
sjaanus authored Nov 12, 2024
1 parent 42198ce commit c8bc401
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/lib/db/user-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,15 @@ class UserStore implements IUserStore {
}

async insert(user: ICreateUser): Promise<User> {
const emailHash = user.email
? this.db.raw('md5(?)', [user.email])
: null;
const rows = await this.db(TABLE)
.insert({ ...mapUserToColumns(user), created_at: new Date() })
.insert({
...mapUserToColumns(user),
email_hash: emailHash,
created_at: new Date(),
})
.returning(USER_COLUMNS);
return rowToUser(rows[0]);
}
Expand Down
18 changes: 18 additions & 0 deletions src/migrations/20241112113555-user-email-hash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
exports.up = (db, cb) => {
db.runSql(`
ALTER TABLE users
ADD COLUMN IF NOT EXISTS email_hash VARCHAR(32);
UPDATE users
SET email_hash = md5(email::text);
`, cb);

};

exports.down = (db, cb) => {
db.runSql(`
ALTER TABLE users
DROP COLUMN IF EXISTS email_hash;
`, cb);
};

23 changes: 23 additions & 0 deletions src/test/e2e/api/admin/user-admin.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { randomId } from '../../../../lib/util/random-id';
import { omitKeys } from '../../../../lib/util/omit-keys';
import type { ISessionStore } from '../../../../lib/types/stores/session-store';
import type { IUnleashStores } from '../../../../lib/types';
import { createHash } from 'crypto';

let stores: IUnleashStores;
let db: ITestDb;
Expand Down Expand Up @@ -405,3 +406,25 @@ test('Anonymises name, username and email fields if anonymiseEventLog flag is se
expect(body.users[0].name).toEqual('[email protected]');
expect(body.users[0].username).toEqual(''); // Not set, so anonymise should return the empty string.
});

test('creates user with email md5 hash', async () => {
await app.request
.post('/api/admin/user-admin')
.send({
email: `[email protected]`,
name: `Some Name Hash`,
rootRole: editorRole.id,
})
.set('Content-Type', 'application/json');

const user = await db
.rawDatabase('users')
.where({ email: '[email protected]' })
.first(['email_hash']);

const expectedHash = createHash('md5')
.update('[email protected]')
.digest('hex');

expect(user.email_hash).toBe(expectedHash);
});

0 comments on commit c8bc401

Please sign in to comment.