Skip to content

Commit

Permalink
Merge pull request #795 from motdotla/error-codes
Browse files Browse the repository at this point in the history
add error.code(s)
  • Loading branch information
motdotla authored Jan 23, 2024
2 parents 883d6a6 + 8911035 commit 55ca625
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. See [standa

## [Unreleased](https://github.com/motdotla/dotenv/compare/v16.3.1...master)

- Add `error.code` to error messages around `.env.vault` decryption [#795](https://github.com/motdotla/dotenv/pull/795)

## [16.3.2](https://github.com/motdotla/dotenv/compare/v16.3.1...v16.3.2) (2024-01-18)

### Added
Expand Down
36 changes: 24 additions & 12 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ function _parseVault (options) {
// Parse .env.vault
const result = DotenvModule.configDotenv({ path: vaultPath })
if (!result.parsed) {
throw new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)
const err = new Error(`MISSING_DATA: Cannot parse ${vaultPath} for an unknown reason`)
err.code = 'MISSING_DATA'
throw err
}

// handle scenario for comma separated keys - for use with key rotation
Expand Down Expand Up @@ -121,7 +123,9 @@ function _instructions (result, dotenvKey) {
uri = new URL(dotenvKey)
} catch (error) {
if (error.code === 'ERR_INVALID_URL') {
throw new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:[email protected]/vault/.env.vault?environment=development')
const err = new Error('INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:[email protected]/vault/.env.vault?environment=development')
err.code = 'INVALID_DOTENV_KEY'
throw err
}

throw error
Expand All @@ -130,20 +134,26 @@ function _instructions (result, dotenvKey) {
// Get decrypt key
const key = uri.password
if (!key) {
throw new Error('INVALID_DOTENV_KEY: Missing key part')
const err = new Error('INVALID_DOTENV_KEY: Missing key part')
err.code = 'INVALID_DOTENV_KEY'
throw err
}

// Get environment
const environment = uri.searchParams.get('environment')
if (!environment) {
throw new Error('INVALID_DOTENV_KEY: Missing environment part')
const err = new Error('INVALID_DOTENV_KEY: Missing environment part')
err.code = 'INVALID_DOTENV_KEY'
throw err
}

// Get ciphertext payload
const environmentKey = `DOTENV_VAULT_${environment.toUpperCase()}`
const ciphertext = result.parsed[environmentKey] // DOTENV_VAULT_PRODUCTION
if (!ciphertext) {
throw new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)
const err = new Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${environmentKey} in your .env.vault file.`)
err.code = 'NOT_FOUND_DOTENV_ENVIRONMENT'
throw err
}

return { ciphertext, key }
Expand Down Expand Up @@ -255,14 +265,14 @@ function decrypt (encrypted, keyStr) {
const decryptionFailed = error.message === 'Unsupported state or unable to authenticate data'

if (isRange || invalidKeyLength) {
const msg = 'INVALID_DOTENV_KEY: It must be 64 characters long (or more)'
throw new Error(msg)
const err = new Error('INVALID_DOTENV_KEY: It must be 64 characters long (or more)')
err.code = 'INVALID_DOTENV_KEY'
throw err
} else if (decryptionFailed) {
const msg = 'DECRYPTION_FAILED: Please check your DOTENV_KEY'
throw new Error(msg)
const err = new Error('DECRYPTION_FAILED: Please check your DOTENV_KEY')
err.code = 'DECRYPTION_FAILED'
throw err
} else {
console.error('Error: ', error.code)
console.error('Error: ', error.message)
throw error
}
}
Expand All @@ -274,7 +284,9 @@ function populate (processEnv, parsed, options = {}) {
const override = Boolean(options && options.override)

if (typeof parsed !== 'object') {
throw new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
const err = new Error('OBJECT_REQUIRED: Please check the processEnv argument being passed to populate')
err.code = 'OBJECT_REQUIRED'
throw err
}

// Set process.env
Expand Down
24 changes: 16 additions & 8 deletions tests/test-config-vault.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,31 @@ t.test('returns parsed object', ct => {
})

t.test('throws not found if .env.vault is empty', ct => {
ct.plan(1)
ct.plan(2)

const readFileSync = sinon.stub(fs, 'readFileSync').returns('') // empty file

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment DOTENV_VAULT_DEVELOPMENT in your .env.vault file.')
ct.equal(e.code, 'NOT_FOUND_DOTENV_ENVIRONMENT')
}

readFileSync.restore()
ct.end()
})

t.test('throws missing data when somehow parsed badly', ct => {
ct.plan(1)
ct.plan(2)

const configDotenvStub = sinon.stub(dotenv, 'configDotenv').returns({ parsed: undefined })

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'MISSING_DATA: Cannot parse tests/.env.vault for an unknown reason')
ct.equal(e.code, 'MISSING_DATA')
}

configDotenvStub.restore()
Expand All @@ -99,12 +101,13 @@ t.test('throws error when invalid formed DOTENV_KEY', ct => {
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('invalid-format-non-uri-format')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:[email protected]/vault/.env.vault?environment=development')
ct.equal(e.code, 'INVALID_DOTENV_KEY')
}

ct.end()
Expand Down Expand Up @@ -132,12 +135,13 @@ t.test('throws error when DOTENV_KEY missing password', ct => {
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('dotenv://[email protected]/vault/.env.vault?environment=development')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'INVALID_DOTENV_KEY: Missing key part')
ct.equal(e.code, 'INVALID_DOTENV_KEY')
}

ct.end()
Expand All @@ -147,12 +151,13 @@ t.test('throws error when DOTENV_KEY missing environment', ct => {
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('dotenv://:key_ddcaa26504cd70a6fef9801901c3981538563a1767c297cb8416e8a38c62fe00@dotenv.org/vault/.env.vault')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'INVALID_DOTENV_KEY: Missing environment part')
ct.equal(e.code, 'INVALID_DOTENV_KEY')
}

ct.end()
Expand Down Expand Up @@ -247,12 +252,13 @@ t.test('raises an INVALID_DOTENV_KEY if key RangeError', ct => {
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('dotenv://:[email protected]/vault/.env.vault?environment=development')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'INVALID_DOTENV_KEY: It must be 64 characters long (or more)')
ct.equal(e.code, 'INVALID_DOTENV_KEY')
}

ct.end()
Expand All @@ -262,12 +268,13 @@ t.test('raises an DECRYPTION_FAILED if key fails to decrypt payload', ct => {
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('dotenv://:key_2c4d267b8c3865f921311612e69273666cc76c008acb577d3e22bc3046fba386@dotenv.org/vault/.env.vault?environment=development')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'DECRYPTION_FAILED: Please check your DOTENV_KEY')
ct.equal(e.code, 'DECRYPTION_FAILED')
}

ct.end()
Expand All @@ -277,12 +284,13 @@ t.test('raises an DECRYPTION_FAILED if both (comma separated) keys fail to decry
envStub.restore()
envStub = sinon.stub(process.env, 'DOTENV_KEY').value('dotenv://:key_2c4d267b8c3865f921311612e69273666cc76c008acb577d3e22bc3046fba386@dotenv.org/vault/.env.vault?environment=development,dotenv://:key_c04959b64473e43dd60c56a536ef8481388528b16759736d89515c25eec69247@dotenv.org/vault/.env.vault?environment=development')

ct.plan(1)
ct.plan(2)

try {
dotenv.config({ path: testPath })
} catch (e) {
ct.equal(e.message, 'DECRYPTION_FAILED: Please check your DOTENV_KEY')
ct.equal(e.code, 'DECRYPTION_FAILED')
}

ct.end()
Expand Down

0 comments on commit 55ca625

Please sign in to comment.