mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-02-16 10:42:08 +00:00
Security fix: update password system for database seeding
This commit is contained in:
@@ -136,8 +136,10 @@ POSTGRES_PRISMA_URL=
|
||||
POSTGRES_URL_NON_POOLING=
|
||||
SHADOW_DATABASE_URL=
|
||||
|
||||
ADMIN_PASSWORD=
|
||||
|
||||
MAPBOX_ACCESS_TOKEN=
|
||||
NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=
|
||||
|
||||
SPARKPOST_API_KEY=
|
||||
SPARKPOST_SENDER_ADDRESS=" > .env
|
||||
```
|
||||
@@ -175,6 +177,8 @@ SPARKPOST_SENDER_ADDRESS=" > .env
|
||||
- `SPARKPOST_API_KEY` is the API key for your SparkPost account.
|
||||
- You can create a free account [here](https://www.sparkpost.com/).
|
||||
- `SPARKPOST_SENDER_ADDRESS` is the email address that will be used to send emails.
|
||||
- `ADMIN_PASSWORD` is the password for the admin account created when seeding the
|
||||
database.
|
||||
|
||||
1. Initialize the database and run the migrations.
|
||||
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -72,6 +72,7 @@
|
||||
"eslint-config-next": "^13.5.4",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"generate-password": "^1.7.1",
|
||||
"onchange": "^7.1.0",
|
||||
"postcss": "^8.4.26",
|
||||
"prettier": "^3.0.0",
|
||||
@@ -5354,6 +5355,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/generate-password": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.7.1.tgz",
|
||||
"integrity": "sha512-9bVYY+16m7W7GczRBDqXE+VVuCX+bWNrfYKC/2p2JkZukFb2sKxT6E3zZ3mJGz7GMe5iRK0A/WawSL3jQfJuNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/geojson-vt": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
|
||||
@@ -14595,6 +14602,12 @@
|
||||
"wide-align": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"generate-password": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.7.1.tgz",
|
||||
"integrity": "sha512-9bVYY+16m7W7GczRBDqXE+VVuCX+bWNrfYKC/2p2JkZukFb2sKxT6E3zZ3mJGz7GMe5iRK0A/WawSL3jQfJuNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"geojson-vt": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz",
|
||||
|
||||
@@ -64,27 +64,28 @@
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^20.4.2",
|
||||
"@types/passport-local": "^1.0.35",
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/react": "^18.2.15",
|
||||
"@types/sparkpost": "^2.1.5",
|
||||
"@vercel/fetch": "^7.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"daisyui": "^3.9.2",
|
||||
"dotenv-cli": "^7.2.1",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-config-airbnb-base": "15.0.0",
|
||||
"eslint-config-airbnb-typescript": "17.1.0",
|
||||
"eslint-config-next": "^13.5.4",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint": "^8.51.0",
|
||||
"generate-password": "^1.7.1",
|
||||
"onchange": "^7.1.0",
|
||||
"postcss": "^8.4.26",
|
||||
"prettier": "^3.0.0",
|
||||
"prettier-plugin-jsdoc": "^1.0.2",
|
||||
"prettier-plugin-tailwindcss": "^0.4.1",
|
||||
"prettier": "^3.0.0",
|
||||
"prisma": "^5.6.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
|
||||
13
src/config/env/index.ts
vendored
13
src/config/env/index.ts
vendored
@@ -28,6 +28,8 @@ const envSchema = z.object({
|
||||
SPARKPOST_API_KEY: z.string(),
|
||||
SPARKPOST_SENDER_ADDRESS: z.string().email(),
|
||||
MAPBOX_ACCESS_TOKEN: z.string(),
|
||||
|
||||
ADMIN_PASSWORD: z.string().regex(/^(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{8,}$/),
|
||||
});
|
||||
|
||||
const parsed = envSchema.safeParse(env);
|
||||
@@ -194,3 +196,14 @@ export const SPARKPOST_SENDER_ADDRESS = parsed.data.SPARKPOST_SENDER_ADDRESS;
|
||||
* @see https://docs.mapbox.com/help/how-mapbox-works/access-tokens/
|
||||
*/
|
||||
export const MAPBOX_ACCESS_TOKEN = parsed.data.MAPBOX_ACCESS_TOKEN;
|
||||
|
||||
/**
|
||||
* Admin password for seeding the database.
|
||||
*
|
||||
* @example
|
||||
* 'abcdefghijklmnopqrstuvwxyz123456';
|
||||
*
|
||||
* @see README.md for instructions on generating a secret key.
|
||||
*/
|
||||
|
||||
export const ADMIN_PASSWORD = parsed.data.ADMIN_PASSWORD;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { hashPassword } from '../../../config/auth/passwordFns';
|
||||
import { ADMIN_PASSWORD } from '../../../config/env';
|
||||
|
||||
import DBClient from '../../DBClient';
|
||||
import GetUserSchema from '../../../services/User/schema/GetUserSchema';
|
||||
import imageUrls from '../util/imageUrls';
|
||||
|
||||
const createAdminUser = async () => {
|
||||
const hash = await hashPassword('Pas!3word');
|
||||
const hash = await hashPassword(ADMIN_PASSWORD);
|
||||
const adminUser: z.infer<typeof GetUserSchema> = await DBClient.instance.user.create({
|
||||
data: {
|
||||
username: 'admin',
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { faker } from '@faker-js/faker';
|
||||
import generator from 'generate-password';
|
||||
|
||||
import crypto from 'crypto';
|
||||
import DBClient from '../../DBClient';
|
||||
import { hashPassword } from '../../../config/auth/passwordFns';
|
||||
import logger from '../../../config/pino/logger';
|
||||
|
||||
interface CreateNewUsersArgs {
|
||||
numberOfUsers: number;
|
||||
@@ -23,9 +26,25 @@ interface UserData {
|
||||
|
||||
const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
||||
const prisma = DBClient.instance;
|
||||
await DBClient.instance.$disconnect();
|
||||
|
||||
const passwords = Array.from({ length: numberOfUsers }, () =>
|
||||
generator.generate({
|
||||
length: 20,
|
||||
symbols: true,
|
||||
numbers: true,
|
||||
uppercase: true,
|
||||
strict: true,
|
||||
}),
|
||||
);
|
||||
|
||||
logger.info('Hashing passwords. This may take a while...');
|
||||
const hashedPasswords = await Promise.all(
|
||||
passwords.map((password) => hashPassword(password)),
|
||||
);
|
||||
|
||||
logger.info('Creating new users. This may take a while...');
|
||||
|
||||
const password = 'passwoRd!3';
|
||||
const hash = await hashPassword(password);
|
||||
const data: UserData[] = [];
|
||||
|
||||
const takenUsernames: string[] = [];
|
||||
@@ -41,6 +60,7 @@ const createNewUsers = async ({ numberOfUsers }: CreateNewUsersArgs) => {
|
||||
.email({ firstName, lastName, provider: 'example.com' })
|
||||
.toLowerCase();
|
||||
|
||||
const hash = hashedPasswords[i];
|
||||
const userAvailable =
|
||||
!takenUsernames.includes(username) && !takenEmails.includes(email);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import createNewUserFollows from './create/createNewUserFollows';
|
||||
await createAdminUser();
|
||||
logger.info('Admin user created successfully.');
|
||||
|
||||
const users = await createNewUsers({ numberOfUsers: 10000 });
|
||||
const users = await createNewUsers({ numberOfUsers: 1000 });
|
||||
logger.info('Users created successfully.');
|
||||
|
||||
const userAvatars = await createNewUserAvatars({ joinData: { users } });
|
||||
|
||||
Reference in New Issue
Block a user