Skip to content

Commit

Permalink
fix: allow publish 10mb tarball package by default (#391)
Browse files Browse the repository at this point in the history
closes #388
  • Loading branch information
fengmk2 committed Feb 3, 2023
1 parent 09a66d1 commit f873b8d
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 13 deletions.
7 changes: 5 additions & 2 deletions app/port/controller/package/SavePackageVersionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type FullPackage = Omit<Static<typeof FullPackageRule>, 'versions' | '_attachmen
}};

// base64 regex https://stackoverflow.com/questions/475074/regex-to-parse-or-validate-base64-data/475217#475217
const PACKAGE_ATTACH_DATA_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
const PACKAGE_ATTACH_DATA_RE = /^[A-Za-z0-9+/]{4}/;

@HTTPController()
export class SavePackageVersionController extends AbstractController {
Expand Down Expand Up @@ -130,9 +130,12 @@ export class SavePackageVersionController extends AbstractController {
}

// check attachment data format and size
if (!attachment.data || typeof attachment.data !== 'string' || !PACKAGE_ATTACH_DATA_RE.test(attachment.data)) {
if (!attachment.data || typeof attachment.data !== 'string') {
throw new UnprocessableEntityError('attachment.data format invalid');
}
if (!PACKAGE_ATTACH_DATA_RE.test(attachment.data)) {
throw new UnprocessableEntityError('attachment.data string format invalid');
}
const tarballBytes = Buffer.from(attachment.data, 'base64');
if (tarballBytes.length !== attachment.length) {
throw new UnprocessableEntityError(`attachment size ${attachment.length} not match download size ${tarballBytes.length}`);
Expand Down
3 changes: 3 additions & 0 deletions config/config.default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export default (appInfo: EggAppConfig) => {

config.logger = {
enablePerformanceTimer: true,
enableFastContextLogger: true,
};

config.logrotator = {
Expand All @@ -161,6 +162,8 @@ export default (appInfo: EggAppConfig) => {
config.bodyParser = {
// saveTag will send version string in JSON format
strict: false,
// set default limit to 10mb, see https://github.com/npm/npm/issues/12750
jsonLimit: '10mb',
};

// https://github.com/xiekw2010/egg-typebox-validate#%E5%A6%82%E4%BD%95%E5%86%99%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E8%A7%84%E5%88%99
Expand Down
65 changes: 54 additions & 11 deletions test/port/controller/package/SavePackageVersionController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import assert from 'assert';
import { app } from 'egg-mock/bootstrap';
import { TestUtil } from 'test/TestUtil';
import { UserRepository } from 'app/repository/UserRepository';
import { calculateIntegrity } from 'app/common/PackageUtil';

describe('test/port/controller/package/SavePackageVersionController.test.ts', () => {
let userRepository: UserRepository;
Expand Down Expand Up @@ -165,6 +166,48 @@ describe('test/port/controller/package/SavePackageVersionController.test.ts', ()
assert.equal(res.body.versions[version].version, version);
});

it('should publish with 4mb tarball', async () => {
const tarball = Buffer.alloc(4 * 1024 * 1024);
const { integrity } = await calculateIntegrity(tarball);
const pkg = await TestUtil.getFullPackage({
attachment: {
data: tarball.toString('base64'),
length: tarball.length,
},
dist: {
integrity,
},
});
await app.httpRequest()
.put(`/${pkg.name}`)
.set('authorization', publisher.authorization)
.set('user-agent', publisher.ua)
.send(pkg)
.expect(201);
});

// unstable on supertest, will random fail with Error: write ECONNRESET
it.skip('should publish fail and response status 413 when tarball >= 10mb', async () => {
const tarball = Buffer.alloc(10 * 1024 * 1024);
const { integrity } = await calculateIntegrity(tarball);
const pkg = await TestUtil.getFullPackage({
attachment: {
data: tarball.toString('base64'),
length: tarball.length,
},
dist: {
integrity,
},
});
const res = await app.httpRequest()
.put(`/${pkg.name}`)
.set('authorization', publisher.authorization)
.set('user-agent', publisher.ua)
.send(pkg)
.expect(413);
console.log(res.body, res.text, res.headers);
});

it('should add new version success', async () => {
const pkg = await TestUtil.getFullPackage({ version: '0.0.0' });
let res = await app.httpRequest()
Expand Down Expand Up @@ -600,7 +643,7 @@ describe('test/port/controller/package/SavePackageVersionController.test.ts', ()
.set('user-agent', publisher.ua)
.send(pkg)
.expect(422);
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment.data format invalid');
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment.data string format invalid');

pkg = await TestUtil.getFullPackage({
attachment: {
Expand All @@ -614,34 +657,34 @@ describe('test/port/controller/package/SavePackageVersionController.test.ts', ()
.send(pkg)
.expect(422);
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment.data format invalid');
});

pkg = await TestUtil.getFullPackage({
it('should 422 when attachment size not match', async () => {
let pkg = await TestUtil.getFullPackage({
attachment: {
data: 'H4sIAAAAAAAAA+2SsWrDMBCGPfspDg2Zine123OyEgeylg6Zau2YR8rVRHEtGkkOg5N0jWaFdujVQAv6W4/7/',
length: 3,
},
});
res = await app.httpRequest()
let res = await app.httpRequest()
.put(`/${pkg.name}`)
.set('authorization', publisher.authorization)
.set('user-agent', publisher.ua)
.send(pkg)
.expect(422);
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment.data format invalid');
});
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment size 3 not match download size 251');

it('should 422 when attachment size not match', async () => {
const pkg = await TestUtil.getFullPackage({
pkg = await TestUtil.getFullPackage({
attachment: {
length: 3,
data: 'H4sIAAAAAAAAA+2SsWrDMBCGPfspDg2Zine123OyEgeylg6Zau2YR8rVRHEtGkkOg5N0jWaFdujVQAv6W4/7/',
},
});
const res = await app.httpRequest()
res = await app.httpRequest()
.put(`/${pkg.name}`)
.set('authorization', publisher.authorization)
.set('user-agent', publisher.ua)
.send(pkg)
.expect(422);
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment size 3 not match download size 251');
assert.equal(res.body.error, '[UNPROCESSABLE_ENTITY] attachment size 251 not match download size 63');
});

it('should 422 dist.integrity invalid', async () => {
Expand Down

0 comments on commit f873b8d

Please sign in to comment.