UNPKG

cnpmcore

Version:
190 lines 15.7 kB
"use strict"; 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); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.UserRoleManager = void 0; const tegg_1 = require("@eggjs/tegg"); const egg_errors_1 = require("egg-errors"); const PackageRepository_1 = require("../repository/PackageRepository"); const PackageUtil_1 = require("../common/PackageUtil"); const RegistryManagerService_1 = require("../core/service/RegistryManagerService"); const TokenService_1 = require("../core/service/TokenService"); let UserRoleManager = class UserRoleManager { constructor() { this.handleAuthorized = false; } // check publish access // 1. admin has all access // 2. has published in current registry // 3. pkg scope is allowed to publish // use AbstractController#ensurePublishAccess ensure pkg exists; async checkPublishAccess(ctx, fullname) { const user = await this.requiredAuthorizedUser(ctx, 'publish'); // 1. admin has all access const isAdmin = await this.isAdmin(ctx); if (isAdmin) { return user; } // 2. check for checkGranularTokenAccess const authorizedUserAndToken = await this.getAuthorizedUserAndToken(ctx); const { token } = authorizedUserAndToken; await this.tokenService.checkGranularTokenAccess(token, fullname); // 3. has published in current registry const [scope, name] = (0, PackageUtil_1.getScopeAndName)(fullname); const pkg = await this.packageRepository.findPackage(scope, name); const selfRegistry = await this.registryManagerService.ensureSelfRegistry(); const inSelfRegistry = pkg?.registryId === selfRegistry.registryId; if (inSelfRegistry) { // 3.1 check in Maintainers table // Higher priority than scope check await this.requiredPackageMaintainer(pkg, user); return user; } if (pkg && !scope && !inSelfRegistry) { // 3.2 public package can't publish in other registry // scope package can be migrated into self registry throw new egg_errors_1.ForbiddenError(`Can\'t modify npm public package "${fullname}"`); } // 4 check scope is allowed to publish await this.requiredPackageScope(scope, user); if (pkg) { // published scoped package await this.requiredPackageMaintainer(pkg, user); } return user; } // { // 'user-agent': 'npm/8.1.2 node/v16.13.1 darwin arm64 workspaces/false', // 'npm-command': 'adduser', // authorization: 'Bearer 379f84d8-ba98-480b-909e-a8260af3a3ee', // 'content-type': 'application/json', // accept: '*/*', // 'content-length': '166', // 'accept-encoding': 'gzip,deflate', // host: 'localhost:7001', // connection: 'keep-alive' // } async getAuthorizedUserAndToken(ctx) { if (this.handleAuthorized) { if (!this.currentAuthorizedUser) return null; return { token: this.currentAuthorizedToken, user: this.currentAuthorizedUser, }; } this.handleAuthorized = true; const authorization = ctx.get('authorization'); if (!authorization) return null; const authorizedUserAndToken = await this.tokenService.getUserAndToken(authorization); if (!authorizedUserAndToken) { return null; } // check token expired & set lastUsedAt await this.tokenService.checkTokenStatus(authorizedUserAndToken.token); this.currentAuthorizedToken = authorizedUserAndToken.token; this.currentAuthorizedUser = authorizedUserAndToken.user; ctx.userId = authorizedUserAndToken.user.userId; return authorizedUserAndToken; } async requiredAuthorizedUser(ctx, role) { const authorizedUserAndToken = await this.getAuthorizedUserAndToken(ctx); if (!authorizedUserAndToken) { const authorization = ctx.get('authorization'); const message = authorization ? 'Invalid token' : 'Login first'; throw new egg_errors_1.UnauthorizedError(message); } const { user, token } = authorizedUserAndToken; // only enable npm client and version check setting will go into this condition if (this.config.cnpmcore.enableNpmClientAndVersionCheck && role === 'publish') { if (token.isReadonly) { throw new egg_errors_1.ForbiddenError(`Read-only Token "${token.tokenMark}" can't publish`); } // only support npm >= 7.0.0 allow publish action // user-agent: "npm/6.14.12 node/v10.24.1 darwin x64" const m = /\bnpm\/(\d{1,5})\./.exec(ctx.get('user-agent')); if (!m) { throw new egg_errors_1.ForbiddenError('Only allow npm client to access'); } const major = parseInt(m[1]); if (major < 7) { throw new egg_errors_1.ForbiddenError('Only allow npm@>=7.0.0 client to access'); } } if (role === 'setting') { if (token.isReadonly) { throw new egg_errors_1.ForbiddenError(`Read-only Token "${token.tokenMark}" can't setting`); } if (token.isAutomation) { throw new egg_errors_1.ForbiddenError(`Automation Token "${token.tokenMark}" can't setting`); } } return user; } async requiredPackageMaintainer(pkg, user) { const maintainers = await this.packageRepository.listPackageMaintainers(pkg.packageId); const maintainer = maintainers.find(m => m.userId === user.userId); if (!maintainer) { const names = maintainers.map(m => m.name).join(', '); throw new egg_errors_1.ForbiddenError(`"${user.name}" not authorized to modify ${pkg.fullname}, please contact maintainers: "${names}"`); } } async requiredPackageScope(scope, user) { const cnpmcoreConfig = this.config.cnpmcore; if (cnpmcoreConfig.allowPublishNonScopePackage) { return; } const allowScopes = user.scopes ?? cnpmcoreConfig.allowScopes; if (!scope) { throw new egg_errors_1.ForbiddenError(`Package scope required, legal scopes: "${allowScopes.join(', ')}"`); } if (!allowScopes.includes(scope)) { throw new egg_errors_1.ForbiddenError(`Scope "${scope}" not match legal scopes: "${allowScopes.join(', ')}"`); } } async isAdmin(ctx) { const authorizedUserAndToken = await this.getAuthorizedUserAndToken(ctx); if (!authorizedUserAndToken) return false; const { user, token } = authorizedUserAndToken; if (token.isReadonly) return false; return user.name in this.config.cnpmcore.admins; } }; exports.UserRoleManager = UserRoleManager; __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", PackageRepository_1.PackageRepository) ], UserRoleManager.prototype, "packageRepository", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", Object) ], UserRoleManager.prototype, "config", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", Object) ], UserRoleManager.prototype, "logger", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", RegistryManagerService_1.RegistryManagerService) ], UserRoleManager.prototype, "registryManagerService", void 0); __decorate([ (0, tegg_1.Inject)(), __metadata("design:type", TokenService_1.TokenService) ], UserRoleManager.prototype, "tokenService", void 0); exports.UserRoleManager = UserRoleManager = __decorate([ (0, tegg_1.ContextProto)({ // only inject on port module accessLevel: tegg_1.AccessLevel.PRIVATE, }) ], UserRoleManager); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVXNlclJvbGVNYW5hZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vYXBwL3BvcnQvVXNlclJvbGVNYW5hZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQUFBLHNDQUtxQjtBQUVyQiwyQ0FBK0Q7QUFDL0QsdUVBQW9FO0FBSXBFLHVEQUF3RDtBQUN4RCxtRkFBZ0Y7QUFDaEYsK0RBQTREO0FBU3JELElBQU0sZUFBZSxHQUFyQixNQUFNLGVBQWU7SUFBckI7UUFZRyxxQkFBZ0IsR0FBRyxLQUFLLENBQUM7SUF5Sm5DLENBQUM7SUFySkMsdUJBQXVCO0lBQ3ZCLDBCQUEwQjtJQUMxQix1Q0FBdUM7SUFDdkMscUNBQXFDO0lBQ3JDLGdFQUFnRTtJQUN6RCxLQUFLLENBQUMsa0JBQWtCLENBQUMsR0FBZSxFQUFFLFFBQWdCO1FBRS9ELE1BQU0sSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUUvRCwwQkFBMEI7UUFDMUIsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3hDLElBQUksT0FBTyxFQUFFO1lBQ1gsT0FBTyxJQUFJLENBQUM7U0FDYjtRQUVELHdDQUF3QztRQUN4QyxNQUFNLHNCQUFzQixHQUFHLE1BQU0sSUFBSSxDQUFDLHlCQUF5QixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pFLE1BQU0sRUFBRSxLQUFLLEVBQUUsR0FBRyxzQkFBdUIsQ0FBQztRQUMxQyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsd0JBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBRWxFLHVDQUF1QztRQUN2QyxNQUFNLENBQUUsS0FBSyxFQUFFLElBQUksQ0FBRSxHQUFHLElBQUEsNkJBQWUsRUFBQyxRQUFRLENBQUMsQ0FBQztRQUNsRCxNQUFNLEdBQUcsR0FBRyxNQUFNLElB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