diff --git a/backend/src/auth/CustomJwtPayload.ts b/backend/src/auth/CustomJwtPayload.ts index 7966b413e..346ff143a 100644 --- a/backend/src/auth/CustomJwtPayload.ts +++ b/backend/src/auth/CustomJwtPayload.ts @@ -1,5 +1,5 @@ import { JwtPayload } from 'jsonwebtoken' export interface CustomJwtPayload extends JwtPayload { - gradidoID: string + gradidoID: Buffer } diff --git a/backend/src/auth/JWT.ts b/backend/src/auth/JWT.ts index 8399c881b..961274eb3 100644 --- a/backend/src/auth/JWT.ts +++ b/backend/src/auth/JWT.ts @@ -11,7 +11,7 @@ export const decode = (token: string): CustomJwtPayload | null => { } } -export const encode = (gradidoID: string): string => { +export const encode = (gradidoID: Buffer): string => { const token = jwt.sign({ gradidoID }, CONFIG.JWT_SECRET, { expiresIn: CONFIG.JWT_EXPIRES_IN, }) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index c9e5ea79f..ede230349 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0054-recalculate_balance_and_decay', + DB_VERSION: '0055-clear_old_password_junk', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index b28cb7c4b..db8169db1 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -328,7 +328,7 @@ export class UserResolver { context.setHeaders.push({ key: 'token', - value: encode(dbUser.gradidoID), + value: encode(Buffer.from(dbUser.gradidoID)), }) const ev = new EventLogin() ev.userId = user.id diff --git a/database/entity/0053-change_password_encryption/User.ts b/database/entity/0053-change_password_encryption/User.ts index c511a98c8..2a3332925 100644 --- a/database/entity/0053-change_password_encryption/User.ts +++ b/database/entity/0053-change_password_encryption/User.ts @@ -34,6 +34,21 @@ 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 + @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) @JoinColumn({ name: 'email_id' }) emailContact: UserContact diff --git a/database/entity/0053-change_password_encryption/UserContact.ts b/database/entity/0053-change_password_encryption/UserContact.ts index c101fba4c..97b12d4cd 100644 --- a/database/entity/0053-change_password_encryption/UserContact.ts +++ b/database/entity/0053-change_password_encryption/UserContact.ts @@ -40,6 +40,9 @@ export class UserContact extends BaseEntity { @Column({ name: 'email_resend_count' }) emailResendCount: number + // @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + // emailHash: Buffer + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) emailChecked: boolean diff --git a/database/entity/0055-clear_old_password_junk/User.ts b/database/entity/0055-clear_old_password_junk/User.ts new file mode 100644 index 000000000..c511a98c8 --- /dev/null +++ b/database/entity/0055-clear_old_password_junk/User.ts @@ -0,0 +1,112 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, + OneToOne, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { UserContact } from '../UserContact' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @OneToOne(() => UserContact, (emailContact: UserContact) => emailContact.user) + @JoinColumn({ name: 'email_id' }) + emailContact: UserContact + + @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) + emailId: number | null + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ + name: 'password_encryption_type', + type: 'int', + unsigned: true, + nullable: false, + default: 0, + }) + passwordEncryptionType: number + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] + + @OneToMany(() => UserContact, (userContact: UserContact) => userContact.user) + @JoinColumn({ name: 'user_id' }) + userContacts?: UserContact[] +} diff --git a/database/entity/0055-clear_old_password_junk/UserContact.ts b/database/entity/0055-clear_old_password_junk/UserContact.ts new file mode 100644 index 000000000..c101fba4c --- /dev/null +++ b/database/entity/0055-clear_old_password_junk/UserContact.ts @@ -0,0 +1,57 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToOne, +} from 'typeorm' +import { User } from './User' + +@Entity('user_contacts', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class UserContact extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'type', + length: 100, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + type: string + + @OneToOne(() => User, (user) => user.emailContact) + user: User + + @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) + userId: number + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ name: 'email_verification_code', type: 'bigint', unsigned: true, unique: true }) + emailVerificationCode: BigInt + + @Column({ name: 'email_opt_in_type_id' }) + emailOptInTypeId: number + + @Column({ name: 'email_resend_count' }) + emailResendCount: number + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 255, unique: false, nullable: true, collation: 'utf8mb4_unicode_ci' }) + phone: string + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'updated_at', nullable: true, default: null, type: 'datetime' }) + updatedAt: Date | null + + @DeleteDateColumn({ name: 'deleted_at', nullable: true }) + deletedAt: Date | null +} diff --git a/database/entity/User.ts b/database/entity/User.ts index b3c00a9b4..07c0ef335 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0053-change_password_encryption/User' +export { User } from './0055-clear_old_password_junk/User' diff --git a/database/entity/UserContact.ts b/database/entity/UserContact.ts index dd74e65c4..5c923c92b 100644 --- a/database/entity/UserContact.ts +++ b/database/entity/UserContact.ts @@ -1 +1 @@ -export { UserContact } from './0053-change_password_encryption/UserContact' +export { UserContact } from './0055-clear_old_password_junk/UserContact' diff --git a/database/migrations/0055-clear_old_password_junk.ts b/database/migrations/0055-clear_old_password_junk.ts new file mode 100644 index 000000000..3e6f3f76a --- /dev/null +++ b/database/migrations/0055-clear_old_password_junk.ts @@ -0,0 +1,16 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE users DROP COLUMN public_key;') + await queryFn('ALTER TABLE users DROP COLUMN privkey;') + await queryFn('ALTER TABLE users DROP COLUMN email_hash;') + await queryFn('ALTER TABLE users DROP COLUMN passphrase;') +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn('ALTER TABLE users ADD COLUMN public_key binary(32) DEFAULT NULL;') + await queryFn('ALTER TABLE users ADD COLUMN privkey binary(80) DEFAULT NULL;') + await queryFn('ALTER TABLE users ADD COLUMN email_hash binary(32) DEFAULT NULL;') + await queryFn('ALTER TABLE users ADD COLUMN passphrase text DEFAULT NULL;') +}