Skip to content

Conversation

@Zachary-Squires
Copy link
Contributor

Description

Changes installOED.sh and docker-compose.yml to automatically generate POSTGRES_PASSWORD and OED_TOKEN_SECRET when OED is launched in production mode. This should remediate an issue where OED_TOKEN_SECRET could be forged to allow a login as an admin. Will also make the postgres database more secure as the password will be much more robust by default. Additionally, installOED.sh now specifically checks if OED_PRODUCTION is no rather than just checking if it is not yes.

Developed and implemented by:
Zachary Squires - https://github.com/Zachary-Squires
Zachary Bates - https://github.com/Zach-O-Bates

Type of change

  • Note merging this changes the database configuration.
  • This change requires a documentation update

Checklist

  • I have followed the OED pull request ideas
  • I have removed text in ( ) from the issue request
  • You acknowledge that every person contributing to this work has signed the OED Contributing License Agreement and each author is listed in the Description section.

Limitations

In order to fully remediate the insecure default configuration we will need to use a separate docker file when launching in development and production, this will be done in a separate PR since it will be intrusive to every OED developer.

Zachary-Squires and others added 2 commits November 11, 2025 13:24
Accidentally pushed with OED_PRODUCTION set to yes
Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks to @Zachary-Squires & @Zach-O-Bates for this contribution. I've made some comments to consider. I'm happy to discuss them. I did some testing but not complete as I'm going to wait for any changes to do that.

if [ -f ".env" ]; then
if grep -q "^OED_TOKEN_SECRET=" .env; then
sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment applies in a general way but put here. I'm thinking about the fact that there are settings in .env and docker-compose.yml that apply to the same case. I think originally it was designed to allow flexibility in how the values were given and to override them. I think the reality is that people don't use this ability. Also, security has become more important so I'm thinking having it in two places is less desirable since people might miss one. Finally, I think OED will be adopting new ways to set values that is more secure and easier so getting to one way now might help for that future effort. First: What do you think about getting rid of one of the ways to set these values? Second: If yes, then should we only use the docker-compose.yml file?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have thoughts on setting it this way? Do you think it should be left for now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided it could be a separate effort and just opened issue #1569 about doing this.

echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env
fi
fi
#If the user is in production and their postgres password has been left default, generating a random one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is actually changing the password for Postgres. I'm not an expert but from what I understand, the POSTGRES_PASSWORD environment variable is used when the DB is initialized. This happens at an earlier stage so the original value is used. I'm also unsure if it changes it if done on a later startup. I tried checking with login and it was not clear but seems it might be an issue. We should discuss this.

I don't know how the token is impacted or if that is okay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I did some testing and it seems like you're exactly right, for the first time since the database is created before this is run it uses the default password but after that it uses the new one. I'm not sure if there's anything I can do about that but I'm open to ideas.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this had been addressed but my testing did not find it working. I did the following:

  • Without OED running, I removed the postgres-data/ directory. This forces complete initialization of the DB on the next startup of OED.
  • I edited src/scripts/installOED.sh so it had:
if [ "$dostart" == "yes" ]; then
	if [ "$INSTALL_MODE" = "development" ]; then

so it used my development environment to force the password initialization to a script generated one.

  • Started OED and it said it set the password.
  • Shut down OED.
  • Edited postgres_data/pg_hba.conf to change trust to password in all local connections to force PG to ask for a password.
  • Restart OED.
  • Open a shell on the OED Docker database container.
    • Do psql -U oed. It asks for the password. If I give an invalid one it fails. If I use the one output by the first run of the install script then it fails. If I use the default OED PG password then it works. This is why I think it is not changing the password.

Do you have thoughts or ideas? I'm happy to talk with you about this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not currently randomizing the password for the oed user, just the postgres superuser. I can also do it for oed if you want.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting we talked about this and you are working to make that happen.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both passwords are now set but, as you told me, you have to restart OED for it to work. I know you are working on this.

Zachary-Squires and others added 4 commits November 17, 2025 17:03
Added:
1. Banners for the make sure to change this value notifications, also added a notification for the token secret.
2. Fixed spelling error.
3. Added spaces to comments.
4. A variable that checks what the installation type is at the start and is used for all checks.
Zachary-Squires and others added 3 commits December 2, 2025 23:14
Added comments in docker-compose.yml to alert users as to the fact passwords are only drawn from this file once. Added something to the .env file to show the code that the password has already been generated. Changed a redundant if statement to an else.
Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zachary-Squires Thank you for the updated version. A number of comments are now resolved. I added a new comment on a couple of old ones and added a few new ones. Please let me know if you need anything.

if [ -f ".env" ]; then
if grep -q "^OED_TOKEN_SECRET=" .env; then
sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have thoughts on setting it this way? Do you think it should be left for now?

echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env
fi
fi
#If the user is in production and their postgres password has been left default, generating a random one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought this had been addressed but my testing did not find it working. I did the following:

  • Without OED running, I removed the postgres-data/ directory. This forces complete initialization of the DB on the next startup of OED.
  • I edited src/scripts/installOED.sh so it had:
if [ "$dostart" == "yes" ]; then
	if [ "$INSTALL_MODE" = "development" ]; then

so it used my development environment to force the password initialization to a script generated one.

  • Started OED and it said it set the password.
  • Shut down OED.
  • Edited postgres_data/pg_hba.conf to change trust to password in all local connections to force PG to ask for a password.
  • Restart OED.
  • Open a shell on the OED Docker database container.
    • Do psql -U oed. It asks for the password. If I give an invalid one it fails. If I use the one output by the first run of the install script then it fails. If I use the default OED PG password then it works. This is why I think it is not changing the password.

Do you have thoughts or ideas? I'm happy to talk with you about this.

Zachary-Squires and others added 3 commits January 19, 2026 15:25
Changes to address feedback on 1/19, added/edited comments, changed changePass.js to changePostgresPass.js
Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Zachary-Squires I'm trying to get all PRs up-to-date so I looked at this one even though you are still working on it. I resolved some comments and left one to think about along with any other open ones.

console.error('Error during Postgres password change:', error.message);

if (error.message.includes('ECONNREFUSED')) {
console.error('Database is not accepting connections yet.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying what the timeout was for. In src/scripts/installOED.sh, it also checks for ECONNREFUSED and then does the wait if it happens. It also makes sure it only tries a max number of times (10) and then errors out. I think that might be better than always calling the setTimeout. Thus, I propose a loop in changePassword and wait if there is a connection error with a max number of loops before it reports and error. The wait could then be reduced to 3 seconds as in installOED.sh so it runs faster in most cases. What do you think about that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the status of this?

echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env
fi
fi
#If the user is in production and their postgres password has been left default, generating a random one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting we talked about this and you are working to make that happen.

Copy link
Member

@huss huss left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks to @Zachary-Squires for addressing many previous comments. I've made a few more to consider and commented on a few older ones. I think this is getting close.

// Update .env with PostgreSQL and OED user passwords
function updateEnvFile(postgresPassword, oedPassword) {
let env = '';
if (fs.existsSync(ENV_PATH)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some comments about what the logic is doing in this function would be helpful.


// Generate a secure random password
function generatePassword() {
return crypto.randomBytes(18).toString('base64');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tab indenting has become space indenting. Could it please be changed back. Let me know if you need any help.

if (error.message.includes('ECONNREFUSED')) {
console.error('Database is not accepting connections yet.');
} else if (error.message.includes('password authentication')) {
console.error('Authentication failed — default password may already be changed.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that it is written to .env, does this still happen regularly or is it a rare event?

I saw that if I tried to change the password twice via manually doing the npm command then it failed this way. I know you told me you were still trying to get it to work after the initial startup and I wonder if this relates to that. What I mean is maybe the process.env.POSTGRES_PASSWORD is not updated on change but I'm very uncertain about this. Whatever it is, it would be nice to track down both the initial setting and future changes. I note it seemed to work fine on the first change of the password via the npm command.

- PGDATA=/var/lib/postgresql/data/pgdata
- POSTGRES_PASSWORD=pleaseChange # default postgres password that should be changed for security.
# The postgres database will only pull from this value on the first
# startup of OED. If a change is desired after this, one must manually
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does one still have to use SQL or will the npm command now do it?

if [ -f ".env" ]; then
if grep -q "^OED_TOKEN_SECRET=" .env; then
sed -i "s/^OED_TOKEN_SECRET=.*/OED_TOKEN_SECRET=$OED_TOKEN_SECRET/" .env
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided it could be a separate effort and just opened issue #1569 about doing this.

console.error('Error during Postgres password change:', error.message);

if (error.message.includes('ECONNREFUSED')) {
console.error('Database is not accepting connections yet.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the status of this?

@@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wondering about the location of this file. All the other files in this directory are scripts of .sh, .bash, etc. Given this, would it make sense and could this be move the src/server/util/?

"webData": "node -e 'require(\"./src/server/data/websiteData.js\").insertWebsiteData()'",
"addLogMsg": "node -e 'require(\"./src/server/services/addLogMsg.js\").addLogMsgToDB()'"
"addLogMsg": "node -e 'require(\"./src/server/services/addLogMsg.js\").addLogMsgToDB()'",
"changePostgresPassword": "node ./src/scripts/changePostgresPass.js"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this directly call changePasswords() as some npm commands do above?


async function changePasswords() {
const postgresPassword = process.argv[2] || generatePassword();
const oedPassword = process.argv[2] || generatePassword();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal but should both passwords have to be the same? Maybe use [2] and [3] so can be different?

echo "OED_TOKEN_SECRET=$OED_TOKEN_SECRET" > .env
fi
fi
#If the user is in production and their postgres password has been left default, generating a random one
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both passwords are now set but, as you told me, you have to restart OED for it to work. I know you are working on this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants