diff --git a/package.json b/package.json index dbb88013..f2543453 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "clean": "aegir clean", "lint": "aegir lint", "dep-check": "aegir dep-check", + "prepublishOnly": "node scripts/update-version.js", "build": "aegir build", "generate": "run-s generate:proto:*", "generate:proto:circuit": "protons ./src/circuit/pb/index.proto", diff --git a/scripts/update-version.js b/scripts/update-version.js new file mode 100644 index 00000000..2620790a --- /dev/null +++ b/scripts/update-version.js @@ -0,0 +1,14 @@ +import { readFile, writeFile } from 'fs/promises' + +const pkg = JSON.parse( + await readFile( + new URL('../package.json', import.meta.url) + ) +) + +await writeFile( + new URL('../src/version.ts', import.meta.url), + `export const version = '${pkg.version}' +export const name = '${pkg.name}' +` +) diff --git a/src/config.ts b/src/config.ts index c82b9d1d..6e88a674 100644 --- a/src/config.ts +++ b/src/config.ts @@ -10,6 +10,7 @@ import type { Libp2pInit } from './index.js' import { codes, messages } from './errors.js' import errCode from 'err-code' import type { RecursivePartial } from '@libp2p/interfaces' +import { isNode, isBrowser, isWebWorker, isElectronMain, isElectronRenderer, isReactNative } from 'wherearewe' const DefaultConfig: Partial = { addresses: { @@ -116,5 +117,14 @@ export function validateConfig (opts: RecursivePartial): Libp2pInit throw errCode(new Error(messages.ERR_PROTECTOR_REQUIRED), codes.ERR_PROTECTOR_REQUIRED) } + // Append user agent version to default AGENT_VERSION depending on the environment + if (resultingOptions.identify.host.agentVersion === AGENT_VERSION) { + if (isNode || isElectronMain) { + resultingOptions.identify.host.agentVersion += ` UserAgent=${globalThis.process.version}` + } else if (isBrowser || isWebWorker || isElectronRenderer || isReactNative) { + resultingOptions.identify.host.agentVersion += ` UserAgent=${globalThis.navigator.userAgent}` + } + } + return resultingOptions } diff --git a/src/version.ts b/src/version.ts index c77a04e1..36a3d88e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,3 +1,2 @@ - export const version = '0.0.0' export const name = 'libp2p' diff --git a/test/identify/service.spec.ts b/test/identify/service.spec.ts index e772bad3..152d00c2 100644 --- a/test/identify/service.spec.ts +++ b/test/identify/service.spec.ts @@ -14,6 +14,7 @@ import { peerIdFromString } from '@libp2p/peer-id' import type { PeerId } from '@libp2p/interface-peer-id' import type { Libp2pNode } from '../../src/libp2p.js' import { pEvent } from 'p-event' +import { AGENT_VERSION } from '../../src/identify/consts.js' describe('libp2p.dialer.identifyService', () => { let peerId: PeerId @@ -147,6 +148,29 @@ describe('libp2p.dialer.identifyService', () => { await pWaitFor(() => connection.streams.length === 0) }) + it('should append UserAgent information to default AGENT_VERSION', async () => { + // Stub environment version for testing dynamic AGENT_VERSION + sinon.stub(process, 'version').value('vTEST') + + if (typeof globalThis.navigator !== 'undefined') { + sinon.stub(navigator, 'userAgent').value('vTEST') + } + + libp2p = await createLibp2pNode(createBaseOptions({ + peerId + })) + + await libp2p.start() + + if (libp2p.identifyService == null) { + throw new Error('Identity service was not configured') + } + + const storedAgentVersion = await libp2p.peerStore.metadataBook.getValue(peerId, 'AgentVersion') + + expect(AGENT_VERSION + ' UserAgent=vTEST').to.equal(uint8ArrayToString(storedAgentVersion ?? new Uint8Array())) + }) + it('should store host data and protocol version into metadataBook', async () => { const agentVersion = 'js-project/1.0.0'