Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit e9b9737

Browse files
committed
fix: fix ls crash (#2546)
* sanitises input to replace multiple slashes with single slashes * removes trailing slashes * uses `0` for padding when `link.depth` results in negative padding N.b will be resolved in a better way by ipfs/js-ipfs-unixfs-exporter#24
1 parent 11ae4c5 commit e9b9737

File tree

2 files changed

+71
-9
lines changed

2 files changed

+71
-9
lines changed

src/cli/commands/ls.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ module.exports = {
4848
const multihashWidth = Math.max.apply(null, links.map((file) => file.hash.length))
4949
const sizeWidth = Math.max.apply(null, links.map((file) => String(file.size).length))
5050

51+
// replace multiple slashes
52+
key = key.replace(/\/(\/+)/g, '/')
53+
54+
// strip trailing flash
55+
if (key.endsWith('/')) {
56+
key = key.replace(/(\/+)$/, '')
57+
}
58+
5159
let pathParts = key.split('/')
5260

5361
if (key.startsWith('/ipfs/')) {
@@ -56,7 +64,10 @@ module.exports = {
5664

5765
links.forEach(link => {
5866
const fileName = link.type === 'dir' ? `${link.name || ''}/` : link.name
59-
const padding = link.depth - pathParts.length
67+
68+
// todo: fix this by resolving https://github.com/ipfs/js-ipfs-unixfs-exporter/issues/24
69+
const padding = Math.max(link.depth - pathParts.length, 0)
70+
6071
print(
6172
rightpad(link.hash, multihashWidth + 1) +
6273
rightpad(link.size || '-', sizeWidth + 1) +

test/cli/ls.js

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,65 @@ describe('ls', () => runOnAndOff((thing) => {
2626
})
2727
})
2828

29-
it('prints nothing for non-existant hashes', function () {
30-
// If the daemon is off, ls should fail
31-
// If the daemon is on, ls should search until it hits a timeout
32-
return Promise.race([
33-
ipfs.fail('ls QmYmW4HiZhotsoSqnv2o1oSssvkRM8b9RweBoH7ao5nki2'),
34-
new Promise((resolve, reject) => setTimeout(resolve, 4000))
35-
])
36-
.catch(() => expect.fail(0, 1, 'Should have thrown or timedout'))
29+
it('supports a trailing slash', async function () {
30+
this.timeout(20 * 1000)
31+
const out = await ipfs('ls Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z/')
32+
expect(out).to.eql(
33+
'QmamKEPmEH9RUsqRQsfNf5evZQDQPYL9KXg1ADeT7mkHkT - blocks/\n' +
34+
'QmPkWYfSLCEBLZu7BZt4kigGDMe3cpogMbeVf97gN2xJDN 3928 config\n' +
35+
'QmUqyZtPmsRy1U5Mo8kz2BAMmk1hfJ7yW1KAFTMB2odsFv - datastore/\n' +
36+
'QmUhUuiTKkkK8J6JZ9zmj8iNHPuNfGYcszgRumzhHBxEEU - init-docs/\n' +
37+
'QmR56UJmAaZLXLdTT1ALrE9vVqV8soUEekm9BMd4FnuYqV 2 version\n'
38+
)
39+
})
40+
41+
it('supports multiple trailing slashes', async function () {
42+
this.timeout(20 * 1000)
43+
const out = await ipfs('ls Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z///')
44+
expect(out).to.eql(
45+
'QmamKEPmEH9RUsqRQsfNf5evZQDQPYL9KXg1ADeT7mkHkT - blocks/\n' +
46+
'QmPkWYfSLCEBLZu7BZt4kigGDMe3cpogMbeVf97gN2xJDN 3928 config\n' +
47+
'QmUqyZtPmsRy1U5Mo8kz2BAMmk1hfJ7yW1KAFTMB2odsFv - datastore/\n' +
48+
'QmUhUuiTKkkK8J6JZ9zmj8iNHPuNfGYcszgRumzhHBxEEU - init-docs/\n' +
49+
'QmR56UJmAaZLXLdTT1ALrE9vVqV8soUEekm9BMd4FnuYqV 2 version\n'
50+
)
51+
})
52+
53+
it('supports multiple intermediate slashes', async function () {
54+
this.timeout(20 * 1000)
55+
const out = await ipfs('ls Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z///init-docs')
56+
expect(out).to.eql(
57+
'QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V 1677 about\n' +
58+
'QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y 189 contact\n' +
59+
'QmegvLXxpVKiZ4b57Xs1syfBVRd8CbucVHAp7KpLQdGieC - docs/\n' +
60+
'QmY5heUM5qgRubMDD1og9fhCPA6QdkMp3QCwd4s7gJsyE7 311 help\n' +
61+
'QmdncfsVm2h5Kqq9hPmU7oAVX2zTSVP3L869tgTbPYnsha 1717 quick-start\n' +
62+
'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB 1091 readme\n' +
63+
'QmTumTjvcYCAvRRwQ8sDRxh8ezmrcr88YFU7iYNroGGTBZ 1016 security-notes\n' +
64+
'QmciSU8hfpAXKjvK5YLUSwApomGSWN5gFbP4EpDAEzu2Te - tour/\n'
65+
)
66+
})
67+
68+
it('supports recursive listing through intermediate directories', async function () {
69+
this.timeout(20 * 1000)
70+
const out = await ipfs('ls -r Qmaj2NmcyAXT8dFmZRRytE12wpcaHADzbChKToMEjBsj5Z/blocks/CIQLB')
71+
expect(out).to.eql(
72+
'QmQ8ag7ysVyCMzJGFjxrUStwWtniQ69c7G9aezbmsKeNYD 10849 CIQLBK52T5EHVHZY5URTG5JS3JCUJDQM2DRB5RVF33DCUUOFJNGVDUI.data\n' +
73+
'QmaSjzSSRanYzRGPXQY6m5SWfSkkfcnzNkurJEQc4chPJx 10807 CIQLBS5HG4PRCRQ7O4EBXFD5QN6MTI5YBYMCVQJDXPKCOVR6RMLHZFQ.data\n'
74+
)
75+
})
76+
77+
it('prints nothing for non-existant hashes', async function () {
78+
if (thing.on) {
79+
// If the daemon is on, ls should search until it hits a timeout
80+
await Promise.race([
81+
ipfs('ls QmYmW4HiZhotsoSqnv2o1oSssvkRM8b9RweBoH7ao5nki2'),
82+
delay(4000)
83+
])
84+
} else {
85+
// If the daemon is off, ls should fail
86+
await ipfs.fail('ls QmYmW4HiZhotsoSqnv2o1oSssvkRM8b9RweBoH7ao5nki2')
87+
}
3788
})
3889

3990
it('adds a header, -v', function () {

0 commit comments

Comments
 (0)