parser

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 23, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package parser provides the factory for creating device-specific parsers that transform vendor configuration files into the platform-agnostic CommonDevice model.

Package parser provides the factory for creating device-specific parsers that transform vendor configuration files into the platform-agnostic CommonDevice model.

External consumers register custom DeviceParser implementations via init() and blank imports, following the database/sql driver registration pattern.

Package parser provides shared XML utilities for device-specific parsers.

Index

Constants

View Source
const DefaultMaxInputSize = 10 * 1024 * 1024 // 10MB

DefaultMaxInputSize is the default maximum size in bytes for XML input. This prevents XML bomb attacks by limiting how much data is read during root-element detection and parsing.

Variables

This section is empty.

Functions

func CharsetReader

func CharsetReader(charset string, input io.Reader) (io.Reader, error)

CharsetReader creates a reader for the specified XML charset declaration. Supported encodings: UTF-8, US-ASCII, ISO-8859-1 (Latin1), and Windows-1252. Only charsets whose ASCII subset matches UTF-8 are accepted, which is sufficient because XML element names use only ASCII-range characters.

func NewSecureXMLDecoder

func NewSecureXMLDecoder(r io.Reader, maxSize int64) *xml.Decoder

NewSecureXMLDecoder returns an *xml.Decoder configured with security hardening:

  • Input size limited to maxSize bytes (prevents XML bomb attacks)
  • Entity expansion disabled (prevents XXE attacks)
  • Charset reader for UTF-8, US-ASCII, ISO-8859-1, and Windows-1252

Both the OPNsense and pfSense parsers delegate to this function to avoid duplicating security hardening logic.

func Register

func Register(deviceType string, fn ConstructorFunc)

Register is a package-level convenience wrapper around DefaultRegistry().Register(). It follows the database/sql.Register() pattern for use in init() functions.

Types

type ConstructorFunc

type ConstructorFunc = func(XMLDecoder) DeviceParser

ConstructorFunc is the factory function signature for creating DeviceParser instances. The XMLDecoder parameter allows injection of the XML parsing backend. External parsers that manage their own XML decoding may ignore it.

type DeviceParser

type DeviceParser interface {
	// Parse reads and converts the configuration, returning non-fatal conversion warnings.
	Parse(ctx context.Context, r io.Reader) (*common.CommonDevice, []common.ConversionWarning, error)
	// ParseAndValidate reads, converts, and validates the configuration, returning non-fatal conversion warnings.
	ParseAndValidate(ctx context.Context, r io.Reader) (*common.CommonDevice, []common.ConversionWarning, error)
}

DeviceParser is the interface for device-specific parsers. Implementations return non-fatal conversion warnings alongside the parsed device model. Callers should log or surface these warnings without treating them as errors.

type DeviceParserRegistry

type DeviceParserRegistry struct {
	// contains filtered or unexported fields
}

DeviceParserRegistry manages registered DeviceParser constructors, keyed by the lowercase XML root element name of the device type they handle. It is safe for concurrent use.

func DefaultRegistry

func DefaultRegistry() *DeviceParserRegistry

DefaultRegistry returns the package-level DeviceParserRegistry singleton. External parsers call Register() on this instance from init().

func NewDeviceParserRegistry

func NewDeviceParserRegistry() *DeviceParserRegistry

NewDeviceParserRegistry returns a new, empty DeviceParserRegistry. Use this constructor in tests to create isolated registry instances that do not pollute the global singleton.

func (*DeviceParserRegistry) Get

func (r *DeviceParserRegistry) Get(deviceType string) (ConstructorFunc, bool)

Get returns the constructor for the given device type, or (nil, false) if no parser is registered for it. deviceType is normalized to lowercase with whitespace trimmed, matching the normalization applied by Register.

func (*DeviceParserRegistry) List

func (r *DeviceParserRegistry) List() []string

List returns a sorted slice of all registered device type names. The returned slice is a copy and safe to modify.

func (*DeviceParserRegistry) Register

func (r *DeviceParserRegistry) Register(deviceType string, fn ConstructorFunc)

Register adds a constructor for the given device type name. deviceType is normalized to lowercase with whitespace trimmed. Panics on duplicate registration, nil factory, or empty device type to surface wiring conflicts at startup (mirrors FormatRegistry and database/sql.Register contracts). Should only be called from init().

func (*DeviceParserRegistry) SupportedDevices

func (r *DeviceParserRegistry) SupportedDevices() string

SupportedDevices returns a formatted string listing all registered device type names, suitable for error messages. When the registry is empty, it returns an actionable hint about missing blank imports. This is the single source of truth for supported-device messaging across factory errors and CLI validation.

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory detects device type and delegates to the appropriate DeviceParser. The XMLDecoder is injected at construction to keep pkg/ free of internal/ imports. The registry defaults to DefaultRegistry() unless overridden via NewFactoryWithRegistry (e.g., for isolated tests).

func NewFactory

func NewFactory(decoder XMLDecoder) *Factory

NewFactory returns a new Factory that uses the given XMLDecoder for parsing and the global DefaultRegistry() for parser lookup. Pass cfgparser.NewXMLParser() from internal/cfgparser at the call site.

func NewFactoryWithRegistry

func NewFactoryWithRegistry(decoder XMLDecoder, reg *DeviceParserRegistry) *Factory

NewFactoryWithRegistry returns a Factory that uses a custom registry instead of the global singleton. This is primarily useful for tests that need isolated registry state without polluting the global registry.

func (*Factory) CreateDevice

func (f *Factory) CreateDevice(
	ctx context.Context,
	r io.Reader,
	deviceTypeOverride common.DeviceType,
	validateMode bool,
) (*common.CommonDevice, []common.ConversionWarning, error)

CreateDevice reads from r, detects (or uses the override) device type, and returns a fully converted CommonDevice along with any non-fatal conversion warnings. When validateMode is true, semantic validation is applied in addition to structural parsing.

type XMLDecoder

type XMLDecoder interface {
	// Parse reads XML from r and returns a parsed OpnSenseDocument.
	Parse(ctx context.Context, r io.Reader) (*schema.OpnSenseDocument, error)
	// ParseAndValidate reads XML from r, parses it, and applies semantic validation.
	ParseAndValidate(ctx context.Context, r io.Reader) (*schema.OpnSenseDocument, error)
}

XMLDecoder parses raw XML input into an OpnSenseDocument. Implementations must handle charset detection, entity expansion protection, and input size limits. The cfgparser.XMLParser in internal/cfgparser provides the default implementation used by the CLI.

Directories

Path Synopsis
Package opnsense provides an OPNsense-specific parser and converter that transforms schema.OpnSenseDocument into the platform-agnostic CommonDevice.
Package opnsense provides an OPNsense-specific parser and converter that transforms schema.OpnSenseDocument into the platform-agnostic CommonDevice.
Package pfsense provides a pfSense-specific parser and converter that transforms pfsense.Document into the platform-agnostic CommonDevice.
Package pfsense provides a pfSense-specific parser and converter that transforms pfsense.Document into the platform-agnostic CommonDevice.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL