mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
As the `MacaroonRootKeyID` field of the `AddActionReq` struct also contains the 4 bytes of the `MacaroonIdentifier`, we change all call sites to instead use the last 4 bytes of the `MacaroonRootKeyID` field. As the `MacaroonIdentifier` field therefore becomes redundant, we also remove it.
351 lines
10 KiB
Go
351 lines
10 KiB
Go
package firewalldb
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/lightninglabs/lightning-terminal/accounts"
|
|
"github.com/lightninglabs/lightning-terminal/session"
|
|
"github.com/lightningnetwork/lnd/fn"
|
|
)
|
|
|
|
// ActionState represents the state of an action.
|
|
type ActionState uint8
|
|
|
|
const (
|
|
// ActionStateUnknown means that the action's state was never
|
|
// initialised. This should never be the case.
|
|
ActionStateUnknown ActionState = 0
|
|
|
|
// ActionStateInit represents that an Action has been created but that
|
|
// is still in the pending state.
|
|
ActionStateInit ActionState = 1
|
|
|
|
// ActionStateDone represents that an Action has been executed
|
|
// successfully.
|
|
ActionStateDone ActionState = 2
|
|
|
|
// ActionStateError represents that an Action did not complete
|
|
// successfully.
|
|
ActionStateError ActionState = 3
|
|
)
|
|
|
|
// AddActionReq is the request that is used to add a new Action to the database.
|
|
// It contains all the information that is needed to create a new Action in the
|
|
// ActionStateInit State.
|
|
type AddActionReq struct {
|
|
// MacaroonRootKeyID is the uint64 / full 8 bytes of the root key ID of
|
|
// the macaroon used to perform the action.
|
|
// If no macaroon was used for the action, then this will not be set.
|
|
//
|
|
// NOTE: for our BoltDB impl, only the lower 32 bits / last 4 bytes of
|
|
// this uint64 are stored. When read back, the upper 32 bits / first 4
|
|
// bytes are zeroed.
|
|
MacaroonRootKeyID fn.Option[uint64]
|
|
|
|
// SessionID holds the optional session ID of the session that this
|
|
// action was performed with.
|
|
//
|
|
// NOTE: for our BoltDB impl, this is not persisted in any way, and we
|
|
// populate it by casting the MacaroonRootKeyID to a session.ID and so
|
|
// is not guaranteed to be linked to an existing session.
|
|
SessionID fn.Option[session.ID]
|
|
|
|
// AccountID holds the optional account ID of the account that this
|
|
// action was performed on.
|
|
//
|
|
// NOTE: for our BoltDB impl, this is not persisted in any way, and we
|
|
// do not populate it on reading from disk.
|
|
AccountID fn.Option[accounts.AccountID]
|
|
|
|
// ActorName is the name of the entity who performed the Action.
|
|
ActorName string
|
|
|
|
// FeatureName is the name of the feature that the Action is being
|
|
// performed by.
|
|
FeatureName string
|
|
|
|
// Trigger is the meta info detailing what caused this action to be
|
|
// executed.
|
|
Trigger string
|
|
|
|
// Intent is the meta info detailing what the intended outcome of this
|
|
// action will be.
|
|
Intent string
|
|
|
|
// StructuredJsonData is extra, structured, info that the Autopilot can
|
|
// send to Litd serialised as a json string.
|
|
StructuredJsonData string
|
|
|
|
// RPCMethod is the URI that was called.
|
|
RPCMethod string
|
|
|
|
// RPCParams is the method parameters of the request in JSON form.
|
|
RPCParamsJson []byte
|
|
}
|
|
|
|
// Action represents an RPC call made through the firewall.
|
|
type Action struct {
|
|
AddActionReq
|
|
|
|
// AttemptedAt is the time at which this action was created.
|
|
AttemptedAt time.Time
|
|
|
|
// State represents the state of the Action.
|
|
State ActionState
|
|
|
|
// ErrorReason is the human-readable reason for why the action failed.
|
|
// It will only be set if State is ActionStateError.
|
|
ErrorReason string
|
|
}
|
|
|
|
// ListActionsQuery can be used to tweak the query to ListActions and
|
|
// listSessionActions.
|
|
type ListActionsQuery struct {
|
|
// IndexOffset is index of the action to inspect.
|
|
IndexOffset uint64
|
|
|
|
// MaxNum is the maximum number of actions to return. If it is set to 0,
|
|
// then no maximum is enforced.
|
|
MaxNum uint64
|
|
|
|
// Reversed indicates whether the actions should be returned in reverse
|
|
// order.
|
|
Reversed bool
|
|
|
|
// CountAll should be set to true if the total number of actions that
|
|
// satisfy the query should be counted and returned. Note that this will
|
|
// make the query slower.
|
|
CountAll bool
|
|
}
|
|
|
|
// listActionsOptions holds the options that can be used to filter the actions
|
|
// that are returned by the ListActions method.
|
|
type listActionOptions struct {
|
|
sessionID session.ID
|
|
groupID session.ID
|
|
featureName string
|
|
actorName string
|
|
methodName string
|
|
state ActionState
|
|
endTime time.Time
|
|
startTime time.Time
|
|
}
|
|
|
|
// newListActionOptions creates a new listActionOptions instance with default
|
|
// query values.
|
|
func newListActionOptions() *listActionOptions {
|
|
return &listActionOptions{}
|
|
}
|
|
|
|
// ListActionOption is a functional option that can be used to tweak the
|
|
// behaviour of the ListActions method.
|
|
type ListActionOption func(*listActionOptions)
|
|
|
|
// WithActionSessionID is a ListActionOption that can be used to select all
|
|
// Actions performed under the given session ID.
|
|
func WithActionSessionID(sessionID session.ID) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.sessionID = sessionID
|
|
}
|
|
}
|
|
|
|
// WithActionGroupID is a ListActionOption that can be used to select all
|
|
// Actions performed under the give group ID.
|
|
func WithActionGroupID(groupID session.ID) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.groupID = groupID
|
|
}
|
|
}
|
|
|
|
// WithActionStartTime is a ListActionOption that can be used to select all
|
|
// Actions that were attempted after the given time.
|
|
func WithActionStartTime(startTime time.Time) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.startTime = startTime
|
|
}
|
|
}
|
|
|
|
// WithActionEndTime is a ListActionOption that can be used to select all
|
|
// Actions that were attempted before the given time.
|
|
func WithActionEndTime(endTime time.Time) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.endTime = endTime
|
|
}
|
|
}
|
|
|
|
// WithActionFeatureName is a ListActionOption that can be used to select all
|
|
// Actions that were performed by the given feature.
|
|
func WithActionFeatureName(featureName string) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.featureName = featureName
|
|
}
|
|
}
|
|
|
|
// WithActionActorName is a ListActionOption that can be used to select all
|
|
// Actions that were performed by the given actor.
|
|
func WithActionActorName(actorName string) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.actorName = actorName
|
|
}
|
|
}
|
|
|
|
// WithActionMethodName is a ListActionOption that can be used to select all
|
|
// Actions that called the given RPC method.
|
|
func WithActionMethodName(methodName string) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.methodName = methodName
|
|
}
|
|
}
|
|
|
|
// WithActionState is a ListActionOption that can be used to select all Actions
|
|
// that are in the given state.
|
|
func WithActionState(state ActionState) ListActionOption {
|
|
return func(o *listActionOptions) {
|
|
o.state = state
|
|
}
|
|
}
|
|
|
|
// ActionsWriteDB is an abstraction over the Actions DB that will allow a
|
|
// caller to add new actions as well as change the values of an existing action.
|
|
type ActionsWriteDB interface {
|
|
AddAction(ctx context.Context, req *AddActionReq) (ActionLocator, error)
|
|
SetActionState(ctx context.Context, al ActionLocator,
|
|
state ActionState, errReason string) error
|
|
}
|
|
|
|
// RuleAction represents a method call that was performed at a certain time at
|
|
// a certain time.
|
|
type RuleAction struct {
|
|
// Method is the URI of the rpc method that was called.
|
|
Method string
|
|
|
|
// PerformedAt is the time at which the action was attempted.
|
|
PerformedAt time.Time
|
|
}
|
|
|
|
// ActionsListDB represents a DB backend that contains Action entries that can
|
|
// be queried. It allows us to abstract away the details of the data storage
|
|
// method.
|
|
type ActionsListDB interface {
|
|
// ListActions returns a list of past Action items.
|
|
ListActions(ctx context.Context) ([]*RuleAction, error)
|
|
}
|
|
|
|
// ActionsReadDB is an abstraction gives a caller access to either a group
|
|
// specific or group and feature specific rules.ActionDB.
|
|
type ActionsReadDB interface {
|
|
GroupActionsDB() ActionsListDB
|
|
GroupFeatureActionsDB() ActionsListDB
|
|
}
|
|
|
|
// ActionReadDBGetter represents a function that can be used to construct
|
|
// an ActionsReadDB.
|
|
type ActionReadDBGetter interface {
|
|
GetActionsReadDB(groupID session.ID, featureName string) ActionsReadDB
|
|
}
|
|
|
|
// GetActionsReadDB is a method on DB that constructs an ActionsReadDB.
|
|
func (db *BoltDB) GetActionsReadDB(groupID session.ID,
|
|
featureName string) ActionsReadDB {
|
|
|
|
return &allActionsReadDB{
|
|
db: db,
|
|
groupID: groupID,
|
|
featureName: featureName,
|
|
}
|
|
}
|
|
|
|
// allActionsReadDb is an implementation of the ActionsReadDB.
|
|
type allActionsReadDB struct {
|
|
db ActionDB
|
|
groupID session.ID
|
|
featureName string
|
|
}
|
|
|
|
var _ ActionsReadDB = (*allActionsReadDB)(nil)
|
|
|
|
// GroupActionsDB returns a rules.ActionsListDB that will give the caller access
|
|
// to all of a groups Actions.
|
|
func (a *allActionsReadDB) GroupActionsDB() ActionsListDB {
|
|
return &groupActionsReadDB{a}
|
|
}
|
|
|
|
// GroupFeatureActionsDB returns a rules.ActionsListDB that will give the caller
|
|
// access to only a specific features Actions in a specific group.
|
|
func (a *allActionsReadDB) GroupFeatureActionsDB() ActionsListDB {
|
|
return &groupFeatureActionsReadDB{a}
|
|
}
|
|
|
|
// groupActionsReadDB is an implementation of the rules.ActionsListDB that will
|
|
// provide read access to all the Actions of a particular group.
|
|
type groupActionsReadDB struct {
|
|
*allActionsReadDB
|
|
}
|
|
|
|
var _ ActionsListDB = (*groupActionsReadDB)(nil)
|
|
|
|
// ListActions will return all the Actions for a particular group.
|
|
func (s *groupActionsReadDB) ListActions(ctx context.Context) ([]*RuleAction,
|
|
error) {
|
|
|
|
sessionActions, _, _, err := s.db.ListActions(
|
|
ctx, nil,
|
|
WithActionGroupID(s.groupID),
|
|
WithActionState(ActionStateDone),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
actions := make([]*RuleAction, len(sessionActions))
|
|
for i, action := range sessionActions {
|
|
actions[i] = actionToRulesAction(action)
|
|
}
|
|
|
|
return actions, nil
|
|
}
|
|
|
|
// groupFeatureActionsReadDB is an implementation of the rules.ActionsListDB that
|
|
// will provide read access to all the Actions of a feature within a particular
|
|
// group.
|
|
type groupFeatureActionsReadDB struct {
|
|
*allActionsReadDB
|
|
}
|
|
|
|
var _ ActionsListDB = (*groupFeatureActionsReadDB)(nil)
|
|
|
|
// ListActions will return all the Actions for a particular group that were
|
|
// executed by a particular feature.
|
|
func (a *groupFeatureActionsReadDB) ListActions(ctx context.Context) (
|
|
[]*RuleAction, error) {
|
|
|
|
featureActions, _, _, err := a.db.ListActions(
|
|
ctx, nil,
|
|
WithActionGroupID(a.groupID),
|
|
WithActionState(ActionStateDone),
|
|
WithActionFeatureName(a.featureName),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
actions := make([]*RuleAction, len(featureActions))
|
|
for i, action := range featureActions {
|
|
actions[i] = actionToRulesAction(action)
|
|
}
|
|
|
|
return actions, nil
|
|
}
|
|
|
|
func actionToRulesAction(a *Action) *RuleAction {
|
|
return &RuleAction{
|
|
Method: a.RPCMethod,
|
|
PerformedAt: a.AttemptedAt,
|
|
}
|
|
}
|
|
|
|
// ActionLocator helps us find an action in the database.
|
|
type ActionLocator interface {
|
|
isActionLocator()
|
|
}
|