Facts

What is a fact

A ‘fact’ in D20 is a data container class which represents some unit of information discovered about either an object (a file, binary blob, etc) or another fact. A fact should be descriptive enough to provide information to a Player to make some decision. This class is given a ‘type’ which is then used to organize all the facts in the system.

Fact Groups

Facts can be grouped up for convenience into fact groups. These groups are then exploded internally into their individual fact types. For example the hash type is actually a fact group which expands to the other fact types that are hashes (‘md5’, ‘sha1’, ‘sha256’, ‘ssdeep’).

Getting Started

Every fact must inherit from the Fact class and must use the registerFact decorator to register itself with the framework. Facts not part of the core distribution need to have their paths passed into the config.

The following is an example of a simple fact:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from d20.Manual.Facts import (Fact,
                            registerFact)

from d20.Manual.Facts.Fields import StringField


@registerFact('hash')
class CRC32HashFact(Fact):
    _type_ = 'crc32'
    value = StringField()

The above code creates a new fact with the type crc32 and as part of the hash fact group. It also contains a single field called value. Both the name of the class and value of _type_ should be unique. There are also a number of reserved names that act as an api. If there is any overlap, D20 will throw an error during the reigstration process.

registerFact

The registerFact decorator is used to register a fact with the framework. By default, it does not require arguments:

@registerFact
class CRC32HashFact(Fact):
    _type_ = 'crc32'
    value = StringField()

The only arguments accepted by the decorator are any fact groups that a fact being defined needs to be placed in:

@registerFact('hash', 'crc')
class CRC32HashFact(Fact):
    _type_ = 'crc32'
    value = StringField()

The above will create the crc32 fact type and add it to the hash and crc fact groups.

Fact Class

The Fact class along with the usage of the decorator provides a fair bit of internal instrumentation that makes it easier to work with. This includes taking any data fields defined and allowing them to be defined at class initialization time by keyword. It further allows you to use Fact Field types to better constrain how the data should be presented and used.

Immutability

After adding a Fact to the framework (via console.addFact), it should be considered immutable. Values should not be changed for any reason. Internally, D20 will update relationships, but this should be left entirely to the framework.

Fact Class Properties

By default the Fact class defines the following properties which should not be redefined:

  • id

  • parentObjects

  • addParentObject

  • remParentObject

  • parentFacts

  • addParentFact

  • remParentFact

  • parentHyps

  • addParentHyp

  • remParentHyp

  • childObjects

  • addChildObject

  • remChildObject

  • childFacts

  • addChildFact

  • remChildFact

  • childHyps

  • addChildHyp

  • remChildHyp

  • factType

  • factGroups

  • creator

  • created

  • tainted

  • save

  • load

The Fact class also defines other ‘private’ variables and so it is not recommened to define any fields that look like _<name>_.

Relationships

As might be indicated from the above properties there are many functions available for dealing with the relationships of facts to other objects. All of these are accessible to Players and NPCs, but must not be used after adding the fact to the framework. D20 handles relationships internally based on the information provided but will not automatically act on calls to these functions after a fact has been registered.

Accessor Methods

The following methods provide read-only information:

id

Returns the unique id of the fact in the framework

parentObjects

Returns a list of object id’s that are considered the ‘parent’ of this fact

parentFacts

Returns a list of fact id’s that are considered the ‘parent’ of this fact

parentHyps

Returns a list of hyp id’s that are considered the ‘parent’ of this fact

childObjects

Returns a list of object id’s that are considered ‘children’ of this fact

childFacts

Returns a list of fact id’s that are considered ‘children’ of this fact

childHyps

Returns a list of hyp id’s that are considered ‘children’ of this fact

factType

Returns the str indicating the type of this fact (e.g., crc32)

factGroups

Returns the list of str of the fact groups this fact was registered into

creator

Returns the name of the element (Player or NPC) that created this fact

created

Returns the unix timestamp when this fact was created

tainted

Returns a boolean value indicating if this Fact is actually a Hypothesis - mainly used for internal housekeeping

The following functions provide the ability to add relationships to facts. They take the numerical id of the element you are trying to relate. Note, these must not be used after adding a fact (or hyp) to the framework:

  • addParentObject

  • remParentObject

  • addParentFact

  • remParentFact

  • addParentHyp

  • remParentHyp

  • addChildObject

  • remChildObject

  • addChildFact

  • remChildFact

  • addChildHyp

  • remChildHyp

Fact Fields

Since Facts are data containers, they need data to contain. To ensure d20 can operate in an automated fashion, data is constrained to classes derived from the FactField class. The examples above uses the StringField class, which is derived from FactField and enforces the type to be a str type.

All fields take the following arguments:

  • required (default=False) - Whether the field is required

  • help (default=None) - A string to override the help/docstring of the field

  • default (no default value) - The default value of this field if not set

  • allowed_values (default=None) - A list of constraining values for this field

Here is a more complete example of a Fact class with a field with more options defined:

1
2
3
4
5
@registerFact('hash')
class CRC32HashFact(Fact):
    _type_ = 'crc'
    bits = IntegerField(required=True, allowed_values=[16,32])
    value = StringField(required=True, help='A CRC value')

To use the above type one could do the following:

foo = CRC32HashFact(bits=32, value="88638800")

The following fields are currently defined:

  • StringField

  • BooleanField

  • BytesField

  • IntegerField

  • FloatField

  • DictField

  • ListField

  • ListDictsField

  • NumericalField

  • StrOrBytesField

Custom Fields

If the existing fields do not meet your needs it is possible to create your own by creating a class that inherits from FactField or its descendants