-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: create config automatically if not provided (#151)
* feat: create config automatically if not provided * fix: better XDG config folder convention * feat: use jsonc-parser for reading config * fix: better internet citizenship * chore: ignore persistent datastore * chore: move default config to another file * docs: add default config example to README * chore: apply suggestions from code review * chore: derive PeerID from privateKey and remove from config * chore: simplify config path * chore: remove unused dep --------- Co-authored-by: Daniel N <[email protected]>
- Loading branch information
Showing
10 changed files
with
183 additions
and
63 deletions.
There are no files selected for viewing
This file contains 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 |
---|---|---|
|
@@ -13,3 +13,4 @@ config/grafana/alerting | |
js-libp2p-datastore | ||
config.json | ||
listening-addrs.txt | ||
datastore |
This file contains 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 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
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains 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 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 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,69 @@ | ||
/* eslint-disable no-console */ | ||
/** | ||
* If a config option isn't used, and a user doesn't already have a config file, | ||
* we should automatically generate one by calling `ipfs init` or similar with | ||
* the Kubo npm package. | ||
*/ | ||
import { writeFile, mkdir, access, constants } from 'node:fs/promises' | ||
import { homedir } from 'node:os' | ||
import { join, isAbsolute } from 'node:path' | ||
import { generateKeyPair } from '@libp2p/crypto/keys' | ||
import { defaultConfig, type BootstrapConfig } from './default-config.js' | ||
import { readConfig } from './load-config.js' | ||
import { encodePrivateKey } from './peer-id.js' | ||
|
||
export const CONFIG_FOLDER = join(homedir(), '.config', '@libp2p', 'amino-dht-bootstrapper') | ||
export const DEFAULT_CONFIG_NAME = 'config.json' | ||
export const CONFIG_PATH = join(CONFIG_FOLDER, DEFAULT_CONFIG_NAME) | ||
|
||
/** | ||
* check if DEFAULT_CONFIG_NAME exists, if it does, use it automatically | ||
* if not, copy `defaultConfig` to `${CONFIG_FOLDER}/config.json` | ||
* create a private key and peer ID and add it to the config | ||
*/ | ||
export async function autoConfig (configPathArg?: string): Promise<BootstrapConfig> { | ||
if (configPathArg != null) { | ||
console.info('Attempting to use config file from %s', configPathArg) | ||
/** | ||
* If a config path is provided, attempt to use it. | ||
* If it's not an absolute path, assume it's relative to the current working directory. | ||
*/ | ||
const configFilepath = isAbsolute(configPathArg) ? configPathArg : join(process.cwd(), configPathArg) | ||
return readConfig(configFilepath) | ||
} | ||
|
||
console.info('Checking for config file at %s', CONFIG_PATH) | ||
try { | ||
const config = readConfig(CONFIG_PATH) | ||
console.info('Config file found') | ||
return config | ||
} catch { | ||
console.info('No config file found, generating one automatically...') | ||
} | ||
|
||
// check for config folder existence, if it doesn't exist, create it. | ||
try { | ||
console.info('Checking for config folder at %s', CONFIG_FOLDER) | ||
await access(CONFIG_FOLDER, constants.R_OK | constants.W_OK) | ||
} catch (e) { | ||
console.info('Config folder not found, creating it...') | ||
await mkdir(CONFIG_FOLDER, { recursive: true }) | ||
} | ||
|
||
try { | ||
console.info('Using default config object: %O', defaultConfig) | ||
const configJson = { ...defaultConfig } | ||
|
||
console.info('Generating private key and peer ID...') | ||
const libp2pGeneratedPrivateKey = await generateKeyPair('Ed25519') | ||
configJson.privateKey = encodePrivateKey(libp2pGeneratedPrivateKey) | ||
|
||
console.info('Writing config file') | ||
await writeFile(CONFIG_PATH, JSON.stringify(configJson, null, 2)) | ||
console.info('Config file created successfully at %s', CONFIG_PATH) | ||
return configJson | ||
} catch (e) { | ||
console.error('Error creating config', e) | ||
throw e | ||
} | ||
} |
This file contains 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,36 @@ | ||
import type { BootstrapInit } from '@libp2p/bootstrap' | ||
import type { AddressManagerInit, ConnectionManagerInit } from 'libp2p' | ||
|
||
export interface BootstrapConfig { | ||
addresses: Omit<AddressManagerInit, 'announceFilter'> | ||
connectionManager: ConnectionManagerInit | ||
bootstrap: BootstrapInit | ||
privateKey: string | ||
} | ||
|
||
export const defaultConfig: BootstrapConfig = { | ||
addresses: { | ||
announce: [], | ||
noAnnounce: [], | ||
listen: [ | ||
'/ip4/0.0.0.0/tcp/4003/ws', | ||
'/ip4/0.0.0.0/tcp/4001', | ||
'/ip6/::/tcp/4004/ws', | ||
'/ip6/::/tcp/4001', | ||
'/ip4/0.0.0.0/udp/4002/webrtc' | ||
] | ||
}, | ||
bootstrap: { | ||
list: [ | ||
'/dns4/am6.bootstrap.libp2p.io/tcp/443/wss/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb', | ||
'/dns4/sg1.bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt', | ||
'/dns4/sv15.bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN' | ||
] | ||
}, | ||
privateKey: 'generated by `auto-config.ts`', | ||
connectionManager: { | ||
inboundConnectionThreshold: 100, | ||
maxIncomingPendingConnections: 100, | ||
maxConnections: 500 | ||
} | ||
} |
This file contains 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 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,25 @@ | ||
import { privateKeyFromProtobuf, privateKeyToProtobuf } from '@libp2p/crypto/keys' | ||
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' | ||
import { toString as uint8ArrayToString } from 'uint8arrays/to-string' | ||
import type { PrivateKey } from '@libp2p/interface' | ||
|
||
/** | ||
* Decode's a privateKey string representation into a PrivateKey object | ||
* for use by js-libp2p. | ||
* | ||
* The string representation is a base64pad encoded protobuf representation of | ||
* the private key. This aligns with the way Kubo stores private keys in | ||
* `~/home/.ipfs/config`. | ||
*/ | ||
export function decodePrivateKey (privkeyStr: string): PrivateKey { | ||
const privkeyBytes = uint8ArrayFromString(privkeyStr, 'base64pad') | ||
return privateKeyFromProtobuf(privkeyBytes) | ||
} | ||
|
||
/** | ||
* Inverse of `decodePrivateKey`. Encodes a PrivateKey object into a string | ||
*/ | ||
export function encodePrivateKey (privkey: PrivateKey): string { | ||
const privKeyBytes = privateKeyToProtobuf(privkey) | ||
return uint8ArrayToString(privKeyBytes, 'base64pad') | ||
} |