This package has been deprecated

Author message:

This package has been deprecated. The package has been moved under a new npm scope: @sectester. See https://www.npmjs.com/package/@sectester/core

@sec-tester/core
TypeScript icon, indicating that this package has built-in type declarations

0.16.0 • Public • Published

@sec-tester/core

Maintainability Test Coverage Build Status NPM Downloads

The core package can be used to obtain a config including credentials from different sources, and provide a simplified abstraction to handle events and commands.

Setup

npm i -s @sec-tester/core

Usage

Configuration

First, you need to generate a new instance of Configuration.

import { Configuration } from '@sec-tester/core';

const config = new Configuration({
  hostname: 'app.neuralegion.com',
  credentials: {
    token: 'your API key'
  }
});

After that, you can resolve the configuration using the IoC container.

const config = config.container.resolve(Configuration);

Options

Configuration can be customized using the following options:

export interface ConfigurationOptions {
  hostname: string;
  credentials?: Credentials;
  logLevel?: LogLevel;
  credentialProviders?: CredentialProvider[];
}

The default configuration is as follows:

{
  logLevel: LogLevel.ERROR,
  credentialProviders: [new EnvCredentialProvider()];
}

hostname

  • type: string

Set the application name (domain name), that is used to establish connection with.

import { Configuration } from '@sec-tester/core';

const config = new Configuration({
  hostname: 'app.neuralegion.com'
});

logLevel

  • type: LogLevel

What level of logs to report. Any logs of a higher level than the setting are shown.

import { Configuration, LogLevel } from '@sec-tester/core';

const config = new Configuration({
  hostname: 'app.neuralegion.com',
  logLevel: LogLevel.ERROR
});

credentials

  • type: Credentials

Set credentials to access the application.

import { Configuration } from '@sec-tester/core';

const config = new Configuration({
  credentials: {
    token: 'your API key'
  }
});

More info about setting up an API key

credentialProviders

  • type: CredentialProvider[]

Allows you to provide credentials and load it in runtime. The configuration will invoke one provider at a time and only continue to the next if no credentials have been located. For example, if the process finds values defined via the BRIGHT_TOKEN environment variables, the file at .sectesterrc will not be read.

EnvCredentialProvider

Use this provider to read credentials from the following environment variable: BRIGHT_TOKEN

If the BRIGHT_TOKEN environment variable is not set or contains a falsy value, it will return undefined.

import { Configuration, EnvCredentialProvider } from '@sec-tester/core';

const credentialsProvider = new EnvCredentialProvider();
const config = new Configuration({
  credentialProviders: [credentialsProvider]
});

Messages

Message is used for syncing state between SDK, application and/or external services. This functionality is done by sending messages outside using a concrete implementation of Dispatcher.

Depending on the type of derived class from the Message, it might be addressed to only one consumer or have typically multiple consumers as well. When a message is sent to multiple consumers, the appropriate event handler in each consumer handles the message.

The Message is a data-holding class, but it implements a Visitor pattern to allow clients to perform operations on it using a visitor class (see Dispatcher) without modifying the source.

For instance, you can dispatch a message in a way that is more approach you or convenient from the client's perspective.

import { CommandDispatcher } from '@sec-tester/core';

const dispatcher = container.resolve(CommandDispatcher);

interface Payload {
  status: 'connected' | 'disconnected';
}

class Ping extends Command<Payload> {
  constructor(payload: Payload) {
    super(payload);
  }
}

// using a visitor pattern
await new Ping({ status: 'connected' }).execute(dispatcher);

// or directly
await dispatcher.execute(new Ping({ status: 'disconnected' }));

The same is applicable for the Event. You just need to use the EventDispatcher instead of CommandDispatcher.

Each message have a correlation ID to ensure atomicity. The regular UUID is used, but you might also want to consider other options.

Request-response

The request-response message (aka Command) style is useful when you need to exchange messages between various external services. Using Command you can easily ensure that the service has actually received the message and sent a response back.

To create an instance of Command use the abstract class as follows:

interface RequestOptions {
  url: string;
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  headers?: Record<string, string>;
  body?: string;
}

class Request<R = unknown> extends Command<RequestOptions, R> {
  constructor(options: RequestOptions) {
    super(options);
  }
}

To adjust its behavior you can use next options:

Option Description
payload Message that we want to transmit to the remote service.
expectReply Indicates whether to wait for a reply. By default true.
ttl Period of time that command should be handled before being discarded. By default 10000 ms.
type The name of a command. By default, it is the name of specific class.
corelationId Used to ensure atomicity while working with EventBus. By default, random UUID.
createdAt The exact date and time the command was created.

Publish-subscribe

When you just want to publish events without waiting for a response, it is better to use the Event. The ideal use case for the publish-subscribe model is when you want to simply notify another service that a certain condition has occurred.

To create an instance of Event use the abstract class as follows:

interface Issue {
  name: string;
  details: string;
  type: string;
  cvss?: string;
  cwe?: string;
}

class IssueDetected extends Event<Issue> {
  constructor(payload: Issue) {
    super(payload);
  }
}

To adjust its behavior you can use next options:

Option Description
payload Message that we want to transmit to the remote service.
type The name of a command. By default, it is the name of specific class.
corelationId Used to ensure atomicity while working with EventBus. By default, random UUID.
createdAt The exact date and time the event was created.

To create an event handler, you should implement the Handler interface and use the @bind() decorator to subscribe a handler to an event:

@bind(IssueDetected)
class IssueDetectedHandler implements EventHandler<Issue> {
  public handle(payload: Issue): Promise<void> {
    // implementation
  }
}

You can register multiple event handlers for a single event pattern and all of them will be automatically triggered in parallel.

@bind(IssueDetected, IssueReopened)
class IssueDetectedHandler implements EventHandler<Issue> {
  public handle(payload: Issue): Promise<void> {
    // implementation
  }
}

You can also use a string and symbol to subscribe a handler to events:

const IssueReopened = Symbol('IssueReopened');

@bind('IssueDetected', IssueReopened)
class IssueDetectedHandler implements EventHandler<Issue> {
  public handle(payload: Issue): Promise<void> {
    // implementation
  }
}

As soon as the IssueDetected event appears, the event handler takes a single argument, the data passed from the client (in this case, an event payload which has been sent over the network).

License

Copyright © 2022 Bright Security.

This project is licensed under the MIT License - see the LICENSE file for details.

Package Sidebar

Install

npm i @sec-tester/core

Weekly Downloads

0

Version

0.16.0

License

MIT

Unpacked Size

60.7 kB

Total Files

114

Last publish

Collaborators

  • derevnjuk