2022-01-31 11:04:55 +08:00
|
|
|
import { PasswordEncryptionMethod, User } from '@logto/schemas';
|
2021-11-18 16:29:24 +08:00
|
|
|
import { nanoid } from 'nanoid';
|
2021-09-08 10:29:14 +08:00
|
|
|
import pRetry from 'p-retry';
|
|
|
|
|
2022-01-31 11:04:55 +08:00
|
|
|
import { findUserByUsername, hasUserWithId } from '@/queries/user';
|
|
|
|
import assertThat from '@/utils/assert-that';
|
2021-09-08 10:29:14 +08:00
|
|
|
import { buildIdGenerator } from '@/utils/id';
|
2021-11-18 16:29:24 +08:00
|
|
|
import { encryptPassword } from '@/utils/password';
|
2021-09-08 10:29:14 +08:00
|
|
|
|
|
|
|
const userId = buildIdGenerator(12);
|
|
|
|
|
|
|
|
export const generateUserId = async (retries = 500) =>
|
|
|
|
pRetry(
|
|
|
|
async () => {
|
|
|
|
const id = userId();
|
|
|
|
|
|
|
|
if (!(await hasUserWithId(id))) {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error('Cannot generate user ID in reasonable retries');
|
|
|
|
},
|
|
|
|
{ retries, factor: 0 } // No need for exponential backoff
|
|
|
|
);
|
2021-11-18 16:29:24 +08:00
|
|
|
|
|
|
|
export const encryptUserPassword = (
|
|
|
|
userId: string,
|
|
|
|
password: string
|
|
|
|
): {
|
|
|
|
passwordEncryptionSalt: string;
|
|
|
|
passwordEncrypted: string;
|
|
|
|
passwordEncryptionMethod: PasswordEncryptionMethod;
|
|
|
|
} => {
|
|
|
|
const passwordEncryptionSalt = nanoid();
|
|
|
|
const passwordEncryptionMethod = PasswordEncryptionMethod.SaltAndPepper;
|
|
|
|
const passwordEncrypted = encryptPassword(
|
|
|
|
userId,
|
|
|
|
password,
|
|
|
|
passwordEncryptionSalt,
|
|
|
|
passwordEncryptionMethod
|
|
|
|
);
|
|
|
|
|
|
|
|
return { passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt };
|
|
|
|
};
|
2022-01-31 11:04:55 +08:00
|
|
|
|
|
|
|
export const findUserByUsernameAndPassword = async (
|
|
|
|
username: string,
|
|
|
|
password: string
|
|
|
|
): Promise<User> => {
|
|
|
|
const user = await findUserByUsername(username);
|
|
|
|
const { id, passwordEncrypted, passwordEncryptionMethod, passwordEncryptionSalt } = user;
|
|
|
|
|
|
|
|
assertThat(
|
|
|
|
passwordEncrypted && passwordEncryptionMethod && passwordEncryptionSalt,
|
|
|
|
'session.invalid_sign_in_method'
|
|
|
|
);
|
|
|
|
|
|
|
|
assertThat(
|
|
|
|
encryptPassword(id, password, passwordEncryptionSalt, passwordEncryptionMethod) ===
|
|
|
|
passwordEncrypted,
|
|
|
|
'session.invalid_credentials'
|
|
|
|
);
|
|
|
|
|
|
|
|
return user;
|
|
|
|
};
|