-
Notifications
You must be signed in to change notification settings - Fork 488
Adding Support for Infisical Password Vault #1609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
Zachary-Squires
wants to merge
28
commits into
OpenEnergyDashboard:development
Choose a base branch
from
Zachary-Squires:password-vault
base: development
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
f3aef3a
Fixes to remediate Issue 2
Zachary-Squires 204f0ef
Update docker-compose.yml
Zachary-Squires 759870d
Update docker-compose.yml to put comments above line
Zachary-Squires a817ee5
Update docker-compose.yml to remove double empty line with spaces at …
Zachary-Squires 4c8354f
Implement PR #1554 Suggestions
Zachary-Squires fa7baf5
Removing extra line at the end of docker-compose.yml
Zachary-Squires 52815d0
Changes to address feedback on PR #1554
Zachary-Squires 805e369
Merge branch 'OpenEnergyDashboard:development' into development
Zachary-Squires 1d3bcc6
Changes to Address Feedback
Zachary-Squires 0d5fa73
Merge branch 'OpenEnergyDashboard:development' into development
Zachary-Squires 05b62c4
Changes to address feedback
Zachary-Squires 5a002c8
Restore executable bit
Zachary-Squires b958b00
Changes to address most recent feedback on PR #1554
Zachary-Squires 1d8c650
Changes to address comments on PR #1554 from Feb 4th
Zachary-Squires 90e5140
Merge branch 'OpenEnergyDashboard:development' into development
Zachary-Squires 3fbc0c2
Changes to address feedback, no restart on install
Zachary-Squires 0211c28
Typo
Zachary-Squires f11c826
Fix for accidentally setting passwords to the defaults
Zachary-Squires ab538b9
Merge branch 'development' into development
Zachary-Squires a8c12ac
Revert commit from OED in docker-compose.yml that makes it crash
Zachary-Squires 99ce3d0
Changes to address 4/9 feedback on #1554
Zachary-Squires 0199d6b
Adding a confirmation when manually changing the password
Zachary-Squires 24e2fb3
Revert "Merge branch 'development' into development"
Zachary-Squires 43d4ef8
Adding support for infisical password vault
Zachary-Squires b5fd5e0
Reverting README.md change
Zachary-Squires 394c93d
Revert "Revert "Merge branch 'development' into development""
Zachary-Squires 54b3791
Changes to address 4/21 feedback on PR #1609
Zachary-Squires 8439239
Merge branch 'OpenEnergyDashboard:development' into password-vault
Zachary-Squires File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| /* 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 | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
|
||
| const { Client } = require('pg'); | ||
| const crypto = require('crypto'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
| const readline = require('readline'); | ||
| const dotenv = require('dotenv'); | ||
|
|
||
| const ROOT_ENV_PATH = path.resolve(__dirname, '..', '..', '..', '.env'); | ||
| const CWD_ENV_PATH = path.resolve(process.cwd(), '.env'); | ||
| const ENV_PATH = fs.existsSync(ROOT_ENV_PATH) ? ROOT_ENV_PATH : CWD_ENV_PATH; | ||
|
|
||
| // Load whichever .env file is available and override existing process vars | ||
| // so repeated invocations in one session can pick up the newest credentials. | ||
| if (fs.existsSync(ENV_PATH)) { | ||
| dotenv.config({ path: ENV_PATH, override: true }); | ||
| } | ||
|
|
||
| // Parse the shared .env file directly so we can prefer the most recent values | ||
| // when npm or Docker still has a stale environment variable. | ||
| function parseEnvFile(envPath) { | ||
| if (!fs.existsSync(envPath)) { | ||
| return {}; | ||
| } | ||
|
|
||
| return dotenv.parse(fs.readFileSync(envPath, 'utf8')); | ||
| } | ||
|
|
||
| // Generate a secure random password | ||
| function generatePassword() { | ||
| return crypto.randomBytes(32).toString('base64'); | ||
| } | ||
|
|
||
| // Escape single quotes in password for SQL | ||
| function escapePassword(password) { | ||
| return password.replace(/'/g, "''"); | ||
| } | ||
|
|
||
| // Prompt the user for an explicit yes/no confirmation | ||
| function promptConfirmation(promptText) { | ||
| const rl = readline.createInterface({ | ||
| input: process.stdin, | ||
| output: process.stdout | ||
| }); | ||
|
|
||
| return new Promise((resolve) => { | ||
| rl.question(`${promptText} `, (answer) => { | ||
| rl.close(); | ||
| resolve(answer.trim().toLowerCase() === 'yes'); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| // Update .env with PostgreSQL and OED user passwords | ||
| function updateEnvFile(postgresPassword, oedPassword) { | ||
| let env = ''; | ||
|
|
||
| // Reading current .env contents if it exists | ||
| if (fs.existsSync(ENV_PATH)) { | ||
| env = fs.readFileSync(ENV_PATH, 'utf8'); | ||
| } | ||
|
|
||
| // Updating the postgres password if it exists, else appending it instead | ||
| if (/^POSTGRES_PASSWORD=/m.test(env)) { | ||
| env = env.replace(/^POSTGRES_PASSWORD=.*/m, `POSTGRES_PASSWORD=${postgresPassword}`); | ||
| } else { | ||
| env = env.trimEnd() + `\nPOSTGRES_PASSWORD=${postgresPassword}\n`; | ||
| } | ||
|
|
||
| // Updating the oed user password if it exists, else appending it instead | ||
| if (/^OED_DB_PASSWORD=/m.test(env)) { | ||
| env = env.replace(/^OED_DB_PASSWORD=.*/m, `OED_DB_PASSWORD=${oedPassword}`); | ||
| } else { | ||
| env = env.trimEnd() + `\nOED_DB_PASSWORD=${oedPassword}\n`; | ||
| } | ||
|
|
||
| // Writing new passwords to .env or creating it if it doesn't exist yet, only allowing the current user to read and write | ||
| fs.writeFileSync(ENV_PATH, env, { mode: 0o600 }); | ||
| console.log('.env updated with new PostgreSQL and OED passwords'); | ||
| } | ||
|
|
||
| // Pause execution | ||
| function sleep(ms) { | ||
| return new Promise((resolve) => setTimeout(resolve, ms)); | ||
| } | ||
|
|
||
| // Detect retryable Postgres errors: | ||
| // 'tuple concurrently updated': row was modified by another transaction | ||
| // 40001 (serialization_failure): concurrent transaction conflict | ||
| // 55P03 (lock_not_available): couldn't acquire lock, may be freed soon | ||
| function shouldRetryError(error) { | ||
| return ( | ||
| error.message.includes('tuple concurrently updated') || | ||
| (error.code && (error.code === '40001' || error.code === '55P03')) | ||
| ); | ||
| } | ||
|
|
||
| // Change the database passwords for both the default postgres user and the OED user | ||
| // if this is done after the initial setup, OED must be restarted to get a connection with the server | ||
| async function changePasswords() { | ||
| const fileEnv = parseEnvFile(ENV_PATH); | ||
|
|
||
| // Determine context: 'install' (automatic, no restart needed) or 'manual' (script, restart needed) | ||
| const isManual = process.argv[4] !== 'install'; | ||
|
|
||
| // Warn if manual invocation that all OED users will lose access until restart | ||
| if (isManual) { | ||
| console.error(''); | ||
| console.error('WARNING: This will change database passwords immediately.'); | ||
| console.error('All currently logged-in users will experience disconnections.'); | ||
| console.error('OED will not work for anyone until the server is restarted.'); | ||
| console.error(''); | ||
|
|
||
| const confirmed = await promptConfirmation('Do you want to continue? Type yes to proceed:'); | ||
| if (!confirmed) { | ||
| console.error('Aborting password change. No changes were made.'); | ||
| process.exit(0); | ||
| } | ||
| } | ||
|
|
||
| // Prefer the most recent passwords from the .env file over process.env which may be outdated | ||
| if (fileEnv.POSTGRES_PASSWORD) { | ||
| process.env.POSTGRES_PASSWORD = fileEnv.POSTGRES_PASSWORD; | ||
| } | ||
| if (fileEnv.OED_DB_PASSWORD) { | ||
| process.env.OED_DB_PASSWORD = fileEnv.OED_DB_PASSWORD; | ||
| } | ||
|
|
||
| // If arguments are included, treat them as the new passwords | ||
| const currentPostgresPassword = fileEnv.POSTGRES_PASSWORD || process.env.POSTGRES_PASSWORD || 'pleaseChange'; | ||
| const newPostgresPassword = process.argv[2] || generatePassword(); | ||
| const newOedPassword = process.argv[3] || generatePassword(); | ||
|
|
||
| const clientConfig = { | ||
| host: process.env.OED_DB_HOST || 'database', | ||
| port: parseInt(process.env.OED_DB_PORT || '5432', 10), | ||
| user: 'postgres', | ||
| password: currentPostgresPassword, | ||
| database: 'postgres', | ||
| connectionTimeoutMillis: 10000 | ||
| }; | ||
|
|
||
| // Try the password update multiple times to handle transient lock error | ||
| for (let attempt = 1; attempt <= 3; attempt += 1) { | ||
| const client = new Client(clientConfig); | ||
|
|
||
| try { | ||
| await client.connect(); | ||
|
|
||
| const sqlPostgres = `ALTER USER postgres WITH PASSWORD '${escapePassword(newPostgresPassword)}'`; | ||
| await client.query(sqlPostgres); | ||
|
|
||
| const sqlOED = `ALTER USER oed WITH PASSWORD '${escapePassword(newOedPassword)}'`; | ||
| await client.query(sqlOED); | ||
|
|
||
| await client.end(); | ||
|
|
||
| updateEnvFile(newPostgresPassword, newOedPassword); | ||
|
|
||
| console.log('********************************************************************************'); | ||
| console.log('Generated a secure PostgreSQL and OED password and applied them successfully.'); | ||
| console.log('The passwords have been stored in ".env" for reference.'); | ||
| if (isManual) { | ||
| console.log(''); | ||
| console.log('CRITICAL: OED is now disconnected for all users.'); | ||
| console.log('You must restart OED immediately for it to function.'); | ||
| console.log('All active user sessions will be terminated.'); | ||
| } else { | ||
| console.log('(Installation mode: restart not required)'); | ||
| } | ||
| console.log('********************************************************************************\n'); | ||
|
|
||
| process.exit(0); | ||
| } catch (error) { | ||
| await client.end().catch(() => {}); | ||
|
|
||
| if (shouldRetryError(error) && attempt < 3) { | ||
| console.error(`Transient Postgres error on attempt ${attempt}: ${error.message}`); | ||
| console.error('Retrying password update...'); | ||
| await sleep(1000 * attempt); | ||
| continue; | ||
| } | ||
|
|
||
| console.error('Error changing PostgreSQL or OED password:', error.message); | ||
|
|
||
| if (error.message.includes('password authentication')) { | ||
| console.error('Authentication failed: default password may already be changed or password used is incorrect.'); | ||
| } | ||
|
|
||
| process.exit(1); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| changePasswords(); | ||
| } | ||
|
|
||
| module.exports = { changePasswords }; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the design doc is in place for OED, it might be nice to put a link to it here so people can easily find the directions for enabling the vault.