'use strict' const crypto = require('crypto') const cloneDeep = require('lodash.clonedeep') const figgyPudding = require('figgy-pudding') const mockTar = require('./util/mock-tarball.js') const { PassThrough } = require('stream') const ssri = require('ssri') const { test } = require('tap') const tnock = require('./util/tnock.js') const publish = require('../publish.js') const OPTS = figgyPudding({ registry: {} })({ registry: 'https://mock.reg/' }) const REG = OPTS.registry test('basic publish', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ token: 'deadbeef' })).then(ret => { t.ok(ret, 'publish succeeded') }) }) }) test('scoped publish', t => { const manifest = { name: '@zkat/libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: '@zkat/libnpmpublish', description: 'some stuff', readme: '', _id: '@zkat/libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: '@zkat/libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: '@zkat/libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/@zkat/libnpmpublish/-/@zkat/libnpmpublish-1.0.0.tgz` } } }, _attachments: { '@zkat/libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/@zkat%2flibnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('retry after a conflict', t => { const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const basePackument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': {}, versions: {}, _attachments: {} } const currentPackument = cloneDeep(Object.assign({}, basePackument, { time: { modified: new Date().toISOString(), created: new Date().toISOString(), '1.0.1': new Date().toISOString() }, 'dist-tags': { latest: '1.0.1' }, maintainers: [{ name: 'zkat', email: 'idk@idk.tech' }], versions: { '1.0.1': { _id: 'libnpmpublish@1.0.1', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: 'libnpmpublish', version: '1.0.1', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.1.tgz` } } }, _attachments: { 'libnpmpublish-1.0.1.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } })) const newPackument = cloneDeep(Object.assign({}, basePackument, { 'dist-tags': { latest: '1.0.0' }, maintainers: [{ name: 'other', email: 'other@idk.tech' }], versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', _npmUser: { name: 'other', email: 'other@idk.tech' }, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', maintainers: [{ name: 'other', email: 'other@idk.tech' }], dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } })) const mergedPackument = cloneDeep(Object.assign({}, basePackument, { time: currentPackument.time, 'dist-tags': { latest: '1.0.0' }, maintainers: currentPackument.maintainers, versions: Object.assign({}, currentPackument.versions, newPackument.versions), _attachments: Object.assign({}, currentPackument._attachments, newPackument._attachments) })) const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.deepEqual(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) srv.get('/libnpmpublish?write=true').reply(200, Object.assign({ _rev: REV }, currentPackument)) srv.put('/libnpmpublish', body => { t.deepEqual(body, Object.assign({ _rev: REV }, mergedPackument), 'posted packument includes _rev and a merged version') return true }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', username: 'other', email: 'other@idk.tech' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('retry after a conflict -- no versions on remote', t => { const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const basePackument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish' } const currentPackument = cloneDeep(Object.assign({}, basePackument, { maintainers: [{ name: 'zkat', email: 'idk@idk.tech' }] })) const newPackument = cloneDeep(Object.assign({}, basePackument, { 'dist-tags': { latest: '1.0.0' }, maintainers: [{ name: 'other', email: 'other@idk.tech' }], versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', _npmUser: { name: 'other', email: 'other@idk.tech' }, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', maintainers: [{ name: 'other', email: 'other@idk.tech' }], dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } })) const mergedPackument = cloneDeep(Object.assign({}, basePackument, { 'dist-tags': { latest: '1.0.0' }, maintainers: currentPackument.maintainers, versions: Object.assign({}, currentPackument.versions, newPackument.versions), _attachments: Object.assign({}, currentPackument._attachments, newPackument._attachments) })) const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.deepEqual(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) srv.get('/libnpmpublish?write=true').reply(200, Object.assign({ _rev: REV }, currentPackument)) srv.put('/libnpmpublish', body => { t.deepEqual(body, Object.assign({ _rev: REV }, mergedPackument), 'posted packument includes _rev and a merged version') return true }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', username: 'other', email: 'other@idk.tech' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('version conflict', t => { const REV = '72-47f2986bfd8e8b55068b204588bbf484' const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const basePackument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': {}, versions: {}, _attachments: {} } const newPackument = cloneDeep(Object.assign({}, basePackument, { 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } })) const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.notOk(body._rev, 'no _rev in initial post') t.deepEqual(body, newPackument, 'got conflicting packument') return true }).reply(409, { error: 'gimme _rev plz' }) srv.get('/libnpmpublish?write=true').reply(200, Object.assign({ _rev: REV }, newPackument)) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then( () => { throw new Error('should not succeed') }, err => { t.equal(err.code, 'EPUBLISHCONFLICT', 'got publish conflict code') } ) }) }) test('publish with basic auth', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, maintainers: [{ name: 'zkat', email: 'kat@example.tech' }], versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', _npmUser: { name: 'zkat', email: 'kat@example.tech' }, maintainers: [{ name: 'zkat', email: 'kat@example.tech' }], name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: /^Basic / }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', username: 'zkat', email: 'kat@example.tech' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('publish base64 string', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData.toString('base64'), OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('publish tar stream', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) const stream = new PassThrough() setTimeout(() => stream.end(tarData), 0) return publish(manifest, stream, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('refuse if package marked private', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', private: true } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then( () => { throw new Error('should not have succeeded') }, err => { t.equal(err.code, 'EPRIVATE', 'got correct error code') } ) }) }) test('publish includes access', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', access: 'public', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ token: 'deadbeef', access: 'public' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('refuse if package is unscoped plus `restricted` access', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', access: 'restricted' })).then( () => { throw new Error('should not have succeeded') }, err => { t.equal(err.code, 'EUNSCOPED', 'got correct error code') } ) }) }) test('refuse if tarball is wrong type', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return publish(manifest, { data: 42 }, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then( () => { throw new Error('should not have succeeded') }, err => { t.equal(err.code, 'EBADTAR', 'got correct error code') } ) }) test('refuse if bad semver on manifest', t => { const manifest = { name: 'libnpmpublish', version: 'lmao', description: 'some stuff' } return publish(manifest, 'deadbeef', OPTS).then( () => { throw new Error('should not have succeeded') }, err => { t.equal(err.code, 'EBADSEMVER', 'got correct error code') } ) }) test('other error code', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, _npmVersion: '6.9.0', name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(500, { error: 'go away' }) return publish(manifest, tarData, OPTS.concat({ npmVersion: '6.9.0', token: 'deadbeef' })).then( () => { throw new Error('should not succeed') }, err => { t.match(err.message, /go away/, 'no retry on non-409') } ) }) }) test('publish includes access', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', access: 'public', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ token: 'deadbeef', access: 'public' })).then(() => { t.ok(true, 'publish succeeded') }) }) }) test('publishConfig on manifest', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', publishConfig: { registry: REG } } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` }, publishConfig: { registry: REG } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, { token: 'deadbeef' }).then(ret => { t.ok(ret, 'publish succeeded') }) }) }) test('publish with encoded _auth', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, maintainers: [ { name: 'myuser', email: 'my@ema.il' } ], versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _npmUser: { name: 'myuser', email: 'my@ema.il' }, maintainers: [ { name: 'myuser', email: 'my@ema.il' } ], _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } const srv = tnock(t, REG) srv.put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ _auth: Buffer.from('myuser:mypassword', 'utf8').toString('base64'), email: 'my@ema.il' })).then(ret => { t.ok(ret, 'publish succeeded using _auth') }) }) }) test('publish with 302 redirect', t => { const manifest = { name: 'libnpmpublish', version: '1.0.0', description: 'some stuff' } return mockTar({ 'package.json': JSON.stringify(manifest), 'index.js': 'console.log("hello world")' }).then(tarData => { const shasum = crypto.createHash('sha1').update(tarData).digest('hex') const integrity = ssri.fromData(tarData, { algorithms: ['sha512'] }) const packument = { name: 'libnpmpublish', description: 'some stuff', readme: '', _id: 'libnpmpublish', 'dist-tags': { latest: '1.0.0' }, versions: { '1.0.0': { _id: 'libnpmpublish@1.0.0', _nodeVersion: process.versions.node, name: 'libnpmpublish', version: '1.0.0', description: 'some stuff', dist: { shasum, integrity: integrity.toString(), tarball: `http://mock.reg/libnpmpublish/-/libnpmpublish-1.0.0.tgz` } } }, _attachments: { 'libnpmpublish-1.0.0.tgz': { 'content_type': 'application/octet-stream', data: tarData.toString('base64'), length: tarData.length } } } tnock(t, REG).put('/libnpmpublish').reply(302, '', { location: 'http://blah.net/libnpmpublish' }) tnock(t, 'http://blah.net').put('/libnpmpublish', body => { t.deepEqual(body, packument, 'posted packument matches expectations') return true }, { authorization: 'Bearer deadbeef' }).reply(201, {}) return publish(manifest, tarData, OPTS.concat({ token: 'deadbeef' })).then(ret => { t.ok(ret, 'publish succeeded') }) }) })