Skip to content

Commit 8ca5cbc

Browse files
feat: unpublish action
1 parent 6b4a6db commit 8ca5cbc

File tree

4 files changed

+3166
-3293
lines changed

4 files changed

+3166
-3293
lines changed

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,18 @@
4949
"node": ">=10"
5050
},
5151
"dependencies": {
52-
"gitlab": "3.5.1",
53-
"global-tunnel-ng": "2.5.3",
52+
"gitlab": "^3.11.4",
53+
"global-tunnel-ng": "~2.5.4",
5454
"http-errors": "1.7.3",
55-
"node-cache": "4.2.0",
55+
"node-cache": "~4.2.1",
5656
"verdaccio": "^4.3.4"
5757
},
5858
"devDependencies": {
5959
"@commitlint/cli": "^8.3.3",
6060
"@commitlint/config-conventional": "^8.3.3",
6161
"@commitlint/travis-cli": "^8.3.3",
6262
"@types/http-errors": "^1.6.3",
63-
"@types/jest": "^24.0.24",
63+
"@types/jest": "^26.0.20",
6464
"@types/lodash": "^4.14.149",
6565
"@types/node": "^13.1.0",
6666
"@typescript-eslint/eslint-plugin": "^2.13.0",
@@ -70,23 +70,23 @@
7070
"@verdaccio/eslint-config": "^8.5.0",
7171
"@verdaccio/types": "^8.5.0",
7272
"body-parser": "^1.19.0",
73-
"cross-env": "^6.0.3",
73+
"cross-env": "^7.0.3",
7474
"eslint": "^6.8.0",
7575
"express": "^4.17.1",
7676
"generate-changelog": "^1.8.0",
7777
"http-status": "^1.4.2",
7878
"husky": "^3.1.0",
7979
"in-publish": "^2.0.0",
80-
"jest": "^24.9.0",
81-
"jest-environment-node": "^24.9.0",
80+
"jest": "^26.6.3",
81+
"jest-environment-node": "^26.6.2",
8282
"kleur": "3.0.3",
8383
"license-checker": "^25.0.1",
8484
"lodash": "^4.17.15",
85-
"markdownlint-cli": "^0.20.0",
85+
"markdownlint-cli": "^0.26.0",
8686
"prettier": "^1.19.1",
8787
"request": "^2.88.0",
8888
"rimraf": "^3.0.0",
89-
"typescript": "^3.7.4"
89+
"typescript": "^4.1.5"
9090
},
9191
"commitlint": {
9292
"extends": [

src/gitlab.ts

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,37 +165,58 @@ export default class VerdaccioGitLab implements IPluginAuth<VerdaccioGitlabConfi
165165
}
166166

167167
public allow_publish(user: RemoteUser, _package: VerdaccioGitlabPackageAccess & PackageAccess, cb: Callback) {
168+
return this._callAction('publish', user, _package, cb);
169+
}
170+
171+
public allow_unpublish(user: RemoteUser, _package: VerdaccioGitlabPackageAccess & PackageAccess, cb: Callback) {
172+
return this._callAction('unpublish', user, _package, cb);
173+
}
174+
175+
private _callAction(name: string, user: RemoteUser, _package: VerdaccioGitlabPackageAccess & PackageAccess, cb: Callback) {
168176
if (!_package.gitlab) return cb(null, false);
169177

170-
const packageScopePermit = false;
178+
const packageName = _package.name as string;
179+
180+
if (this._isActionAllowed(name, user, packageName)) {
181+
return cb(null, true);
182+
} else {
183+
return cb(this._getActionPermissionError(packageName));
184+
}
185+
}
186+
187+
private _isActionAllowed(actionName: string, user: RemoteUser, packageName: string): boolean {
171188
let packagePermit = false;
172-
// Only allow to publish packages when:
189+
190+
// Only allow to (un)publish packages when:
173191
// - the package has exactly the same name as one of the user groups, or
174192
// - the package scope is the same as one of the user groups
175193
for (const real_group of user.real_groups) {
176194
// jscs:ignore requireCamelCaseOrUpperCaseIdentifiers
177195
this.logger.trace(
178-
`[gitlab] publish: checking group: ${real_group} for user: ${user.name || ''} and package: ${_package.name}`
196+
`[gitlab] ${actionName}: checking group: ${real_group} for user: ${user.name || ''} and package: ${packageName}`
179197
);
180198

181-
if (this._matchGroupWithPackage(real_group, _package.name as string)) {
199+
if (this._matchGroupWithPackage(real_group, packageName)) {
182200
packagePermit = true;
183201
break;
184202
}
185203
}
186204

187-
if (packagePermit || packageScopePermit) {
188-
const perm = packagePermit ? 'package-name' : 'package-scope';
189-
this.logger.debug(
190-
`[gitlab] user: ${user.name || ''} allowed to publish package: ${_package.name} based on ${perm}`
191-
);
192-
return cb(null, true);
193-
} else {
194-
this.logger.debug(`[gitlab] user: ${user.name || ''} denied from publishing package: ${_package.name}`);
195-
// @ts-ignore
196-
const missingPerm = _package.name.indexOf('@') === 0 ? 'package-scope' : 'package-name';
197-
return cb(getForbidden(`must have required permissions: ${this.publishLevel || ''} at ${missingPerm}`));
198-
}
205+
this.logger.debug(
206+
`[gitlab] user: ${user.name || ''} ` + (
207+
packagePermit
208+
? `allowed to ${actionName} package: ${packageName} based on package-name`
209+
: `denied from ${actionName}ing package: ${packageName}`
210+
)
211+
);
212+
213+
return packagePermit;
214+
}
215+
216+
private _getActionPermissionError(packageName: string) {
217+
// @ts-ignore
218+
const missingPerm = packageName.startsWith('@') ? 'package-scope' : 'package-name';
219+
return getForbidden(`must have required permissions: ${this.publishLevel || ''} at ${missingPerm}`);
199220
}
200221

201222
private _matchGroupWithPackage(real_group: string, package_name: string): boolean {

test/unit/gitlab.spec.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,25 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
177177
verdaccioGitlab.allow_publish(config.remoteUser, _package, cb);
178178
});
179179

180+
test('should allow unpublish of package based on user group', done => {
181+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
182+
const _package: VerdaccioGitlabPackageAccess = {
183+
name: '@myGroup/myPackage',
184+
access: ['$all'],
185+
gitlab: true,
186+
publish: ['$authenticated'],
187+
proxy: ['npmjs'],
188+
};
189+
190+
const cb: Callback = (err, data) => {
191+
expect(err).toBeFalsy();
192+
expect(data).toBe(true);
193+
done();
194+
};
195+
196+
verdaccioGitlab.allow_unpublish(config.remoteUser, _package, cb);
197+
});
198+
180199
test('should allow publish of package based on user project', done => {
181200
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
182201
const _package: VerdaccioGitlabPackageAccess = {
@@ -196,6 +215,25 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
196215
verdaccioGitlab.allow_publish(config.remoteUser, _package, cb);
197216
});
198217

218+
test('should allow unpublish of package based on user project', done => {
219+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
220+
const _package: VerdaccioGitlabPackageAccess = {
221+
name: '@anotherGroup/myProject',
222+
access: ['$all'],
223+
gitlab: true,
224+
publish: ['$authenticated'],
225+
proxy: ['npmjs'],
226+
};
227+
228+
const cb: Callback = (err, data) => {
229+
expect(err).toBeFalsy();
230+
expect(data).toBe(true);
231+
done();
232+
};
233+
234+
verdaccioGitlab.allow_unpublish(config.remoteUser, _package, cb);
235+
});
236+
199237
test('should allow publish of package based on user name', done => {
200238
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
201239
const _package: VerdaccioGitlabPackageAccess = {
@@ -215,6 +253,25 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
215253
verdaccioGitlab.allow_publish(config.remoteUser, _package, cb);
216254
});
217255

256+
test('should allow unpublish of package based on user name', done => {
257+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
258+
const _package: VerdaccioGitlabPackageAccess = {
259+
name: config.user,
260+
access: ['$all'],
261+
gitlab: true,
262+
publish: ['$authenticated'],
263+
proxy: ['npmjs'],
264+
};
265+
266+
const cb: Callback = (err, data) => {
267+
expect(err).toBeFalsy();
268+
expect(data).toBe(true);
269+
done();
270+
};
271+
272+
verdaccioGitlab.allow_unpublish(config.remoteUser, _package, cb);
273+
});
274+
218275
test('should deny publish of package based on unauthenticated', done => {
219276
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
220277
const unauthenticatedUser: RemoteUser = {
@@ -239,6 +296,30 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
239296
verdaccioGitlab.allow_publish(unauthenticatedUser, _package, cb);
240297
});
241298

299+
test('should deny unpublish of package based on unauthenticated', done => {
300+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
301+
const unauthenticatedUser: RemoteUser = {
302+
real_groups: [],
303+
groups: [],
304+
name: undefined,
305+
};
306+
const _package: VerdaccioGitlabPackageAccess = {
307+
name: config.user,
308+
access: ['$all'],
309+
gitlab: true,
310+
publish: ['$authenticated'],
311+
proxy: ['npmjs'],
312+
};
313+
314+
const cb: Callback = (err, data) => {
315+
expect(err).toBeTruthy();
316+
expect(data).toBeFalsy();
317+
done();
318+
};
319+
320+
verdaccioGitlab.allow_unpublish(unauthenticatedUser, _package, cb);
321+
});
322+
242323
test('should deny publish of package based on group', done => {
243324
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
244325
const _package: VerdaccioGitlabPackageAccess = {
@@ -258,6 +339,25 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
258339
verdaccioGitlab.allow_publish(config.remoteUser, _package, cb);
259340
});
260341

342+
test('should deny unpublish of package based on group', done => {
343+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
344+
const _package: VerdaccioGitlabPackageAccess = {
345+
name: '@anotherGroup/myPackage',
346+
access: ['$all'],
347+
gitlab: true,
348+
publish: ['$authenticated'],
349+
proxy: ['npmjs'],
350+
};
351+
352+
const cb: Callback = (err, data) => {
353+
expect(err).toBeTruthy();
354+
expect(data).toBeFalsy();
355+
done();
356+
};
357+
358+
verdaccioGitlab.allow_unpublish(config.remoteUser, _package, cb);
359+
});
360+
261361
test('should deny publish of package based on user', done => {
262362
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
263363
const _package: VerdaccioGitlabPackageAccess = {
@@ -276,4 +376,23 @@ describe('Gitlab Auth Plugin Unit Tests', () => {
276376

277377
verdaccioGitlab.allow_publish(config.remoteUser, _package, cb);
278378
});
379+
380+
test('should deny unpublish of package based on user', done => {
381+
const verdaccioGitlab: VerdaccioGitlab = new VerdaccioGitlab(config.verdaccioGitlabConfig, config.options);
382+
const _package: VerdaccioGitlabPackageAccess = {
383+
name: 'anotherUser',
384+
access: ['$all'],
385+
gitlab: true,
386+
publish: ['$authenticated'],
387+
proxy: ['npmjs'],
388+
};
389+
390+
const cb: Callback = (err, data) => {
391+
expect(err).toBeTruthy();
392+
expect(data).toBeFalsy();
393+
done();
394+
};
395+
396+
verdaccioGitlab.allow_unpublish(config.remoteUser, _package, cb);
397+
});
279398
});

0 commit comments

Comments
 (0)