UNPKG

cnpmcore

Version:

Private NPM Registry for Enterprise

246 lines 23.3 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import { Type } from '@eggjs/typebox-validate/typebox'; import { HTTPContext, Context, HTTPBody, HTTPController, HTTPMethod, HTTPMethodEnum, HTTPParam, Inject } from 'egg'; import { ConflictError, ForbiddenError, UnprocessableEntityError } from 'egg/errors'; import { isEqual } from 'lodash-es'; import { checkData, fromData } from 'ssri'; import validateNpmPackageName from 'validate-npm-package-name'; import { FULLNAME_REG_STRING, extractPackageJSON, getScopeAndName } from "../../../common/PackageUtil.js"; import { Description as DescriptionType, Name as NameType, TagWithVersionRule, VersionRule } from "../../typebox.js"; import { AbstractController } from "../AbstractController.js"; const STRICT_CHECK_TARBALL_FIELDS = [ 'name', 'version', 'scripts', 'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies', 'license', 'licenses', 'bin', ]; const FullPackageRule = Type.Object({ name: NameType, // Since we don't validate versions & _attachments previous, here we use Type.Any() just for object validate versions: Type.Optional(Type.Any()), _attachments: Type.Optional(Type.Any()), description: Type.Optional(DescriptionType), 'dist-tags': Type.Optional(Type.Record(Type.String(), Type.String())), readme: Type.Optional(Type.String({ transform: ['trim'] })), }); // 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}/; let SavePackageVersionController = class SavePackageVersionController extends AbstractController { // https://github.com/cnpm/cnpmjs.org/blob/master/docs/registry-api.md#publish-a-new-package // https://github.com/npm/libnpmpublish/blob/main/publish.js#L43 async save(ctx, fullname, pkg) { this.validateNpmCommand(ctx); ctx.tValidate(FullPackageRule, pkg); const { user } = await this.ensurePublishAccess(ctx, fullname, false); // oxlint-disable-next-line no-param-reassign fullname = fullname.trim(); if (fullname !== pkg.name) { throw new UnprocessableEntityError(`fullname(${fullname}) not match package.name(${pkg.name})`); } // Using https://github.com/npm/validate-npm-package-name to validate package name const validateResult = validateNpmPackageName(pkg.name); if (!validateResult.validForNewPackages) { // if pkg already exists, still allow to publish const [scope, name] = getScopeAndName(fullname); const pkg = await this.packageRepository.findPackage(scope, name); if (!pkg) { const errors = (validateResult.errors || validateResult.warnings || []).join(', '); throw new UnprocessableEntityError(`package.name invalid, errors: ${errors}`); } } const versions = Object.values(pkg.versions); if (versions.length === 0) { throw new UnprocessableEntityError('versions is empty'); } // auth maintainter const attachments = pkg._attachments ?? {}; const attachmentFilename = Object.keys(attachments)[0]; if (!attachmentFilename) { // `deprecated: ''` meaning remove deprecated message const isDeprecatedRequest = versions.some((version) => 'deprecated' in version); // handle deprecated request // PUT /:fullname?write=true // https://github.com/npm/cli/blob/latest/lib/commands/deprecate.js#L48 if (isDeprecatedRequest) { return await this.saveDeprecatedVersions(pkg.name, versions); } // invalid attachments throw new UnprocessableEntityError('_attachments is empty'); } // handle add new version const packageVersion = versions[0]; // check version format ctx.tValidate(VersionRule, packageVersion); const attachment = attachments[attachmentFilename]; const distTags = pkg['dist-tags'] ?? {}; let tagNames = Object.keys(distTags); if (tagNames.length === 0) { throw new UnprocessableEntityError('dist-tags is empty'); } const [scope, name] = getScopeAndName(fullname); // see @https://github.com/cnpm/cnpmcore/issues/574 // add default latest tag if (!distTags.latest) { const existsPkg = await this.packageRepository.findPackage(scope, name); const existsLatestTag = existsPkg && (await this.packageRepository.findPackageTag(existsPkg?.packageId, 'latest')); if (!existsPkg || !existsLatestTag) { this.logger.warn('[package:version:add] add default latest tag'); distTags.latest = distTags[tagNames[0]]; tagNames = [...tagNames, 'latest']; } } const tagWithVersion = { tag: tagNames[0], version: distTags[tagNames[0]] }; ctx.tValidate(TagWithVersionRule, tagWithVersion); if (tagWithVersion.version !== packageVersion.version) { throw new UnprocessableEntityError(`dist-tags version "${tagWithVersion.version}" not match package version "${packageVersion.version}"`); } // check attachment data format and size 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}`); } // check integrity or shasum const integrity = packageVersion.dist?.integrity; // for content security reason // check integrity if (integrity) { const algorithm = checkData(tarballBytes, integrity); if (!algorithm) { throw new UnprocessableEntityError('dist.integrity invalid'); } } else { const integrityObj = fromData(tarballBytes, { algorithms: ['sha1'], }); const shasum = integrityObj.sha1[0].hexDigest(); if (packageVersion.dist?.shasum && packageVersion.dist.shasum !== shasum) { // if integrity not exists, check shasum throw new UnprocessableEntityError('dist.shasum invalid'); } } // https://github.com/cnpm/cnpmcore/issues/542 // check tgz & manifests if (this.config.cnpmcore.strictValidateTarballPkg) { const tarballPkg = await extractPackageJSON(tarballBytes); const versionManifest = pkg.versions[tarballPkg.version]; const diffKeys = STRICT_CHECK_TARBALL_FIELDS.filter((key) => { const targetKey = key; return !isEqual(tarballPkg[key], versionManifest[targetKey]); }); if (diffKeys.length > 0) { throw new UnprocessableEntityError(`${diffKeys} mismatch between tarball and manifest`); } } // make sure readme is string const readme = typeof packageVersion.readme === 'string' ? packageVersion.readme : ''; // remove readme packageVersion.readme = undefined; // make sure description is string if (typeof packageVersion.description !== 'string') { packageVersion.description = ''; } const registry = await this.registryManagerService.ensureSelfRegistry(); let packageVersionEntity; const lockName = `${pkg.name}:publish`; const lockRes = await this.cacheAdapter.usingLock(`${pkg.name}:publish`, 60, async () => { packageVersionEntity = await this.packageManagerService.publish({ scope, name, version: packageVersion.version, description: packageVersion.description, packageJson: packageVersion, readme, dist: { content: tarballBytes, }, tags: tagNames, registryId: registry.registryId, isPrivate: true, }, user); }); // lock fail if (!lockRes) { this.logger.warn('[package:version:add] check lock:%s fail', lockName); throw new ConflictError('Unable to create the publication lock, please try again later.'); } this.logger.info('[package:version:add] %s@%s, packageVersionId: %s, tag: %s, userId: %s', packageVersion.name, packageVersion.version, packageVersionEntity?.packageVersionId, tagWithVersion.tag, user?.userId); ctx.status = 201; return { ok: true, rev: `${packageVersionEntity?.id}-${packageVersionEntity?.packageVersionId}`, }; } // https://github.com/cnpm/cnpmjs.org/issues/415 async saveDeprecatedVersions(fullname, versions) { const pkg = await this.getPackageEntityByFullname(fullname); await this.packageManagerService.saveDeprecatedVersions(pkg, versions.map((v) => ({ version: v.version, deprecated: v.deprecated }))); return { ok: true }; } validateNpmCommand(ctx) { // forbidden star/unstar request // npm@6: referer: 'star [REDACTED]' // npm@>=7: 'npm-command': 'star' let command = ctx.get('npm-command'); if (!command) { command = ctx.get('referer').split(' ', 1)[0]; } if (command === 'star' || command === 'unstar') { throw new ForbiddenError(`npm ${command} is not allowed`); } } }; __decorate([ Inject(), __metadata("design:type", Function) ], SavePackageVersionController.prototype, "packageManagerService", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], SavePackageVersionController.prototype, "registryManagerService", void 0); __decorate([ Inject(), __metadata("design:type", Function) ], SavePackageVersionController.prototype, "cacheAdapter", void 0); __decorate([ HTTPMethod({ // PUT /:fullname // https://www.npmjs.com/package/path-to-regexp#custom-matching-parameters path: `/:fullname(${FULLNAME_REG_STRING})`, method: HTTPMethodEnum.PUT, }), __param(0, HTTPContext()), __param(1, HTTPParam()), __param(2, HTTPBody()), __metadata("design:type", Function), __metadata("design:paramtypes", [Context, String, Object]), __metadata("design:returntype", Promise) ], SavePackageVersionController.prototype, "save", null); SavePackageVersionController = __decorate([ HTTPController() ], SavePackageVersionController); export { SavePackageVersionController }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2F2ZVBhY2thZ2VWZXJzaW9uQ29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2FwcC9wb3J0L2NvbnRyb2xsZXIvcGFja2FnZS9TYXZlUGFja2FnZVZlcnNpb25Db250cm9sbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQWUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNwRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsY0FBYyxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwSCxPQUFPLEVBQUUsYUFBYSxFQUFFLGNBQWMsRUFBRSx3QkFBd0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNyRixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBRTNDLE9BQU8sc0JBQXNCLE1BQU0sMkJBQTJCLENBQUM7QUFHL0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSzFHLE9BQU8sRUFBRSxXQUFXLElBQUksZUFBZSxFQUFFLElBQUksSUFBSSxRQUFRLEVBQUUsa0JBQWtCLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDckgsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFOUQsTUFBTSwyQkFBMkIsR0FBMEI7SUFDekQsTUFBTTtJQUNOLFNBQVM7SUFDVCxTQUFTO0lBQ1QsY0FBYztJQUNkLGlCQUFpQjtJQUNqQixrQkFBa0I7SUFDbEIsc0JBQXNCO0lBQ3RCLFNBQVM7SUFDVCxVQUFVO0lBQ1YsS0FBSztDQUNOLENBQUM7QUFnQkYsTUFBTSxl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