diff --git a/.golangci.yml b/.golangci.yml index 10a42338b..7ff39caa1 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,6 +1,6 @@ run: # timeout for analysis - deadline: 4m + timeout: 4m build-tags: - autopilotrpc diff --git a/Makefile b/Makefile index 070f0860b..76fdb57d4 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,11 @@ ifneq ($(workers),) LINT_WORKERS = --concurrency=$(workers) endif -DOCKER_TOOLS = docker run -v $$(pwd):/build litd-tools +DOCKER_TOOLS = docker run \ + -v $(shell bash -c "go env GOCACHE || (mkdir -p /tmp/go-cache; echo /tmp/go-cache)"):/tmp/build/.cache \ + -v $(shell bash -c "go env GOMODCACHE || (mkdir -p /tmp/go-modcache; echo /tmp/go-modcache)"):/tmp/build/.modcache \ + -v $(shell bash -c "mkdir -p /tmp/go-lint-cache; echo /tmp/go-lint-cache"):/root/.cache/golangci-lint \ + -v $$(pwd):/build litd-tools ITEST_TAGS := integration itest $(LND_RELEASE_TAGS) ITEST_LDFLAGS := $(call make_ldflags, $(ITEST_TAGS)) diff --git a/app/src/types/generated/lit-autopilot_pb.d.ts b/app/src/types/generated/lit-autopilot_pb.d.ts index a933a4024..adc68d7a6 100644 --- a/app/src/types/generated/lit-autopilot_pb.d.ts +++ b/app/src/types/generated/lit-autopilot_pb.d.ts @@ -32,6 +32,12 @@ export class AddAutopilotSessionRequest extends jspb.Message { getLinkedGroupId_asB64(): string; setLinkedGroupId(value: Uint8Array | string): void; + getPrivacyFlags(): string; + setPrivacyFlags(value: string): void; + + getPrivacyFlagsSet(): boolean; + setPrivacyFlagsSet(value: boolean): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): AddAutopilotSessionRequest.AsObject; static toObject(includeInstance: boolean, msg: AddAutopilotSessionRequest): AddAutopilotSessionRequest.AsObject; @@ -52,6 +58,8 @@ export namespace AddAutopilotSessionRequest { sessionRules?: lit_sessions_pb.RulesMap.AsObject, noPrivacyMapper: boolean, linkedGroupId: Uint8Array | string, + privacyFlags: string, + privacyFlagsSet: boolean, } } @@ -236,6 +244,9 @@ export class Feature extends jspb.Message { getDefaultConfig(): string; setDefaultConfig(value: string): void; + getPrivacyFlags(): string; + setPrivacyFlags(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): Feature.AsObject; static toObject(includeInstance: boolean, msg: Feature): Feature.AsObject; @@ -254,6 +265,7 @@ export namespace Feature { permissionsListList: Array, requiresUpgrade: boolean, defaultConfig: string, + privacyFlags: string, } } diff --git a/app/src/types/generated/lit-autopilot_pb.js b/app/src/types/generated/lit-autopilot_pb.js index 3e8e7fad7..0902b8c56 100644 --- a/app/src/types/generated/lit-autopilot_pb.js +++ b/app/src/types/generated/lit-autopilot_pb.js @@ -81,7 +81,9 @@ proto.litrpc.AddAutopilotSessionRequest.toObject = function(includeInstance, msg featuresMap: (f = msg.getFeaturesMap()) ? f.toObject(includeInstance, proto.litrpc.FeatureConfig.toObject) : [], sessionRules: (f = msg.getSessionRules()) && lit$sessions_pb.RulesMap.toObject(includeInstance, f), noPrivacyMapper: jspb.Message.getFieldWithDefault(msg, 7, false), - linkedGroupId: msg.getLinkedGroupId_asB64() + linkedGroupId: msg.getLinkedGroupId_asB64(), + privacyFlags: jspb.Message.getFieldWithDefault(msg, 9, "0"), + privacyFlagsSet: jspb.Message.getFieldWithDefault(msg, 10, false) }; if (includeInstance) { @@ -153,6 +155,14 @@ proto.litrpc.AddAutopilotSessionRequest.deserializeBinaryFromReader = function(m var value = /** @type {!Uint8Array} */ (reader.readBytes()); msg.setLinkedGroupId(value); break; + case 9: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setPrivacyFlags(value); + break; + case 10: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setPrivacyFlagsSet(value); + break; default: reader.skipField(); break; @@ -236,6 +246,20 @@ proto.litrpc.AddAutopilotSessionRequest.serializeBinaryToWriter = function(messa f ); } + f = message.getPrivacyFlags(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 9, + f + ); + } + f = message.getPrivacyFlagsSet(); + if (f) { + writer.writeBool( + 10, + f + ); + } }; @@ -405,6 +429,38 @@ proto.litrpc.AddAutopilotSessionRequest.prototype.setLinkedGroupId = function(va }; +/** + * optional uint64 privacy_flags = 9; + * @return {string} + */ +proto.litrpc.AddAutopilotSessionRequest.prototype.getPrivacyFlags = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 9, "0")); +}; + + +/** @param {string} value */ +proto.litrpc.AddAutopilotSessionRequest.prototype.setPrivacyFlags = function(value) { + jspb.Message.setProto3StringIntField(this, 9, value); +}; + + +/** + * optional bool privacy_flags_set = 10; + * Note that Boolean fields may be set to 0/1 when serialized from a Java server. + * You should avoid comparisons like {@code val === true/false} in those cases. + * @return {boolean} + */ +proto.litrpc.AddAutopilotSessionRequest.prototype.getPrivacyFlagsSet = function() { + return /** @type {boolean} */ (jspb.Message.getFieldWithDefault(this, 10, false)); +}; + + +/** @param {boolean} value */ +proto.litrpc.AddAutopilotSessionRequest.prototype.setPrivacyFlagsSet = function(value) { + jspb.Message.setProto3BooleanField(this, 10, value); +}; + + /** * Generated by JsPbCodeGenerator. @@ -1660,7 +1716,8 @@ proto.litrpc.Feature.toObject = function(includeInstance, msg) { permissionsListList: jspb.Message.toObjectList(msg.getPermissionsListList(), proto.litrpc.Permissions.toObject, includeInstance), requiresUpgrade: jspb.Message.getFieldWithDefault(msg, 5, false), - defaultConfig: jspb.Message.getFieldWithDefault(msg, 6, "") + defaultConfig: jspb.Message.getFieldWithDefault(msg, 6, ""), + privacyFlags: jspb.Message.getFieldWithDefault(msg, 7, "0") }; if (includeInstance) { @@ -1724,6 +1781,10 @@ proto.litrpc.Feature.deserializeBinaryFromReader = function(msg, reader) { var value = /** @type {string} */ (reader.readString()); msg.setDefaultConfig(value); break; + case 7: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setPrivacyFlags(value); + break; default: reader.skipField(); break; @@ -1793,6 +1854,13 @@ proto.litrpc.Feature.serializeBinaryToWriter = function(message, writer) { f ); } + f = message.getPrivacyFlags(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 7, + f + ); + } }; @@ -1907,6 +1975,21 @@ proto.litrpc.Feature.prototype.setDefaultConfig = function(value) { }; +/** + * optional uint64 privacy_flags = 7; + * @return {string} + */ +proto.litrpc.Feature.prototype.getPrivacyFlags = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 7, "0")); +}; + + +/** @param {string} value */ +proto.litrpc.Feature.prototype.setPrivacyFlags = function(value) { + jspb.Message.setProto3StringIntField(this, 7, value); +}; + + /** * Generated by JsPbCodeGenerator. diff --git a/app/src/types/generated/lit-sessions_pb.d.ts b/app/src/types/generated/lit-sessions_pb.d.ts index 21091df50..314a2edfc 100644 --- a/app/src/types/generated/lit-sessions_pb.d.ts +++ b/app/src/types/generated/lit-sessions_pb.d.ts @@ -160,6 +160,9 @@ export class Session extends jspb.Message { getFeatureConfigsMap(): jspb.Map; clearFeatureConfigsMap(): void; + getPrivacyFlags(): string; + setPrivacyFlags(value: string): void; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): Session.AsObject; static toObject(includeInstance: boolean, msg: Session): Session.AsObject; @@ -190,6 +193,7 @@ export namespace Session { revokedAt: string, groupId: Uint8Array | string, featureConfigsMap: Array<[string, string]>, + privacyFlags: string, } } diff --git a/app/src/types/generated/lit-sessions_pb.js b/app/src/types/generated/lit-sessions_pb.js index ba6a2b788..07339cfdf 100644 --- a/app/src/types/generated/lit-sessions_pb.js +++ b/app/src/types/generated/lit-sessions_pb.js @@ -760,7 +760,8 @@ proto.litrpc.Session.toObject = function(includeInstance, msg) { autopilotFeatureInfoMap: (f = msg.getAutopilotFeatureInfoMap()) ? f.toObject(includeInstance, proto.litrpc.RulesMap.toObject) : [], revokedAt: jspb.Message.getFieldWithDefault(msg, 16, "0"), groupId: msg.getGroupId_asB64(), - featureConfigsMap: (f = msg.getFeatureConfigsMap()) ? f.toObject(includeInstance, undefined) : [] + featureConfigsMap: (f = msg.getFeatureConfigsMap()) ? f.toObject(includeInstance, undefined) : [], + privacyFlags: jspb.Message.getFieldWithDefault(msg, 19, "0") }; if (includeInstance) { @@ -874,6 +875,10 @@ proto.litrpc.Session.deserializeBinaryFromReader = function(msg, reader) { jspb.Map.deserializeBinary(message, reader, jspb.BinaryReader.prototype.readString, jspb.BinaryReader.prototype.readString, null, ""); }); break; + case 19: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setPrivacyFlags(value); + break; default: reader.skipField(); break; @@ -1024,6 +1029,13 @@ proto.litrpc.Session.serializeBinaryToWriter = function(message, writer) { if (f && f.getLength() > 0) { f.serializeBinary(18, writer, jspb.BinaryWriter.prototype.writeString, jspb.BinaryWriter.prototype.writeString); } + f = message.getPrivacyFlags(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 19, + f + ); + } }; @@ -1440,6 +1452,21 @@ proto.litrpc.Session.prototype.clearFeatureConfigsMap = function() { }; +/** + * optional uint64 privacy_flags = 19; + * @return {string} + */ +proto.litrpc.Session.prototype.getPrivacyFlags = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 19, "0")); +}; + + +/** @param {string} value */ +proto.litrpc.Session.prototype.setPrivacyFlags = function(value) { + jspb.Message.setProto3StringIntField(this, 19, value); +}; + + /** * Generated by JsPbCodeGenerator. diff --git a/app/src/util/tests/sampleData.ts b/app/src/util/tests/sampleData.ts index 6497171fc..3c4be2750 100644 --- a/app/src/util/tests/sampleData.ts +++ b/app/src/util/tests/sampleData.ts @@ -977,6 +977,7 @@ export const litListSessions: LIT.ListSessionsResponse.AsObject = { ], ], featureConfigsMap: [['SampleFeature', '{}']], + privacyFlags: '0', }, { id: '', @@ -1059,6 +1060,7 @@ export const litListSessions: LIT.ListSessionsResponse.AsObject = { ], ], featureConfigsMap: [['SampleFeature', '{}']], + privacyFlags: '0', }, ], }; diff --git a/autopilotserver/client.go b/autopilotserver/client.go index 953a94064..e98a9ee21 100644 --- a/autopilotserver/client.go +++ b/autopilotserver/client.go @@ -362,6 +362,7 @@ func (c *Client) ListFeatures(ctx context.Context) (map[string]*Feature, Permissions: perms, Rules: rules, DefaultConfig: feature.DefaultConfig, + PrivacyFlags: feature.PrivacyFlags, } } @@ -378,11 +379,12 @@ func (c *Client) ListFeatures(ctx context.Context) (map[string]*Feature, // Note: this is part of the Autopilot interface. func (c *Client) RegisterSession(ctx context.Context, pubKey *btcec.PublicKey, mailboxAddr string, devServer bool, featureConf map[string][]byte, - groupKey *btcec.PublicKey, linkSig []byte) (*btcec.PublicKey, error) { + groupKey *btcec.PublicKey, linkSig []byte, + privacyFlags uint64) (*btcec.PublicKey, error) { remotePub, err := c.registerSession( ctx, pubKey, mailboxAddr, devServer, featureConf, - groupKey, linkSig, + groupKey, linkSig, privacyFlags, ) if err != nil { log.Errorf("unsuccessful registration of session %x", @@ -428,8 +430,8 @@ func (c *Client) trackClient(pubKey *btcec.PublicKey) { // public key with the autopilot server. func (c *Client) registerSession(ctx context.Context, pubKey *btcec.PublicKey, mailboxAddr string, devServer bool, featureConfig map[string][]byte, - groupLocalPub *btcec.PublicKey, linkSig []byte) (*btcec.PublicKey, - error) { + groupLocalPub *btcec.PublicKey, linkSig []byte, + privacyFlags uint64) (*btcec.PublicKey, error) { client, cleanup, err := c.getClientConn() if err != nil { @@ -452,6 +454,7 @@ func (c *Client) registerSession(ctx context.Context, pubKey *btcec.PublicKey, LndVersion: marshalVersion(c.cfg.LndVersion), GroupResponderKey: groupKey, GroupResponderSig: linkSig, + PrivacyFlags: privacyFlags, }, ) if err != nil { diff --git a/autopilotserver/client_test.go b/autopilotserver/client_test.go index ad616dea2..3dcb07727 100644 --- a/autopilotserver/client_test.go +++ b/autopilotserver/client_test.go @@ -45,7 +45,9 @@ func TestAutopilotClient(t *testing.T) { require.ErrorContains(t, err, "no such client") // Register the client. - _, err = client.RegisterSession(ctx, pubKey, "", false, nil, nil, nil) + _, err = client.RegisterSession( + ctx, pubKey, "", false, nil, nil, nil, 0, + ) require.NoError(t, err) // Assert that the server sees the new client and has it in the Active diff --git a/autopilotserver/interface.go b/autopilotserver/interface.go index 57fcb6d3b..5a98d8ad9 100644 --- a/autopilotserver/interface.go +++ b/autopilotserver/interface.go @@ -30,7 +30,7 @@ type Autopilot interface { RegisterSession(ctx context.Context, pubKey *btcec.PublicKey, mailboxAddr string, devServer bool, featureConf map[string][]byte, linkedGroupKey *btcec.PublicKey, - linkSig []byte) (*btcec.PublicKey, error) + linkSig []byte, privacyFlags uint64) (*btcec.PublicKey, error) // ActivateSession attempts to inform the autopilot server that the // given session is still active. After this is called, the autopilot @@ -73,6 +73,9 @@ type Feature struct { // represents the default configuration we can use if the user doesn't // specify any. DefaultConfig []byte + + // PrivacyFlags is a list of privacy flags that the feature requires. + PrivacyFlags uint64 } // RuleValues holds the default value along with the sane max and min values diff --git a/autopilotserver/mock/server.go b/autopilotserver/mock/server.go index 9d18f74d1..cbee85d45 100644 --- a/autopilotserver/mock/server.go +++ b/autopilotserver/mock/server.go @@ -12,6 +12,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightninglabs/lightning-terminal/autopilotserverrpc" "github.com/lightninglabs/lightning-terminal/rules" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lntest/node" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -50,8 +51,9 @@ const ( ) type clientSession struct { - key *btcec.PrivateKey - state ClientState + key *btcec.PrivateKey + state ClientState + privacyFlags uint64 } // NewServer constructs a new MockAutoPilotServer. @@ -127,7 +129,7 @@ func (m *Server) Terms(context.Context, *autopilotserverrpc.TermsRequest) ( } // ListFeatures converts the mockFeatures into the form that the autopilot -// server would. +// server would return. // // Note: this is part of the autopilotrpc.AutopilotServer interface. func (m *Server) ListFeatures(_ context.Context, @@ -146,6 +148,7 @@ func (m *Server) ListFeatures(_ context.Context, Description: f.Description, Rules: rules, PermissionsList: permissionsToRPC(f.Permissions), + PrivacyFlags: f.PrivacyFlags, } } @@ -202,8 +205,9 @@ func (m *Server) RegisterSession(_ context.Context, } m.sessions[hex.EncodeToString(req.ResponderPubKey)] = &clientSession{ - key: priv, - state: ClientStateActive, + key: priv, + state: ClientStateActive, + privacyFlags: req.PrivacyFlags, } return &autopilotserverrpc.RegisterSessionResponse{ @@ -297,11 +301,32 @@ func (m *Server) SetClientState(remoteKey *btcec.PublicKey, return nil } +func (m *Server) GetPrivacyFlags(remoteKey *btcec.PublicKey) ( + session.PrivacyFlags, error) { + + m.sessMu.Lock() + defer m.sessMu.Unlock() + + key := hex.EncodeToString(remoteKey.SerializeCompressed()) + sess, ok := m.sessions[key] + if !ok { + return session.PrivacyFlags{}, fmt.Errorf("no such client found") + } + + privacyFlags, err := session.Deserialize(sess.privacyFlags) + if err != nil { + return session.PrivacyFlags{}, err + } + + return privacyFlags, nil +} + // Feature is a feature that the autopilot server could return. type Feature struct { - Description string - Rules map[string]*RuleRanges - Permissions map[string][]bakery.Op + Description string + Rules map[string]*RuleRanges + Permissions map[string][]bakery.Op + PrivacyFlags uint64 } // defaultFeatures is an example of a set of features that the autopilot server diff --git a/autopilotserverrpc/autopilotserver.pb.go b/autopilotserverrpc/autopilotserver.pb.go index b8c2ec3a4..dd9aece8e 100644 --- a/autopilotserverrpc/autopilotserver.pb.go +++ b/autopilotserverrpc/autopilotserver.pb.go @@ -373,6 +373,9 @@ type Feature struct { PermissionsList []*Permissions `protobuf:"bytes,4,rep,name=permissions_list,json=permissionsList,proto3" json:"permissions_list,omitempty"` // The JSON-marshaled representation of a feature's default configuration. DefaultConfig []byte `protobuf:"bytes,5,opt,name=default_config,json=defaultConfig,proto3" json:"default_config,omitempty"` + // This feature may require relaxed privacy obfuscation that can be enabled + // with these flags. + PrivacyFlags uint64 `protobuf:"varint,6,opt,name=privacy_flags,json=privacyFlags,proto3" json:"privacy_flags,omitempty"` } func (x *Feature) Reset() { @@ -442,6 +445,13 @@ func (x *Feature) GetDefaultConfig() []byte { return nil } +func (x *Feature) GetPrivacyFlags() uint64 { + if x != nil { + return x.PrivacyFlags + } + return 0 +} + type Rule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -659,6 +669,8 @@ type RegisterSessionRequest struct { // The signature by the first responder key of the serialised new responder // key. GroupResponderSig []byte `protobuf:"bytes,8,opt,name=group_responder_sig,json=groupResponderSig,proto3" json:"group_responder_sig,omitempty"` + // The privacy flags used by this session. + PrivacyFlags uint64 `protobuf:"varint,9,opt,name=privacy_flags,json=privacyFlags,proto3" json:"privacy_flags,omitempty"` } func (x *RegisterSessionRequest) Reset() { @@ -749,6 +761,13 @@ func (x *RegisterSessionRequest) GetGroupResponderSig() []byte { return nil } +func (x *RegisterSessionRequest) GetPrivacyFlags() uint64 { + if x != nil { + return x.PrivacyFlags + } + return 0 +} + type RegisterSessionResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -924,7 +943,7 @@ var file_autopilotserver_proto_rawDesc = []byte{ 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0xc4, 0x02, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, + 0x02, 0x38, 0x01, 0x22, 0xe9, 0x02, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, @@ -939,109 +958,114 @@ var file_autopilotserver_proto_rawDesc = []byte{ 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x52, 0x0a, 0x0a, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, - 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6e, 0x0a, 0x04, 0x52, 0x75, - 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, - 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x6d, 0x61, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x64, 0x0a, 0x0b, 0x50, 0x65, - 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, - 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x22, 0x3b, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8e, 0x04, - 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x75, - 0x62, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x69, 0x6c, 0x62, 0x6f, 0x78, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x69, 0x6c, - 0x62, 0x6f, 0x78, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x76, 0x5f, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x65, 0x76, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x3e, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x0e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, - 0x3c, 0x0a, 0x0b, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x0a, 0x6c, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, - 0x0b, 0x6c, 0x6e, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x0a, 0x6c, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x13, 0x67, - 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x73, - 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x69, 0x67, 0x1a, 0x41, 0x0a, 0x13, 0x46, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, - 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x69, - 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x50, - 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x42, 0x0a, 0x14, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, + 0x79, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x52, 0x0a, 0x0a, 0x52, + 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x75, 0x74, + 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, + 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x6e, 0x0a, 0x04, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x64, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, + 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x3d, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x61, 0x75, 0x74, + 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, + 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x3b, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0xb3, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x64, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x76, - 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x32, 0xfa, 0x03, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, - 0x12, 0x4c, 0x0a, 0x05, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x6f, - 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, - 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x75, - 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, - 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, - 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x27, - 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, - 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x6a, 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, + 0x64, 0x65, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x69, + 0x6c, 0x62, 0x6f, 0x78, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x6d, 0x61, 0x69, 0x6c, 0x62, 0x6f, 0x78, 0x41, 0x64, 0x64, 0x72, 0x12, 0x1d, 0x0a, 0x0a, + 0x64, 0x65, 0x76, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x64, 0x65, 0x76, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x67, 0x0a, 0x0f, 0x66, + 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, - 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x12, 0x2a, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, - 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, - 0x63, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0d, 0x52, 0x65, 0x76, - 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x61, 0x75, 0x74, + 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x12, 0x3c, 0x0a, 0x0b, 0x6c, 0x69, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x6f, + 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6c, 0x69, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0b, 0x6c, 0x6e, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, + 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6c, 0x6e, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x2e, 0x0a, 0x13, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x64, 0x65, 0x72, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x4b, 0x65, 0x79, + 0x12, 0x2e, 0x0a, 0x13, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x64, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x53, 0x69, 0x67, + 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x5f, 0x66, 0x6c, 0x61, 0x67, + 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, + 0x46, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x45, 0x0a, 0x17, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, + 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, + 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x50, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22, + 0x42, 0x0a, 0x14, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x75, 0x62, + 0x4b, 0x65, 0x79, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xfa, 0x03, 0x0a, + 0x09, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x12, 0x4c, 0x0a, 0x05, 0x54, 0x65, + 0x72, 0x6d, 0x73, 0x12, 0x20, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, + 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, + 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x27, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, + 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x28, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x0f, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, + 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x0f, 0x41, 0x63, 0x74, 0x69, 0x76, + 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2a, 0x2e, 0x61, 0x75, 0x74, + 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, + 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, + 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x63, 0x74, 0x69, + 0x76, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, - 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, - 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x69, 0x67, 0x68, - 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x61, - 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, - 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, + 0x2e, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, + 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x2d, + 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, + 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/autopilotserverrpc/autopilotserver.proto b/autopilotserverrpc/autopilotserver.proto index 3f29e80a3..923d4e56f 100644 --- a/autopilotserverrpc/autopilotserver.proto +++ b/autopilotserverrpc/autopilotserver.proto @@ -92,6 +92,12 @@ message Feature { The JSON-marshaled representation of a feature's default configuration. */ bytes default_config = 5; + + /* + This feature may require relaxed privacy obfuscation that can be enabled + with these flags. + */ + uint64 privacy_flags = 6; } message Rule { @@ -187,6 +193,11 @@ message RegisterSessionRequest { key. */ bytes group_responder_sig = 8; + + /* + The privacy flags used by this session. + */ + uint64 privacy_flags = 9; } message RegisterSessionResponse { diff --git a/cmd/litcli/autopilot.go b/cmd/litcli/autopilot.go index b21b91942..025ea2a9b 100644 --- a/cmd/litcli/autopilot.go +++ b/cmd/litcli/autopilot.go @@ -11,6 +11,7 @@ import ( "github.com/lightninglabs/lightning-terminal/litrpc" "github.com/lightninglabs/lightning-terminal/rules" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lnrpc" "github.com/urfave/cli" ) @@ -129,6 +130,29 @@ var addAutopilotSessionCmd = cli.Command{ `An empty rule map is allowed with {} to ` + `use the default rules.`, }, + cli.StringFlag{ + Name: "privacy-flags", + Usage: "String representation of privacy flags to set " + + "for the session. Each individual flag will " + + "remove privacy from certain aspects of " + + "messages transmitted to autopilot. " + + "The strongest privacy is on by " + + "default and an empty string means full " + + "privacy. Some features may not be able to " + + "run correctly with full privacy, see the " + + "autopilot features call for a list of " + + "default required privacy flags. Those " + + "minimally required privacy flags are set " + + "automatically if nothing is specified here. " + + "Combining several features will " + + "require the union of all individual " + + "feature's privacy flags, which is why it is " + + "recommended to register each feature " + + "separately for best privacy. Linking to a " + + "previous session must preserve privacy " + + "flags of the previous session. Example: " + + "\"ClearPubkeys|ClearAmounts\"", + }, }, } @@ -403,6 +427,19 @@ func initAutopilotSession(ctx *cli.Context) error { } } + var privacyFlags uint64 + var privacyFlagsSet bool + if ctx.IsSet("privacy-flags") { + privacyFlagsSet = true + + flags, err := session.Parse(ctx.String("privacy-flags")) + if err != nil { + return err + } + + privacyFlags = flags.Serialize() + } + resp, err := client.AddAutopilotSession( ctxb, &litrpc.AddAutopilotSessionRequest{ Label: ctx.String("label"), @@ -411,6 +448,8 @@ func initAutopilotSession(ctx *cli.Context) error { DevServer: ctx.Bool("devserver"), Features: featureMap, LinkedGroupId: groupID, + PrivacyFlags: privacyFlags, + PrivacyFlagsSet: privacyFlagsSet, }, ) if err != nil { diff --git a/firewall/privacy_mapper.go b/firewall/privacy_mapper.go index 9a0761ee7..2a57e9761 100644 --- a/firewall/privacy_mapper.go +++ b/firewall/privacy_mapper.go @@ -59,21 +59,21 @@ var _ mid.RequestInterceptor = (*PrivacyMapper)(nil) // PrivacyMapper is a RequestInterceptor that maps any pseudo names in certain // requests to their real values and vice versa for responses. type PrivacyMapper struct { - newDB firewalldb.NewPrivacyMapDB - randIntn func(int) (int, error) - sessionIDIndexDB session.IDToGroupIndex + newDB firewalldb.NewPrivacyMapDB + randIntn func(int) (int, error) + sessionDB firewalldb.SessionDB } // NewPrivacyMapper returns a new instance of PrivacyMapper. The randIntn // function is used to draw randomness for request field obfuscation. func NewPrivacyMapper(newDB firewalldb.NewPrivacyMapDB, randIntn func(int) (int, error), - sessionIDIndexDB session.IDToGroupIndex) *PrivacyMapper { + sessionDB firewalldb.SessionDB) *PrivacyMapper { return &PrivacyMapper{ - newDB: newDB, - randIntn: randIntn, - sessionIDIndexDB: sessionIDIndexDB, + newDB: newDB, + randIntn: randIntn, + sessionDB: sessionDB, } } @@ -110,12 +110,6 @@ func (p *PrivacyMapper) Intercept(ctx context.Context, return nil, fmt.Errorf("could not extract ID from macaroon") } - // Get group ID for session ID. - groupID, err := p.sessionIDIndexDB.GetGroupID(sessionID) - if err != nil { - return nil, err - } - log.Tracef("PrivacyMapper: Intercepting %v", ri) switch r := req.InterceptType.(type) { @@ -133,7 +127,7 @@ func (p *PrivacyMapper) Intercept(ctx context.Context, } replacement, err := p.checkAndReplaceIncomingRequest( - ctx, r.Request.MethodFullUri, msg, groupID, + ctx, r.Request.MethodFullUri, msg, sessionID, ) if err != nil { return mid.RPCErr(req, err) @@ -167,7 +161,7 @@ func (p *PrivacyMapper) Intercept(ctx context.Context, } replacement, err := p.replaceOutgoingResponse( - ctx, r.Response.MethodFullUri, msg, groupID, + ctx, r.Response.MethodFullUri, msg, sessionID, ) if err != nil { return mid.RPCErr(req, err) @@ -192,14 +186,19 @@ func (p *PrivacyMapper) Intercept(ctx context.Context, // checkAndReplaceIncomingRequest inspects an incoming request and optionally // modifies some of the request parameters. func (p *PrivacyMapper) checkAndReplaceIncomingRequest(ctx context.Context, - uri string, req proto.Message, groupID session.ID) (proto.Message, + uri string, req proto.Message, sessionID session.ID) (proto.Message, error) { - db := p.newDB(groupID) + session, err := p.sessionDB.GetSessionByID(sessionID) + if err != nil { + return nil, err + } + + db := p.newDB(session.GroupID) // If we don't have a handler for the URI, we don't allow the request // to go through. - checker, ok := p.checkers(db)[uri] + checker, ok := p.checkers(db, session.PrivacyFlags)[uri] if !ok { return nil, ErrNotSupportedByPrivacyMapper } @@ -218,13 +217,18 @@ func (p *PrivacyMapper) checkAndReplaceIncomingRequest(ctx context.Context, // replaceOutgoingResponse inspects the responses before sending them out to the // client and replaces them if needed. func (p *PrivacyMapper) replaceOutgoingResponse(ctx context.Context, uri string, - resp proto.Message, groupID session.ID) (proto.Message, error) { + resp proto.Message, sessionID session.ID) (proto.Message, error) { - db := p.newDB(groupID) + session, err := p.sessionDB.GetSessionByID(sessionID) + if err != nil { + return nil, err + } + + db := p.newDB(session.GroupID) // If we don't have a handler for the URI, we don't allow the response // to go to avoid accidental leaks. - checker, ok := p.checkers(db)[uri] + checker, ok := p.checkers(db, session.PrivacyFlags)[uri] if !ok { return nil, ErrNotSupportedByPrivacyMapper } @@ -240,64 +244,66 @@ func (p *PrivacyMapper) replaceOutgoingResponse(ctx context.Context, uri string, return checker.HandleResponse(ctx, resp) } -func (p *PrivacyMapper) checkers( - db firewalldb.PrivacyMapDB) map[string]mid.RoundTripChecker { +func (p *PrivacyMapper) checkers(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) map[string]mid.RoundTripChecker { return map[string]mid.RoundTripChecker{ "/lnrpc.Lightning/GetInfo": mid.NewResponseRewriter( &lnrpc.GetInfoRequest{}, &lnrpc.GetInfoResponse{}, - handleGetInfoResponse(db), mid.PassThroughErrorHandler, + handleGetInfoResponse(db, flags), + mid.PassThroughErrorHandler, ), "/lnrpc.Lightning/ForwardingHistory": mid.NewResponseRewriter( &lnrpc.ForwardingHistoryRequest{}, &lnrpc.ForwardingHistoryResponse{}, - handleFwdHistoryResponse(db, p.randIntn), + handleFwdHistoryResponse(db, flags, p.randIntn), mid.PassThroughErrorHandler, ), "/lnrpc.Lightning/FeeReport": mid.NewResponseRewriter( &lnrpc.FeeReportRequest{}, &lnrpc.FeeReportResponse{}, - handleFeeReportResponse(db), + handleFeeReportResponse(db, flags), mid.PassThroughErrorHandler, ), "/lnrpc.Lightning/ListChannels": mid.NewFullRewriter( &lnrpc.ListChannelsRequest{}, &lnrpc.ListChannelsResponse{}, - handleListChannelsRequest(db), - handleListChannelsResponse(db, p.randIntn), + handleListChannelsRequest(db, flags), + handleListChannelsResponse(db, flags, p.randIntn), mid.PassThroughErrorHandler, ), "/lnrpc.Lightning/UpdateChannelPolicy": mid.NewFullRewriter( &lnrpc.PolicyUpdateRequest{}, &lnrpc.PolicyUpdateResponse{}, - handleUpdatePolicyRequest(db), - handleUpdatePolicyResponse(db), + handleUpdatePolicyRequest(db, flags), + handleUpdatePolicyResponse(db, flags), mid.PassThroughErrorHandler, ), } } -func handleGetInfoResponse(db firewalldb.PrivacyMapDB) func(ctx context.Context, +func handleGetInfoResponse(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) func(ctx context.Context, r *lnrpc.GetInfoResponse) (proto.Message, error) { - return func(ctx context.Context, r *lnrpc.GetInfoResponse) ( + return func(_ context.Context, r *lnrpc.GetInfoResponse) ( proto.Message, error) { - var pseudoPubKey string - err := db.Update( - func(tx firewalldb.PrivacyMapTx) error { - var err error - pseudoPubKey, err = firewalldb.HideString( - tx, r.IdentityPubkey, - ) - if err != nil { - return err - } + // We hide the pubkey unless it is disabled. + pseudoPubKey := r.IdentityPubkey + if !flags.Contains(session.ClearPubkeys) { + err := db.Update( + func(tx firewalldb.PrivacyMapTx) error { + var err error + pseudoPubKey, err = firewalldb.HideString( + tx, r.IdentityPubkey, + ) - return nil - }, - ) - if err != nil { - return nil, err + return err + }, + ) + if err != nil { + return nil, err + } } return &lnrpc.GetInfoResponse{ @@ -327,6 +333,7 @@ func handleGetInfoResponse(db firewalldb.PrivacyMapDB) func(ctx context.Context, } func handleFwdHistoryResponse(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags, randIntn func(int) (int, error)) func(ctx context.Context, r *lnrpc.ForwardingHistoryResponse) (proto.Message, error) { @@ -339,36 +346,48 @@ func handleFwdHistoryResponse(db firewalldb.PrivacyMapDB, err := db.Update(func(tx firewalldb.PrivacyMapTx) error { for i, fe := range r.ForwardingEvents { - // Deterministically hide channel ids. - chanIn, err := firewalldb.HideUint64( - tx, fe.ChanIdIn, - ) - if err != nil { - return err - } - - chanOut, err := firewalldb.HideUint64( - tx, fe.ChanIdOut, - ) - if err != nil { - return err - } + var err error - // We randomize the outgoing amount for privacy. - amtOutMsat, err := hideAmount( - randIntn, amountVariation, - fe.AmtOutMsat, - ) - if err != nil { - return err + chanIn := fe.ChanIdIn + chanOut := fe.ChanIdOut + if !flags.Contains(session.ClearChanIDs) { + // Deterministically hide channel ids. + chanIn, err = firewalldb.HideUint64( + tx, chanIn, + ) + if err != nil { + return err + } + + chanOut, err = firewalldb.HideUint64( + tx, chanOut, + ) + if err != nil { + return err + } } - // We randomize fees for privacy. - feeMsat, err := hideAmount( - randIntn, amountVariation, fe.FeeMsat, - ) - if err != nil { - return err + amtOutMsat := fe.AmtOutMsat + feeMsat := fe.FeeMsat + if !flags.Contains(session.ClearAmounts) { + // We randomize the outgoing amount for + // privacy. + amtOutMsat, err = hideAmount( + randIntn, amountVariation, + amtOutMsat, + ) + if err != nil { + return err + } + + // We randomize fees for privacy. + feeMsat, err = hideAmount( + randIntn, amountVariation, + feeMsat, + ) + if err != nil { + return err + } } // Populate other fields in a consistent manner. @@ -377,13 +396,16 @@ func handleFwdHistoryResponse(db firewalldb.PrivacyMapDB, amtIn := amtInMsat / 1000 fee := feeMsat / 1000 - // We randomize the forwarding timestamp. - timestamp, err := hideTimestamp( - randIntn, timeVariation, - time.Unix(0, int64(fe.TimestampNs)), - ) - if err != nil { - return err + timestamp := time.Unix(0, int64(fe.TimestampNs)) + if !flags.Contains(session.ClearTimeStamps) { + // We randomize the forwarding timestamp. + timestamp, err = hideTimestamp( + randIntn, timeVariation, + timestamp, + ) + if err != nil { + return err + } } fwdEvents[i] = &lnrpc.ForwardingEvent{ @@ -416,9 +438,9 @@ func handleFwdHistoryResponse(db firewalldb.PrivacyMapDB, } } -func handleFeeReportResponse(db firewalldb.PrivacyMapDB) func( - ctx context.Context, r *lnrpc.FeeReportResponse) (proto.Message, - error) { +func handleFeeReportResponse(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) func(ctx context.Context, + r *lnrpc.FeeReportResponse) (proto.Message, error) { return func(ctx context.Context, r *lnrpc.FeeReportResponse) ( proto.Message, error) { @@ -426,19 +448,27 @@ func handleFeeReportResponse(db firewalldb.PrivacyMapDB) func( chanFees := make([]*lnrpc.ChannelFeeReport, len(r.ChannelFees)) err := db.Update(func(tx firewalldb.PrivacyMapTx) error { + var err error + for i, c := range r.ChannelFees { - chanID, err := firewalldb.HideUint64( - tx, c.ChanId, - ) - if err != nil { - return err + chanID := c.ChanId + if !flags.Contains(session.ClearChanIDs) { + chanID, err = firewalldb.HideUint64( + tx, chanID, + ) + if err != nil { + return err + } } - chanPoint, err := firewalldb.HideChanPointStr( - tx, c.ChannelPoint, - ) - if err != nil { - return err + chanPoint := c.ChannelPoint + if !flags.Contains(session.ClearChanIDs) { + chanPoint, err = firewalldb.HideChanPointStr( + tx, chanPoint, + ) + if err != nil { + return err + } } chanFees[i] = &lnrpc.ChannelFeeReport{ @@ -465,9 +495,9 @@ func handleFeeReportResponse(db firewalldb.PrivacyMapDB) func( } } -func handleListChannelsRequest(db firewalldb.PrivacyMapDB) func( - ctx context.Context, r *lnrpc.ListChannelsRequest) (proto.Message, - error) { +func handleListChannelsRequest(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) func(ctx context.Context, + r *lnrpc.ListChannelsRequest) (proto.Message, error) { return func(ctx context.Context, r *lnrpc.ListChannelsRequest) ( proto.Message, error) { @@ -476,6 +506,10 @@ func handleListChannelsRequest(db firewalldb.PrivacyMapDB) func( return nil, nil } + if flags.Contains(session.ClearPubkeys) { + return r, nil + } + err := db.View(func(tx firewalldb.PrivacyMapTx) error { peer, err := firewalldb.RevealBytes(tx, r.Peer) if err != nil { @@ -494,6 +528,7 @@ func handleListChannelsRequest(db firewalldb.PrivacyMapDB) func( } func handleListChannelsResponse(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags, randIntn func(int) (int, error)) func(ctx context.Context, r *lnrpc.ListChannelsResponse) (proto.Message, error) { @@ -501,47 +536,66 @@ func handleListChannelsResponse(db firewalldb.PrivacyMapDB, proto.Message, error) { hideAmount := func(a int64) (int64, error) { - hiddenAmount, err := hideAmount( - randIntn, amountVariation, uint64(a), - ) - if err != nil { - return 0, err + if !flags.Contains(session.ClearAmounts) { + hiddenAmount, err := hideAmount( + randIntn, amountVariation, uint64(a), + ) + if err != nil { + return 0, err + } + + return int64(hiddenAmount), nil } - return int64(hiddenAmount), nil + return a, nil } + hidePubkeys := !flags.Contains(session.ClearPubkeys) + hideChanIds := !flags.Contains(session.ClearChanIDs) + channels := make([]*lnrpc.Channel, len(r.Channels)) err := db.Update(func(tx firewalldb.PrivacyMapTx) error { for i, c := range r.Channels { - // Deterministically hide the peer pubkey, - // the channel point, and the channel id. - remotePub, err := firewalldb.HideString( - tx, c.RemotePubkey, - ) - if err != nil { - return err - } + var err error - chanPoint, err := firewalldb.HideChanPointStr( - tx, c.ChannelPoint, - ) - if err != nil { - return err + // We hide the remote pubkey unless it is + // disabled. + remotePub := c.RemotePubkey + if hidePubkeys { + remotePub, err = firewalldb.HideString( + tx, c.RemotePubkey, + ) + if err != nil { + return err + } } - chanID, err := firewalldb.HideUint64( - tx, c.ChanId, - ) - if err != nil { - return err + chanPoint := c.ChannelPoint + chanID := c.ChanId + if hideChanIds { + chanPoint, err = firewalldb.HideChanPointStr( + tx, c.ChannelPoint, + ) + if err != nil { + return err + } + + chanID, err = firewalldb.HideUint64( + tx, c.ChanId, + ) + if err != nil { + return err + } } // We hide the initiator. - initiator, err := hideBool(randIntn) - if err != nil { - return err + initiator := c.Initiator + if !flags.Contains(session.ClearChanInitiator) { + initiator, err = hideBool(randIntn) + if err != nil { + return err + } } // Consider the capacity to be public @@ -563,8 +617,12 @@ func handleListChannelsResponse(db firewalldb.PrivacyMapDB, localBalance = c.Capacity } - // We adapt the remote balance accordingly. - remoteBalance := c.Capacity - localBalance + remoteBalance := c.RemoteBalance + if !flags.Contains(session.ClearAmounts) { + // We adapt the remote balance + // accordingly. + remoteBalance = c.Capacity - localBalance + } // We hide the total sats sent and received. satsReceived, err := hideAmount( @@ -587,6 +645,11 @@ func handleListChannelsResponse(db firewalldb.PrivacyMapDB, []*lnrpc.HTLC, len(c.PendingHtlcs), ) + // Only show the HTLCs if the flag is set. + if flags.Contains(session.ClearHTLCs) { + copy(pendingHtlcs, c.PendingHtlcs) + } + // We hide the unsettled balance. unsettled, err := hideAmount(c.UnsettledBalance) if err != nil { @@ -648,11 +711,11 @@ func handleListChannelsResponse(db firewalldb.PrivacyMapDB, } } -func handleUpdatePolicyRequest(db firewalldb.PrivacyMapDB) func( - ctx context.Context, r *lnrpc.PolicyUpdateRequest) (proto.Message, - error) { +func handleUpdatePolicyRequest(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) func(ctx context.Context, + r *lnrpc.PolicyUpdateRequest) (proto.Message, error) { - return func(ctx context.Context, r *lnrpc.PolicyUpdateRequest) ( + return func(_ context.Context, r *lnrpc.PolicyUpdateRequest) ( proto.Message, error) { chanPoint := r.GetChanPoint() @@ -668,21 +731,19 @@ func handleUpdatePolicyRequest(db firewalldb.PrivacyMapDB) func( return nil, err } - index := chanPoint.GetOutputIndex() - - var ( - newTxid string - newIndex uint32 - ) - err = db.View(func(tx firewalldb.PrivacyMapTx) error { - var err error - newTxid, newIndex, err = firewalldb.RevealChanPoint( - tx, txid.String(), index, - ) - return err - }) - if err != nil { - return nil, err + newTxid := txid.String() + newIndex := chanPoint.GetOutputIndex() + if !flags.Contains(session.ClearChanIDs) { + err = db.View(func(tx firewalldb.PrivacyMapTx) error { + var err error + newTxid, newIndex, err = firewalldb.RevealChanPoint( + tx, newTxid, newIndex, + ) + return err + }) + if err != nil { + return nil, err + } } r.Scope = &lnrpc.PolicyUpdateRequest_ChanPoint{ @@ -698,13 +759,17 @@ func handleUpdatePolicyRequest(db firewalldb.PrivacyMapDB) func( } } -func handleUpdatePolicyResponse(db firewalldb.PrivacyMapDB) func( - ctx context.Context, r *lnrpc.PolicyUpdateResponse) (proto.Message, - error) { +func handleUpdatePolicyResponse(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) func(ctx context.Context, + r *lnrpc.PolicyUpdateResponse) (proto.Message, error) { - return func(ctx context.Context, r *lnrpc.PolicyUpdateResponse) ( + return func(_ context.Context, r *lnrpc.PolicyUpdateResponse) ( proto.Message, error) { + if flags.Contains(session.ClearChanIDs) { + return r, nil + } + failedUpdates := make( []*lnrpc.FailedUpdate, len(r.FailedUpdates), ) @@ -862,8 +927,8 @@ func CryptoRandIntn(n int) (int, error) { // ObfuscateConfig alters the config string by replacing sensitive data with // random values and returns new replacement pairs. We only substitute items in // strings, numbers are left unchanged. -func ObfuscateConfig(db firewalldb.PrivacyMapReader, configB []byte) ([]byte, - map[string]string, error) { +func ObfuscateConfig(db firewalldb.PrivacyMapReader, configB []byte, + flags session.PrivacyFlags) ([]byte, map[string]string, error) { if len(configB) == 0 { return nil, nil, nil @@ -913,29 +978,46 @@ func ObfuscateConfig(db firewalldb.PrivacyMapReader, configB []byte) ([]byte, for i, value := range stringList { value := strings.TrimSpace(value) - // We first check if we have a mapping for this value - // already. - obfVal, haveValue := db.GetPseudo(value) - if haveValue { - obfuscatedValues[i] = obfVal - - continue - } + alreadyHave := func() (string, bool) { + // We check if we have obfuscated this value + // already in this run. + obfVal, ok := privMapPairs[value] + if ok { + return obfVal, true + } - // We check if we have obfuscated this value already in - // this run. - obfVal, haveValue = privMapPairs[value] - if haveValue { - obfuscatedValues[i] = obfVal + // We first check if we have a mapping for this + // value already within the database. + obfVal, ok = db.GetPseudo(value) + if ok { + return obfVal, true + } - continue + return "", false } // From here on we create new obfuscated values. // Try to replace with a chan point. _, _, err := firewalldb.DecodeChannelPoint(value) if err == nil { - obfVal, err = firewalldb.NewPseudoChanPoint() + // We don't obfuscate channel points if the flag + // is set. + if flags.Contains(session.ClearChanIDs) { + obfuscatedValues[i] = value + + continue + } + + // We replace the channel point with a random + // value, should we already have it. + if obfVal, ok := alreadyHave(); ok { + obfuscatedValues[i] = obfVal + + continue + } + + // Otherwise we create a new mapping. + obfVal, err := firewalldb.NewPseudoChanPoint() if err != nil { return nil, nil, err } @@ -950,6 +1032,23 @@ func ObfuscateConfig(db firewalldb.PrivacyMapReader, configB []byte) ([]byte, // value. _, err = hex.DecodeString(value) if err == nil && len(value) == pubKeyLen { + // We don't obfuscate pubkeys if the flag is + // set. + if flags.Contains(session.ClearPubkeys) { + obfuscatedValues[i] = value + + continue + } + + // We replace the pubkey with a random value, + // should we already have it. + if obfVal, ok := alreadyHave(); ok { + obfuscatedValues[i] = obfVal + + continue + } + + // Otherwise we create a new mapping. obfVal, err := firewalldb.NewPseudoStr( len(value), ) @@ -973,6 +1072,23 @@ func ObfuscateConfig(db firewalldb.PrivacyMapReader, configB []byte) ([]byte, if err == nil && minChanIDLen <= length && length <= maxChanIDLen { + // We don't obfuscate channel ids if the flag is + // set. + if flags.Contains(session.ClearChanIDs) { + obfuscatedValues[i] = value + + continue + } + + // We replace the channel id with a random + // value, should we already have it. + if obfVal, ok := alreadyHave(); ok { + obfuscatedValues[i] = obfVal + + continue + } + + // Otherwise we create a new mapping. obfVal, err := firewalldb.NewPseudoStr(length) if err != nil { return nil, nil, err diff --git a/firewall/privacy_mapper_test.go b/firewall/privacy_mapper_test.go index edd16b98f..4c302e8c2 100644 --- a/firewall/privacy_mapper_test.go +++ b/firewall/privacy_mapper_test.go @@ -3,7 +3,6 @@ package firewall import ( "context" "encoding/json" - "fmt" "testing" "time" @@ -20,8 +19,58 @@ import ( // TestPrivacyMapper tests that the PrivacyMapper correctly intercepts specific // RPC calls. func TestPrivacyMapper(t *testing.T) { + var ( + clearForwarding = &lnrpc.ForwardingHistoryResponse{ + ForwardingEvents: []*lnrpc.ForwardingEvent{ + { + AmtIn: 2_000, + AmtInMsat: 2_000_000, + AmtOut: 1_000, + AmtOutMsat: 1_000_000, + Fee: 1_000, + FeeMsat: 1_000_000, + Timestamp: 1_000, + TimestampNs: 1_000_000_000_000, + ChanIdIn: 123, + ChanIdOut: 321, + }, + { + AmtIn: 3_000, + AmtInMsat: 3_000_000, + AmtOut: 2_000, + AmtOutMsat: 2_000_000, + Fee: 1_000, + FeeMsat: 1_000_000, + Timestamp: 1_000, + TimestampNs: 1_000_000_000_000, + ChanIdIn: 678, + ChanIdOut: 876, + }, + }, + } + + clearListChannel = &lnrpc.ListChannelsResponse{ + Channels: []*lnrpc.Channel{ + { + Capacity: 1_000_000, + RemoteBalance: 600_000, + LocalBalance: 499_000, + CommitFee: 1_000, + TotalSatoshisSent: 500_000, + TotalSatoshisReceived: 450_000, + RemotePubkey: "01020304", + Initiator: false, + ChanId: 123, + ChannelPoint: "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd:0", + PendingHtlcs: []*lnrpc.HTLC{{HashLock: []byte("aaaa")}, {HashLock: []byte("bbbb")}}, + }, + }, + } + ) + tests := []struct { name string + privacyFlags session.PrivacyFlags uri string msgType rpcperms.InterceptType msg proto.Message @@ -44,37 +93,41 @@ func TestPrivacyMapper(t *testing.T) { }, }, { - name: "ForwardingHistory Response", - uri: "/lnrpc.Lightning/ForwardingHistory", + name: "GetInfo Response clear pubkey", + uri: "/lnrpc.Lightning/GetInfo", msgType: rpcperms.TypeResponse, - msg: &lnrpc.ForwardingHistoryResponse{ - ForwardingEvents: []*lnrpc.ForwardingEvent{ - { - AmtIn: 2_000, - AmtInMsat: 2_000_000, - AmtOut: 1_000, - AmtOutMsat: 1_000_000, - Fee: 1_000, - FeeMsat: 1_000_000, - Timestamp: 1_000, - TimestampNs: 1_000_000_000_000, - ChanIdIn: 123, - ChanIdOut: 321, - }, - { - AmtIn: 3_000, - AmtInMsat: 3_000_000, - AmtOut: 2_000, - AmtOutMsat: 2_000_000, - Fee: 1_000, - FeeMsat: 1_000_000, - Timestamp: 1_000, - TimestampNs: 1_000_000_000_000, - ChanIdIn: 678, - ChanIdOut: 876, - }, + privacyFlags: session.PrivacyFlags{ + session.ClearPubkeys, + }, + msg: &lnrpc.GetInfoResponse{ + Alias: "Tinker Bell", + IdentityPubkey: "Tinker Bell's pub key", + Uris: []string{ + "Neverland 1", + "Neverland 2", }, }, + expectedReplacement: &lnrpc.GetInfoResponse{ + IdentityPubkey: "Tinker Bell's pub key", + }, + }, + { + name: "ForwardingHistory Response clear", + uri: "/lnrpc.Lightning/ForwardingHistory", + privacyFlags: []session.PrivacyFlag{ + session.ClearChanIDs, + session.ClearAmounts, + session.ClearTimeStamps, + }, + msgType: rpcperms.TypeResponse, + msg: clearForwarding, + expectedReplacement: clearForwarding, + }, + { + name: "ForwardingHistory Response", + uri: "/lnrpc.Lightning/ForwardingHistory", + msgType: rpcperms.TypeResponse, + msg: clearForwarding, expectedReplacement: &lnrpc.ForwardingHistoryResponse{ ForwardingEvents: []*lnrpc.ForwardingEvent{ { @@ -148,23 +201,7 @@ func TestPrivacyMapper(t *testing.T) { name: "ListChannels Response", uri: "/lnrpc.Lightning/ListChannels", msgType: rpcperms.TypeResponse, - msg: &lnrpc.ListChannelsResponse{ - Channels: []*lnrpc.Channel{ - { - Capacity: 1_000_000, - RemoteBalance: 600_000, - LocalBalance: 499_000, - CommitFee: 1_000, - TotalSatoshisSent: 500_000, - TotalSatoshisReceived: 450_000, - RemotePubkey: "01020304", - Initiator: false, - ChanId: 123, - ChannelPoint: "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd:0", - PendingHtlcs: []*lnrpc.HTLC{{HashLock: []byte("aaaa")}, {HashLock: []byte("bbbb")}}, - }, - }, - }, + msg: clearListChannel, expectedReplacement: &lnrpc.ListChannelsResponse{ Channels: []*lnrpc.Channel{ { @@ -183,6 +220,20 @@ func TestPrivacyMapper(t *testing.T) { }, }, }, + { + name: "ListChannels Response clear", + privacyFlags: []session.PrivacyFlag{ + session.ClearPubkeys, + session.ClearChanIDs, + session.ClearAmounts, + session.ClearHTLCs, + session.ClearChanInitiator, + }, + uri: "/lnrpc.Lightning/ListChannels", + msgType: rpcperms.TypeResponse, + msg: clearListChannel, + expectedReplacement: clearListChannel, + }, { name: "UpdateChannelPolicy Request txid string", uri: "/lnrpc.Lightning/UpdateChannelPolicy", @@ -292,17 +343,20 @@ func TestPrivacyMapper(t *testing.T) { "01020304": "c8134495", } - db := newMockDB(t, mapPreloadRealToPseudo, sessionID) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Initialize privacy mapping. + db := newMockDB(t, mapPreloadRealToPseudo, sessionID) - err = db.AddSessionAndGroupIDPair(sessionID, sessionID) - require.NoError(t, err) + pd := firewalldb.NewMockSessionDB() + pd.AddPair(sessionID, sessionID) + err = pd.AddPrivacyFlags(sessionID, test.privacyFlags) + require.NoError(t, err) - // randIntn is used for deterministic testing. - randIntn := func(n int) (int, error) { return 100, nil } - p := NewPrivacyMapper(db.NewSessionDB, randIntn, db) + // randIntn is used for deterministic testing. + randIntn := func(n int) (int, error) { return 100, nil } + p := NewPrivacyMapper(db.NewSessionDB, randIntn, pd) - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { rawMsg, err := proto.Marshal(test.msg) require.NoError(t, err) @@ -341,6 +395,14 @@ func TestPrivacyMapper(t *testing.T) { // Subtest to test behavior with real randomness. t.Run("Response with randomness", func(t *testing.T) { + // Initialize privacy mapping. + db := newMockDB(t, mapPreloadRealToPseudo, sessionID) + + pd := firewalldb.NewMockSessionDB() + pd.AddPair(sessionID, sessionID) + err := pd.AddPrivacyFlags(sessionID, session.PrivacyFlags{}) + require.NoError(t, err) + msg := &lnrpc.ForwardingHistoryResponse{ ForwardingEvents: []*lnrpc.ForwardingEvent{ { @@ -360,7 +422,7 @@ func TestPrivacyMapper(t *testing.T) { rawMsg, err := proto.Marshal(msg) require.NoError(t, err) - p = NewPrivacyMapper(db.NewSessionDB, CryptoRandIntn, db) + p := NewPrivacyMapper(db.NewSessionDB, CryptoRandIntn, pd) require.NoError(t, err) // We test the independent outgoing amount (incoming amount @@ -373,7 +435,7 @@ func TestPrivacyMapper(t *testing.T) { // We keep track of the timestamp. We test only the timestamp in // seconds as there can be numerical inaccuracies with the // nanosecond one. - timestamp := msg.ForwardingEvents[0].Timestamp + timestamp := msg.ForwardingEvents[0].TimestampNs / 1e9 timestampInterval := uint64(timeVariation) / 1e9 minTime := timestamp - timestampInterval maxTime := timestamp + timestampInterval @@ -447,19 +509,12 @@ func TestPrivacyMapper(t *testing.T) { type mockDB struct { privDB map[string]*mockPrivacyMapDB - - sessionIDIndex map[session.ID]session.ID - groupIDIndex map[session.ID][]session.ID } func newMockDB(t *testing.T, preloadRealToPseudo map[string]string, sessID session.ID) mockDB { - db := mockDB{ - privDB: make(map[string]*mockPrivacyMapDB), - sessionIDIndex: make(map[session.ID]session.ID), - groupIDIndex: make(map[session.ID][]session.ID), - } + db := mockDB{privDB: make(map[string]*mockPrivacyMapDB)} sessDB := db.NewSessionDB(sessID) _ = sessDB.Update(func(tx firewalldb.PrivacyMapTx) error { @@ -484,30 +539,6 @@ func (m mockDB) NewSessionDB(sessionID session.ID) firewalldb.PrivacyMapDB { return newDB } -func (m mockDB) AddSessionAndGroupIDPair(sessionID, groupID session.ID) error { - m.sessionIDIndex[sessionID] = groupID - m.groupIDIndex[groupID] = append(m.groupIDIndex[groupID], sessionID) - return nil -} - -func (m mockDB) GetGroupID(sessionID session.ID) (session.ID, error) { - groupID, ok := m.sessionIDIndex[sessionID] - if !ok { - return session.ID{}, fmt.Errorf("group ID not found") - } - - return groupID, nil -} - -func (m mockDB) GetSessionIDs(groupID session.ID) ([]session.ID, error) { - sessionIDs, ok := m.groupIDIndex[groupID] - if !ok { - return nil, fmt.Errorf("group ID not found") - } - - return sessionIDs, nil -} - func newMockPrivacyMapDB() *mockPrivacyMapDB { return &mockPrivacyMapDB{ r2p: make(map[string]string), @@ -723,12 +754,14 @@ func TestHideBool(t *testing.T) { // correctly. func TestObfuscateConfig(t *testing.T) { tests := []struct { - name string - config []byte - knownMap map[string]string - expectedNewPairs int - expectErr bool - notExpectSameLen bool + name string + config []byte + knownMap map[string]string + privacyFlags session.PrivacyFlags + expectedNewPairs int + expectErr bool + notExpectSameLen bool + expectUnobfuscated bool }{ { name: "empty", @@ -743,6 +776,18 @@ func TestObfuscateConfig(t *testing.T) { `"586b59212da4623c40dcc68c4573da1719e5893630790c9f2db8940fff3efd8cd4"]}`), expectedNewPairs: 4, }, + { + // A flag can be used to turn off obfuscation for + // pubkeys. + name: "no pubkeys obfuscation", + config: []byte(`{"version":1,"list":` + + `["d23da57575cdcb878ac191e1e0c8a5c4f061b11cfdc7a8ec5c9d495270de66fdbf",` + + `"1234567890123"]}`), + privacyFlags: []session.PrivacyFlag{ + session.ClearPubkeys, + }, + expectedNewPairs: 1, + }, { // We don't generate new pairs for pubkeys that we // already have a mapping. @@ -758,6 +803,20 @@ func TestObfuscateConfig(t *testing.T) { }, expectedNewPairs: 3, }, + { + // We don't obfuscate if we already have a mapping, but + // the obfuscation is turned off. + name: "several pubkeys with known replacement or duplicates", + config: []byte(`{"list":` + + `["586b59212da4623c40dcc68c4573da1719e5893630790c9f2db8940fff3efd8cd4",` + + `"0e092708c9e737115ff14a85b65466561280d77c1b8cd666bc655536ad81ccca85"]}`), + knownMap: map[string]string{ + "586b59212da4623c40dcc68c4573da1719e5893630790c9f2db8940fff3efd8cd4": "123456789012345678901234567890123456789012345678901234567890123456", + }, + privacyFlags: []session.PrivacyFlag{session.ClearPubkeys}, + expectedNewPairs: 0, + expectUnobfuscated: true, + }, { // We don't substitute unknown items. name: "all invalid pubkeys", @@ -829,6 +888,19 @@ func TestObfuscateConfig(t *testing.T) { `123456789012345678901]}`), expectedNewPairs: 0, }, + { + // We don't obfuscate channel ids and points if the + // corresponding privacy flag is set. + // format. + name: "clear channel ids", + config: []byte(`{"version":1,"list":` + + `["1234567890123",` + + `"e092708c9e737115ff14a85ab65466561280d77c1b8cd666bc655536ad81ccca:1"]}`), + expectedNewPairs: 0, + privacyFlags: []session.PrivacyFlag{ + session.ClearChanIDs, + }, + }, } // assertConfigStructure checks that the structure of the config is @@ -877,7 +949,7 @@ func TestObfuscateConfig(t *testing.T) { db := firewalldb.NewPrivacyMapPairs(tt.knownMap) config, privMapPairs, err := ObfuscateConfig( - db, tt.config, + db, tt.config, tt.privacyFlags, ) if tt.expectErr { require.Error(t, err) @@ -905,6 +977,12 @@ func TestObfuscateConfig(t *testing.T) { if !tt.notExpectSameLen { require.Equal(t, len(tt.config), len(config)) } + + // We expect the config to be unobfuscated if we have + // the corresponding privacy flag. + if tt.expectUnobfuscated { + require.Equal(t, tt.config, config) + } }) } } diff --git a/firewall/rule_enforcer.go b/firewall/rule_enforcer.go index db304b7a6..1ffe38caf 100644 --- a/firewall/rule_enforcer.go +++ b/firewall/rule_enforcer.go @@ -30,7 +30,7 @@ var _ mid.RequestInterceptor = (*RuleEnforcer)(nil) type RuleEnforcer struct { ruleDB firewalldb.RulesDB actionsDB firewalldb.ActionReadDBGetter - sessionIDIndexDB session.IDToGroupIndex + sessionDB firewalldb.SessionDB markActionErrored func(reqID uint64, reason string) error newPrivMap firewalldb.NewPrivacyMapDB @@ -52,7 +52,7 @@ type featurePerms func(ctx context.Context) (map[string]map[string]bool, error) // NewRuleEnforcer constructs a new RuleEnforcer instance. func NewRuleEnforcer(ruleDB firewalldb.RulesDB, actionsDB firewalldb.ActionReadDBGetter, - sessionIDIndex session.IDToGroupIndex, + sessionIDIndex firewalldb.SessionDB, getFeaturePerms featurePerms, permsMgr *perms.Manager, nodeID [33]byte, routerClient lndclient.RouterClient, lndClient lndclient.LightningClient, ruleMgrs rules.ManagerSet, @@ -70,7 +70,7 @@ func NewRuleEnforcer(ruleDB firewalldb.RulesDB, ruleMgrs: ruleMgrs, markActionErrored: markActionErrored, newPrivMap: privMap, - sessionIDIndexDB: sessionIDIndex, + sessionDB: sessionIDIndex, } } @@ -224,12 +224,7 @@ func (r *RuleEnforcer) handleRequest(ctx context.Context, return nil, fmt.Errorf("could not extract ID from macaroon") } - groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID) - if err != nil { - return nil, err - } - - rules, err := r.collectEnforcers(ri, groupID) + rules, err := r.collectEnforcers(ri, sessionID) if err != nil { return nil, fmt.Errorf("error parsing rules: %v", err) } @@ -269,12 +264,7 @@ func (r *RuleEnforcer) handleResponse(ctx context.Context, return nil, fmt.Errorf("could not extract ID from macaroon") } - groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID) - if err != nil { - return nil, err - } - - enforcers, err := r.collectEnforcers(ri, groupID) + enforcers, err := r.collectEnforcers(ri, sessionID) if err != nil { return nil, fmt.Errorf("error parsing rules: %v", err) } @@ -308,12 +298,7 @@ func (r *RuleEnforcer) handleErrorResponse(ctx context.Context, return nil, fmt.Errorf("could not extract ID from macaroon") } - groupID, err := r.sessionIDIndexDB.GetGroupID(sessionID) - if err != nil { - return nil, err - } - - enforcers, err := r.collectEnforcers(ri, groupID) + enforcers, err := r.collectEnforcers(ri, sessionID) if err != nil { return nil, fmt.Errorf("error parsing rules: %v", err) } @@ -338,8 +323,8 @@ func (r *RuleEnforcer) handleErrorResponse(ctx context.Context, // collectRule initialises and returns all the Rules that need to be enforced // for the given request. -func (r *RuleEnforcer) collectEnforcers(ri *RequestInfo, groupID session.ID) ( - []rules.Enforcer, error) { +func (r *RuleEnforcer) collectEnforcers(ri *RequestInfo, + sessionID session.ID) ([]rules.Enforcer, error) { ruleEnforcers := make( []rules.Enforcer, 0, @@ -349,7 +334,7 @@ func (r *RuleEnforcer) collectEnforcers(ri *RequestInfo, groupID session.ID) ( for rule, value := range ri.Rules.FeatureRules[ri.MetaInfo.Feature] { r, err := r.initRule( ri.RequestID, rule, []byte(value), ri.MetaInfo.Feature, - groupID, false, ri.WithPrivacy, + sessionID, false, ri.WithPrivacy, ) if err != nil { return nil, err @@ -363,30 +348,40 @@ func (r *RuleEnforcer) collectEnforcers(ri *RequestInfo, groupID session.ID) ( // initRule initialises a rule.Rule with any required config values. func (r *RuleEnforcer) initRule(reqID uint64, name string, value []byte, - featureName string, groupID session.ID, sessionRule, - privacy bool) (rules.Enforcer, error) { + featureName string, sessionID session.ID, + sessionRule, privacy bool) (rules.Enforcer, error) { ruleValues, err := r.ruleMgrs.InitRuleValues(name, value) if err != nil { return nil, err } + session, err := r.sessionDB.GetSessionByID(sessionID) + if err != nil { + return nil, err + } + if privacy { - privMap := r.newPrivMap(groupID) - ruleValues, err = ruleValues.PseudoToReal(privMap) + privMap := r.newPrivMap(session.GroupID) + + ruleValues, err = ruleValues.PseudoToReal( + privMap, session.PrivacyFlags, + ) if err != nil { return nil, fmt.Errorf("could not prepare rule "+ "value: %v", err) } } - allActionsDB := r.actionsDB.GetActionsReadDB(groupID, featureName) + allActionsDB := r.actionsDB.GetActionsReadDB( + session.GroupID, featureName, + ) actionsDB := allActionsDB.GroupFeatureActionsDB() - rulesDB := r.ruleDB.GetKVStores(name, groupID, featureName) + rulesDB := r.ruleDB.GetKVStores(name, session.GroupID, featureName) if sessionRule { actionsDB = allActionsDB.GroupActionsDB() - rulesDB = r.ruleDB.GetKVStores(name, groupID, "") + rulesDB = r.ruleDB.GetKVStores(name, session.GroupID, "") } cfg := &rules.ConfigImpl{ diff --git a/firewalldb/actions_test.go b/firewalldb/actions_test.go index 5a9c4f41f..72b6376b2 100644 --- a/firewalldb/actions_test.go +++ b/firewalldb/actions_test.go @@ -5,7 +5,6 @@ import ( "testing" "time" - "github.com/lightninglabs/lightning-terminal/session" "github.com/stretchr/testify/require" ) @@ -346,9 +345,9 @@ func TestListGroupActions(t *testing.T) { group1 := intToSessionID(0) // Link session 1 and session 2 to group 1. - index := newMockSessionIDIndex() - index.addPair(sessionID1, group1) - index.addPair(sessionID2, group1) + index := NewMockSessionDB() + index.AddPair(sessionID1, group1) + index.AddPair(sessionID2, group1) db, err := NewDB(t.TempDir(), "test.db", index) require.NoError(t, err) @@ -382,48 +381,3 @@ func TestListGroupActions(t *testing.T) { require.Equal(t, sessionID1, al[0].SessionID) require.Equal(t, sessionID2, al[1].SessionID) } - -type mockSessionIDIndex struct { - sessionToGroupID map[session.ID]session.ID - groupToSessionIDs map[session.ID][]session.ID -} - -var _ session.IDToGroupIndex = (*mockSessionIDIndex)(nil) - -func newMockSessionIDIndex() *mockSessionIDIndex { - return &mockSessionIDIndex{ - sessionToGroupID: make(map[session.ID]session.ID), - groupToSessionIDs: make(map[session.ID][]session.ID), - } -} - -func (m *mockSessionIDIndex) addPair(sessionID, groupID session.ID) { - m.sessionToGroupID[sessionID] = groupID - - m.groupToSessionIDs[groupID] = append( - m.groupToSessionIDs[groupID], sessionID, - ) -} - -func (m *mockSessionIDIndex) GetGroupID(sessionID session.ID) (session.ID, - error) { - - id, ok := m.sessionToGroupID[sessionID] - if !ok { - return session.ID{}, fmt.Errorf("no group ID found for " + - "session ID") - } - - return id, nil -} - -func (m *mockSessionIDIndex) GetSessionIDs(groupID session.ID) ([]session.ID, - error) { - - ids, ok := m.groupToSessionIDs[groupID] - if !ok { - return nil, fmt.Errorf("no session IDs found for group ID") - } - - return ids, nil -} diff --git a/firewalldb/db.go b/firewalldb/db.go index a79fcb478..2c5a1d7a8 100644 --- a/firewalldb/db.go +++ b/firewalldb/db.go @@ -8,7 +8,6 @@ import ( "path/filepath" "time" - "github.com/lightninglabs/lightning-terminal/session" "go.etcd.io/bbolt" ) @@ -42,13 +41,11 @@ var ( type DB struct { *bbolt.DB - sessionIDIndex session.IDToGroupIndex + sessionIDIndex SessionDB } // NewDB creates a new bolt database that can be found at the given directory. -func NewDB(dir, fileName string, sessionIDIndex session.IDToGroupIndex) (*DB, - error) { - +func NewDB(dir, fileName string, sessionIDIndex SessionDB) (*DB, error) { firstInit := false path := filepath.Join(dir, fileName) diff --git a/firewalldb/interface.go b/firewalldb/interface.go new file mode 100644 index 000000000..6e6509573 --- /dev/null +++ b/firewalldb/interface.go @@ -0,0 +1,12 @@ +package firewalldb + +import "github.com/lightninglabs/lightning-terminal/session" + +// SessionDB is an interface that abstracts the database operations needed for +// the privacy mapper to function. +type SessionDB interface { + session.IDToGroupIndex + + // GetSessionByID returns the session for a specific id. + GetSessionByID(session.ID) (*session.Session, error) +} diff --git a/firewalldb/mock.go b/firewalldb/mock.go new file mode 100644 index 000000000..4030dde3f --- /dev/null +++ b/firewalldb/mock.go @@ -0,0 +1,80 @@ +package firewalldb + +import ( + "fmt" + + "github.com/lightninglabs/lightning-terminal/session" +) + +type mockSessionDB struct { + sessionToGroupID map[session.ID]session.ID + groupToSessionIDs map[session.ID][]session.ID + privacyFlags map[session.ID]session.PrivacyFlags +} + +var _ SessionDB = (*mockSessionDB)(nil) + +// NewMockSessionDB creates a new mock privacy map details instance. +func NewMockSessionDB() *mockSessionDB { + return &mockSessionDB{ + sessionToGroupID: make(map[session.ID]session.ID), + groupToSessionIDs: make(map[session.ID][]session.ID), + privacyFlags: make(map[session.ID]session.PrivacyFlags), + } +} + +// AddPair adds a new session to group ID pair to the mock details. +func (m *mockSessionDB) AddPair(sessionID, groupID session.ID) { + m.sessionToGroupID[sessionID] = groupID + + m.groupToSessionIDs[groupID] = append( + m.groupToSessionIDs[groupID], sessionID, + ) +} + +// GetGroupID returns the group ID for the given session ID. +func (m *mockSessionDB) GetGroupID(sessionID session.ID) (session.ID, error) { + id, ok := m.sessionToGroupID[sessionID] + if !ok { + return session.ID{}, fmt.Errorf("no group ID found for " + + "session ID") + } + + return id, nil +} + +// GetSessionIDs returns the set of session IDs that are in the group +func (m *mockSessionDB) GetSessionIDs(groupID session.ID) ([]session.ID, error) { + ids, ok := m.groupToSessionIDs[groupID] + if !ok { + return nil, fmt.Errorf("no session IDs found for group ID") + } + + return ids, nil +} + +// GetSessionByID returns the session for a specific id. +func (m *mockSessionDB) GetSessionByID(sessionID session.ID) (*session.Session, + error) { + + s, ok := m.sessionToGroupID[sessionID] + if !ok { + return nil, fmt.Errorf("no session found for session ID") + } + + f, ok := m.privacyFlags[sessionID] + if !ok { + return nil, fmt.Errorf("no privacy flags found for session ID") + } + + return &session.Session{GroupID: s, PrivacyFlags: f}, nil +} + +// AddPrivacyFlags is a helper that adds privacy flags to the mock session db. +func (m *mockSessionDB) AddPrivacyFlags(sessionID session.ID, + flags session.PrivacyFlags) error { + + m.privacyFlags[sessionID] = flags + + return nil +} diff --git a/itest/litd_firewall_test.go b/itest/litd_firewall_test.go index d93775d72..fab5ad2f9 100644 --- a/itest/litd_firewall_test.go +++ b/itest/litd_firewall_test.go @@ -184,6 +184,299 @@ func testFirewallRules(ctx context.Context, net *NetworkHarness, t.t.Run("session linking", func(_ *testing.T) { testSessionLinking(net, t) }) + + t.t.Run("privacy flags", func(_ *testing.T) { + testPrivacyFlags(net, t) + }) +} + +// testPrivacyFlags tests that the privacy flags are enforced correctly. +// We want to test the three privacy related interactions: +// 1. the privacy mapper for the interception of messages +// 2. the rule enforcer's privacy mapping +// 3. the feature config's obfuscation +func testPrivacyFlags(net *NetworkHarness, t *harnessTest) { + ctx := context.Background() + + net.autopilotServer.ResetDefaultFeatures() + + // We assert that we only have a single channel open between Alice and + // Bob. + aliceChannels, err := net.Alice.ListChannels( + ctx, &lnrpc.ListChannelsRequest{}, + ) + require.NoError(t.t, err) + require.Len(t.t, aliceChannels.Channels, 1) + require.Equal(t.t, net.Bob.PubKeyStr, + aliceChannels.Channels[0].RemotePubkey) + + // Set up a connection to Alice's lit RPC server. + cfg := net.Alice.Cfg + rawConn, err := connectRPC(ctx, cfg.LitAddr(), cfg.LitTLSCertPath) + require.NoError(t.t, err) + defer rawConn.Close() + + litAutopilotClient := litrpc.NewAutopilotClient(rawConn) + + macBytes, err := os.ReadFile(cfg.LitMacPath) + require.NoError(t.t, err) + ctxm := macaroonContext(ctx, macBytes) + + // Set up private and non-private features within the mock autopilot + // server. + privateFeature := &mock.Feature{ + Description: "manages your channel privately", + Rules: map[string]*mock.RuleRanges{ + rules.PeersRestrictName: { + Default: &rules.PeerRestrict{}, + MinVal: &rules.PeerRestrict{}, + MaxVal: &rules.PeerRestrict{}, + }, + }, + Permissions: map[string][]bakery.Op{ + "/lnrpc.Lightning/ListChannels": {{ + Entity: "offchain", + Action: "read", + }}, + }, + // We set no flags to indicate that we want full privacy. + PrivacyFlags: 0, + } + + clearPubkeysFlags := session.PrivacyFlags{session.ClearPubkeys} + nonPrivateFeature := &mock.Feature{ + Description: "manages your channel with cleartext pubkeys", + Rules: map[string]*mock.RuleRanges{ + rules.PeersRestrictName: { + Default: &rules.PeerRestrict{}, + MinVal: &rules.PeerRestrict{}, + MaxVal: &rules.PeerRestrict{}, + }, + }, + Permissions: map[string][]bakery.Op{ + "/lnrpc.Lightning/ListChannels": {{ + Entity: "offchain", + Action: "read", + }}, + }, + PrivacyFlags: clearPubkeysFlags.Serialize(), + } + + net.autopilotServer.SetFeatures(map[string]*mock.Feature{ + "Private": privateFeature, + "NonPrivate": nonPrivateFeature, + }) + + featResp, err := litAutopilotClient.ListAutopilotFeatures( + ctxm, &litrpc.ListAutopilotFeaturesRequest{}, + ) + require.NoError(t.t, err) + require.Len(t.t, featResp.Features, 2) + + // Now we set up an initial autopilot session. The session will register + // both features. They have different privacy flags, which will result + // in registering a session with the lowest overall privacy. + sessFeatures := map[string]*litrpc.FeatureConfig{ + "Private": {}, + "NonPrivate": {}, + } + + session0, err := litAutopilotClient.AddAutopilotSession( + ctxm, &litrpc.AddAutopilotSessionRequest{ + Label: "integration-test", + ExpiryTimestampSeconds: uint64( + time.Now().Add(5 * time.Minute).Unix(), + ), + MailboxServerAddr: mailboxServerAddr, + Features: sessFeatures, + }, + ) + require.NoError(t.t, err) + + assertPrivacyFlags(net, t, session0.Session, clearPubkeysFlags) + + // The peer restrict list contains Bob's pubkey in order to check + // against the privacy db later if the pubkey was obfuscated before any + // request was made or not. + peerRestrict := &litrpc.RuleValue_PeerRestrict{ + PeerRestrict: &litrpc.PeerRestrict{ + PeerIds: []string{net.Bob.PubKeyStr}, + }, + } + + // Create a feature configuration map for some pubkey, it will be + // obfuscated depending on the privacy flags. + configPubkey := "0e092708c9e737115ff14a85b65466561280d" + + "77c1b8cd666bc655536ad81ccca85" + + config := struct { + PubKeys []string `json:"pubkeys"` + }{ + PubKeys: []string{configPubkey}, + } + configBytes, err := json.Marshal(config) + require.NoError(t.t, err) + + // We now set up a single *private* feature within a session using + // restrictions and a config. + privFeature := map[string]*litrpc.FeatureConfig{ + "Private": { + Rules: &litrpc.RulesMap{ + Rules: map[string]*litrpc.RuleValue{ + rules.PeersRestrictName: { + Value: peerRestrict, + }, + }, + }, + Config: configBytes, + }, + } + + session1, err := litAutopilotClient.AddAutopilotSession( + ctxm, &litrpc.AddAutopilotSessionRequest{ + Label: "integration-test", + ExpiryTimestampSeconds: uint64( + time.Now().Add(5 * time.Minute).Unix(), + ), + MailboxServerAddr: mailboxServerAddr, + Features: privFeature, + }, + ) + require.NoError(t.t, err) + + assertPrivacyFlags(net, t, session1.Session, session.PrivacyFlags{}) + + // Set up a client connection to query the privacy mapper. + litFWClient := litrpc.NewFirewallClient(rawConn) + + // We should have a pseudo pair in the privacy mapper for Bob's pubkey + // due to the peer restriction and a pseudo pair for the config pubkey + // due to the feature config. + assertPseudo(ctxm, t.t, litFWClient, session1.Session.GroupId, + net.Bob.PubKeyStr, "") + assertPseudo(ctxm, t.t, litFWClient, session1.Session.GroupId, + configPubkey, "") + + // We now set up a partially deobfuscated session. + nonPrivFeature := map[string]*litrpc.FeatureConfig{ + "NonPrivate": { + Rules: &litrpc.RulesMap{ + Rules: map[string]*litrpc.RuleValue{ + rules.PeersRestrictName: { + Value: peerRestrict, + }, + }, + }, + Config: configBytes, + }, + } + + session2, err := litAutopilotClient.AddAutopilotSession( + ctxm, &litrpc.AddAutopilotSessionRequest{ + Label: "integration-test", + ExpiryTimestampSeconds: uint64( + time.Now().Add(5 * time.Minute).Unix(), + ), + MailboxServerAddr: mailboxServerAddr, + Features: nonPrivFeature, + }, + ) + require.NoError(t.t, err) + + assertPrivacyFlags(net, t, session2.Session, clearPubkeysFlags) + + // We shouldn't have a pseudo pair in the privacy mapper for Bob's + // pubkey or the config pubkey as pubkey mapping was turned off. + assertPseudo(ctxm, t.t, litFWClient, session2.Session.GroupId, + net.Bob.PubKeyStr, "no such key found") + assertPseudo(ctxm, t.t, litFWClient, session2.Session.GroupId, + configPubkey, "no such key found") + + // Set up a client from the PoV of the autopilot server for the private + // session. + lndConn1, metaDataInjector, cleanup1 := newAutopilotLndConn( + ctx, t.t, net, session1.Session, + ) + t.t.Cleanup(func() { require.NoError(t.t, cleanup1()) }) + + metaInfo1 := &firewall.InterceptMetaInfo{ + ActorName: "Autopilot Server", + Feature: "Private", + } + caveat1, err := metaInfo1.ToCaveat() + require.NoError(t.t, err) + caveatCreds1 := metaDataInjector.addCaveat(caveat1) + + // Set up a client from the PoV of the autopilot server for the + // non-private session. + lndConn2, metaDataInjector, cleanup2 := newAutopilotLndConn( + ctx, t.t, net, session2.Session, + ) + t.t.Cleanup(func() { require.NoError(t.t, cleanup2()) }) + + // The autopilot server is expected to add a MetaInfo caveat to any + // request that it makes. So we add that now and specify that it is + // initially making requests on behalf of the NonPrivate feature. + metaInfo2 := &firewall.InterceptMetaInfo{ + ActorName: "Autopilot Server", + Feature: "NonPrivate", + } + caveat2, err := metaInfo2.ToCaveat() + require.NoError(t.t, err) + caveatCreds2 := metaDataInjector.addCaveat(caveat2) + + // We compare Alice's channels to the obfuscated and non-obfuscated + // channels. + obfuscatedChannels, err := lndConn1.ListChannels( + ctx, &lnrpc.ListChannelsRequest{}, caveatCreds1, + ) + require.NoError(t.t, err) + require.Len(t.t, obfuscatedChannels.Channels, 1) + + nonObfuscatedChannels, err := lndConn2.ListChannels( + ctx, &lnrpc.ListChannelsRequest{}, caveatCreds2, + ) + require.NoError(t.t, err) + require.Len(t.t, nonObfuscatedChannels.Channels, 1) + + clearChan := aliceChannels.Channels[0] + nonObfChan := nonObfuscatedChannels.Channels[0] + obfChan := obfuscatedChannels.Channels[0] + + // In the non-obfuscated response we expect to see the clear text + // pubkey, while in the obfuscated response we expect to see a different + // pubkey. + require.Equal(t.t, clearChan.RemotePubkey, nonObfChan.RemotePubkey) + require.NotEqual(t.t, clearChan.RemotePubkey, obfChan.RemotePubkey) + + // Other fields are still obfuscated. + require.NotEqual(t.t, clearChan.ChannelPoint, nonObfChan.ChannelPoint) + require.NotEqual(t.t, obfChan.ChannelPoint, nonObfChan.ChannelPoint) + + // We now link to the private session registering a non-private + // feature. We expect that the new privacy flags have downgraded the + // privacy. Revoke the previous obfuscated session. + _, err = litAutopilotClient.RevokeAutopilotSession( + ctxm, &litrpc.RevokeAutopilotSessionRequest{ + LocalPublicKey: session1.Session.LocalPublicKey, + }, + ) + require.NoError(t.t, err) + + session3, err := litAutopilotClient.AddAutopilotSession( + ctxm, &litrpc.AddAutopilotSessionRequest{ + Label: "integration-test", + ExpiryTimestampSeconds: uint64( + time.Now().Add(5 * time.Minute).Unix(), + ), + MailboxServerAddr: mailboxServerAddr, + Features: nonPrivFeature, + LinkedGroupId: session1.Session.GroupId, + }, + ) + require.NoError(t.t, err) + + assertPrivacyFlags(net, t, session3.Session, clearPubkeysFlags) } // testSessionLinking will test the expected behaviour across linked sessions. @@ -366,32 +659,9 @@ func testSessionLinking(net *NetworkHarness, t *harnessTest) { // getPseudo is a helper that can be used to query Alice's privacy map // DB to get the pseudo value for a given real value. getPseudo := func(groupID []byte, input any, expError string) string { - var in string - - switch inp := input.(type) { - case string: - in = inp - case uint64: - in = firewalldb.Uint64ToStr(inp) - default: - t.Fatalf("unhandled input type: %T", input) - } - - privMapResp, err := litFWClient.PrivacyMapConversion( - ctxm, &litrpc.PrivacyMapConversionRequest{ - GroupId: groupID, - RealToPseudo: true, - Input: in, - }, + return assertPseudo( + ctxm, t.t, litFWClient, groupID, input, expError, ) - if expError != "" { - require.ErrorContains(t.t, err, expError) - - return "" - } - require.NoError(t.t, err) - - return privMapResp.Output } // At this point, we already expect there to be entries in the privacy @@ -421,26 +691,10 @@ func testSessionLinking(net *NetworkHarness, t *harnessTest) { // Now, let's connect to the LiT node from the point of view of the // autopilot server. - - // From the session creation response, we can extract Lit's local public - // key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + lndConn, metaDataInjector, cleanup1 := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup1()) }) // The autopilot server is expected to add a MetaInfo caveat to any // request that it makes. So we add that now and specify that it is @@ -569,11 +823,6 @@ func testSessionLinking(net *NetworkHarness, t *harnessTest) { ) require.NoError(t.t, err) - // Also close the autopilot connection to the first session so that it - // doesn't continue to try and connect. - require.NoError(t.t, pilotConn.Close()) - pilotConn = nil - sessResp2, err := litAutopilotClient.AddAutopilotSession( ctxm, &litrpc.AddAutopilotSessionRequest{ Label: "integration-test", @@ -600,19 +849,11 @@ func testSessionLinking(net *NetworkHarness, t *harnessTest) { // Now we connect to LiT from the PoV of the autopilot server but this // time using the new session. - litdPub, err = btcec.ParsePubKey(sessResp2.Session.LocalPublicKey) - require.NoError(t.t, err) - - pilotPriv, err = net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - pilotConn, metaDataInjector, err = connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + lndConn, metaDataInjector, cleanup2 := newAutopilotLndConn( + ctx, t.t, net, sessResp2.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() + t.t.Cleanup(func() { require.NoError(t.t, cleanup2()) }) - lndConn = lnrpc.NewLightningClient(pilotConn) caveatCreds1 = metaDataInjector.addCaveat(caveat1) // List the channels and ensure that the same mapping was used as for @@ -724,23 +965,11 @@ func testRateLimitAndPrivacyMapper(net *NetworkHarness, t *harnessTest) { ) require.NoError(t.t, err) - // From the response, we can extract Lit's local public key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + // We now connect to the mailbox from the PoV of the autopilot server. + lndConn, metaDataInjector, cleanup := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup()) }) // The autopilot server is expected to add a MetaInfo caveat to any // request that it makes. So we add that now and specify that it is @@ -962,24 +1191,11 @@ func testHistoryLimitRule(net *NetworkHarness, t *harnessTest) { ) require.NoError(t.t, err) - // From the response, we can extract Lit's local public key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + // We now connect to the mailbox from the PoV of the autopilot server. + lndConn, metaDataInjector, cleanup := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup()) }) // First, we will test the "AutoFees" feature which uses a duration to // specify a history limit. The duration specified is 48 hours and so @@ -1120,23 +1336,11 @@ func testChanPolicyBoundsRule(net *NetworkHarness, t *harnessTest) { ) require.NoError(t.t, err) - // From the response, we can extract Lit's local public key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + // We now connect to the mailbox from the PoV of the autopilot server. + lndConn, metaDataInjector, cleanup := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup()) }) // The autopilot server is expected to add a MetaInfo caveat to any // request that it makes. So we add that now and specify that it is @@ -1396,23 +1600,11 @@ func testPeerAndChannelRestrictRules(net *NetworkHarness, t *harnessTest) { ) require.NoError(t.t, err) - // From the response, we can extract Lit's local public key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + // We now connect to the mailbox from the PoV of the autopilot server. + lndConn, metaDataInjector, cleanup := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup()) }) // The autopilot server is expected to add a MetaInfo caveat to any // request that it makes. So we add that now and specify that it is @@ -1680,23 +1872,11 @@ func testLargeHttpHeader(ctx context.Context, net *NetworkHarness, ) require.NoError(t.t, err) - // From the response, we can extract Lit's local public key. - litdPub, err := btcec.ParsePubKey(sessResp.Session.LocalPublicKey) - require.NoError(t.t, err) - - // We then query the autopilot server to extract the private key that - // it will be using for this session. - pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) - require.NoError(t.t, err) - - // Now we can connect to the mailbox from the PoV of the autopilot - // server. - pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( - ctx, pilotPriv, litdPub, + // We now connect to the mailbox from the PoV of the autopilot server. + lndConn, metaDataInjector, cleanup := newAutopilotLndConn( + ctx, t.t, net, sessResp.Session, ) - require.NoError(t.t, err) - defer pilotConn.Close() - lndConn := lnrpc.NewLightningClient(pilotConn) + t.t.Cleanup(func() { require.NoError(t.t, cleanup()) }) // The autopilot server is expected to add a MetaInfo caveat to any // request that it makes. So we add that now and specify that it is @@ -1723,6 +1903,83 @@ func testLargeHttpHeader(ctx context.Context, net *NetworkHarness, require.Equal(t.t, aliceInfo.Alias, getInfoReq.Alias) } +// assertPrivacyFlags is a helper function that asserts that the privacy +// flags for the session are as expected. +func assertPrivacyFlags(net *NetworkHarness, t *harnessTest, + sess *litrpc.Session, expectedFlags session.PrivacyFlags) { + + litdPub, err := btcec.ParsePubKey(sess.LocalPublicKey) + require.NoError(t.t, err) + + flags, err := net.autopilotServer.GetPrivacyFlags(litdPub) + require.NoError(t.t, err) + + require.True(t.t, flags.Equal(expectedFlags)) +} + +// assertPseudo is a helper that can be used to query a privacy map DB to get +// the pseudo value for a given real value. +func assertPseudo(ctxm context.Context, t *testing.T, + litFWClient litrpc.FirewallClient, groupID []byte, input any, + expError string) string { + + var in string + + switch inp := input.(type) { + case string: + in = inp + case uint64: + in = firewalldb.Uint64ToStr(inp) + default: + t.Fatalf("unhandled input type: %T", input) + } + + privMapResp, err := litFWClient.PrivacyMapConversion( + ctxm, &litrpc.PrivacyMapConversionRequest{ + GroupId: groupID, + RealToPseudo: true, + Input: in, + }, + ) + if expError != "" { + require.ErrorContains(t, err, expError) + + return "" + } + require.NoError(t, err) + + return privMapResp.Output +} + +// newAutopilotLndConn creates a new connection to the mailbox server from the +// PoV of the autopilot server. It also returns a cleanup function that should +// be called when the test is done. +func newAutopilotLndConn(ctx context.Context, t *testing.T, net *NetworkHarness, + session *litrpc.Session) (lnrpc.LightningClient, *metadataInjector, + func() error) { + + // From the session creation response, we can extract Lit's local public + // key. + litdPub, err := btcec.ParsePubKey(session.LocalPublicKey) + require.NoError(t, err) + + // We then query the autopilot server to extract the private key that + // will be used for this session. + pilotPriv, err := net.autopilotServer.GetPrivKey(litdPub) + require.NoError(t, err) + + // Now we can connect to the mailbox from the PoV of the autopilot + // server. + pilotConn, metaDataInjector, err := connectMailboxWithRemoteKey( + ctx, pilotPriv, litdPub, + ) + require.NoError(t, err) + + lndConn := lnrpc.NewLightningClient(pilotConn) + + return lndConn, metaDataInjector, pilotConn.Close +} + // connectMailboxWithRemoteKey tries to establish a connection through LNC using // the given local and remote keys and the test mailbox server. func connectMailboxWithRemoteKey(ctx context.Context, diff --git a/litrpc/lit-autopilot.pb.go b/litrpc/lit-autopilot.pb.go index af79c3ba1..7da6f8cf4 100644 --- a/litrpc/lit-autopilot.pb.go +++ b/litrpc/lit-autopilot.pb.go @@ -43,6 +43,11 @@ type AddAutopilotSessionRequest struct { NoPrivacyMapper bool `protobuf:"varint,7,opt,name=no_privacy_mapper,json=noPrivacyMapper,proto3" json:"no_privacy_mapper,omitempty"` // Set to the ID of the group to link this session to, if any. LinkedGroupId []byte `protobuf:"bytes,8,opt,name=linked_group_id,json=linkedGroupId,proto3" json:"linked_group_id,omitempty"` + // The privacy flags used by this session. If set, then privacy_flags_set must + // be set. + PrivacyFlags uint64 `protobuf:"varint,9,opt,name=privacy_flags,json=privacyFlags,proto3" json:"privacy_flags,omitempty"` + // Indicates whether privacy flags are set. + PrivacyFlagsSet bool `protobuf:"varint,10,opt,name=privacy_flags_set,json=privacyFlagsSet,proto3" json:"privacy_flags_set,omitempty"` } func (x *AddAutopilotSessionRequest) Reset() { @@ -133,6 +138,20 @@ func (x *AddAutopilotSessionRequest) GetLinkedGroupId() []byte { return nil } +func (x *AddAutopilotSessionRequest) GetPrivacyFlags() uint64 { + if x != nil { + return x.PrivacyFlags + } + return 0 +} + +func (x *AddAutopilotSessionRequest) GetPrivacyFlagsSet() bool { + if x != nil { + return x.PrivacyFlagsSet + } + return false +} + type FeatureConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -520,6 +539,9 @@ type Feature struct { RequiresUpgrade bool `protobuf:"varint,5,opt,name=requires_upgrade,json=requiresUpgrade,proto3" json:"requires_upgrade,omitempty"` // The JSON-marshaled representation of a feature's default configuration. DefaultConfig string `protobuf:"bytes,6,opt,name=default_config,json=defaultConfig,proto3" json:"default_config,omitempty"` + // This feature may require relaxed privacy obfuscation that can be enabled + // with these flags. + PrivacyFlags uint64 `protobuf:"varint,7,opt,name=privacy_flags,json=privacyFlags,proto3" json:"privacy_flags,omitempty"` } func (x *Feature) Reset() { @@ -596,6 +618,13 @@ func (x *Feature) GetDefaultConfig() string { return "" } +func (x *Feature) GetPrivacyFlags() uint64 { + if x != nil { + return x.PrivacyFlags + } + return 0 +} + type RuleValues struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -735,7 +764,7 @@ var file_lit_autopilot_proto_rawDesc = []byte{ 0x0a, 0x13, 0x6c, 0x69, 0x74, 0x2d, 0x61, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x1a, 0x12, 0x6c, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xec, 0x03, 0x0a, 0x1a, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, + 0x6f, 0x22, 0xbd, 0x04, 0x0a, 0x1a, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x3c, 0x0a, 0x18, 0x65, 0x78, 0x70, 0x69, 0x72, 0x79, @@ -760,119 +789,126 @@ var file_lit_autopilot_proto_rawDesc = []byte{ 0x01, 0x28, 0x08, 0x52, 0x0f, 0x6e, 0x6f, 0x50, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x12, 0x26, 0x0a, 0x0f, 0x6c, 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x6c, - 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x1a, 0x52, 0x0a, 0x0d, - 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x4f, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x26, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x10, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x4d, - 0x61, 0x70, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, - 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x4c, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, - 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0x48, 0x0a, 0x1b, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, - 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, - 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbe, 0x01, 0x0a, 0x1d, 0x4c, 0x69, + 0x69, 0x6e, 0x6b, 0x65, 0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, + 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x46, 0x6c, 0x61, 0x67, + 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x5f, 0x66, 0x6c, 0x61, + 0x67, 0x73, 0x5f, 0x73, 0x65, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x70, 0x72, + 0x69, 0x76, 0x61, 0x63, 0x79, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x53, 0x65, 0x74, 0x1a, 0x52, 0x0a, + 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x2b, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x4f, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x12, 0x26, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, + 0x4d, 0x61, 0x70, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, + 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x22, 0x4c, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, + 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x48, 0x0a, 0x1b, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, - 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x08, 0x66, - 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, - 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, - 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x4c, 0x0a, 0x0d, - 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x1d, 0x52, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6c, - 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, - 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd1, 0x02, 0x0a, 0x07, 0x46, 0x65, 0x61, 0x74, - 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x75, 0x6c, - 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x10, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0f, 0x70, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x72, - 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x55, - 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, - 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x4c, 0x0a, - 0x0a, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, - 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb1, 0x01, 0x0a, 0x0a, - 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x6e, - 0x6f, 0x77, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, - 0x12, 0x2d, 0x0a, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, - 0x2e, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x69, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x2e, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, - 0x61, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, - 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x3a, 0x0a, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x74, - 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x32, 0xa0, 0x03, 0x0a, 0x09, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, - 0x12, 0x64, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, - 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x6c, 0x69, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, - 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x25, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, - 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x13, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, - 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, - 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, - 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x41, 0x75, - 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, - 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbe, 0x01, 0x0a, 0x1d, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x08, + 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, + 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, + 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x4c, 0x0a, + 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x49, 0x0a, 0x1d, 0x52, + 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x75, 0x62, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xf6, 0x02, 0x0a, 0x07, 0x46, 0x65, 0x61, + 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x05, 0x72, 0x75, + 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3e, 0x0a, 0x10, + 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x6c, 0x69, 0x73, 0x74, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x0f, 0x70, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x10, + 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x73, + 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, + 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, + 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x46, 0x6c, + 0x61, 0x67, 0x73, 0x1a, 0x4c, 0x0a, 0x0a, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xb1, 0x01, 0x0a, 0x0a, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x05, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x12, 0x2d, 0x0a, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x64, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x09, 0x6d, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x69, 0x6e, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2e, 0x0a, 0x09, 0x6d, 0x61, 0x78, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x78, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x61, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x3a, 0x0a, 0x0a, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, + 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6f, 0x70, + 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0xa0, 0x03, 0x0a, 0x09, 0x41, 0x75, 0x74, + 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x12, 0x64, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, + 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, - 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5e, 0x0a, 0x13, + 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, + 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, + 0x2e, 0x41, 0x64, 0x64, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x15, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x24, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x67, 0x0a, 0x16, - 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, - 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, - 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, - 0x73, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x74, 0x65, 0x72, 0x6d, - 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x6c, 0x69, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, + 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x67, 0x0a, 0x16, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, + 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x2e, 0x6c, + 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, + 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, + 0x6f, 0x6b, 0x65, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x34, 0x5a, 0x32, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, + 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, + 0x67, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x74, 0x72, 0x70, + 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/litrpc/lit-autopilot.proto b/litrpc/lit-autopilot.proto index c67ba3938..1555858a5 100644 --- a/litrpc/lit-autopilot.proto +++ b/litrpc/lit-autopilot.proto @@ -78,6 +78,17 @@ message AddAutopilotSessionRequest { Set to the ID of the group to link this session to, if any. */ bytes linked_group_id = 8; + + /* + The privacy flags used by this session. If set, then privacy_flags_set must + be set. + */ + uint64 privacy_flags = 9; + + /* + Indicates whether privacy flags are set. + */ + bool privacy_flags_set = 10; } message FeatureConfig { @@ -166,6 +177,12 @@ message Feature { The JSON-marshaled representation of a feature's default configuration. */ string default_config = 6; + + /* + This feature may require relaxed privacy obfuscation that can be enabled + with these flags. + */ + uint64 privacy_flags = 7; } message RuleValues { diff --git a/litrpc/lit-autopilot.swagger.json b/litrpc/lit-autopilot.swagger.json index f1a9a3d43..41475354a 100644 --- a/litrpc/lit-autopilot.swagger.json +++ b/litrpc/lit-autopilot.swagger.json @@ -167,6 +167,15 @@ "type": "string", "format": "byte", "description": "Set to the ID of the group to link this session to, if any." + }, + "privacy_flags": { + "type": "string", + "format": "uint64", + "description": "The privacy flags used by this session. If set, then privacy_flags_set must\nbe set." + }, + "privacy_flags_set": { + "type": "boolean", + "description": "Indicates whether privacy flags are set." } } }, @@ -269,6 +278,11 @@ "default_config": { "type": "string", "description": "The JSON-marshaled representation of a feature's default configuration." + }, + "privacy_flags": { + "type": "string", + "format": "uint64", + "description": "This feature may require relaxed privacy obfuscation that can be enabled\nwith these flags." } } }, @@ -599,6 +613,11 @@ "type": "string" }, "description": "Configurations for each individual feature mapping from the feature name to\na JSON-serialized configuration." + }, + "privacy_flags": { + "type": "string", + "format": "uint64", + "description": "Privacy flags used for the session that determine how the privacy mapper\noperates." } } }, diff --git a/litrpc/lit-sessions.pb.go b/litrpc/lit-sessions.pb.go index 402558bc3..1cf8e67e1 100644 --- a/litrpc/lit-sessions.pb.go +++ b/litrpc/lit-sessions.pb.go @@ -404,6 +404,9 @@ type Session struct { // Configurations for each individual feature mapping from the feature name to // a JSON-serialized configuration. FeatureConfigs map[string]string `protobuf:"bytes,18,rep,name=feature_configs,json=featureConfigs,proto3" json:"feature_configs,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // Privacy flags used for the session that determine how the privacy mapper + // operates. + PrivacyFlags uint64 `protobuf:"varint,19,opt,name=privacy_flags,json=privacyFlags,proto3" json:"privacy_flags,omitempty"` } func (x *Session) Reset() { @@ -564,6 +567,13 @@ func (x *Session) GetFeatureConfigs() map[string]string { return nil } +func (x *Session) GetPrivacyFlags() uint64 { + if x != nil { + return x.PrivacyFlags + } + return 0 +} + type MacaroonRecipe struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1577,7 +1587,7 @@ var file_lit_sessions_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, - 0xf2, 0x07, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x97, 0x08, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x39, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x74, 0x61, @@ -1630,168 +1640,170 @@ var file_lit_sessions_proto_rawDesc = []byte{ 0x0b, 0x32, 0x23, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x1a, 0x59, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x6f, 0x70, 0x69, - 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, - 0x6c, 0x65, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x0e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, - 0x52, 0x65, 0x63, 0x69, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6c, 0x69, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x50, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x76, 0x65, 0x61, 0x74, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x76, 0x65, 0x61, 0x74, 0x73, 0x22, 0x15, - 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, - 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x52, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x6c, - 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x6c, 0x6f, - 0x63, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x17, 0x0a, 0x15, - 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x08, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x4d, - 0x61, 0x70, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, - 0x4d, 0x61, 0x70, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, - 0x72, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x0a, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x75, - 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x92, 0x04, 0x0a, 0x09, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x12, 0x32, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, - 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x09, 0x72, 0x61, 0x74, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4b, 0x0a, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, - 0x69, 0x63, 0x79, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, - 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x48, 0x00, 0x52, - 0x10, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x6f, 0x75, 0x6e, 0x64, - 0x73, 0x12, 0x3b, 0x0a, 0x0d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x00, - 0x52, 0x0c, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x42, - 0x0a, 0x10, 0x6f, 0x66, 0x66, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x62, 0x75, 0x64, 0x67, - 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x4f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, - 0x48, 0x00, 0x52, 0x0e, 0x6f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, - 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x6f, 0x6e, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x62, - 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6c, 0x69, - 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, - 0x65, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x6f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, - 0x67, 0x65, 0x74, 0x12, 0x36, 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x73, - 0x65, 0x6c, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x74, 0x72, - 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x48, 0x00, 0x52, - 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x12, 0x44, 0x0a, 0x10, 0x63, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, - 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x48, 0x00, - 0x52, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, - 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69, - 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x48, 0x00, - 0x52, 0x0c, 0x70, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x42, 0x07, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x67, 0x0a, 0x09, 0x52, 0x61, 0x74, 0x65, 0x4c, - 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2b, 0x0a, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, - 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x12, 0x2d, 0x0a, 0x0b, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, - 0x52, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x22, 0x43, 0x0a, 0x04, 0x52, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x69, 0x74, 0x65, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x69, 0x74, - 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x75, 0x6d, 0x5f, - 0x68, 0x6f, 0x75, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x6e, 0x75, 0x6d, - 0x48, 0x6f, 0x75, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x0c, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x09, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x08, 0x64, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x08, - 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc5, 0x02, 0x0a, 0x13, 0x43, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x73, - 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x73, 0x61, - 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x69, 0x6e, - 0x42, 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, - 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, - 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x42, 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, - 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x70, 0x70, 0x6d, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x69, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x50, - 0x70, 0x6d, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x70, - 0x70, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x52, 0x61, 0x74, - 0x65, 0x50, 0x70, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, 0x5f, 0x63, 0x6c, 0x74, 0x76, - 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x69, - 0x6e, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x61, - 0x78, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, - 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, - 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x69, 0x6e, - 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, - 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x42, - 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, - 0x22, 0x5e, 0x0a, 0x0e, 0x4f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, - 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x6d, 0x73, - 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0a, 0x6d, 0x61, - 0x78, 0x41, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, - 0x66, 0x65, 0x65, 0x73, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, - 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x46, 0x65, 0x65, 0x73, 0x4d, 0x73, 0x61, 0x74, - 0x22, 0x6f, 0x0a, 0x0d, 0x4f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, - 0x74, 0x12, 0x2e, 0x0a, 0x11, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x5f, 0x61, 0x6d, - 0x74, 0x5f, 0x73, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, - 0x52, 0x0f, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x41, 0x6d, 0x74, 0x53, 0x61, 0x74, - 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x61, 0x74, 0x5f, 0x70, 0x65, 0x72, - 0x5f, 0x76, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, - 0x01, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x53, 0x61, 0x74, 0x50, 0x65, 0x72, 0x56, 0x42, 0x79, 0x74, - 0x65, 0x22, 0x0c, 0x0a, 0x0a, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, 0x22, - 0x36, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, - 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0a, 0x63, 0x68, 0x61, - 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x73, 0x22, 0x29, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x65, 0x65, 0x72, 0x5f, - 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x65, 0x65, 0x72, 0x49, - 0x64, 0x73, 0x2a, 0xa1, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, 0x52, - 0x4f, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x00, 0x12, 0x17, - 0x0a, 0x13, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, 0x4e, 0x5f, - 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, 0x4e, 0x5f, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, - 0x02, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x49, 0x5f, 0x50, 0x41, 0x53, - 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, 0x54, 0x59, 0x50, 0x45, 0x5f, - 0x41, 0x55, 0x54, 0x4f, 0x50, 0x49, 0x4c, 0x4f, 0x54, 0x10, 0x04, 0x12, 0x19, 0x0a, 0x15, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, 0x4e, 0x5f, 0x41, 0x43, 0x43, - 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x2a, 0x59, 0x0a, 0x0c, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, - 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x5f, 0x55, 0x53, 0x45, 0x10, 0x01, 0x12, 0x11, 0x0a, 0x0d, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, - 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, - 0x03, 0x32, 0xe8, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x43, - 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x6c, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x69, 0x76, 0x61, 0x63, + 0x79, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x63, 0x79, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x1a, 0x59, 0x0a, 0x19, 0x41, + 0x75, 0x74, 0x6f, 0x70, 0x69, 0x6c, 0x6f, 0x74, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6c, 0x69, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x68, 0x0a, 0x0e, 0x4d, 0x61, 0x63, + 0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x69, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x0b, 0x70, + 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x61, 0x63, 0x61, 0x72, 0x6f, + 0x6f, 0x6e, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x61, 0x76, + 0x65, 0x61, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x61, 0x76, 0x65, + 0x61, 0x74, 0x73, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x43, 0x0a, 0x14, 0x4c, 0x69, + 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x40, 0x0a, 0x14, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x08, 0x52, + 0x75, 0x6c, 0x65, 0x73, 0x4d, 0x61, 0x70, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, + 0x52, 0x75, 0x6c, 0x65, 0x73, 0x4d, 0x61, 0x70, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x1a, 0x4b, 0x0a, 0x0a, 0x52, 0x75, + 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x75, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x92, 0x04, 0x0a, 0x09, 0x52, 0x75, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x32, 0x0a, 0x0a, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x6c, 0x69, + 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6c, 0x69, 0x74, 0x72, + 0x70, 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x09, + 0x72, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4b, 0x0a, 0x12, 0x63, 0x68, 0x61, + 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x43, + 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, 0x6f, 0x75, 0x6e, + 0x64, 0x73, 0x48, 0x00, 0x52, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x42, 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x3b, 0x0a, 0x0d, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x12, 0x42, 0x0a, 0x10, 0x6f, 0x66, 0x66, 0x5f, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x5f, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x42, + 0x75, 0x64, 0x67, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x6f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x12, 0x3f, 0x0a, 0x0f, 0x6f, 0x6e, 0x5f, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x5f, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x15, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4f, 0x6e, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x6f, 0x6e, 0x43, 0x68, 0x61, + 0x69, 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x12, 0x36, 0x0a, 0x0c, 0x73, 0x65, 0x6e, 0x64, + 0x5f, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x6c, 0x66, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x65, + 0x6c, 0x66, 0x48, 0x00, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x53, 0x65, 0x6c, 0x66, + 0x12, 0x44, 0x0a, 0x10, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x74, + 0x72, 0x69, 0x63, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6c, 0x69, 0x74, + 0x72, 0x70, 0x63, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x74, 0x72, + 0x69, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, + 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x12, 0x3b, 0x0a, 0x0d, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, + 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x74, 0x72, + 0x69, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x70, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x74, 0x72, + 0x69, 0x63, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x67, 0x0a, 0x09, + 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2b, 0x0a, 0x0a, 0x72, 0x65, 0x61, + 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, + 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x52, 0x09, 0x72, 0x65, 0x61, + 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2d, 0x0a, 0x0b, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x69, + 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x52, 0x0a, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x43, 0x0a, 0x04, 0x52, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, + 0x0a, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0a, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x0a, + 0x09, 0x6e, 0x75, 0x6d, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, + 0x52, 0x08, 0x6e, 0x75, 0x6d, 0x48, 0x6f, 0x75, 0x72, 0x73, 0x22, 0x51, 0x0a, 0x0c, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0a, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, + 0x30, 0x01, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1e, 0x0a, + 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, + 0x02, 0x30, 0x01, 0x52, 0x08, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc5, 0x02, + 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x42, + 0x6f, 0x75, 0x6e, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x62, 0x61, 0x73, + 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x42, 0x61, 0x73, 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, + 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x42, 0x61, 0x73, + 0x65, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x69, 0x6e, 0x5f, 0x72, 0x61, 0x74, + 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, 0x69, 0x6e, + 0x52, 0x61, 0x74, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x20, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x72, + 0x61, 0x74, 0x65, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x6d, + 0x61, 0x78, 0x52, 0x61, 0x74, 0x65, 0x50, 0x70, 0x6d, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x6e, + 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x0c, 0x6d, 0x69, 0x6e, 0x43, 0x6c, 0x74, 0x76, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, + 0x24, 0x0a, 0x0e, 0x6d, 0x61, 0x78, 0x5f, 0x63, 0x6c, 0x74, 0x76, 0x5f, 0x64, 0x65, 0x6c, 0x74, + 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6d, 0x61, 0x78, 0x43, 0x6c, 0x74, 0x76, + 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x0d, 0x6d, 0x69, 0x6e, 0x5f, 0x68, 0x74, 0x6c, + 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x48, 0x74, 0x6c, 0x63, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, + 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x74, 0x6c, 0x63, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x74, 0x6c, + 0x63, 0x4d, 0x73, 0x61, 0x74, 0x22, 0x5e, 0x0a, 0x0e, 0x4f, 0x66, 0x66, 0x43, 0x68, 0x61, 0x69, + 0x6e, 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0c, 0x6d, 0x61, 0x78, 0x5f, 0x61, + 0x6d, 0x74, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, + 0x01, 0x52, 0x0a, 0x6d, 0x61, 0x78, 0x41, 0x6d, 0x74, 0x4d, 0x73, 0x61, 0x74, 0x12, 0x26, 0x0a, + 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x66, 0x65, 0x65, 0x73, 0x5f, 0x6d, 0x73, 0x61, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x46, 0x65, 0x65, + 0x73, 0x4d, 0x73, 0x61, 0x74, 0x22, 0x6f, 0x0a, 0x0d, 0x4f, 0x6e, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x42, 0x75, 0x64, 0x67, 0x65, 0x74, 0x12, 0x2e, 0x0a, 0x11, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, + 0x74, 0x65, 0x5f, 0x61, 0x6d, 0x74, 0x5f, 0x73, 0x61, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0f, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x41, + 0x6d, 0x74, 0x53, 0x61, 0x74, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x6d, 0x61, 0x78, 0x5f, 0x73, 0x61, + 0x74, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x76, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x53, 0x61, 0x74, 0x50, 0x65, + 0x72, 0x56, 0x42, 0x79, 0x74, 0x65, 0x22, 0x0c, 0x0a, 0x0a, 0x53, 0x65, 0x6e, 0x64, 0x54, 0x6f, + 0x53, 0x65, 0x6c, 0x66, 0x22, 0x36, 0x0a, 0x0f, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, + 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x6e, + 0x65, 0x6c, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x04, 0x42, 0x02, 0x30, 0x01, + 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x49, 0x64, 0x73, 0x22, 0x29, 0x0a, 0x0c, + 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x12, 0x19, 0x0a, 0x08, + 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x73, 0x2a, 0xa1, 0x01, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x4f, 0x4e, 0x4c, + 0x59, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, + 0x52, 0x4f, 0x4f, 0x4e, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, 0x4e, 0x5f, 0x43, 0x55, + 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, + 0x49, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x03, 0x12, 0x12, 0x0a, 0x0e, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x55, 0x54, 0x4f, 0x50, 0x49, 0x4c, 0x4f, 0x54, 0x10, 0x04, + 0x12, 0x19, 0x0a, 0x15, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x43, 0x41, 0x52, 0x4f, 0x4f, + 0x4e, 0x5f, 0x41, 0x43, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x10, 0x05, 0x2a, 0x59, 0x0a, 0x0c, 0x53, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x10, + 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x5f, 0x55, 0x53, 0x45, 0x10, 0x01, + 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x56, 0x4f, 0x4b, 0x45, + 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x45, 0x58, 0x50, + 0x49, 0x52, 0x45, 0x44, 0x10, 0x03, 0x32, 0xe8, 0x01, 0x0a, 0x08, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x19, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, - 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, - 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x1c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, - 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x34, 0x5a, 0x32, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, - 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, - 0x6e, 0x67, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, 0x2f, 0x6c, 0x69, 0x74, 0x72, - 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, + 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0d, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, + 0x76, 0x6f, 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x76, 0x6f, + 0x6b, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, 0x67, 0x2d, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x61, 0x6c, + 0x2f, 0x6c, 0x69, 0x74, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/litrpc/lit-sessions.proto b/litrpc/lit-sessions.proto index 83618640b..8d2e2cd0a 100644 --- a/litrpc/lit-sessions.proto +++ b/litrpc/lit-sessions.proto @@ -212,6 +212,12 @@ message Session { a JSON-serialized configuration. */ map feature_configs = 18; + + /* + Privacy flags used for the session that determine how the privacy mapper + operates. + */ + uint64 privacy_flags = 19; } message MacaroonRecipe { diff --git a/litrpc/lit-sessions.swagger.json b/litrpc/lit-sessions.swagger.json index 6ed0ff1b6..41b4b2312 100644 --- a/litrpc/lit-sessions.swagger.json +++ b/litrpc/lit-sessions.swagger.json @@ -473,6 +473,11 @@ "type": "string" }, "description": "Configurations for each individual feature mapping from the feature name to\na JSON-serialized configuration." + }, + "privacy_flags": { + "type": "string", + "format": "uint64", + "description": "Privacy flags used for the session that determine how the privacy mapper\noperates." } } }, diff --git a/proto/lit-autopilot.proto b/proto/lit-autopilot.proto index c67ba3938..3c0c56767 100644 --- a/proto/lit-autopilot.proto +++ b/proto/lit-autopilot.proto @@ -78,6 +78,17 @@ message AddAutopilotSessionRequest { Set to the ID of the group to link this session to, if any. */ bytes linked_group_id = 8; + + /* + The privacy flags used by this session. If set, then privacy_flags_set must + be set. + */ + uint64 privacy_flags = 9 [jstype = JS_STRING]; + + /* + Indicates whether privacy flags are set. + */ + bool privacy_flags_set = 10; } message FeatureConfig { @@ -166,6 +177,12 @@ message Feature { The JSON-marshaled representation of a feature's default configuration. */ string default_config = 6; + + /* + This feature may require relaxed privacy obfuscation that can be enabled + with these flags. + */ + uint64 privacy_flags = 7 [jstype = JS_STRING]; } message RuleValues { diff --git a/proto/lit-sessions.proto b/proto/lit-sessions.proto index 83618640b..edf8332d1 100644 --- a/proto/lit-sessions.proto +++ b/proto/lit-sessions.proto @@ -212,6 +212,12 @@ message Session { a JSON-serialized configuration. */ map feature_configs = 18; + + /* + Privacy flags used for the session that determine how the privacy mapper + operates. + */ + uint64 privacy_flags = 19 [jstype = JS_STRING]; } message MacaroonRecipe { diff --git a/rules/chan_policy_bounds.go b/rules/chan_policy_bounds.go index b20bcccb4..ef939d7da 100644 --- a/rules/chan_policy_bounds.go +++ b/rules/chan_policy_bounds.go @@ -8,6 +8,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/protobuf/proto" ) @@ -318,8 +319,8 @@ func (f *ChanPolicyBounds) RuleName() string { // find the real values. This is a no-op for the ChanPolicyBounds rule. // // NOTE: this is part of the Values interface. -func (f *ChanPolicyBounds) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, - error) { +func (f *ChanPolicyBounds) PseudoToReal(_ firewalldb.PrivacyMapDB, + _ session.PrivacyFlags) (Values, error) { return f, nil } @@ -329,8 +330,8 @@ func (f *ChanPolicyBounds) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, // that should be persisted. This is a no-op for the ChanPolicyBounds rule. // // NOTE: this is part of the Values interface. -func (f *ChanPolicyBounds) RealToPseudo(_ firewalldb.PrivacyMapReader) (Values, - map[string]string, error) { +func (f *ChanPolicyBounds) RealToPseudo(_ firewalldb.PrivacyMapReader, + _ session.PrivacyFlags) (Values, map[string]string, error) { return f, nil, nil } diff --git a/rules/channel_restrictions.go b/rules/channel_restrictions.go index cf27a528b..8594dde5e 100644 --- a/rules/channel_restrictions.go +++ b/rules/channel_restrictions.go @@ -8,6 +8,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/protobuf/proto" ) @@ -334,10 +335,18 @@ func (c *ChannelRestrict) ToProto() *litrpc.RuleValue { // It constructs a new ChannelRestrict instance with these real channel IDs. // // NOTE: this is part of the Values interface. -func (c *ChannelRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, - error) { +func (c *ChannelRestrict) PseudoToReal(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) (Values, error) { restrictList := make([]uint64, len(c.DenyList)) + + // We don't obfuscate the channel IDs if the channel id flag is set. + if flags.Contains(session.ClearChanIDs) { + copy(restrictList, c.DenyList) + + return &ChannelRestrict{DenyList: restrictList}, nil + } + err := db.View(func(tx firewalldb.PrivacyMapTx) error { for i, chanID := range c.DenyList { real, err := firewalldb.RevealUint64(tx, chanID) @@ -349,15 +358,12 @@ func (c *ChannelRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, } return nil - }, - ) + }) if err != nil { return nil, err } - return &ChannelRestrict{ - DenyList: restrictList, - }, nil + return &ChannelRestrict{DenyList: restrictList}, nil } // RealToPseudo converts all the real channel IDs into pseudo IDs. It returns a @@ -365,11 +371,19 @@ func (c *ChannelRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, // not find in the given PrivacyMapReader. // // NOTE: this is part of the Values interface. -func (c *ChannelRestrict) RealToPseudo(db firewalldb.PrivacyMapReader) (Values, - map[string]string, error) { +func (c *ChannelRestrict) RealToPseudo(db firewalldb.PrivacyMapReader, + flags session.PrivacyFlags) (Values, map[string]string, error) { pseudoIDs := make([]uint64, len(c.DenyList)) privMapPairs := make(map[string]string) + + // We don't obfuscate the channel IDs if the channel id flag is set. + if flags.Contains(session.ClearChanIDs) { + copy(pseudoIDs, c.DenyList) + + return &ChannelRestrict{DenyList: pseudoIDs}, privMapPairs, nil + } + for i, c := range c.DenyList { // TODO(elle): check that this channel actually exists @@ -390,7 +404,5 @@ func (c *ChannelRestrict) RealToPseudo(db firewalldb.PrivacyMapReader) (Values, pseudoIDs[i] = pseudoCp } - return &ChannelRestrict{ - DenyList: pseudoIDs, - }, privMapPairs, nil + return &ChannelRestrict{DenyList: pseudoIDs}, privMapPairs, nil } diff --git a/rules/channel_restrictions_test.go b/rules/channel_restrictions_test.go index 1e7d00bbd..d6ef6e8c8 100644 --- a/rules/channel_restrictions_test.go +++ b/rules/channel_restrictions_test.go @@ -9,6 +9,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightninglabs/lightning-terminal/firewalldb" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/lnrpc" "github.com/stretchr/testify/require" @@ -173,6 +174,7 @@ func TestChannelRestrictRealToPseudo(t *testing.T) { tests := []struct { name string + privacyFlags session.PrivacyFlags dbPreLoad map[string]string expectNewPairs map[string]bool }{ @@ -200,6 +202,12 @@ func TestChannelRestrictRealToPseudo(t *testing.T) { chanID3: true, }, }, + { + name: "turned off mapping", + privacyFlags: session.PrivacyFlags{ + session.ClearChanIDs, + }, + }, } // Construct the ChannelRestrict deny list. Note that we repeat one of @@ -240,7 +248,9 @@ func TestChannelRestrictRealToPseudo(t *testing.T) { // rule. This will return the rule value in its pseudo // form along with any new privacy map pairs that should // be added to the DB. - v, newPairs, err := cr.RealToPseudo(privMapPairDB) + v, newPairs, err := cr.RealToPseudo( + privMapPairDB, test.privacyFlags, + ) require.NoError(t, err) require.Len(t, newPairs, len(test.expectNewPairs)) @@ -257,6 +267,16 @@ func TestChannelRestrictRealToPseudo(t *testing.T) { denyList, ok := v.(*ChannelRestrict) require.True(t, ok) + // We expect the original deny list if we switch off + // privacy mapping. + if test.privacyFlags.Contains( + session.ClearChanIDs) { + + for _, p := range cr.DenyList { + expectedDenyList[p] = true + } + } + // Assert that the resulting deny list is the same // length as the un-obfuscated one. require.Len(t, denyList.DenyList, len(cr.DenyList)) diff --git a/rules/history_limit.go b/rules/history_limit.go index 4d4ab95d3..8ca0270fa 100644 --- a/rules/history_limit.go +++ b/rules/history_limit.go @@ -8,6 +8,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/protobuf/proto" ) @@ -255,8 +256,8 @@ func (h *HistoryLimit) GetStartDate() time.Time { // find the real values. This is a no-op for the HistoryLimit rule. // // NOTE: this is part of the Values interface. -func (h *HistoryLimit) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, - error) { +func (h *HistoryLimit) PseudoToReal(_ firewalldb.PrivacyMapDB, + _ session.PrivacyFlags) (Values, error) { return h, nil } @@ -266,8 +267,8 @@ func (h *HistoryLimit) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, // that should be persisted. This is a no-op for the HistoryLimit rule. // // NOTE: this is part of the Values interface. -func (h *HistoryLimit) RealToPseudo(_ firewalldb.PrivacyMapReader) (Values, - map[string]string, error) { +func (h *HistoryLimit) RealToPseudo(_ firewalldb.PrivacyMapReader, + _ session.PrivacyFlags) (Values, map[string]string, error) { return h, nil, nil } diff --git a/rules/interfaces.go b/rules/interfaces.go index 83b09224c..66fc27bfd 100644 --- a/rules/interfaces.go +++ b/rules/interfaces.go @@ -6,6 +6,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" + "github.com/lightninglabs/lightning-terminal/session" "google.golang.org/protobuf/proto" ) @@ -62,13 +63,14 @@ type Values interface { // keys, channel IDs, channel points etc. It returns a map of any new // real to pseudo strings that should be persisted that it did not find // in the given PrivacyMapReader. - RealToPseudo(db firewalldb.PrivacyMapReader) (Values, map[string]string, - error) + RealToPseudo(db firewalldb.PrivacyMapReader, + flags session.PrivacyFlags) (Values, map[string]string, error) // PseudoToReal attempts to convert any appropriate pseudo fields in // the rule Values to their corresponding real values. It uses the // passed PrivacyMapDB to find the real values. - PseudoToReal(db firewalldb.PrivacyMapDB) (Values, error) + PseudoToReal(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) (Values, error) } // Marshal converts the rule Values to a json byte slice. diff --git a/rules/manager_set.go b/rules/manager_set.go index 027bb602b..1ea9e66bf 100644 --- a/rules/manager_set.go +++ b/rules/manager_set.go @@ -31,7 +31,8 @@ func (m ManagerSet) InitEnforcer(cfg Config, name string, mgr, ok := m[name] if !ok { - return nil, ErrUnknownRule + return nil, fmt.Errorf("%w %s, please upgrade", ErrUnknownRule, + name) } return mgr.NewEnforcer(cfg, values) @@ -54,7 +55,8 @@ func (m ManagerSet) UnmarshalRuleValues(name string, proto *litrpc.RuleValue) ( mgr, ok := m[name] if !ok { - return nil, ErrUnknownRule + return nil, fmt.Errorf("%w %s, please upgrade", ErrUnknownRule, + name) } return mgr.NewValueFromProto(proto) @@ -67,7 +69,8 @@ func (m ManagerSet) InitRuleValues(name string, valueBytes []byte) (Values, mgr, ok := m[name] if !ok { - return nil, ErrUnknownRule + return nil, fmt.Errorf("%w %s, please upgrade", ErrUnknownRule, + name) } v := mgr.EmptyValue() diff --git a/rules/peer_restrictions.go b/rules/peer_restrictions.go index 793149c37..eff2dc1f6 100644 --- a/rules/peer_restrictions.go +++ b/rules/peer_restrictions.go @@ -8,6 +8,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/lnrpc" "google.golang.org/protobuf/proto" @@ -341,13 +342,21 @@ func (c *PeerRestrict) ToProto() *litrpc.RuleValue { // It constructs a new PeerRestrict instance with these real peer IDs. // // NOTE: this is part of the Values interface. -func (c *PeerRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, - error) { +func (c *PeerRestrict) PseudoToReal(db firewalldb.PrivacyMapDB, + flags session.PrivacyFlags) (Values, error) { restrictList := make([]string, len(c.DenyList)) + + // We don't obfuscate if the clear pubkeys flag is set. + if flags.Contains(session.ClearPubkeys) { + copy(restrictList, c.DenyList) + + return &PeerRestrict{DenyList: restrictList}, nil + } + err := db.View(func(tx firewalldb.PrivacyMapTx) error { - for i, chanID := range c.DenyList { - real, err := firewalldb.RevealString(tx, chanID) + for i, peerPubKey := range c.DenyList { + real, err := firewalldb.RevealString(tx, peerPubKey) if err != nil { return err } @@ -362,9 +371,7 @@ func (c *PeerRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, return nil, err } - return &PeerRestrict{ - DenyList: restrictList, - }, nil + return &PeerRestrict{DenyList: restrictList}, nil } // RealToPseudo converts all the real peer IDs into pseudo IDs. It returns a map @@ -372,11 +379,19 @@ func (c *PeerRestrict) PseudoToReal(db firewalldb.PrivacyMapDB) (Values, // find in the given PrivacyMapReader. // // NOTE: this is part of the Values interface. -func (c *PeerRestrict) RealToPseudo(db firewalldb.PrivacyMapReader) (Values, - map[string]string, error) { +func (c *PeerRestrict) RealToPseudo(db firewalldb.PrivacyMapReader, + flags session.PrivacyFlags) (Values, map[string]string, error) { pseudoIDs := make([]string, len(c.DenyList)) privMapPairs := make(map[string]string) + + // We don't obfuscate if the clear pubkeys flag is set. + if flags.Contains(session.ClearPubkeys) { + copy(pseudoIDs, c.DenyList) + + return &PeerRestrict{DenyList: pseudoIDs}, privMapPairs, nil + } + for i, id := range c.DenyList { // TODO(elle): check that this peer is actually one of our // channel peers. diff --git a/rules/peer_restrictions_test.go b/rules/peer_restrictions_test.go index b1f0af4cd..ed93ababb 100644 --- a/rules/peer_restrictions_test.go +++ b/rules/peer_restrictions_test.go @@ -8,6 +8,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightninglabs/lightning-terminal/firewalldb" + "github.com/lightninglabs/lightning-terminal/session" "github.com/lightninglabs/lndclient" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/routing/route" @@ -157,6 +158,7 @@ func TestPeerRestrictCheckRequest(t *testing.T) { func TestPeerRestrictRealToPseudo(t *testing.T) { tests := []struct { name string + privacyFlags session.PrivacyFlags dbPreLoad map[string]string expectNewPairs map[string]bool }{ @@ -184,6 +186,12 @@ func TestPeerRestrictRealToPseudo(t *testing.T) { "peer 3": true, }, }, + { + name: "turned off mapping", + privacyFlags: []session.PrivacyFlag{ + session.ClearPubkeys, + }, + }, } // Construct the PeerRestrict deny list. Note that we repeat one of @@ -219,7 +227,9 @@ func TestPeerRestrictRealToPseudo(t *testing.T) { // rule. This will return the rule value in its pseudo // form along with any new privacy map pairs that should // be added to the DB. - v, newPairs, err := pr.RealToPseudo(privMapPairDB) + v, newPairs, err := pr.RealToPseudo( + privMapPairDB, test.privacyFlags, + ) require.NoError(t, err) require.Len(t, newPairs, len(test.expectNewPairs)) @@ -230,6 +240,14 @@ func TestPeerRestrictRealToPseudo(t *testing.T) { expectedDenyList[p] = true } + // We expect the original deny list if we switch off + // privacy mapping. + if test.privacyFlags.Contains(session.ClearPubkeys) { + for _, p := range pr.DenyList { + expectedDenyList[p] = true + } + } + // Assert that the element in the resulting deny list // matches all the elements in our expected deny list. denyList, ok := v.(*PeerRestrict) @@ -241,8 +259,8 @@ func TestPeerRestrictRealToPseudo(t *testing.T) { // Now iterate over the deny list and assert that each // value appears in our expected deny list. - for _, channel := range denyList.DenyList { - require.True(t, expectedDenyList[channel]) + for _, peer := range denyList.DenyList { + require.True(t, expectedDenyList[peer]) } }) } diff --git a/rules/rate_limit.go b/rules/rate_limit.go index ddafe9c9f..8f776dcc7 100644 --- a/rules/rate_limit.go +++ b/rules/rate_limit.go @@ -7,6 +7,7 @@ import ( "github.com/lightninglabs/lightning-terminal/firewalldb" "github.com/lightninglabs/lightning-terminal/litrpc" + "github.com/lightninglabs/lightning-terminal/session" "google.golang.org/protobuf/proto" "gopkg.in/macaroon-bakery.v2/bakery" ) @@ -266,8 +267,8 @@ func (r *RateLimit) ToProto() *litrpc.RuleValue { // find the real values. This is a no-op for the RateLimit rule. // // NOTE: this is part of the Values interface. -func (r *RateLimit) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, - error) { +func (r *RateLimit) PseudoToReal(_ firewalldb.PrivacyMapDB, + _ session.PrivacyFlags) (Values, error) { return r, nil } @@ -277,8 +278,8 @@ func (r *RateLimit) PseudoToReal(_ firewalldb.PrivacyMapDB) (Values, // that should be persisted. This is a no-op for the RateLimit rule. // // NOTE: this is part of the Values interface. -func (r *RateLimit) RealToPseudo(_ firewalldb.PrivacyMapReader) (Values, - map[string]string, error) { +func (r *RateLimit) RealToPseudo(_ firewalldb.PrivacyMapReader, + flags session.PrivacyFlags) (Values, map[string]string, error) { return r, nil, nil } diff --git a/session/interface.go b/session/interface.go index 1d080eb8e..00f109d5d 100644 --- a/session/interface.go +++ b/session/interface.go @@ -63,6 +63,7 @@ type Session struct { RemotePublicKey *btcec.PublicKey FeatureConfig *FeaturesConfig WithPrivacyMapper bool + PrivacyFlags PrivacyFlags // GroupID is the Session ID of the very first Session in the linked // group of sessions. If this is the very first session in the group @@ -78,7 +79,7 @@ type MacaroonBaker func(ctx context.Context, rootKeyID uint64, func NewSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type, expiry time.Time, serverAddr string, devServer bool, perms []bakery.Op, caveats []macaroon.Caveat, featureConfig FeaturesConfig, - privacy bool, linkedGroupID *ID) (*Session, error) { + privacy bool, linkedGroupID *ID, flags PrivacyFlags) (*Session, error) { _, pairingSecret, err := mailbox.NewPassphraseEntropy() if err != nil { @@ -111,6 +112,7 @@ func NewSession(id ID, localPrivKey *btcec.PrivateKey, label string, typ Type, LocalPublicKey: localPrivKey.PubKey(), RemotePublicKey: nil, WithPrivacyMapper: privacy, + PrivacyFlags: flags, GroupID: groupID, } diff --git a/session/migration1/tlv.go b/session/migration1/tlv.go index aa3370b71..54105a87d 100644 --- a/session/migration1/tlv.go +++ b/session/migration1/tlv.go @@ -531,15 +531,17 @@ func permsDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error { func caveatsEncoder(w io.Writer, val interface{}, buf *[8]byte) error { if v, ok := val.(*[]macaroon.Caveat); ok { for _, c := range *v { + id := c.Id tlvRecords := []tlv.Record{ - tlv.MakePrimitiveRecord(typeCaveatID, &c.Id), + tlv.MakePrimitiveRecord(typeCaveatID, &id), } - if c.VerificationId != nil { + verificationId := c.VerificationId + if verificationId != nil { tlvRecords = append(tlvRecords, tlv.MakePrimitiveRecord( typeCaveatVerificationID, - &c.VerificationId, + &verificationId, ), ) } diff --git a/session/privacy_flags.go b/session/privacy_flags.go new file mode 100644 index 000000000..297e94935 --- /dev/null +++ b/session/privacy_flags.go @@ -0,0 +1,178 @@ +package session + +import ( + "errors" + "fmt" + "slices" + "strings" +) + +// PrivacyFlag is an enum representing privacy flags for obfuscation behavior of +// feature configuration, feature rules and API calls. Privacy is on by default, +// by setting a privacy flag one can disable certain obfuscation behavior. +type PrivacyFlag uint64 + +// ErrUnknownPrivacyFlag is an error that is returned when an unknown privacy +// flag is used. +var ErrUnknownPrivacyFlag = errors.New("unknown privacy flag") + +const ( + + // ClearPubkeys is a privacy flag that indicates that the public node + // ids in API should be treated as clear text. + ClearPubkeys PrivacyFlag = 0 + + // ClearAmounts is a privacy flag that indicates that the amounts in the + // API should not be obfuscated. + ClearAmounts PrivacyFlag = 1 + + // ClearChanIDs is a privacy flag that indicates that the channel id and + // channel points in API should not be obfuscated. + ClearChanIDs PrivacyFlag = 2 + + // ClearTimeStamps is a privacy flag that indicates that the timestamps + // in the API should not be obfuscated. + ClearTimeStamps PrivacyFlag = 3 + + // ClearChanInitiator is a privacy flag that indicates that the channel + // initiator in the API should not be obfuscated. + ClearChanInitiator PrivacyFlag = 4 + + // ClearHTLCs is a privacy flag that indicates that the HTLCs in the API + // should not be obfuscated. + ClearHTLCs PrivacyFlag = 5 +) + +var flagMap = map[PrivacyFlag]string{ + ClearPubkeys: "ClearPubkeys", + ClearAmounts: "ClearAmounts", + ClearChanIDs: "ClearChanIDs", + ClearTimeStamps: "ClearTimeStamps", + ClearChanInitiator: "ClearChanInitiator", + ClearHTLCs: "ClearHTLCs", +} + +// String returns a string representation of the privacy flag. +func (f PrivacyFlag) String() string { + flagStr, ok := flagMap[f] + if !ok { + return "Unknown" + } + + return flagStr +} + +// Validate returns an error if a privacy flag is unknown. +func (f PrivacyFlag) Validate() error { + _, ok := flagMap[f] + if !ok { + return ErrUnknownPrivacyFlag + } + + return nil +} + +// PrivacyFlags is a struct representing a set of privacy flags. +type PrivacyFlags []PrivacyFlag + +// String returns a string representation of the privacy flags. +func (f PrivacyFlags) String() string { + // We sort to get a stable string representation without modification of + // the original slice. + c := make(PrivacyFlags, len(f)) + copy(c, f) + slices.Sort(c[:]) + + if len(c) == 0 { + return "" + } + + result := c[0].String() + for _, flag := range c[1:] { + result += "|" + result += flag.String() + } + + return result +} + +// Serialize returns a serialized representation of the privacy flags. +func (f PrivacyFlags) Serialize() uint64 { + var result uint64 + for _, flag := range f { + result |= 1 << uint64(flag) + } + + return result +} + +// Deserialize returns a PrivacyFlags struct from a serialized +// representation. +func Deserialize(serialized uint64) (PrivacyFlags, error) { + var flags PrivacyFlags + for i := 0; i < 64; i++ { + // We check if the i-th bit is set. + if serialized&(1<