diff --git a/backend/src/graphql/enum/PasswordEncryptionType.ts b/backend/src/graphql/enum/PasswordEncryptionType.ts index 4f23aa693..b3a00d748 100644 --- a/backend/src/graphql/enum/PasswordEncryptionType.ts +++ b/backend/src/graphql/enum/PasswordEncryptionType.ts @@ -1,8 +1,8 @@ import { registerEnumType } from 'type-graphql' export enum PasswordEncryptionType { - EMAIL = 0, - ONE_TIME = 1, + NO_PASSWORD = 0, + EMAIL = 1, GRADIDO_ID = 2, } diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index cf4ad8d4b..791ed4c8e 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -146,6 +146,7 @@ describe('UserResolver', () => { publisherId: 1234, referrerId: null, contributionLinkId: null, + passwordEncryptionType: 1, }, ]) const valUUID = validateUUID(user[0].gradidoID) diff --git a/backend/src/password/EmailEncryptr.ts b/backend/src/password/EmailEncryptr.ts deleted file mode 100644 index 59098e207..000000000 --- a/backend/src/password/EmailEncryptr.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { User } from '@entity/User' -import { PasswordEncryptr } from './PasswordEncryptr' -import { SecretKeyCryptographyCreateKey } from './EncryptorUtils' - -export class EmailEncryptr implements PasswordEncryptr { - async encryptPassword(dbUser: User, password: string): Promise { - const keyBuffer = SecretKeyCryptographyCreateKey(dbUser.emailContact.email, password) // return short and long hash - const passwordHash = keyBuffer[0].readBigUInt64LE() - - return passwordHash - } - - async verifyPassword(dbUser: User, password: string): Promise { - if (BigInt(password) !== (await this.encryptPassword(dbUser, dbUser.password.toString()))) { - return false - } - return true - } -} diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index 6609ff075..5f6f4b416 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -1,5 +1,7 @@ import CONFIG from '@/config' import { backendLogger as logger } from '@/server/logger' +import { User } from '@entity/User' +import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -50,3 +52,15 @@ export const SecretKeyCryptographyCreateKey = (salt: string, password: string): ) return [encryptionKeyHash, encryptionKey] } + +export const getBasicCryptographicKey = (dbUser: User): string | null => { + if (dbUser.passwordEncryptionType === PasswordEncryptionType.NO_PASSWORD) { + return null + } else if (dbUser.passwordEncryptionType === PasswordEncryptionType.EMAIL) { + return dbUser.emailContact.email + } else if (dbUser.passwordEncryptionType === PasswordEncryptionType.GRADIDO_ID) { + return dbUser.gradidoID + } + + throw new Error(`Unknown password encryption type: ${dbUser.passwordEncryptionType}`) +} diff --git a/backend/src/password/GradidoIDEncryptr.ts b/backend/src/password/GradidoIDEncryptr.ts deleted file mode 100644 index 630bee056..000000000 --- a/backend/src/password/GradidoIDEncryptr.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { User } from '@entity/User' -import { SecretKeyCryptographyCreateKey } from './EncryptorUtils' -import { PasswordEncryptr } from './PasswordEncryptr' - -export class GradidoIDEncryptr implements PasswordEncryptr { - async encryptPassword(dbUser: User, password: string): Promise { - const keyBuffer = SecretKeyCryptographyCreateKey(dbUser.gradidoID, password) // return short and long hash - const passwordHash = keyBuffer[0].readBigUInt64LE() - - return passwordHash - } - - async verifyPassword(dbUser: User, password: string): Promise { - if (BigInt(password) !== (await this.encryptPassword(dbUser, dbUser.password.toString()))) { - return false - } - return true - } -} diff --git a/backend/src/password/PasswordEncryptr.ts b/backend/src/password/PasswordEncryptr.ts index 24d949be9..24dc7f352 100644 --- a/backend/src/password/PasswordEncryptr.ts +++ b/backend/src/password/PasswordEncryptr.ts @@ -1,6 +1,30 @@ import { User } from '@entity/User' +import { logger } from '@test/testSetup' +import { getBasicCryptographicKey, SecretKeyCryptographyCreateKey } from './EncryptorUtils' -export interface PasswordEncryptr { - encryptPassword(dbUser: User, password: string): Promise - verifyPassword(dbUser: User, password: string): Promise +export class PasswordEncryptr { + async encryptPassword(dbUser: User, password: string): Promise { + const basicKey = getBasicCryptographicKey(dbUser) + if (!basicKey) logger.error('Password not set for user ' + dbUser.id) + else { + const keyBuffer = SecretKeyCryptographyCreateKey(basicKey, password) // return short and long hash + const passwordHash = keyBuffer[0].readBigUInt64LE() + return passwordHash + } + + throw new Error('Password not set for user ' + dbUser.id) // user has no password + } + + async verifyPassword(dbUser: User, password: string): Promise { + const basicKey = getBasicCryptographicKey(dbUser) + if (!basicKey) logger.error('Password not set for user ' + dbUser.id) + else { + if (BigInt(password) !== (await this.encryptPassword(dbUser, dbUser.password.toString()))) { + return false + } + return true + } + + throw new Error('Password not set for user ' + dbUser.id) // user has no password + } } diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index e885b7043..87d0432dc 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -26,6 +26,8 @@ const communityDbUser: dbUser = { isAdmin: null, publisherId: 0, passphrase: '', + // default password encryption type + passwordEncryptionType: 2, hasId: function (): boolean { throw new Error('Function not implemented.') }, diff --git a/database/entity/0053-change_password_encryption/User.ts b/database/entity/0053-change_password_encryption/User.ts index bf2d02268..fac4e1031 100644 --- a/database/entity/0053-change_password_encryption/User.ts +++ b/database/entity/0053-change_password_encryption/User.ts @@ -34,20 +34,20 @@ export class User extends BaseEntity { }) alias: string - /* - @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) - pubKey: Buffer - @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) - privKey: Buffer - @Column({ - type: 'text', - name: 'passphrase', - collation: 'utf8mb4_unicode_ci', - nullable: true, - default: null, - }) - passphrase: string - */ + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) @JoinColumn({ name: 'email_id' }) diff --git a/database/entity/0053-change_password_encryption/UserContact.ts b/database/entity/0053-change_password_encryption/UserContact.ts index 05bfdfffe..97b12d4cd 100644 --- a/database/entity/0053-change_password_encryption/UserContact.ts +++ b/database/entity/0053-change_password_encryption/UserContact.ts @@ -5,8 +5,6 @@ import { Column, DeleteDateColumn, OneToOne, - JoinColumn, - ManyToOne, } from 'typeorm' import { User } from './User' @@ -59,8 +57,4 @@ export class UserContact extends BaseEntity { @DeleteDateColumn({ name: 'deleted_at', nullable: true }) deletedAt: Date | null - - @ManyToOne(() => User, (user) => user.userContacts) - @JoinColumn({ name: 'user_id' }) - contactUser: User }