refactor(core): Introduce password utility (no-changelog) (#7979)
## Summary Provide details about your pull request and what it adds, fixes, or changes. Photos and videos are recommended. Continue breaking down `UserManagementHelper.ts` ... #### How to test the change: 1. ... ## Issues fixed Include links to Github issue or Community forum post or **Linear ticket**: > Important in order to close automatically and provide context to reviewers ... ## Review / Merge checklist - [ ] PR title and summary are descriptive. **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** ([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md)) - [ ] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up ticket created. - [ ] Tests included. > A bug is not considered fixed, unless a test is added to prevent it from happening again. A feature is not complete without tests. > > *(internal)* You can use Slack commands to trigger [e2e tests](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#a39f9e5ba64a48b58a71d81c837e8227) or [deploy test instance](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#f6a177d32bde4b57ae2da0b8e454bfce) or [deploy early access version on Cloud](https://www.notion.so/n8n/Cloudbot-3dbe779836004972b7057bc989526998?pvs=4#fef2d36ab02247e1a0f65a74f6fb534e).
This commit is contained in:
@@ -1,17 +1,13 @@
|
||||
import { In } from 'typeorm';
|
||||
import { compare, genSaltSync, hash } from 'bcryptjs';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
import type { WhereClause } from '@/Interfaces';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { MAX_PASSWORD_LENGTH, MIN_PASSWORD_LENGTH } from '@db/entities/User';
|
||||
import config from '@/config';
|
||||
import { License } from '@/License';
|
||||
import { getWebhookBaseUrl } from '@/WebhookHelpers';
|
||||
import { UserRepository } from '@db/repositories/user.repository';
|
||||
import type { Scope } from '@n8n/permissions';
|
||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||
import { ApplicationError } from 'n8n-workflow';
|
||||
|
||||
export function isSharingEnabled(): boolean {
|
||||
return Container.get(License).isSharingEnabled();
|
||||
@@ -30,42 +26,6 @@ export function generateUserInviteUrl(inviterId: string, inviteeId: string): str
|
||||
return `${getInstanceBaseUrl()}/signup?inviterId=${inviterId}&inviteeId=${inviteeId}`;
|
||||
}
|
||||
|
||||
// TODO: Enforce at model level
|
||||
export function validatePassword(password?: string): string {
|
||||
if (!password) {
|
||||
throw new BadRequestError('Password is mandatory');
|
||||
}
|
||||
|
||||
const hasInvalidLength =
|
||||
password.length < MIN_PASSWORD_LENGTH || password.length > MAX_PASSWORD_LENGTH;
|
||||
|
||||
const hasNoNumber = !/\d/.test(password);
|
||||
|
||||
const hasNoUppercase = !/[A-Z]/.test(password);
|
||||
|
||||
if (hasInvalidLength || hasNoNumber || hasNoUppercase) {
|
||||
const message: string[] = [];
|
||||
|
||||
if (hasInvalidLength) {
|
||||
message.push(
|
||||
`Password must be ${MIN_PASSWORD_LENGTH} to ${MAX_PASSWORD_LENGTH} characters long.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (hasNoNumber) {
|
||||
message.push('Password must contain at least 1 number.');
|
||||
}
|
||||
|
||||
if (hasNoUppercase) {
|
||||
message.push('Password must contain at least 1 uppercase letter.');
|
||||
}
|
||||
|
||||
throw new BadRequestError(message.join(' '));
|
||||
}
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
export async function getUserById(userId: string): Promise<User> {
|
||||
const user = await Container.get(UserRepository).findOneOrFail({
|
||||
where: { id: userId },
|
||||
@@ -74,28 +34,6 @@ export async function getUserById(userId: string): Promise<User> {
|
||||
return user;
|
||||
}
|
||||
|
||||
// ----------------------------------
|
||||
// hashing
|
||||
// ----------------------------------
|
||||
|
||||
export const hashPassword = async (validPassword: string): Promise<string> =>
|
||||
hash(validPassword, genSaltSync(10));
|
||||
|
||||
export async function compareHash(plaintext: string, hashed: string): Promise<boolean | undefined> {
|
||||
try {
|
||||
return await compare(plaintext, hashed);
|
||||
} catch (e) {
|
||||
const error = e instanceof Error ? e : new Error(`${e}`);
|
||||
|
||||
if (error instanceof Error && error.message.includes('Invalid salt version')) {
|
||||
error.message +=
|
||||
'. Comparison against unhashed string. Please check that the value compared against has been hashed.';
|
||||
}
|
||||
|
||||
throw new ApplicationError(error.message, { cause: error });
|
||||
}
|
||||
}
|
||||
|
||||
// return the difference between two arrays
|
||||
export function rightDiff<T1, T2>(
|
||||
[arr1, keyExtractor1]: [T1[], (item: T1) => string],
|
||||
|
||||
Reference in New Issue
Block a user