Skip to content

Commit

Permalink
Add --recreateStationIdOnError (#563)
Browse files Browse the repository at this point in the history
* Add `--recreateStationIdOnError`

* add passing test

* add passing test

* add passing test, fix style

* improve error message
  • Loading branch information
juliangruber authored Aug 2, 2024
1 parent fe02c6e commit f9b5cc7
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 10 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,12 @@ $ station --help
Usage: station [options]

Options:
-j, --json Output JSON [boolean]
--experimental Also run experimental modules [boolean]
-v, --version Show version number [boolean]
-h, --help Show help [boolean]
-j, --json Output JSON [boolean]
--experimental Also run experimental modules [boolean]
--recreateStationIdOnError Recreate Station ID if it is corrupted
[boolean]
-v, --version Show version number [boolean]
-h, --help Show help [boolean]
```
### `$ station --version`
Expand Down
6 changes: 5 additions & 1 deletion bin/station.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ yargs(hideBin(process.argv))
.option('experimental', {
type: 'boolean',
description: 'Also run experimental modules'
})
.option('recreateStationIdOnError', {
type: 'boolean',
description: 'Recreate Station ID if it is corrupted'
}),
({ json, experimental }) => station({ json, experimental })
({ json, experimental, recreateStationIdOnError }) => station({ json, experimental, recreateStationIdOnError })
)
.version(`${pkg.name}: ${pkg.version}`)
.alias('v', 'version')
Expand Down
4 changes: 2 additions & 2 deletions commands/station.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const panic = (msg, exitCode = 1) => {
process.exit(exitCode)
}

export const station = async ({ json, experimental }) => {
export const station = async ({ json, recreateStationIdOnError, experimental }) => {
if (!FIL_WALLET_ADDRESS) panic('FIL_WALLET_ADDRESS required')
if (FIL_WALLET_ADDRESS.startsWith('f1')) {
panic('Invalid FIL_WALLET_ADDRESS: f1 addresses are currently not supported. Please use an f4 or 0x address.')
Expand All @@ -46,7 +46,7 @@ export const station = async ({ json, experimental }) => {
panic('Invalid FIL_WALLET_ADDRESS ethereum address', 2)
}

const keypair = await getStationId({ secretsDir: paths.secrets, passphrase: PASSPHRASE })
const keypair = await getStationId({ secretsDir: paths.secrets, passphrase: PASSPHRASE, recreateOnError: recreateStationIdOnError })
const STATION_ID = keypair.publicKey

const fetchRes = await pRetry(
Expand Down
8 changes: 5 additions & 3 deletions lib/station-id.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { subtle, getRandomValues } from 'node:crypto'
* @param {object} args
* @param {string} args.secretsDir
* @param {string} args.passphrase
* @param {boolean} [args.recreateOnError]
* @param {import('node:console')} [args.log]
* @returns {Promise<{publicKey: string, privateKey: string}>}
*/
export async function getStationId ({ secretsDir, passphrase, log = console }) {
export async function getStationId ({ secretsDir, passphrase, recreateOnError = false, log = console }) {
assert.strictEqual(typeof secretsDir, 'string', 'secretsDir must be a string')

await fs.mkdir(secretsDir, { recursive: true })
Expand All @@ -21,7 +22,8 @@ export async function getStationId ({ secretsDir, passphrase, log = console }) {
log.error('Loaded Station ID: %s', keypair.publicKey)
return keypair
} catch (err) {
if (err.code === 'ENOENT' && err.path === keystore) {
if (recreateOnError || (err.code === 'ENOENT' && err.path === keystore)) {
if (recreateOnError) console.error(err)
// the keystore file does not exist, create a new key
return await generateKeypair(keystore, passphrase, { log })
} else {
Expand Down Expand Up @@ -61,7 +63,7 @@ async function loadKeypair (keystore, passphrase, { log }) {
plaintext = await decrypt(passphrase, ciphertext)
} catch (err) {
throw new Error(
'Cannot decrypt Station ID file. Did you configure the correct PASSPHRASE?',
'Cannot decrypt Station ID file. Did you configure the correct PASSPHRASE? Alternatively overwrite it using `--recreateStationIdOnError`',
{ cause: err }
)
}
Expand Down
53 changes: 53 additions & 0 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,59 @@ describe('CLI', () => {
await once(ps.stdout, 'data')
ps.kill()
})
it('fails with the wrong pass phrase', async () => {
const STATE_ROOT = getUniqueTempDir()
const ps = execa(station, {
env: {
STATE_ROOT,
FIL_WALLET_ADDRESS,
PASSPHRASE
}
})
await once(ps.stdout, 'data')
ps.kill()
try {
await execa(station, {
env: {
STATE_ROOT,
FIL_WALLET_ADDRESS,
PASSPHRASE: `${PASSPHRASE}x`
}
})
} catch (err) {
assert.strictEqual(err.exitCode, 1)
return
}
assert.fail('Expected Station Core to return a non-zero exit code')
})
})

describe('--recreateStationIdOnError', () => {
it('recreates the station id on demand', async () => {
const STATE_ROOT = getUniqueTempDir()
{
const ps = execa(station, {
env: {
STATE_ROOT,
FIL_WALLET_ADDRESS,
PASSPHRASE
}
})
await once(ps.stdout, 'data')
ps.kill()
}
{
const ps = execa(station, ['--recreateStationIdOnError'], {
env: {
STATE_ROOT,
FIL_WALLET_ADDRESS,
PASSPHRASE: `${PASSPHRASE}x`
}
})
await once(ps.stdout, 'data')
ps.kill()
}
})
})

describe('--version', () => {
Expand Down
6 changes: 6 additions & 0 deletions test/station-id.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ describe('station-id', () => {
)
})

it('recreates unreadable station ids on demand', async () => {
const secretsDir = getUniqueTempDir()
await getStationId({ secretsDir, passphrase: 'secret', log })
await getStationId({ secretsDir, passphrase: 'new pass', recreateOnError: true, log })
})

it('encrypts plaintext station_id file when PASSPHRASE is provided', async () => {
const secretsDir = getUniqueTempDir()
const generated = await getStationId({ secretsDir, passphrase: '', log })
Expand Down

0 comments on commit f9b5cc7

Please sign in to comment.