Skip to content

Commit

Permalink
feat(plugin): improve plugin loader (#3370)
Browse files Browse the repository at this point in the history
* feat(plugin): implement scope package support plugins

* feat(plugin): improve plugin loader

* chore: fix build

* chore: cover config path case

* chore: async ui thene plugin

* chore: store async plugin

* chore: refactor plugin loader auth

* feat: filter refactoring

* chore: remove old plugin loader

* chore: add changeset

* chore: add docs

* chore: refactor relative plugin loader

* Update user.jwt.spec.ts

* Update user.jwt.spec.ts
  • Loading branch information
juanpicado committed Sep 16, 2022
1 parent 98afd48 commit 9fc2e79
Show file tree
Hide file tree
Showing 67 changed files with 807 additions and 525 deletions.
3 changes: 1 addition & 2 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@
],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
"updateInternalDependencies": "patch"
}
76 changes: 76 additions & 0 deletions .changeset/early-jokes-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
'@verdaccio/api': major
'@verdaccio/auth': major
'@verdaccio/config': major
'@verdaccio/types': major
'@verdaccio/loaders': major
'@verdaccio/node-api': major
'verdaccio-audit': major
'verdaccio-auth-memory': major
'verdaccio-htpasswd': major
'@verdaccio/local-storage': major
'verdaccio-memory': major
'@verdaccio/server': major
'@verdaccio/server-fastify': major
'@verdaccio/store': major
'@verdaccio/test-helper': major
'customprefix-auth': major
'verdaccio': major
'@verdaccio/web': major
---

feat(plugins): improve plugin loader

### Changes

- Add scope plugin support to 6.x https://github.com/verdaccio/verdaccio/pull/3227
- Avoid config collisions https://github.com/verdaccio/verdaccio/issues/928
- https://github.com/verdaccio/verdaccio/issues/1394
- `config.plugins` plugin path validations
- Updated algorithm for plugin loader.
- improved documentation (included dev)

## Features

- Add scope plugin support to 6.x https://github.com/verdaccio/verdaccio/pull/3227
- Custom prefix:

```
// config.yaml
server:
pluginPrefix: mycompany
middleware:
audit:
foo: 1
```

This configuration will look up for `mycompany-audit` instead `Verdaccio-audit`.

## Breaking Changes

### sinopia plugins

- `sinopia` fallback support is removed, but can be restored using `pluginPrefix`

### plugin filter

- method rename `filter_metadata`->`filterMetadata`

### Plugin constructor does not merge configs anymore https://github.com/verdaccio/verdaccio/issues/928

The plugin receives as first argument `config`, which represents the config of the plugin. Example:

```
// config.yaml
auth:
plugin:
foo: 1
bar: 2
export class Plugin<T> {
public constructor(config: T, options: PluginOptions) {
console.log(config);
// {foo:1, bar: 2}
}
}
```
116 changes: 0 additions & 116 deletions docs/development.md

This file was deleted.

1 change: 1 addition & 0 deletions jest/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = {
},
verbose: false,
collectCoverage: true,
coverageReporters: ['text', 'html'],
collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!**/partials/**', '!**/fixture/**'],
coveragePathIgnorePatterns: ['node_modules', 'fixtures'],
coverageThreshold: {
Expand Down
3 changes: 2 additions & 1 deletion packages/api/test/integration/_helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export const getConf = (conf) => {
};

export async function initializeServer(configName): Promise<Application> {
return initializeServerHelper(getConf(configName), [apiMiddleware], Storage);
const config = getConf(configName);
return initializeServerHelper(config, [apiMiddleware], Storage);
}

export function createUser(app, name: string, password: string): supertest.Test {
Expand Down
3 changes: 3 additions & 0 deletions packages/api/test/integration/publish.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jest.mock('@verdaccio/auth', () => ({
apiJWTmiddleware() {
return mockApiJWTmiddleware();
}
init() {
return Promise.resolve();
}
allow_access(_d, f_, cb) {
cb(null, true);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/api/test/integration/user.jwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { createUser, getPackage, initializeServer } from './_helper';

const FORBIDDEN_VUE = 'authorization required to access package vue';

jest.setTimeout(20000);

describe('token', () => {
describe('basics', () => {
const FAKE_TOKEN: string = buildToken(TOKEN_BEARER, 'fake');
Expand Down
3 changes: 3 additions & 0 deletions packages/api/test/integration/user.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jest.mock('@verdaccio/auth', () => ({
apiJWTmiddleware() {
return mockApiJWTmiddleware();
}
init() {
return Promise.resolve();
}
allow_access(_d, f_, cb) {
cb(null, true);
}
Expand Down
47 changes: 27 additions & 20 deletions packages/auth/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import buildDebug from 'debug';
import { NextFunction, Request, Response } from 'express';
import _ from 'lodash';
import { HTPasswd, HTPasswdConfig } from 'verdaccio-htpasswd';
import { HTPasswd } from 'verdaccio-htpasswd';

import { createAnonymousRemoteUser, createRemoteUser } from '@verdaccio/config';
import {
Expand All @@ -12,7 +12,7 @@ import {
VerdaccioError,
errorUtils,
} from '@verdaccio/core';
import { loadPlugin } from '@verdaccio/loaders';
import { asyncLoadPlugin } from '@verdaccio/loaders';
import {
AllowAccess,
AuthPluginPackage,
Expand Down Expand Up @@ -82,6 +82,7 @@ export interface IAuth extends IBasicAuth<Config>, IAuthMiddleware, TokenEncrypt
plugins: any[];
allow_unpublish(pkg: AuthPluginPackage, user: RemoteUser, callback: Callback): void;
invalidateToken(token: string): Promise<void>;
init(): Promise<void>;
}

class Auth implements IAuth {
Expand All @@ -94,24 +95,32 @@ class Auth implements IAuth {
this.config = config;
this.logger = LoggerApi.logger.child({ sub: 'auth' });
this.secret = config.secret;
this.plugins = [];
if (!this.secret) {
throw new TypeError('secret it is required value on initialize the auth class');
}
}

public async init() {
let plugins = await this.loadPlugin();
debug('auth plugins found %s', plugins.length);
if (!plugins || plugins.length === 0) {
plugins = this.loadDefaultPlugin();
}
this.plugins = plugins;

this.plugins =
_.isNil(config?.auth) === false ? this._loadPlugin(config) : this.loadDefaultPlugin(config);
this._applyDefaultPlugins();
}

private loadDefaultPlugin(config: Config) {
const plugingConf: HTPasswdConfig = { ...config, file: './htpasswd' };
const pluginOptions: PluginOptions<{}> = {
config,
private loadDefaultPlugin() {
debug('load default auth plugin');
const pluginOptions: PluginOptions = {
config: this.config,
logger: this.logger,
};
let authPlugin;
try {
authPlugin = new HTPasswd(plugingConf, pluginOptions as any as PluginOptions<HTPasswdConfig>);
authPlugin = new HTPasswd({ file: './htpasswd' }, pluginOptions as any as PluginOptions);
} catch (error: any) {
debug('error on loading auth htpasswd plugin stack: %o', error);
return [];
Expand All @@ -120,22 +129,20 @@ class Auth implements IAuth {
return [authPlugin];
}

private _loadPlugin(config: Config): IPluginAuth<Config>[] {
const pluginOptions = {
config,
logger: this.logger,
};

return loadPlugin<IPluginAuth<Config>>(
config,
config.auth,
pluginOptions,
private async loadPlugin(): Promise<IPluginAuth<Config>[]> {
return asyncLoadPlugin<IPluginAuth<Config>>(
this.config.auth,
{
config: this.config,
logger: this.logger,
},
(plugin: IPluginAuth<Config>): boolean => {
const { authenticate, allow_access, allow_publish } = plugin;

// @ts-ignore
return authenticate || allow_access || allow_publish;
}
},
this.config?.server?.pluginPrefix
);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/auth/test/auth-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('Auth utilities', () => {
): Promise<string> {
const config: Config = getConfig(configFileName, secret);
const auth: IAuth = new Auth(config);
await auth.init();
// @ts-ignore
const spy = jest.spyOn(auth, methodToSpy);
// @ts-ignore
Expand Down Expand Up @@ -409,6 +410,7 @@ describe('Auth utilities', () => {
const secret = 'b2df428b9929d3ace7c598bbf4e496b2';
const config: Config = getConfig('security-legacy', secret);
const auth: IAuth = new Auth(config);
await auth.init();
const token = auth.aesEncrypt(null);
const security: Security = config.security;
const credentials = getMiddlewareCredentials(
Expand Down

0 comments on commit 9fc2e79

Please sign in to comment.