0

I have a simple web application that allows for registering of new users using bcrypt to store the password.

My TypeORM User entity looks like:

@Entity()
export class User extends BaseEntity {
    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column({
        type: 'nvarchar',
        length: 256,
        nullable: false,
        unique: true,
    })
    username: string;

    @Column({
        type: 'nvarchar',
        length: 256,
        nullable: false,
    })
    password: string;

    @BeforeInsert() async hashPassword() {
        this.password = await bcrypt.hash(this.password, 10); // salt rounds
    }

    async comparePasswordAsync(attempt: string): Promise<boolean> {
        return await bcrypt.compare(attempt, this.password);
    }
}

The creation of new users using an exposed endpoint works fine. Now, let's say I want to ship the product with a default admin account in the User table.

How do I write a migrator such that it adds a default username and password for an admin account?

Here is my migrator:

export class UserTable1594240665620 implements MigrationInterface {
    public async up(queryRunner: QueryRunner): Promise<void> {
        // Create the user table
        await queryRunner.query(`
            CREATE TABLE user(
                id VARCHAR(36) PRIMARY KEY NOT NULL,
                username VARCHAR(256) UNIQUE NOT NULL,
                password VARCHAR(256) NOT NULL,
            );`);

        // Add the default user
        await queryRunner.query(`INSERT INTO user(id, username, password)
             VALUES (UUID(), 'defaultAdmin', ????);
        `);
    }

    public async down(queryRunner: QueryRunner): Promise<void> {
        await queryRunner.query(`DROP TABLE user`);
    }
}

What do I put into the ??? in the above code in order to save the hashed default admin password?

noblerare
  • 10,277
  • 23
  • 78
  • 140
  • 2
    Itf you do this, you need to force them to choose a new password on first login. Also force them to do this before anyone else can use the site / application. Many applications and devices have been hacked over the years because users never changed the admin password and it was the same for all or from a small fixed set. – Dave S Jul 08 '20 at 22:40
  • @DaveS Will do. Thanks for that. – noblerare Jul 09 '20 at 17:50

1 Answers1

1

Well hello again (I just answered another one of your questions).

Per Dave S comment, beware of the security implications of having a default user...

As another security comment, you should also use both a salt and a hashed password, never a hash on its own. Save both the salt and hash in your user entity.

Be sure to use bcryptjs library over bcrypt. They work identically but you won't have deployment issues with bcryptjs.

import * as bcrypt from 'bcryptjs'

// ...

const password = 'example'
const salt = await bcrypt.genSalt()
const passwordHash = await bcrypt.hash(password, salt)

As for cleanly inserting values, note that you can get a lot more out of your queryRunner in TypeORM, e.g.:

queryRunner.manager.createQueryBuilder()

Check the docs for the Query Builder but this is a pretty straightforward API, e.g. .insert().into(...).values({ ... }).execute().

Refer to the docs at https://typeorm.io/#/insert-query-builder

You can generate a fresh salt as well as a hash for your default password and then insert those values as part of inserting your default user.

Cheers!

firxworx
  • 1,161
  • 11
  • 10