Skip to content

Commit b93d957

Browse files
committed
fix: require V2 signatures
This is part of deprecation described in ipfs/js-ipfs#4197 - record creation continues to create both V1 and V2 signatures - record validation no longer accepts V1 signatures Meaning: - modern nodes are 100% V2, they ignore V1 signatures - legacy nodes (go-ipfs < v0.9.0, js-ipfs before Jun 2021) are still able to resolve names created by js-ipns, because V1 is still present
1 parent 0f5340a commit b93d957

File tree

4 files changed

+27
-11
lines changed

4 files changed

+27
-11
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# ipns <!-- omit in toc -->
22

3-
[![ipfs.io](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io)
4-
[![IRC](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
3+
[![ipfs.tech](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.tech)
54
[![Discord](https://img.shields.io/discord/806902334369824788?style=flat-square)](https://discord.gg/ipfs)
65
[![codecov](https://img.shields.io/codecov/c/github/ipfs/js-ipns.svg?style=flat-square)](https://codecov.io/gh/ipfs/js-ipns)
76
[![CI](https://img.shields.io/github/workflow/status/ipfs/js-ipns/test%20&%20maybe%20release/master?style=flat-square)](https://github.com/ipfs/js-ipns/actions/workflows/js-test-and-release.yml)

src/index.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ const _create = async (peerId: PeerId, value: Uint8Array, seq: number | bigint,
9595
}
9696

9797
const privateKey = await unmarshalPrivateKey(peerId.privateKey)
98-
const signatureV1 = await sign(privateKey, value, validityType, isoValidity)
98+
const signatureV1 = await signLegacyV1(privateKey, value, validityType, isoValidity)
9999
const data = createCborData(value, isoValidity, validityType, seq, ttl)
100100
const sigData = ipnsEntryDataForV2Sig(data)
101101
const signatureV2 = await privateKey.sign(sigData)
@@ -144,9 +144,9 @@ export { peerIdToRoutingKey } from './utils.js'
144144
export { peerIdFromRoutingKey } from './utils.js'
145145

146146
/**
147-
* Sign ipns record data
147+
* Sign ipns record data using the legacy V1 signature scheme
148148
*/
149-
const sign = async (privateKey: PrivateKey, value: Uint8Array, validityType: IpnsEntry.ValidityType, validity: Uint8Array) => {
149+
const signLegacyV1 = async (privateKey: PrivateKey, value: Uint8Array, validityType: IpnsEntry.ValidityType, validity: Uint8Array) => {
150150
try {
151151
const dataForSignature = ipnsEntryDataForV1Sig(value, validityType, validity)
152152

src/validator.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import errCode from 'err-code'
22
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
33
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
44
import { IpnsEntry } from './pb/ipns.js'
5-
import { parseRFC3339, extractPublicKey, ipnsEntryDataForV1Sig, ipnsEntryDataForV2Sig, unmarshal, peerIdFromRoutingKey, parseCborData } from './utils.js'
5+
import { parseRFC3339, extractPublicKey, ipnsEntryDataForV2Sig, unmarshal, peerIdFromRoutingKey, parseCborData } from './utils.js'
66
import * as ERRORS from './errors.js'
77
import type { IPNSEntry } from './index.js'
88
import type { PublicKey } from '@libp2p/interface-keys'
@@ -27,8 +27,7 @@ export const validate = async (publicKey: PublicKey, entry: IPNSEntry) => {
2727

2828
validateCborDataMatchesPbData(entry)
2929
} else {
30-
signature = entry.signature ?? new Uint8Array(0)
31-
dataForSignature = ipnsEntryDataForV1Sig(value, validityType, validity)
30+
throw errCode(new Error('missing data or signatureV2'), ERRORS.ERR_SIGNATURE_VERIFICATION)
3231
}
3332

3433
// Validate Signature

test/index.spec.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,35 @@ describe('ipns', function () {
6060
await ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))
6161
})
6262

63-
it('should validate a v1 message', async () => {
63+
it('should fail to validate a v1 (deprecated legacy) message', async () => {
6464
const sequence = 0
6565
const validity = 1000000
6666

6767
const entry = await ipns.create(peerId, cid, sequence, validity)
6868

69-
// extra fields added for v2 sigs
69+
// remove the extra fields added for v2 sigs
7070
delete entry.data
7171
delete entry.signatureV2
7272

73-
await ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))
73+
// confirm a v1 exists
74+
expect(entry).to.have.property('signature')
75+
76+
await expect(ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))).to.eventually.be.rejected().with.property('code', ERRORS.ERR_SIGNATURE_VERIFICATION)
77+
})
78+
79+
it('should fail to validate a v2 without v2 signature (ignore v1)', async () => {
80+
const sequence = 0
81+
const validity = 1000000
82+
83+
const entry = await ipns.create(peerId, cid, sequence, validity)
84+
85+
// remove v2 sig
86+
delete entry.signatureV2
87+
88+
// confirm a v1 exists
89+
expect(entry).to.have.property('signature')
90+
91+
await expect(ipnsValidator(peerIdToRoutingKey(peerId), marshal(entry))).to.eventually.be.rejected().with.property('code', ERRORS.ERR_SIGNATURE_VERIFICATION)
7492
})
7593

7694
it('should fail to validate a bad record', async () => {

0 commit comments

Comments
 (0)