Skip to content

Commit

Permalink
Fix default localhost in mail server. (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonepl authored Nov 30, 2024
1 parent 4239d4c commit cfed58c
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 30 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ dist-ssr


mail-server/.env
mail-server/.env.local.config
mail-server/.env.local.secret
mail-server/.env.config
mail-server/.env.secret
mail-server/coverage
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ This web portfolio runs an Nginx web server to host the static files within a do

This web portfolio uses a NodeJS mail server which you must configured to send emails.

* Read name `.env.local.config.example` to `.env.local.config` and update PORT value if needed
* Read name `.env.local.secret.example` to `.env.local.secret` and provide the
* Read name `.env.config.example` to `.env.config` and update PORT value if needed
* Read name `.env.secret.example` to `.env.secret` and provide the

```
# Email server
Expand Down
4 changes: 2 additions & 2 deletions entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ create_network() {
create_secret() {
if ! docker secret ls | grep -q "mail_server_secret"; then
log_message "INFO" "Creating Docker secret 'mail_server_secret'..."
docker secret create mail_server_secret $MAIL_SERVER_DIR/.env.local.secret
docker secret create mail_server_secret $MAIL_SERVER_DIR/.env.secret
else
log_message "INFO" "Docker secret 'mail_server_secret' already exists."
fi
Expand All @@ -54,7 +54,7 @@ create_secret() {
create_config() {
if ! docker config ls | grep -q "mail_server_config"; then
log_message "INFO" "Creating Docker config 'mail_server_config'..."
docker config create mail_server_config $MAIL_SERVER_DIR/.env.local.config
docker config create mail_server_config $MAIL_SERVER_DIR/.env.config
else
log_message "INFO" "Docker config 'mail_server_config' already exists."
fi
Expand Down
2 changes: 2 additions & 0 deletions mail-server/.env.config.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
EMAIL_PORT=3000
EMAIL_HOST=localhost
1 change: 0 additions & 1 deletion mail-server/.env.local.config.example

This file was deleted.

File renamed without changes.
6 changes: 6 additions & 0 deletions mail-server/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Change Log

# 1.0.2
* Fix default localhost in mail server. Fix text alignment in UI

# 1.0.1
* Fix mail server config target directory

## 1.0.0
* Initial Commit.
2 changes: 1 addition & 1 deletion mail-server/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.1
1.0.2
3 changes: 3 additions & 0 deletions mail-server/routes/email.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ const nodemailer = require('nodemailer');
const router = express.Router();

const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOST,
port: process.env.EMAIL_PORT,
service: process.env.SERVICE,
secure: false,
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
Expand Down
6 changes: 3 additions & 3 deletions mail-server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ const app = express();
loadEnv();

app.use(express.json());
app.set('trust proxy', 1);

// Middlewares
applyCorsMiddleware(app);

// Setup routes
app.use('/send-email', emailRateLimiter, sendEmailRoutes);

const PORT = process.env.PORT || 3000;
if (process.env.NODE_ENV !== 'test') {
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
app.listen(process.env.EMAIL_PORT, () => {
console.log(`Server running on port ${process.env.EMAIL_PORT}`);
});
}

Expand Down
25 changes: 21 additions & 4 deletions mail-server/utils/envHelper.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
const fs = require('fs');
const path = require('path');
const { exit } = require('process');

const REQUIRED_ENV_VARS = ['SERVICE', 'EMAIL_USER', 'EMAIL_PASS', 'FORWARD_EMAIL_USER'];
const REQUIRED_SECRETS = ['SERVICE', 'EMAIL_USER', 'EMAIL_PASS', 'FORWARD_EMAIL_USER'];
const SECRETS_PATH = '/run/secrets/mail_server_secret';
const CONFIG_PATH = '/run/config/mail_server_config';

// Load environment variables
function loadEnv() {
loadEnvFromFile(SECRETS_PATH);
loadEnvFromFile(CONFIG_PATH);
process.env["NODE_ENV"] = process.env.NODE_ENV || 'production';
loadEnvDefaults();
};

function loadEnvFromFile(filePath) {
Expand Down Expand Up @@ -39,7 +38,7 @@ function loadEnvFromFile(filePath) {
});

// Check for missing required environment variables
const missingVars = REQUIRED_ENV_VARS.filter((varName) => !process.env[varName]);
const missingVars = REQUIRED_SECRETS.filter((varName) => !process.env[varName]);
if (missingVars.length > 0) {
console.error(`Missing required environment variables: ${missingVars.join(', ')}`);
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
Expand All @@ -55,4 +54,22 @@ function loadEnvFromFile(filePath) {
}
}

function loadEnvDefaults() {
if (process.env.NODE_ENV === undefined) {
console.info("NODE_ENV is undefined, defaulting to 'production'");
}

if (process.env.EMAIL_PORT === undefined) {
console.info("EMAIL_PORT is undefined, defaulting to 3000");
}

if (process.env.EMAIL_HOST === undefined) {
console.info("EMAIL_HOST is undefined, defaulting to 'localhost'");
}

process.env["NODE_ENV"] = process.env.NODE_ENV || 'production';
process.env["EMAIL_PORT"] = process.env.EMAIL_PORT || 3000;
process.env["EMAIL_HOST"] = process.env.EMAIL_HOST || "localhost";
}

module.exports = loadEnv;
33 changes: 18 additions & 15 deletions mail-server/utils/envHelper.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// loadEnv.test.js

const fs = require('fs');
const path = require('path');
const { exit } = require('process');
const loadEnv = require('./envHelper'); // Path to your loadEnv.js file
const loadEnv = require('./envHelper');


// Mock the external dependencies
jest.mock('fs');
jest.mock('path');
jest.mock('process', () => ({
Expand All @@ -13,65 +13,68 @@ jest.mock('process', () => ({
}));

describe('loadEnv', () => {
const requiredEnvVars = ['SERVICE', 'EMAIL_USER', 'EMAIL_PASS', 'FORWARD_EMAIL_USER'];
const requiredEnvVars = ['SERVICE', 'EMAIL_USER', 'EMAIL_PASS', 'EMAIL_HOST', 'EMAIL_PORT', 'FORWARD_EMAIL_USER'];
const SECRETS_PATH = '/run/secrets/mail_server_secret';
const CONFIG_PATH = '/run/config/mail_server_config';

beforeEach(() => {
// Clear process.env before each test to ensure a clean environment
requiredEnvVars.forEach((varName) => {
delete process.env[varName];
});
jest.clearAllMocks();
});

it('should load environment variables from valid files', () => {
// Arrange: mock fs to simulate file existence and content
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nEMAIL_PASS=value3\nFORWARD_EMAIL_USER=value4');
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nEMAIL_PASS=value3\nFORWARD_EMAIL_USER=value4\nEMAIL_PORT=1234\nEMAIL_HOST=example.com');

loadEnv();

// Assert: verify that the environment variables are set correctly
expect(process.env.SERVICE).toBe('value1');
expect(process.env.EMAIL_USER).toBe('value2');
expect(process.env.EMAIL_PASS).toBe('value3');
expect(process.env.FORWARD_EMAIL_USER).toBe('value4');
expect(exit).not.toHaveBeenCalled();
expect(process.env.EMAIL_PORT).toBe('1234');
expect(process.env.EMAIL_HOST).toBe('example.com');
});

it('should load default config environment variables if files do not exist', () => {
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nEMAIL_PASS=value3\nFORWARD_EMAIL_USER=value4');

loadEnv();

expect(process.env.EMAIL_PORT).toBe('3000');
expect(process.env.EMAIL_HOST).toBe('localhost');
})

it('should log a warning and exit if a file does not exist', () => {
// Arrange: mock fs to simulate file not found
fs.existsSync.mockReturnValue(false);

expect(() => loadEnv()).toThrow('File not found: /run/secrets/mail_server_secret');
});

it('should log a warning and exit if required environment variables are missing', () => {
// Arrange: mock fs to simulate file existence and content
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nEMAIL_PASS=value3');

expect(() => loadEnv()).toThrow('Missing required environment variables: FORWARD_EMAIL_USER');
});

it('should log a warning if a line in the file is malformed', () => {
// Arrange: mock fs to simulate file with malformed line
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nFORWARD_EMAIL_USER= value3\nEMAIL_PASS=\n\nBAD_LINE');

expect(() => loadEnv()).toThrow('Missing required environment variables: EMAIL_PASS');
});

it('should not load environment variables if NODE_ENV is "development"', () => {
// Arrange: mock fs to simulate file existence and content
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('SERVICE=value1\nEMAIL_USER=value2\nEMAIL_PASS=value3\nFORWARD_EMAIL_USER=value4');
process.env.NODE_ENV = 'development';

loadEnv();

// Assert: verify that the environment variables are not loaded in development mode

expect(process.env.SERVICE).toBeUndefined();
expect(process.env.EMAIL_USER).toBeUndefined();
expect(process.env.EMAIL_PASS).toBeUndefined();
Expand Down
6 changes: 6 additions & 0 deletions portfolio/src/sections/Hero/HeroStyles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
}
}

@media (width <= 800px) {
.description {
max-width: 34ch;
}
}

@media (width >= 1400px) {
.container {
.hero {
Expand Down

0 comments on commit cfed58c

Please sign in to comment.