Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(password): more password module improvements #143

Merged
merged 1 commit into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/nestjs-auth-github/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"devDependencies": {
"@concepta/nestjs-crud": "^4.0.0-alpha.35",
"@concepta/nestjs-jwt": "^4.0.0-alpha.35",
"@concepta/nestjs-password": "^4.0.0-alpha.35",
"@concepta/nestjs-typeorm-ext": "^4.0.0-alpha.35",
"@concepta/nestjs-user": "^4.0.0-alpha.35",
"@nestjs/testing": "^9.0.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/nestjs-auth-github/src/auth-github.module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
UserLookupService,
UserMutateService,
} from '@concepta/nestjs-user';
import { PasswordModule } from '@concepta/nestjs-password';
import { FederatedModule } from '@concepta/nestjs-federated';
import { AuthGithubController } from './auth-github.controller';
import { AuthGithubModule } from './auth-github.module';
Expand Down Expand Up @@ -44,6 +45,7 @@ describe(AuthGithubModule, () => {
},
}),
CrudModule.forRoot({}),
PasswordModule.forRoot({}),
UserModule.forRoot({
entities: {
user: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ export class AuthLocalValidateUserService
}

// validate password
const isValid = await this.passwordValidationService.validateObject({
passwordPlain: dto.password,
object: user,
});
const isValid = await this.passwordValidationService.validateObject(
dto.password,
user,
);

// password is valid?
if (!isValid) {
Expand Down
1 change: 1 addition & 0 deletions packages/nestjs-auth-recovery/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@concepta/nestjs-crud": "^4.0.0-alpha.35",
"@concepta/nestjs-email": "^4.0.0-alpha.35",
"@concepta/nestjs-otp": "^4.0.0-alpha.35",
"@concepta/nestjs-password": "^4.0.0-alpha.35",
"@concepta/nestjs-typeorm-ext": "^4.0.0-alpha.35",
"@concepta/nestjs-user": "^4.0.0-alpha.35",
"@concepta/typeorm-seeding": "^4.0.0-beta.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { UserEntityFixture } from './user/entities/user-entity.fixture';

import { default as ormConfig } from './ormconfig.fixture';
import { MailerServiceFixture } from './email/mailer.service.fixture';
import { PasswordModule } from '@concepta/nestjs-password';

@Module({
imports: [
Expand All @@ -42,6 +43,7 @@ import { MailerServiceFixture } from './email/mailer.service.fixture';
},
},
}),
PasswordModule.forRoot({}),
UserModule.forRoot({
entities: {
user: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import { default as ormConfig } from './ormconfig.fixture';
@Module({
imports: [
EventModule.forRoot({}),
PasswordModule.forRoot({}),
TypeOrmExtModule.forRoot(ormConfig),
CrudModule.forRoot({}),
MailerModule.forRoot({ transport: { host: '' } }),
Expand Down Expand Up @@ -58,6 +57,7 @@ import { default as ormConfig } from './ormconfig.fixture';
},
},
}),
PasswordModule.forRoot({}),
UserModule.forRoot({
settings: {
invitationRequestEvent: InvitationAcceptedEventAsync,
Expand Down
1 change: 1 addition & 0 deletions packages/nestjs-org/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
},
"devDependencies": {
"@concepta/nestjs-invitation": "^4.0.0-alpha.35",
"@concepta/nestjs-password": "^4.0.0-alpha.35",
"@concepta/nestjs-user": "^4.0.0-alpha.35",
"@concepta/typeorm-seeding": "^4.0.0-beta.0",
"@faker-js/faker": "^6.0.0-alpha.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { InvitationEntityFixture } from '../__fixtures__/invitation.entity.fixtu
import { OrgFactory } from '../seeding/org.factory';
import { OrgEntityInterface } from '../interfaces/org-entity.interface';
import { OwnerFactoryFixture } from '../__fixtures__/owner-factory.fixture';
import { PasswordModule } from '@concepta/nestjs-password';

describe(InvitationAcceptedListener, () => {
const category = INVITATION_MODULE_CATEGORY_ORG_KEY;
Expand Down Expand Up @@ -51,6 +52,7 @@ describe(InvitationAcceptedListener, () => {
InvitationEntityFixture,
],
}),
PasswordModule.forRoot({}),
UserModule.forRoot({
entities: {
user: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('password configuration', () => {

expect(config).toMatchObject({
maxPasswordAttempts: 3,
minPasswordStrength: 8,
minPasswordStrength: 0,
});
});

Expand All @@ -39,7 +39,7 @@ describe('password configuration', () => {
const config = await passwordDefaultConfig();

expect(config.maxPasswordAttempts).toBe(3);
expect(config.minPasswordStrength).toBe(8);
expect(config.minPasswordStrength).toBe(0);
});

it('configProcessNotNull', async () => {
Expand Down Expand Up @@ -92,7 +92,7 @@ describe('password configuration', () => {

expect(config).toMatchObject({
maxPasswordAttempts: 3,
minPasswordStrength: 8,
minPasswordStrength: 0,
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const passwordDefaultConfig = registerAs(

minPasswordStrength: process.env.PASSWORD_MIN_PASSWORD_STRENGTH
? Number.parseInt(process.env.PASSWORD_MIN_PASSWORD_STRENGTH)
: 8,
: process.env?.NODE_ENV === 'production'
? 8
: 0,
}),
);
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import { PasswordPlainInterface } from '@concepta/ts-common';
import { PasswordStorageInterface } from './password-storage.interface';

/**
* Password Creation Service Interface
*/
export interface PasswordCreationServiceInterface {
/**
* Check if password is strong
* @param password
* @returns
* Create password for an object (optionally).
*
* @param object An object containing the new password to hash.
* @param options.salt Optional salt. If not provided, one will be generated.
* @param options.required Set to true if password is required.
* @param options.currentPassword Optional current password object to validate.
* @returns A new object with the password hashed, with salt added.
*/
isStrong(password: string): boolean;
createObject<T extends PasswordPlainInterface>(
object: T,
options?: {
salt?: string;
required?: boolean;
currentPassword?: {
password: string;
object: PasswordStorageInterface;
};
},
): Promise<
Omit<T, 'password'> | (Omit<T, 'password'> & PasswordStorageInterface)
>;

/**
* Check if attempt is valid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,30 @@ export interface PasswordStorageServiceInterface {
* Hash a password using a salt, if no
* was passed, then generate one automatically.
*
* @param password Password to be hashed
* @param salt Optional salt. If not provided, one will be generated.
* @param options.password Password to be hashed
* @param options.salt Optional salt. If not provided, one will be generated.
*/
hash(password: string, salt?: string): Promise<PasswordStorageInterface>;
hash(
password: string,
options?: {
salt?: string;
},
): Promise<PasswordStorageInterface>;

/**
* Hash password for an object.
*
* @param object An object containing the new password to hash.
* @param salt Optional salt. If not provided, one will be generated.
* @param options.salt Optional salt. If not provided, one will be generated.
* @param options.required Set to true if password is required.
* @returns A new object with the password hashed, with salt added.
*/
hashObject<T extends PasswordPlainInterface>(
object: T,
salt?: string,
): Promise<Omit<T, 'password'> & PasswordStorageInterface>;

/**
* Hash password for an object if password property exists.
*
* @param object An object containing the new password to hash.
* @param salt Optional salt. If not provided, one will be generated.
* @returns A new object with the password hashed, with salt added.
*/
hashObjectOptional<T extends Partial<PasswordPlainInterface>>(
object: T,
salt?: string,
options?: {
salt?: string;
required?: boolean;
},
): Promise<
Omit<T, 'password'> | (Omit<T, 'password'> & PasswordStorageInterface)
>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ export interface PasswordValidationServiceInterface {
/**
* Validate if password matches and its valid.
*
* @param options.passwordPlain Plain text password
* @param options.password Plain text password
* @param options.passwordHash Password hashed
* @param options.passwordSalt salt to be used on plain password to see it match
*/
validate(options: {
passwordPlain: string;
password: string;
passwordHash: string;
passwordSalt: string;
}): Promise<boolean>;
Expand All @@ -23,8 +23,9 @@ export interface PasswordValidationServiceInterface {
* @param options.passwordPlain Plain text password
* @param options.object The object on which the password and salt are stored
*/
validateObject<T extends PasswordStorageInterface>(options: {
passwordPlain: string;
object: T;
}): Promise<boolean>;
validateObject<T extends PasswordStorageInterface>(
passwordPlain: string,

object: T,
): Promise<boolean>;
}
Loading