Browse Source

zse zod for validation

pull/1355/head
Bernd Storath 8 months ago
parent
commit
30ff8554b9
  1. 11
      src/i18n.config.ts
  2. 26
      src/server/utils/password.ts
  3. 11
      src/server/utils/types.ts
  4. 17
      src/services/database/lowdb.ts
  5. 6
      src/services/database/repositories/database.ts

11
src/i18n.config.ts

@ -48,11 +48,6 @@ export default defineI18nConfig(() => ({
Permanent: 'Permanent',
OneTimeLink: 'Generate short one time link',
errorInit: 'Initialization failed.',
errorDatabaseConn: 'Failed to connect to the database.',
errorPasswordReq:
'Password does not meet the strength requirements. It must be at least 12 characters long, with at least one uppercase letter, one lowercase letter, one number, and one special character.',
errorUsernameReq: 'Username must be longer than 8 characters.',
errorUserExist: 'User already exists.',
},
ua: {
name: 'Ім`я',
@ -280,12 +275,6 @@ export default defineI18nConfig(() => ({
Permanent: 'Permanent',
OneTimeLink: 'Générer un lien court à usage unique',
errorInit: "Échec de l'initialisation.",
errorDatabaseConn: 'Échec de la connexion à la base de données.',
errorPasswordReq:
'Le mot de passe ne répond pas aux exigences de sécurité. Il doit comporter au moins 12 caractères, dont au moins une lettre majuscule, une lettre minuscule, un chiffre et un caractère spécial.',
errorUsernameReq:
"Le nom d'utilisateur doit comporter plus de 8 caractères.",
errorUserExist: "L'utilisateur existe déjà.",
},
de: {
// github.com/florian-asche

26
src/server/utils/password.ts

@ -10,32 +10,6 @@ export function isPasswordValid(password: string, hash: string): boolean {
return bcrypt.compareSync(password, hash);
}
/**
* Checks if a password is strong based on following criteria :
*
* - minimum length of 12 characters
* - contains at least one uppercase letter
* - contains at least one lowercase letter
* - contains at least one number
* - contains at least one special character (e.g., !@#$%^&*(),.?":{}|<>).
*
* @param {string} password - The password to validate
* @returns {boolean} `true` if the password is strong, otherwise `false`
*/
export function isPasswordStrong(password: string): boolean {
if (password.length < 12) {
return false;
}
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
return hasUpperCase && hasLowerCase && hasNumber && hasSpecialChar;
}
/**
* Hashes a password.
*

11
src/server/utils/types.ts

@ -1,6 +1,8 @@
import type { ZodSchema } from 'zod';
import { z, ZodError } from 'zod';
// TODO: use i18n for messages
const safeStringRefine = z
.string()
.refine(
@ -28,10 +30,19 @@ const file = z
const username = z
.string({ message: 'Username must be a valid string' })
.min(8, 'Username must be at least 8 Characters')
.pipe(safeStringRefine);
const password = z
.string({ message: 'Password must be a valid string' })
.min(12, 'Password must be at least 12 Characters')
.regex(/[A-Z]/, 'Password must have at least 1 uppercase letter')
.regex(/[a-z]/, 'Password must have at least 1 lowercase letter')
.regex(/\d/, 'Password must have at least 1 number')
.regex(
/[!@#$%^&*(),.?":{}|<>]/,
'Password must have at least 1 special character'
)
.pipe(safeStringRefine);
const remember = z.boolean({ message: 'Remember must be a valid boolean' });

17
src/services/database/lowdb.ts

@ -40,7 +40,7 @@ export default class LowDB extends DatabaseProvider {
DEBUG('Migrations ran successfully');
} catch (e) {
DEBUG(e);
throw new DatabaseError(DatabaseError.ERROR_INIT);
throw new Error('Failed to initialize Database');
}
this.#connected = true;
DEBUG('Connected successfully');
@ -78,21 +78,14 @@ export default class LowDB extends DatabaseProvider {
async createUser(username: string, password: string) {
DEBUG('Create User');
// TODO: should be handled by zod. completely remove database error
if (username.length < 8) {
throw new DatabaseError(DatabaseError.ERROR_USERNAME_REQ);
}
if (!isPasswordStrong(password)) {
throw new DatabaseError(DatabaseError.ERROR_PASSWORD_REQ);
}
// TODO: multiple names are no problem
const isUserExist = this.#db.data.users.find(
(user) => user.username === username
);
if (isUserExist) {
throw new DatabaseError(DatabaseError.ERROR_USER_EXIST);
throw createError({
statusCode: 409,
statusMessage: 'Username already taken',
});
}
const now = new Date().toISOString();

6
src/services/database/repositories/database.ts

@ -79,7 +79,7 @@ export abstract class DatabaseProvider
*
* Example:
* ```typescript
* throw new DatabaseError(DatabaseError.ERROR_PASSWORD_REQ);
* throw new DatabaseError(DatabaseError.ERROR_INIT);
* ...
* // event handler routes
* if (error instanceof DatabaseError) {
@ -98,10 +98,6 @@ export abstract class DatabaseProvider
*/
export class DatabaseError extends Error {
static readonly ERROR_INIT = 'errorInit';
static readonly ERROR_PASSWORD_REQ = 'errorPasswordReq';
static readonly ERROR_USER_EXIST = 'errorUserExist';
static readonly ERROR_DATABASE_CONNECTION = 'errorDatabaseConn';
static readonly ERROR_USERNAME_REQ = 'errorUsernameReq';
constructor(message: string) {
super(message);

Loading…
Cancel
Save