From 6d8f77815793068afe278918a71043ab613007ce Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Thu, 4 Mar 2021 22:18:30 +0000 Subject: [PATCH] mfa: add WithMFA to session-related audit events (#5833) * mfa: put device UUID in MFAVerified cert extensions Instead of just a bool, add the device UUID. This will be used in audit events when a session is started using MFA-issued certs. * Add WithMFA to session-related audit events Also extract a common function for parsing SSH certs. --- api/types/events/events.pb.go | 684 +++++++++++++++++---------------- api/types/events/events.proto | 2 + lib/auth/auth.go | 20 +- lib/auth/auth_test.go | 7 +- lib/auth/auth_with_roles.go | 2 +- lib/auth/grpcserver.go | 32 +- lib/auth/grpcserver_test.go | 24 +- lib/auth/init.go | 7 +- lib/auth/init_test.go | 4 +- lib/auth/native/native.go | 4 +- lib/auth/native/native_test.go | 15 +- lib/auth/test/suite.go | 15 +- lib/auth/tls_test.go | 24 +- lib/client/api.go | 7 +- lib/client/interfaces.go | 11 +- lib/kube/proxy/forwarder.go | 7 +- lib/reversetunnel/cache.go | 7 +- lib/services/authority.go | 6 +- lib/services/role_test.go | 11 +- lib/srv/app/server.go | 2 +- lib/srv/app/session.go | 1 + lib/srv/authhandlers.go | 5 +- lib/srv/ctx.go | 25 +- lib/srv/db/common/audit.go | 3 + lib/srv/db/mysql/engine.go | 2 +- lib/srv/db/postgres/engine.go | 2 +- lib/srv/exec.go | 7 +- lib/srv/exec_test.go | 32 +- lib/sshutils/parse.go | 36 ++ lib/sshutils/signer.go | 7 +- lib/tlsca/ca.go | 12 +- lib/web/apps.go | 1 + lib/web/sessions.go | 11 +- 33 files changed, 529 insertions(+), 506 deletions(-) create mode 100644 lib/sshutils/parse.go diff --git a/api/types/events/events.pb.go b/api/types/events/events.pb.go index 9e5c823390d42..360ed13bcbf0a 100644 --- a/api/types/events/events.pb.go +++ b/api/types/events/events.pb.go @@ -51,7 +51,7 @@ func (m *Metadata) Reset() { *m = Metadata{} } func (m *Metadata) String() string { return proto.CompactTextString(m) } func (*Metadata) ProtoMessage() {} func (*Metadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{0} + return fileDescriptor_events_183547552ed1ab9b, []int{0} } func (m *Metadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -83,7 +83,9 @@ var xxx_messageInfo_Metadata proto.InternalMessageInfo // SesssionMetadata is a common session event metadata type SessionMetadata struct { // SessionID is a unique UUID of the session. - SessionID string `protobuf:"bytes,1,opt,name=SessionID,proto3" json:"sid"` + SessionID string `protobuf:"bytes,1,opt,name=SessionID,proto3" json:"sid"` + // WithMFA is a UUID of an MFA device used to start this session. + WithMFA string `protobuf:"bytes,2,opt,name=WithMFA,proto3" json:"with_mfa,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -93,7 +95,7 @@ func (m *SessionMetadata) Reset() { *m = SessionMetadata{} } func (m *SessionMetadata) String() string { return proto.CompactTextString(m) } func (*SessionMetadata) ProtoMessage() {} func (*SessionMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{1} + return fileDescriptor_events_183547552ed1ab9b, []int{1} } func (m *SessionMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -137,7 +139,7 @@ func (m *UserMetadata) Reset() { *m = UserMetadata{} } func (m *UserMetadata) String() string { return proto.CompactTextString(m) } func (*UserMetadata) ProtoMessage() {} func (*UserMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{2} + return fileDescriptor_events_183547552ed1ab9b, []int{2} } func (m *UserMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -188,7 +190,7 @@ func (m *ServerMetadata) Reset() { *m = ServerMetadata{} } func (m *ServerMetadata) String() string { return proto.CompactTextString(m) } func (*ServerMetadata) ProtoMessage() {} func (*ServerMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{3} + return fileDescriptor_events_183547552ed1ab9b, []int{3} } func (m *ServerMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -234,7 +236,7 @@ func (m *ConnectionMetadata) Reset() { *m = ConnectionMetadata{} } func (m *ConnectionMetadata) String() string { return proto.CompactTextString(m) } func (*ConnectionMetadata) ProtoMessage() {} func (*ConnectionMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{4} + return fileDescriptor_events_183547552ed1ab9b, []int{4} } func (m *ConnectionMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -281,7 +283,7 @@ func (m *KubernetesClusterMetadata) Reset() { *m = KubernetesClusterMeta func (m *KubernetesClusterMetadata) String() string { return proto.CompactTextString(m) } func (*KubernetesClusterMetadata) ProtoMessage() {} func (*KubernetesClusterMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{5} + return fileDescriptor_events_183547552ed1ab9b, []int{5} } func (m *KubernetesClusterMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -332,7 +334,7 @@ func (m *KubernetesPodMetadata) Reset() { *m = KubernetesPodMetadata{} } func (m *KubernetesPodMetadata) String() string { return proto.CompactTextString(m) } func (*KubernetesPodMetadata) ProtoMessage() {} func (*KubernetesPodMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{6} + return fileDescriptor_events_183547552ed1ab9b, []int{6} } func (m *KubernetesPodMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -391,7 +393,7 @@ func (m *SessionStart) Reset() { *m = SessionStart{} } func (m *SessionStart) String() string { return proto.CompactTextString(m) } func (*SessionStart) ProtoMessage() {} func (*SessionStart) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{7} + return fileDescriptor_events_183547552ed1ab9b, []int{7} } func (m *SessionStart) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -444,7 +446,7 @@ func (m *SessionJoin) Reset() { *m = SessionJoin{} } func (m *SessionJoin) String() string { return proto.CompactTextString(m) } func (*SessionJoin) ProtoMessage() {} func (*SessionJoin) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{8} + return fileDescriptor_events_183547552ed1ab9b, []int{8} } func (m *SessionJoin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -498,7 +500,7 @@ func (m *SessionPrint) Reset() { *m = SessionPrint{} } func (m *SessionPrint) String() string { return proto.CompactTextString(m) } func (*SessionPrint) ProtoMessage() {} func (*SessionPrint) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{9} + return fileDescriptor_events_183547552ed1ab9b, []int{9} } func (m *SessionPrint) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -553,7 +555,7 @@ func (m *SessionReject) Reset() { *m = SessionReject{} } func (m *SessionReject) String() string { return proto.CompactTextString(m) } func (*SessionReject) ProtoMessage() {} func (*SessionReject) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{10} + return fileDescriptor_events_183547552ed1ab9b, []int{10} } func (m *SessionReject) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -610,7 +612,7 @@ func (m *Resize) Reset() { *m = Resize{} } func (m *Resize) String() string { return proto.CompactTextString(m) } func (*Resize) ProtoMessage() {} func (*Resize) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{11} + return fileDescriptor_events_183547552ed1ab9b, []int{11} } func (m *Resize) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -679,7 +681,7 @@ func (m *SessionEnd) Reset() { *m = SessionEnd{} } func (m *SessionEnd) String() string { return proto.CompactTextString(m) } func (*SessionEnd) ProtoMessage() {} func (*SessionEnd) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{12} + return fileDescriptor_events_183547552ed1ab9b, []int{12} } func (m *SessionEnd) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -725,7 +727,7 @@ func (m *BPFMetadata) Reset() { *m = BPFMetadata{} } func (m *BPFMetadata) String() string { return proto.CompactTextString(m) } func (*BPFMetadata) ProtoMessage() {} func (*BPFMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{13} + return fileDescriptor_events_183547552ed1ab9b, []int{13} } func (m *BPFMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -771,7 +773,7 @@ func (m *Status) Reset() { *m = Status{} } func (m *Status) String() string { return proto.CompactTextString(m) } func (*Status) ProtoMessage() {} func (*Status) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{14} + return fileDescriptor_events_183547552ed1ab9b, []int{14} } func (m *Status) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -830,7 +832,7 @@ func (m *SessionCommand) Reset() { *m = SessionCommand{} } func (m *SessionCommand) String() string { return proto.CompactTextString(m) } func (*SessionCommand) ProtoMessage() {} func (*SessionCommand) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{15} + return fileDescriptor_events_183547552ed1ab9b, []int{15} } func (m *SessionCommand) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -886,7 +888,7 @@ func (m *SessionDisk) Reset() { *m = SessionDisk{} } func (m *SessionDisk) String() string { return proto.CompactTextString(m) } func (*SessionDisk) ProtoMessage() {} func (*SessionDisk) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{16} + return fileDescriptor_events_183547552ed1ab9b, []int{16} } func (m *SessionDisk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -944,7 +946,7 @@ func (m *SessionNetwork) Reset() { *m = SessionNetwork{} } func (m *SessionNetwork) String() string { return proto.CompactTextString(m) } func (*SessionNetwork) ProtoMessage() {} func (*SessionNetwork) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{17} + return fileDescriptor_events_183547552ed1ab9b, []int{17} } func (m *SessionNetwork) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -998,7 +1000,7 @@ func (m *SessionData) Reset() { *m = SessionData{} } func (m *SessionData) String() string { return proto.CompactTextString(m) } func (*SessionData) ProtoMessage() {} func (*SessionData) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{18} + return fileDescriptor_events_183547552ed1ab9b, []int{18} } func (m *SessionData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1048,7 +1050,7 @@ func (m *SessionLeave) Reset() { *m = SessionLeave{} } func (m *SessionLeave) String() string { return proto.CompactTextString(m) } func (*SessionLeave) ProtoMessage() {} func (*SessionLeave) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{19} + return fileDescriptor_events_183547552ed1ab9b, []int{19} } func (m *SessionLeave) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1100,7 +1102,7 @@ func (m *UserLogin) Reset() { *m = UserLogin{} } func (m *UserLogin) String() string { return proto.CompactTextString(m) } func (*UserLogin) ProtoMessage() {} func (*UserLogin) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{20} + return fileDescriptor_events_183547552ed1ab9b, []int{20} } func (m *UserLogin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1150,7 +1152,7 @@ func (m *ResourceMetadata) Reset() { *m = ResourceMetadata{} } func (m *ResourceMetadata) String() string { return proto.CompactTextString(m) } func (*ResourceMetadata) ProtoMessage() {} func (*ResourceMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{21} + return fileDescriptor_events_183547552ed1ab9b, []int{21} } func (m *ResourceMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1200,7 +1202,7 @@ func (m *UserCreate) Reset() { *m = UserCreate{} } func (m *UserCreate) String() string { return proto.CompactTextString(m) } func (*UserCreate) ProtoMessage() {} func (*UserCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{22} + return fileDescriptor_events_183547552ed1ab9b, []int{22} } func (m *UserCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1246,7 +1248,7 @@ func (m *UserDelete) Reset() { *m = UserDelete{} } func (m *UserDelete) String() string { return proto.CompactTextString(m) } func (*UserDelete) ProtoMessage() {} func (*UserDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{23} + return fileDescriptor_events_183547552ed1ab9b, []int{23} } func (m *UserDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1290,7 +1292,7 @@ func (m *UserPasswordChange) Reset() { *m = UserPasswordChange{} } func (m *UserPasswordChange) String() string { return proto.CompactTextString(m) } func (*UserPasswordChange) ProtoMessage() {} func (*UserPasswordChange) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{24} + return fileDescriptor_events_183547552ed1ab9b, []int{24} } func (m *UserPasswordChange) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1351,7 +1353,7 @@ func (m *AccessRequestCreate) Reset() { *m = AccessRequestCreate{} } func (m *AccessRequestCreate) String() string { return proto.CompactTextString(m) } func (*AccessRequestCreate) ProtoMessage() {} func (*AccessRequestCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{25} + return fileDescriptor_events_183547552ed1ab9b, []int{25} } func (m *AccessRequestCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1401,7 +1403,7 @@ func (m *PortForward) Reset() { *m = PortForward{} } func (m *PortForward) String() string { return proto.CompactTextString(m) } func (*PortForward) ProtoMessage() {} func (*PortForward) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{26} + return fileDescriptor_events_183547552ed1ab9b, []int{26} } func (m *PortForward) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1449,7 +1451,7 @@ func (m *X11Forward) Reset() { *m = X11Forward{} } func (m *X11Forward) String() string { return proto.CompactTextString(m) } func (*X11Forward) ProtoMessage() {} func (*X11Forward) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{27} + return fileDescriptor_events_183547552ed1ab9b, []int{27} } func (m *X11Forward) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1495,7 +1497,7 @@ func (m *CommandMetadata) Reset() { *m = CommandMetadata{} } func (m *CommandMetadata) String() string { return proto.CompactTextString(m) } func (*CommandMetadata) ProtoMessage() {} func (*CommandMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{28} + return fileDescriptor_events_183547552ed1ab9b, []int{28} } func (m *CommandMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1552,7 +1554,7 @@ func (m *Exec) Reset() { *m = Exec{} } func (m *Exec) String() string { return proto.CompactTextString(m) } func (*Exec) ProtoMessage() {} func (*Exec) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{29} + return fileDescriptor_events_183547552ed1ab9b, []int{29} } func (m *Exec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1608,7 +1610,7 @@ func (m *SCP) Reset() { *m = SCP{} } func (m *SCP) String() string { return proto.CompactTextString(m) } func (*SCP) ProtoMessage() {} func (*SCP) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{30} + return fileDescriptor_events_183547552ed1ab9b, []int{30} } func (m *SCP) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1658,7 +1660,7 @@ func (m *Subsystem) Reset() { *m = Subsystem{} } func (m *Subsystem) String() string { return proto.CompactTextString(m) } func (*Subsystem) ProtoMessage() {} func (*Subsystem) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{31} + return fileDescriptor_events_183547552ed1ab9b, []int{31} } func (m *Subsystem) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1710,7 +1712,7 @@ func (m *ClientDisconnect) Reset() { *m = ClientDisconnect{} } func (m *ClientDisconnect) String() string { return proto.CompactTextString(m) } func (*ClientDisconnect) ProtoMessage() {} func (*ClientDisconnect) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{32} + return fileDescriptor_events_183547552ed1ab9b, []int{32} } func (m *ClientDisconnect) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1758,7 +1760,7 @@ func (m *AuthAttempt) Reset() { *m = AuthAttempt{} } func (m *AuthAttempt) String() string { return proto.CompactTextString(m) } func (*AuthAttempt) ProtoMessage() {} func (*AuthAttempt) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{33} + return fileDescriptor_events_183547552ed1ab9b, []int{33} } func (m *AuthAttempt) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1804,7 +1806,7 @@ func (m *ResetPasswordTokenCreate) Reset() { *m = ResetPasswordTokenCrea func (m *ResetPasswordTokenCreate) String() string { return proto.CompactTextString(m) } func (*ResetPasswordTokenCreate) ProtoMessage() {} func (*ResetPasswordTokenCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{34} + return fileDescriptor_events_183547552ed1ab9b, []int{34} } func (m *ResetPasswordTokenCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1850,7 +1852,7 @@ func (m *RoleCreate) Reset() { *m = RoleCreate{} } func (m *RoleCreate) String() string { return proto.CompactTextString(m) } func (*RoleCreate) ProtoMessage() {} func (*RoleCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{35} + return fileDescriptor_events_183547552ed1ab9b, []int{35} } func (m *RoleCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1896,7 +1898,7 @@ func (m *RoleDelete) Reset() { *m = RoleDelete{} } func (m *RoleDelete) String() string { return proto.CompactTextString(m) } func (*RoleDelete) ProtoMessage() {} func (*RoleDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{36} + return fileDescriptor_events_183547552ed1ab9b, []int{36} } func (m *RoleDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1942,7 +1944,7 @@ func (m *TrustedClusterCreate) Reset() { *m = TrustedClusterCreate{} } func (m *TrustedClusterCreate) String() string { return proto.CompactTextString(m) } func (*TrustedClusterCreate) ProtoMessage() {} func (*TrustedClusterCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{37} + return fileDescriptor_events_183547552ed1ab9b, []int{37} } func (m *TrustedClusterCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1988,7 +1990,7 @@ func (m *TrustedClusterDelete) Reset() { *m = TrustedClusterDelete{} } func (m *TrustedClusterDelete) String() string { return proto.CompactTextString(m) } func (*TrustedClusterDelete) ProtoMessage() {} func (*TrustedClusterDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{38} + return fileDescriptor_events_183547552ed1ab9b, []int{38} } func (m *TrustedClusterDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2035,7 +2037,7 @@ func (m *TrustedClusterTokenCreate) Reset() { *m = TrustedClusterTokenCr func (m *TrustedClusterTokenCreate) String() string { return proto.CompactTextString(m) } func (*TrustedClusterTokenCreate) ProtoMessage() {} func (*TrustedClusterTokenCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{39} + return fileDescriptor_events_183547552ed1ab9b, []int{39} } func (m *TrustedClusterTokenCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2081,7 +2083,7 @@ func (m *GithubConnectorCreate) Reset() { *m = GithubConnectorCreate{} } func (m *GithubConnectorCreate) String() string { return proto.CompactTextString(m) } func (*GithubConnectorCreate) ProtoMessage() {} func (*GithubConnectorCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{40} + return fileDescriptor_events_183547552ed1ab9b, []int{40} } func (m *GithubConnectorCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2127,7 +2129,7 @@ func (m *GithubConnectorDelete) Reset() { *m = GithubConnectorDelete{} } func (m *GithubConnectorDelete) String() string { return proto.CompactTextString(m) } func (*GithubConnectorDelete) ProtoMessage() {} func (*GithubConnectorDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{41} + return fileDescriptor_events_183547552ed1ab9b, []int{41} } func (m *GithubConnectorDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2173,7 +2175,7 @@ func (m *OIDCConnectorCreate) Reset() { *m = OIDCConnectorCreate{} } func (m *OIDCConnectorCreate) String() string { return proto.CompactTextString(m) } func (*OIDCConnectorCreate) ProtoMessage() {} func (*OIDCConnectorCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{42} + return fileDescriptor_events_183547552ed1ab9b, []int{42} } func (m *OIDCConnectorCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2219,7 +2221,7 @@ func (m *OIDCConnectorDelete) Reset() { *m = OIDCConnectorDelete{} } func (m *OIDCConnectorDelete) String() string { return proto.CompactTextString(m) } func (*OIDCConnectorDelete) ProtoMessage() {} func (*OIDCConnectorDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{43} + return fileDescriptor_events_183547552ed1ab9b, []int{43} } func (m *OIDCConnectorDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2265,7 +2267,7 @@ func (m *SAMLConnectorCreate) Reset() { *m = SAMLConnectorCreate{} } func (m *SAMLConnectorCreate) String() string { return proto.CompactTextString(m) } func (*SAMLConnectorCreate) ProtoMessage() {} func (*SAMLConnectorCreate) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{44} + return fileDescriptor_events_183547552ed1ab9b, []int{44} } func (m *SAMLConnectorCreate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2311,7 +2313,7 @@ func (m *SAMLConnectorDelete) Reset() { *m = SAMLConnectorDelete{} } func (m *SAMLConnectorDelete) String() string { return proto.CompactTextString(m) } func (*SAMLConnectorDelete) ProtoMessage() {} func (*SAMLConnectorDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{45} + return fileDescriptor_events_183547552ed1ab9b, []int{45} } func (m *SAMLConnectorDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2375,7 +2377,7 @@ func (m *KubeRequest) Reset() { *m = KubeRequest{} } func (m *KubeRequest) String() string { return proto.CompactTextString(m) } func (*KubeRequest) ProtoMessage() {} func (*KubeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{46} + return fileDescriptor_events_183547552ed1ab9b, []int{46} } func (m *KubeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2427,7 +2429,7 @@ func (m *AppSessionStart) Reset() { *m = AppSessionStart{} } func (m *AppSessionStart) String() string { return proto.CompactTextString(m) } func (*AppSessionStart) ProtoMessage() {} func (*AppSessionStart) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{47} + return fileDescriptor_events_183547552ed1ab9b, []int{47} } func (m *AppSessionStart) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2482,7 +2484,7 @@ func (m *AppSessionChunk) Reset() { *m = AppSessionChunk{} } func (m *AppSessionChunk) String() string { return proto.CompactTextString(m) } func (*AppSessionChunk) ProtoMessage() {} func (*AppSessionChunk) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{48} + return fileDescriptor_events_183547552ed1ab9b, []int{48} } func (m *AppSessionChunk) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2532,7 +2534,7 @@ func (m *AppSessionRequest) Reset() { *m = AppSessionRequest{} } func (m *AppSessionRequest) String() string { return proto.CompactTextString(m) } func (*AppSessionRequest) ProtoMessage() {} func (*AppSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{49} + return fileDescriptor_events_183547552ed1ab9b, []int{49} } func (m *AppSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2582,7 +2584,7 @@ func (m *DatabaseMetadata) Reset() { *m = DatabaseMetadata{} } func (m *DatabaseMetadata) String() string { return proto.CompactTextString(m) } func (*DatabaseMetadata) ProtoMessage() {} func (*DatabaseMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{50} + return fileDescriptor_events_183547552ed1ab9b, []int{50} } func (m *DatabaseMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2636,7 +2638,7 @@ func (m *DatabaseSessionStart) Reset() { *m = DatabaseSessionStart{} } func (m *DatabaseSessionStart) String() string { return proto.CompactTextString(m) } func (*DatabaseSessionStart) ProtoMessage() {} func (*DatabaseSessionStart) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{51} + return fileDescriptor_events_183547552ed1ab9b, []int{51} } func (m *DatabaseSessionStart) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2686,7 +2688,7 @@ func (m *DatabaseSessionQuery) Reset() { *m = DatabaseSessionQuery{} } func (m *DatabaseSessionQuery) String() string { return proto.CompactTextString(m) } func (*DatabaseSessionQuery) ProtoMessage() {} func (*DatabaseSessionQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{52} + return fileDescriptor_events_183547552ed1ab9b, []int{52} } func (m *DatabaseSessionQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2734,7 +2736,7 @@ func (m *DatabaseSessionEnd) Reset() { *m = DatabaseSessionEnd{} } func (m *DatabaseSessionEnd) String() string { return proto.CompactTextString(m) } func (*DatabaseSessionEnd) ProtoMessage() {} func (*DatabaseSessionEnd) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{53} + return fileDescriptor_events_183547552ed1ab9b, []int{53} } func (m *DatabaseSessionEnd) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2780,7 +2782,7 @@ func (m *MFADeviceMetadata) Reset() { *m = MFADeviceMetadata{} } func (m *MFADeviceMetadata) String() string { return proto.CompactTextString(m) } func (*MFADeviceMetadata) ProtoMessage() {} func (*MFADeviceMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{54} + return fileDescriptor_events_183547552ed1ab9b, []int{54} } func (m *MFADeviceMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2826,7 +2828,7 @@ func (m *MFADeviceAdd) Reset() { *m = MFADeviceAdd{} } func (m *MFADeviceAdd) String() string { return proto.CompactTextString(m) } func (*MFADeviceAdd) ProtoMessage() {} func (*MFADeviceAdd) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{55} + return fileDescriptor_events_183547552ed1ab9b, []int{55} } func (m *MFADeviceAdd) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2872,7 +2874,7 @@ func (m *MFADeviceDelete) Reset() { *m = MFADeviceDelete{} } func (m *MFADeviceDelete) String() string { return proto.CompactTextString(m) } func (*MFADeviceDelete) ProtoMessage() {} func (*MFADeviceDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{56} + return fileDescriptor_events_183547552ed1ab9b, []int{56} } func (m *MFADeviceDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2961,7 +2963,7 @@ func (m *OneOf) Reset() { *m = OneOf{} } func (m *OneOf) String() string { return proto.CompactTextString(m) } func (*OneOf) ProtoMessage() {} func (*OneOf) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{57} + return fileDescriptor_events_183547552ed1ab9b, []int{57} } func (m *OneOf) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4408,7 +4410,7 @@ func (m *StreamStatus) Reset() { *m = StreamStatus{} } func (m *StreamStatus) String() string { return proto.CompactTextString(m) } func (*StreamStatus) ProtoMessage() {} func (*StreamStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{58} + return fileDescriptor_events_183547552ed1ab9b, []int{58} } func (m *StreamStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4456,7 +4458,7 @@ func (m *SessionUpload) Reset() { *m = SessionUpload{} } func (m *SessionUpload) String() string { return proto.CompactTextString(m) } func (*SessionUpload) ProtoMessage() {} func (*SessionUpload) Descriptor() ([]byte, []int) { - return fileDescriptor_events_01283626fda9ca01, []int{59} + return fileDescriptor_events_183547552ed1ab9b, []int{59} } func (m *SessionUpload) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4627,6 +4629,12 @@ func (m *SessionMetadata) MarshalTo(dAtA []byte) (int, error) { i = encodeVarintEvents(dAtA, i, uint64(len(m.SessionID))) i += copy(dAtA[i:], m.SessionID) } + if len(m.WithMFA) > 0 { + dAtA[i] = 0x12 + i++ + i = encodeVarintEvents(dAtA, i, uint64(len(m.WithMFA))) + i += copy(dAtA[i:], m.WithMFA) + } if m.XXX_unrecognized != nil { i += copy(dAtA[i:], m.XXX_unrecognized) } @@ -8747,6 +8755,10 @@ func (m *SessionMetadata) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + l = len(m.WithMFA) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -10735,6 +10747,35 @@ func (m *SessionMetadata) Unmarshal(dAtA []byte) error { } m.SessionID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field WithMFA", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.WithMFA = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -23546,264 +23587,265 @@ var ( ErrIntOverflowEvents = fmt.Errorf("proto: integer overflow") ) -func init() { proto.RegisterFile("events.proto", fileDescriptor_events_01283626fda9ca01) } - -var fileDescriptor_events_01283626fda9ca01 = []byte{ - // 4082 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3c, 0xdf, 0x6f, 0x1c, 0x49, - 0x5a, 0xf3, 0xdb, 0x33, 0xdf, 0xd8, 0xb1, 0x5d, 0x71, 0x92, 0x4e, 0x36, 0x49, 0x27, 0x9d, 0xdb, - 0xac, 0xc3, 0x66, 0x63, 0xc5, 0xeb, 0xdb, 0x2c, 0x07, 0x68, 0xd7, 0x63, 0x3b, 0x37, 0x66, 0x9d, - 0xd8, 0x5b, 0x76, 0x8e, 0x7b, 0xb9, 0xb5, 0x7a, 0xa6, 0x2b, 0x76, 0x93, 0x99, 0xee, 0xb9, 0xee, - 0x1e, 0x27, 0xde, 0x27, 0x7e, 0xbc, 0xdc, 0xc3, 0x22, 0xa1, 0xe3, 0x09, 0xf1, 0x00, 0x12, 0xe2, - 0x01, 0x84, 0x00, 0xf1, 0x80, 0x78, 0x5f, 0x0e, 0xad, 0x84, 0x0e, 0x4e, 0xc7, 0x33, 0x03, 0xac, - 0xc4, 0xcb, 0x48, 0xfc, 0x03, 0x08, 0x09, 0x54, 0x5f, 0x55, 0x77, 0x57, 0xf7, 0xb4, 0x9d, 0x4d, - 0x9c, 0x93, 0xe5, 0xc4, 0x6f, 0xf6, 0xf7, 0xab, 0xaa, 0xbf, 0xaf, 0xea, 0xab, 0xfa, 0x7e, 0xd4, - 0xc0, 0x38, 0xdb, 0x63, 0x4e, 0xe0, 0xdf, 0xe9, 0x79, 0x6e, 0xe0, 0x92, 0x8a, 0xf8, 0xef, 0xd2, - 0xcc, 0x8e, 0xbb, 0xe3, 0x22, 0x68, 0x8e, 0xff, 0x25, 0xb0, 0x97, 0xf4, 0x1d, 0xd7, 0xdd, 0xe9, - 0xb0, 0x39, 0xfc, 0xaf, 0xd5, 0x7f, 0x3c, 0x17, 0xd8, 0x5d, 0xe6, 0x07, 0x66, 0xb7, 0x27, 0x09, - 0x2e, 0xa7, 0x09, 0xfc, 0xc0, 0xeb, 0xb7, 0x03, 0x81, 0x35, 0x7e, 0x54, 0x80, 0xea, 0x03, 0x16, - 0x98, 0x96, 0x19, 0x98, 0xe4, 0x32, 0x94, 0x57, 0x1d, 0x8b, 0x3d, 0xd3, 0xf2, 0xd7, 0xf2, 0xb3, - 0xc5, 0x46, 0x65, 0x38, 0xd0, 0x0b, 0xcc, 0xa6, 0x02, 0x48, 0xae, 0x40, 0x69, 0x6b, 0xbf, 0xc7, - 0xb4, 0xc2, 0xb5, 0xfc, 0x6c, 0xad, 0x51, 0x1b, 0x0e, 0xf4, 0x32, 0xce, 0x8c, 0x22, 0x98, 0x5c, - 0x87, 0xc2, 0xea, 0xb2, 0x56, 0x44, 0xe4, 0xf4, 0x70, 0xa0, 0x4f, 0xf4, 0x6d, 0xeb, 0xb6, 0xdb, - 0xb5, 0x03, 0xd6, 0xed, 0x05, 0xfb, 0xb4, 0xb0, 0xba, 0x4c, 0x6e, 0x42, 0x69, 0xc9, 0xb5, 0x98, - 0x56, 0x42, 0x22, 0x32, 0x1c, 0xe8, 0x67, 0xda, 0xae, 0xc5, 0x14, 0x2a, 0xc4, 0x93, 0x8f, 0xa1, - 0xb4, 0x65, 0x77, 0x99, 0x56, 0xbe, 0x96, 0x9f, 0xad, 0xcf, 0x5f, 0xba, 0x23, 0xbe, 0xe0, 0x4e, - 0xf8, 0x05, 0x77, 0xb6, 0xc2, 0x4f, 0x6c, 0x4c, 0x7d, 0x35, 0xd0, 0x73, 0xc3, 0x81, 0x5e, 0xe2, - 0x5f, 0xfd, 0xfb, 0xff, 0xae, 0xe7, 0x29, 0x72, 0x92, 0x79, 0xa8, 0x2f, 0x75, 0xfa, 0x7e, 0xc0, - 0xbc, 0x87, 0x66, 0x97, 0x69, 0x15, 0x1c, 0x70, 0x6a, 0x38, 0xd0, 0xc7, 0xdb, 0x02, 0xbc, 0xed, - 0x98, 0x5d, 0x46, 0x55, 0x22, 0xe3, 0x43, 0x98, 0xdc, 0x64, 0xbe, 0x6f, 0xbb, 0x4e, 0xa4, 0x90, - 0xb7, 0xa1, 0x26, 0x41, 0xab, 0xcb, 0xa8, 0x94, 0x5a, 0x63, 0x6c, 0x38, 0xd0, 0x8b, 0xbe, 0x6d, - 0xd1, 0x18, 0x63, 0xfc, 0x06, 0x8c, 0x3f, 0xf2, 0x99, 0xa7, 0xe8, 0xb1, 0xc4, 0xff, 0x97, 0x1c, - 0x55, 0x3e, 0xbf, 0xbe, 0xcf, 0x3c, 0x8a, 0x50, 0x72, 0x0b, 0xca, 0x6b, 0xee, 0x8e, 0xed, 0x48, - 0x45, 0x9e, 0x1d, 0x0e, 0xf4, 0xc9, 0x0e, 0x07, 0x28, 0x7a, 0x10, 0x14, 0xc6, 0xdf, 0x14, 0xe1, - 0xcc, 0x26, 0xf3, 0xf6, 0x14, 0xd9, 0x8b, 0x7c, 0x96, 0x1c, 0xc2, 0xe7, 0xec, 0xf7, 0xcc, 0x36, - 0x93, 0xc3, 0x5c, 0x18, 0x0e, 0xf4, 0xb3, 0x4e, 0x08, 0x54, 0x64, 0xa5, 0xe9, 0xc9, 0x2d, 0xa8, - 0x0a, 0xd0, 0xea, 0xb2, 0x9c, 0xc3, 0xc4, 0x70, 0xa0, 0xd7, 0x7c, 0x84, 0x6d, 0xdb, 0x16, 0x8d, - 0xd0, 0x64, 0x25, 0x1c, 0xbf, 0xe9, 0xfa, 0x01, 0x17, 0x2e, 0x0d, 0x7c, 0x65, 0x38, 0xd0, 0x2f, - 0x4a, 0x86, 0x5d, 0x89, 0x52, 0x86, 0x4c, 0x31, 0x91, 0x5f, 0x06, 0x10, 0x90, 0x45, 0xcb, 0xf2, - 0xa4, 0xf9, 0x2f, 0x0e, 0x07, 0xfa, 0x39, 0x29, 0xc2, 0xb4, 0x2c, 0x4f, 0x61, 0x57, 0x88, 0x49, - 0x17, 0xc6, 0xc5, 0x7f, 0x6b, 0x66, 0x8b, 0x75, 0x7c, 0xad, 0x7c, 0xad, 0x38, 0x5b, 0x9f, 0x9f, - 0xbd, 0x23, 0xb7, 0x48, 0x52, 0x3b, 0x77, 0x54, 0xd2, 0x15, 0x27, 0xf0, 0xf6, 0x1b, 0xba, 0x5c, - 0x21, 0x17, 0xe4, 0x50, 0x1d, 0xc4, 0x29, 0x83, 0x25, 0xc4, 0x5f, 0xfa, 0x08, 0xa6, 0x47, 0x64, - 0x90, 0x29, 0x28, 0x3e, 0x61, 0xfb, 0x42, 0xcf, 0x94, 0xff, 0x49, 0x66, 0xa0, 0xbc, 0x67, 0x76, - 0xfa, 0x72, 0x33, 0x50, 0xf1, 0xcf, 0x77, 0x0a, 0x1f, 0xe6, 0x8d, 0xbf, 0xcf, 0x03, 0x59, 0x72, - 0x1d, 0x87, 0xb5, 0x03, 0x75, 0x25, 0x7d, 0x00, 0xb5, 0x35, 0xb7, 0x6d, 0x76, 0x50, 0x01, 0xc2, - 0x60, 0xda, 0x70, 0xa0, 0xcf, 0xf0, 0x2f, 0xbf, 0xd3, 0xe1, 0x18, 0x65, 0x4a, 0x31, 0x29, 0xd7, - 0x1c, 0x65, 0x5d, 0x37, 0x60, 0xc8, 0x58, 0x88, 0x35, 0x87, 0x8c, 0x1e, 0xa2, 0x54, 0xcd, 0xc5, - 0xc4, 0x64, 0x0e, 0xaa, 0x1b, 0x7c, 0xc7, 0xb4, 0xdd, 0x8e, 0xb4, 0x1a, 0x2e, 0x35, 0xdc, 0x45, - 0x0a, 0x4b, 0x44, 0x64, 0xfc, 0x4e, 0x01, 0x2e, 0x7e, 0xd2, 0x6f, 0x31, 0xcf, 0x61, 0x01, 0xf3, - 0xe5, 0xd6, 0x88, 0xbe, 0xe0, 0x21, 0x4c, 0x8f, 0x20, 0xe5, 0x97, 0x5c, 0x1b, 0x0e, 0xf4, 0xcb, - 0x4f, 0x22, 0xe4, 0xb6, 0xdc, 0x63, 0xca, 0x20, 0xa3, 0xac, 0xa4, 0x09, 0x93, 0x31, 0x90, 0x6f, - 0x0c, 0x5f, 0x2b, 0x5c, 0x2b, 0xce, 0xd6, 0x1a, 0x57, 0x87, 0x03, 0xfd, 0x92, 0x22, 0x8d, 0x6f, - 0x1d, 0xd5, 0x60, 0x69, 0x36, 0xf2, 0x09, 0x4c, 0xc5, 0xa0, 0xef, 0x7a, 0x6e, 0xbf, 0xe7, 0x6b, - 0x45, 0x14, 0xa5, 0x0f, 0x07, 0xfa, 0x5b, 0x8a, 0xa8, 0x1d, 0x44, 0x2a, 0xb2, 0x46, 0x18, 0x8d, - 0xff, 0x2a, 0xc2, 0xb9, 0x18, 0xb8, 0xe1, 0x5a, 0x91, 0x02, 0xd6, 0x55, 0x05, 0x6c, 0xb8, 0x16, - 0x7a, 0x16, 0xa1, 0x80, 0xeb, 0xc3, 0x81, 0x7e, 0x45, 0x19, 0xa7, 0xe7, 0x5a, 0xdb, 0xa9, 0x2d, - 0x31, 0xca, 0x4b, 0x3e, 0x83, 0xf3, 0x23, 0x40, 0xb1, 0xa3, 0x85, 0x9d, 0x6f, 0x0e, 0x07, 0xba, - 0x91, 0x21, 0x35, 0xbd, 0xc1, 0x0f, 0x90, 0x42, 0x4c, 0xb8, 0xa0, 0xa8, 0xdd, 0x75, 0x02, 0xd3, - 0x76, 0xa4, 0x43, 0x14, 0xeb, 0xe1, 0x9d, 0xe1, 0x40, 0xbf, 0xa1, 0xda, 0x2d, 0xa4, 0x49, 0x4f, - 0xfe, 0x20, 0x39, 0xc4, 0x02, 0x2d, 0x03, 0xb5, 0xda, 0x35, 0x77, 0x42, 0x2f, 0x3f, 0x3b, 0x1c, - 0xe8, 0xdf, 0xca, 0x1c, 0xc3, 0xe6, 0x54, 0xca, 0x20, 0x07, 0x4a, 0x22, 0x14, 0x48, 0x8c, 0x7b, - 0xe8, 0x5a, 0x0c, 0xbf, 0xa1, 0x8c, 0xf2, 0x8d, 0xe1, 0x40, 0xbf, 0xaa, 0xc8, 0x77, 0x5c, 0x8b, - 0xa5, 0xa7, 0x9f, 0xc1, 0x6d, 0xfc, 0x6f, 0x89, 0x3b, 0x16, 0xf4, 0xe0, 0x9b, 0x81, 0xe9, 0x05, - 0xe4, 0x3b, 0xf1, 0x41, 0x88, 0x56, 0xad, 0xcf, 0x4f, 0x85, 0x4e, 0x26, 0x84, 0x37, 0xc6, 0xb9, - 0x33, 0xf9, 0xd9, 0x40, 0xcf, 0x0f, 0x07, 0x7a, 0x8e, 0x56, 0x95, 0xdd, 0x2d, 0x1c, 0x7e, 0x01, - 0xf9, 0x66, 0x42, 0x3e, 0xf5, 0x50, 0x48, 0xf1, 0x8a, 0xa3, 0xe0, 0x23, 0x18, 0x93, 0x73, 0x40, - 0x8b, 0xd4, 0xe7, 0x2f, 0xc4, 0x7e, 0x2d, 0x71, 0x12, 0xa5, 0xb8, 0x43, 0x2e, 0xf2, 0xab, 0x50, - 0x11, 0xee, 0x0a, 0xb5, 0x5d, 0x9f, 0x3f, 0x9f, 0xed, 0x17, 0x53, 0xec, 0x92, 0x87, 0x34, 0x01, - 0x62, 0x57, 0x15, 0x9d, 0xb6, 0x52, 0xc2, 0xa8, 0x13, 0x4b, 0x49, 0x51, 0x78, 0xc9, 0x07, 0x30, - 0xbe, 0xc5, 0xbc, 0xae, 0xed, 0x98, 0x9d, 0x4d, 0xfb, 0xf3, 0xf0, 0xc0, 0xc5, 0x13, 0xde, 0xb7, - 0x3f, 0x57, 0x6d, 0x91, 0xa0, 0x23, 0x3f, 0xc8, 0x72, 0x2a, 0x63, 0x38, 0x91, 0xeb, 0xe1, 0x44, - 0x0e, 0x74, 0x49, 0xa9, 0xf9, 0x64, 0xf8, 0x98, 0x4f, 0x61, 0x22, 0xb1, 0x37, 0xb4, 0x2a, 0x8a, - 0xbe, 0x32, 0x2a, 0x5a, 0xd9, 0xe8, 0x29, 0xb1, 0x49, 0x09, 0xfc, 0x44, 0x5c, 0x75, 0xec, 0xc0, - 0x36, 0x3b, 0x4b, 0x6e, 0xb7, 0x6b, 0x3a, 0x96, 0x56, 0x43, 0x57, 0x83, 0x27, 0xa2, 0x2d, 0x30, - 0xdb, 0x6d, 0x81, 0x52, 0x4f, 0xc4, 0x24, 0x93, 0xf1, 0xe7, 0x45, 0xa8, 0x4b, 0x23, 0xfe, 0xba, - 0x6b, 0x3b, 0xa7, 0xab, 0xef, 0x28, 0xab, 0x2f, 0x73, 0x15, 0x55, 0x5e, 0xd5, 0x2a, 0x32, 0xbe, - 0x28, 0x44, 0xae, 0x62, 0xc3, 0xb3, 0x9d, 0xa3, 0xb9, 0x8a, 0x9b, 0x00, 0x4b, 0xbb, 0x7d, 0xe7, - 0x89, 0xb8, 0x68, 0x17, 0xe2, 0x8b, 0x76, 0xdb, 0xa6, 0x0a, 0x86, 0xdf, 0xb6, 0x97, 0xb9, 0x7c, - 0x6e, 0x99, 0xf1, 0x46, 0xed, 0x2b, 0x21, 0x29, 0xff, 0x1e, 0x45, 0x30, 0xd1, 0xa1, 0xdc, 0xd8, - 0x0f, 0x98, 0x8f, 0x9a, 0x2f, 0x8a, 0xdb, 0x78, 0x8b, 0x03, 0xa8, 0x80, 0x93, 0x05, 0x98, 0x5e, - 0x66, 0x1d, 0x73, 0xff, 0x81, 0xdd, 0xe9, 0xd8, 0x3e, 0x6b, 0xbb, 0x8e, 0xe5, 0xa3, 0x92, 0xe5, - 0x70, 0x5d, 0x9f, 0x8e, 0x12, 0x10, 0x03, 0x2a, 0xeb, 0x8f, 0x1f, 0xfb, 0x2c, 0x40, 0xf5, 0x15, - 0x1b, 0x30, 0x1c, 0xe8, 0x15, 0x17, 0x21, 0x54, 0x62, 0x8c, 0x9f, 0x17, 0x60, 0x42, 0xaa, 0x83, - 0xb2, 0xdf, 0x64, 0xed, 0xe3, 0x71, 0x9d, 0xf1, 0xda, 0x2b, 0x1e, 0x79, 0xed, 0x95, 0x8e, 0xb0, - 0xf6, 0x0c, 0xa8, 0x50, 0x66, 0xfa, 0x72, 0x05, 0xd7, 0x84, 0xc6, 0x3c, 0x84, 0x50, 0x89, 0x21, - 0xd7, 0x61, 0xec, 0x81, 0xf9, 0xcc, 0xee, 0xf6, 0xbb, 0x52, 0xad, 0x18, 0x44, 0x74, 0xcd, 0x67, - 0x34, 0x84, 0x1b, 0x7f, 0x5d, 0xe2, 0x72, 0xb8, 0xaf, 0x3c, 0x99, 0xae, 0xe0, 0xd5, 0x29, 0x34, - 0x36, 0x6c, 0xf9, 0x25, 0x0c, 0xfb, 0xc6, 0x1c, 0x44, 0xc6, 0x5f, 0x8c, 0xf1, 0xa0, 0x0a, 0xb5, - 0xbf, 0xe2, 0x58, 0xa7, 0xab, 0xe6, 0x28, 0xab, 0x66, 0x19, 0xa6, 0x57, 0x9c, 0x5d, 0xd3, 0x69, - 0x33, 0x8b, 0xb2, 0xb6, 0xeb, 0x59, 0xb6, 0xb3, 0x83, 0x4b, 0xa7, 0xda, 0x38, 0x3f, 0x1c, 0xe8, - 0x84, 0x49, 0xe4, 0xb6, 0x17, 0x62, 0xe9, 0x28, 0x03, 0xb9, 0x0b, 0xf5, 0x55, 0x27, 0x60, 0x9e, - 0xd9, 0x0e, 0xec, 0x3d, 0x86, 0xab, 0xa7, 0xda, 0x98, 0x1c, 0x0e, 0xf4, 0xba, 0x1d, 0x83, 0xa9, - 0x4a, 0x43, 0x16, 0x60, 0x7c, 0xc3, 0xf4, 0x02, 0xbb, 0x6d, 0xf7, 0x4c, 0x27, 0xf0, 0xb5, 0x2a, - 0xde, 0x25, 0x30, 0x51, 0xd1, 0x53, 0xe0, 0x34, 0x41, 0x45, 0x7e, 0x00, 0x35, 0xbc, 0xb3, 0x62, - 0x92, 0xa4, 0xf6, 0xdc, 0x24, 0xc9, 0x8d, 0x38, 0x04, 0x46, 0xb5, 0x6f, 0xfb, 0x9c, 0x39, 0xde, - 0x0a, 0x98, 0x37, 0x89, 0x25, 0x92, 0xef, 0xc3, 0xd8, 0x8a, 0x63, 0xa1, 0x70, 0x78, 0xae, 0x70, - 0x43, 0x0a, 0x3f, 0x1f, 0x0b, 0x77, 0x7b, 0x29, 0xd9, 0xa1, 0xb8, 0xec, 0x5d, 0x56, 0xff, 0xc5, - 0xed, 0xb2, 0xf1, 0x5f, 0xc0, 0x75, 0x6f, 0xe2, 0x65, 0xae, 0x7b, 0x9f, 0x43, 0xbd, 0xb1, 0x71, - 0x3f, 0xda, 0x70, 0x17, 0xa1, 0xb8, 0x21, 0x33, 0x4a, 0x25, 0x71, 0x18, 0xf4, 0x6c, 0x8b, 0x72, - 0x18, 0xb9, 0x05, 0xd5, 0x25, 0x0c, 0x53, 0x65, 0x72, 0xa6, 0x24, 0x92, 0x33, 0x6d, 0x84, 0x61, - 0x72, 0x26, 0x44, 0x93, 0xb7, 0x61, 0x6c, 0xc3, 0x73, 0x77, 0x3c, 0xb3, 0x2b, 0xe3, 0xb9, 0xfa, - 0x70, 0xa0, 0x8f, 0xf5, 0x04, 0x88, 0x86, 0x38, 0xe3, 0x0f, 0xf2, 0x50, 0xd9, 0x0c, 0xcc, 0xa0, - 0xef, 0x73, 0x8e, 0xcd, 0x7e, 0xbb, 0xcd, 0x7c, 0x1f, 0xc7, 0xae, 0x0a, 0x0e, 0x5f, 0x80, 0x68, - 0x88, 0x23, 0xb7, 0xa0, 0xbc, 0xe2, 0x79, 0xae, 0xa7, 0x66, 0xa8, 0x18, 0x07, 0xa8, 0x19, 0x2a, - 0xa4, 0x20, 0xf7, 0xa0, 0x2e, 0xdc, 0x84, 0xef, 0xf3, 0x98, 0x4f, 0xcc, 0xe3, 0xdc, 0x70, 0xa0, - 0x4f, 0x77, 0x05, 0x48, 0x61, 0x51, 0x29, 0x8d, 0x2f, 0x31, 0xb5, 0x85, 0x4b, 0x46, 0x2a, 0xe9, - 0x4d, 0xbc, 0x03, 0xbf, 0x0f, 0xc5, 0xc6, 0xc6, 0x7d, 0xe9, 0xb3, 0xce, 0x86, 0xac, 0xca, 0x52, - 0x49, 0xf1, 0x71, 0x6a, 0x72, 0x19, 0x4a, 0x1b, 0x7c, 0xf9, 0x54, 0x70, 0x79, 0x60, 0x7a, 0xb1, - 0xc7, 0xd7, 0x0f, 0x42, 0x11, 0x6b, 0x06, 0xbb, 0xe8, 0x7e, 0x64, 0xf2, 0xb1, 0x67, 0x06, 0xbb, - 0x14, 0xa1, 0x1c, 0xbb, 0xe8, 0xed, 0xec, 0x49, 0x47, 0x83, 0x58, 0xd3, 0xdb, 0xd9, 0xa3, 0x08, - 0x25, 0x73, 0x00, 0x94, 0x05, 0x7d, 0xcf, 0xc1, 0x34, 0x2d, 0xf7, 0x2c, 0x65, 0xe1, 0xc0, 0x3c, - 0x84, 0x6e, 0xb7, 0x5d, 0x8b, 0x51, 0x85, 0xc4, 0xf8, 0xb3, 0x38, 0x8c, 0x59, 0xb6, 0xfd, 0x27, - 0xa7, 0x26, 0x7c, 0x01, 0x13, 0x72, 0x23, 0x55, 0x32, 0x8d, 0xa4, 0x43, 0xf9, 0x7e, 0xc7, 0xdc, - 0xf1, 0xd1, 0x86, 0x65, 0x71, 0xb9, 0x7f, 0xcc, 0x01, 0x54, 0xc0, 0x53, 0x76, 0xaa, 0x3e, 0xdf, - 0x4e, 0xff, 0x16, 0xef, 0xb6, 0x87, 0x2c, 0x78, 0xea, 0x7a, 0xa7, 0xa6, 0xfa, 0xa6, 0xa6, 0xba, - 0x09, 0x63, 0x9b, 0x5e, 0x1b, 0xd3, 0xaf, 0xc2, 0x5a, 0xe3, 0xc3, 0x81, 0x5e, 0xf5, 0xbd, 0x36, - 0x66, 0xad, 0x69, 0x88, 0xe4, 0x74, 0xcb, 0x7e, 0x80, 0x74, 0x63, 0x31, 0x9d, 0xe5, 0x07, 0x92, - 0x4e, 0x22, 0x25, 0xdd, 0x86, 0xeb, 0x05, 0xd2, 0x70, 0x11, 0x5d, 0xcf, 0xf5, 0x02, 0x1a, 0x22, - 0xc9, 0xbb, 0x00, 0x5b, 0x4b, 0x1b, 0xdf, 0x63, 0x1e, 0xaa, 0x4b, 0xec, 0x45, 0x74, 0xd7, 0x7b, - 0x02, 0x44, 0x15, 0xb4, 0xf1, 0x97, 0xca, 0x3e, 0xe4, 0x06, 0x3a, 0x4d, 0x27, 0x1c, 0xe1, 0x2e, - 0x39, 0x0f, 0x53, 0x18, 0x43, 0x6f, 0x79, 0xa6, 0xe3, 0x77, 0xed, 0x20, 0x60, 0x96, 0xf4, 0xb5, - 0x18, 0x39, 0x07, 0xcf, 0xe8, 0x08, 0x9e, 0xdc, 0x86, 0x09, 0x84, 0x51, 0xd6, 0x66, 0xf6, 0x1e, - 0xb3, 0x70, 0x0d, 0x48, 0x06, 0xef, 0x19, 0x4d, 0x22, 0x8d, 0x7f, 0x8a, 0x33, 0x0a, 0x6b, 0xcc, - 0xdc, 0x63, 0xa7, 0xf6, 0x3a, 0x82, 0xbd, 0x8c, 0x3f, 0x2d, 0x42, 0x8d, 0x7f, 0x11, 0xd6, 0xcc, - 0x8e, 0x45, 0x95, 0x0b, 0xe1, 0x0d, 0x4b, 0x6a, 0xf2, 0x4c, 0xa4, 0x09, 0x84, 0x8e, 0x68, 0x40, - 0xdc, 0xc6, 0x6e, 0x43, 0xe5, 0x01, 0x0b, 0x76, 0x5d, 0x4b, 0xa6, 0xca, 0x67, 0x86, 0x03, 0x7d, - 0xaa, 0x8b, 0x10, 0xe5, 0xd6, 0x24, 0x69, 0xc8, 0x13, 0x20, 0xab, 0x16, 0x73, 0x02, 0x3b, 0xd8, - 0x5f, 0x0c, 0x02, 0xcf, 0x6e, 0xf5, 0x03, 0xe6, 0x4b, 0xbd, 0x5d, 0x18, 0xb9, 0xa0, 0x6f, 0x62, - 0x91, 0x17, 0xb3, 0xe3, 0x33, 0x66, 0x44, 0x1e, 0x8b, 0xfd, 0x9f, 0x81, 0x5e, 0x11, 0x34, 0x34, - 0x43, 0x2c, 0xf9, 0x14, 0x6a, 0x0f, 0xee, 0x2f, 0x2e, 0xb3, 0x3d, 0xbb, 0xcd, 0x64, 0x26, 0xed, - 0x62, 0xa4, 0xc5, 0x10, 0x11, 0xa9, 0x04, 0x2b, 0x59, 0xdd, 0xc7, 0xe6, 0xb6, 0x85, 0x70, 0xb5, - 0x92, 0x15, 0x11, 0x1b, 0x5f, 0xe7, 0x61, 0x8a, 0x32, 0xdf, 0xed, 0x7b, 0x31, 0x27, 0xb9, 0x09, - 0x25, 0xa5, 0x8c, 0x82, 0x61, 0x7a, 0x2a, 0x77, 0x8f, 0x78, 0xb2, 0x0a, 0x63, 0x2b, 0xcf, 0x7a, - 0xb6, 0xc7, 0x7c, 0x69, 0x9b, 0xc3, 0x42, 0x92, 0xb3, 0x32, 0x24, 0x19, 0x63, 0x82, 0x45, 0xc6, - 0x20, 0xe2, 0x1f, 0xf2, 0x01, 0xd4, 0x1e, 0xf5, 0x2c, 0x33, 0x60, 0x56, 0x63, 0x5f, 0xde, 0x57, - 0x71, 0xfe, 0x7d, 0x01, 0xdc, 0x6e, 0xed, 0xab, 0xf3, 0x8f, 0x48, 0xc9, 0x0d, 0x28, 0x6e, 0x6d, - 0xad, 0x49, 0x53, 0x61, 0x81, 0x3b, 0x08, 0xd4, 0xa2, 0x1d, 0xc7, 0x1a, 0x3f, 0x2e, 0x00, 0xf0, - 0x15, 0xb1, 0xe4, 0x31, 0x33, 0x38, 0x9e, 0x6d, 0xdd, 0x80, 0x6a, 0xa8, 0x66, 0xb9, 0x1a, 0xb5, - 0x90, 0x37, 0xad, 0xfe, 0xf4, 0xd8, 0x21, 0x9e, 0x5f, 0x40, 0xa8, 0xdb, 0xc1, 0xec, 0x62, 0x31, - 0xac, 0xf5, 0x7b, 0x1c, 0x40, 0x05, 0x9c, 0xbc, 0x0b, 0x35, 0xb9, 0x01, 0x5d, 0x4f, 0x26, 0xbe, - 0x44, 0x98, 0x12, 0x02, 0x69, 0x8c, 0x37, 0xfe, 0x21, 0x2f, 0x94, 0xb2, 0xcc, 0x3a, 0xec, 0xe4, - 0x2a, 0xc5, 0xf8, 0x51, 0x1e, 0x08, 0x17, 0xb6, 0x61, 0xfa, 0xfe, 0x53, 0xd7, 0xb3, 0x96, 0x76, - 0x4d, 0x67, 0xe7, 0x58, 0x3e, 0xc7, 0xf8, 0x71, 0x09, 0xce, 0x2e, 0x8a, 0xa0, 0x8d, 0xfd, 0xb0, - 0xcf, 0xfc, 0xe0, 0x84, 0xaf, 0xb7, 0x5b, 0xc9, 0xf5, 0x86, 0x01, 0x27, 0xae, 0x37, 0x35, 0xe0, - 0x14, 0x2b, 0xef, 0x5b, 0x50, 0x93, 0xdf, 0xbc, 0xba, 0x2c, 0x57, 0x1e, 0x1e, 0xb2, 0xb6, 0x45, - 0x63, 0x04, 0x79, 0x0f, 0xc6, 0xe5, 0x3f, 0xdc, 0xd7, 0x86, 0x69, 0x40, 0x5c, 0xc7, 0x3e, 0x07, - 0xd0, 0x04, 0x9a, 0x7c, 0x1b, 0x6a, 0x7c, 0x71, 0xee, 0x98, 0x7c, 0x39, 0x8f, 0xc5, 0xed, 0x14, - 0x56, 0x08, 0x54, 0x5d, 0x42, 0x44, 0xc9, 0x1d, 0xb8, 0xcc, 0xfd, 0x56, 0x63, 0x07, 0x2e, 0x72, - 0xbf, 0xaa, 0x03, 0x97, 0x59, 0xe0, 0xcf, 0xa0, 0xbe, 0xe8, 0x38, 0x6e, 0x60, 0xf2, 0x43, 0xcb, - 0x97, 0x79, 0x9b, 0x03, 0x3d, 0xf7, 0x0d, 0x2c, 0xf2, 0xc7, 0xf4, 0x99, 0xae, 0x5b, 0x15, 0x68, - 0xfc, 0x71, 0x01, 0xea, 0xfc, 0xe6, 0x78, 0xdf, 0xf5, 0x9e, 0x9a, 0xde, 0xf1, 0x84, 0xd3, 0xc9, - 0x43, 0xbd, 0x78, 0x84, 0x4b, 0x58, 0x7c, 0xa4, 0x96, 0x5e, 0xe0, 0x48, 0xe5, 0xe1, 0x2d, 0xbf, - 0x81, 0x97, 0xe3, 0xb8, 0x0a, 0x6f, 0xdf, 0x08, 0x35, 0x7e, 0xab, 0x00, 0xf0, 0xfd, 0xbb, 0x77, - 0xdf, 0x60, 0x05, 0x19, 0x7f, 0x94, 0x87, 0x49, 0x99, 0x6f, 0x51, 0xba, 0x9c, 0xc6, 0xc2, 0xe4, - 0x56, 0x3e, 0xce, 0x23, 0xc9, 0xa4, 0x16, 0x0d, 0x71, 0x64, 0x1e, 0xaa, 0x2b, 0xcf, 0xec, 0x00, - 0x43, 0x4e, 0x91, 0x18, 0x12, 0xb9, 0x51, 0x09, 0x53, 0x5b, 0x4a, 0x42, 0x3a, 0xf2, 0x5e, 0x98, - 0x49, 0x2a, 0xc6, 0x9b, 0x8a, 0x33, 0xac, 0x64, 0x66, 0x93, 0x8c, 0xbf, 0x2b, 0x41, 0x69, 0xe5, - 0x19, 0x6b, 0x9f, 0x70, 0xd3, 0x28, 0x37, 0xeb, 0xd2, 0x11, 0x6f, 0xd6, 0x2f, 0x93, 0xcd, 0xfe, - 0x28, 0xb6, 0x67, 0x25, 0x39, 0x7c, 0xca, 0xf2, 0xe9, 0xe1, 0x43, 0x4b, 0x9f, 0xbc, 0x62, 0xc8, - 0x4f, 0x8a, 0x50, 0xdc, 0x5c, 0xda, 0x38, 0x5d, 0x37, 0xc7, 0xba, 0x6e, 0x0e, 0x4f, 0x3d, 0x1a, - 0x50, 0x59, 0x14, 0x3a, 0xaa, 0xc6, 0x95, 0x52, 0x13, 0x21, 0x54, 0x62, 0x8c, 0x2f, 0x0a, 0x50, - 0xdb, 0xec, 0xb7, 0xfc, 0x7d, 0x3f, 0x60, 0xdd, 0x13, 0x6e, 0xcd, 0xcb, 0x32, 0xb6, 0x29, 0xc5, - 0xda, 0xc0, 0xa6, 0x53, 0x11, 0xd1, 0xdc, 0x08, 0x3d, 0xa3, 0x72, 0x7b, 0x8e, 0x3c, 0x63, 0xe8, - 0x0f, 0xff, 0xb6, 0x00, 0x53, 0x4b, 0x1d, 0x9b, 0x39, 0xc1, 0xb2, 0xed, 0xcb, 0xbb, 0xf5, 0x09, - 0xd7, 0xca, 0xd1, 0x92, 0x06, 0xdf, 0xa0, 0xda, 0x6e, 0xfc, 0x76, 0x01, 0xea, 0x8b, 0xfd, 0x60, - 0x77, 0x31, 0xc0, 0xc3, 0xe5, 0x8d, 0x3c, 0xe6, 0x7f, 0x9e, 0x07, 0x8d, 0x32, 0x9f, 0x05, 0x61, - 0xb0, 0xb2, 0xe5, 0x3e, 0x61, 0xce, 0x2b, 0x88, 0x12, 0xd4, 0xdb, 0x7e, 0xe1, 0x25, 0x6f, 0xfb, - 0xa1, 0x52, 0x8b, 0x2f, 0x18, 0xf5, 0xf0, 0x38, 0x92, 0x07, 0x01, 0xaf, 0xc9, 0x67, 0xbc, 0x82, - 0x70, 0xf8, 0x38, 0x3f, 0xe3, 0x9f, 0xf3, 0x30, 0xb3, 0xe5, 0xf1, 0x13, 0xdd, 0x92, 0x07, 0xfb, - 0x09, 0xb7, 0xcb, 0xe8, 0x07, 0x9d, 0x70, 0x0b, 0xfd, 0x6b, 0x1e, 0x2e, 0x26, 0x3f, 0xe8, 0x75, - 0xf0, 0x02, 0xff, 0x92, 0x87, 0x73, 0xdf, 0xb5, 0x83, 0xdd, 0x7e, 0x2b, 0xca, 0x30, 0xbd, 0x7e, - 0x5f, 0x74, 0xc2, 0x57, 0xde, 0x4f, 0xf3, 0x70, 0x76, 0x7d, 0x75, 0x79, 0xe9, 0x75, 0xb1, 0xd0, - 0xc8, 0xf7, 0xbc, 0x06, 0xf6, 0xd9, 0x5c, 0x7c, 0xb0, 0xf6, 0x3a, 0xd9, 0x27, 0xf1, 0x3d, 0x27, - 0xdc, 0x3e, 0xbf, 0x5b, 0x81, 0x3a, 0x0f, 0x70, 0x65, 0x92, 0xf2, 0x8d, 0xbe, 0xf2, 0xcf, 0x43, - 0x5d, 0xaa, 0x01, 0x63, 0xcb, 0x72, 0xfc, 0x94, 0xcf, 0x13, 0xe0, 0x6d, 0x8c, 0x31, 0x55, 0x22, - 0x1e, 0x7a, 0x7d, 0x8f, 0x79, 0x2d, 0xb5, 0xbd, 0x62, 0x8f, 0x79, 0x2d, 0x8a, 0x50, 0xb2, 0x16, - 0x17, 0xa2, 0x16, 0x37, 0x56, 0xf1, 0xdd, 0x8f, 0x0c, 0x59, 0xf1, 0x21, 0x93, 0x27, 0x71, 0xdb, - 0x66, 0xcf, 0x16, 0x2f, 0x86, 0xd4, 0x07, 0x43, 0x69, 0x4e, 0xf2, 0x10, 0xa6, 0x43, 0x58, 0xfc, - 0x80, 0xa7, 0x9a, 0x21, 0x2e, 0xeb, 0xe9, 0xce, 0x28, 0x2b, 0xf9, 0x08, 0xc6, 0x43, 0xe0, 0x27, - 0x36, 0x3e, 0x2f, 0xe0, 0xa2, 0xde, 0x1a, 0x0e, 0xf4, 0x0b, 0x91, 0xa8, 0x27, 0x76, 0xa2, 0xdb, - 0x2c, 0xc1, 0xa0, 0x0a, 0xc0, 0xf8, 0x13, 0x32, 0x04, 0xa4, 0x8a, 0x6c, 0x09, 0x06, 0xf2, 0x6d, - 0x14, 0xd0, 0x73, 0x1d, 0x9f, 0x61, 0xb2, 0xaf, 0x8e, 0xbd, 0x07, 0x58, 0xf2, 0xf2, 0x24, 0x5c, - 0x74, 0x98, 0x24, 0xc8, 0xc8, 0x3a, 0x40, 0x9c, 0x94, 0x91, 0xad, 0x77, 0x2f, 0x9c, 0x2e, 0x52, - 0x44, 0x18, 0xff, 0x57, 0x80, 0xc9, 0xc5, 0x5e, 0xef, 0xf4, 0x95, 0xce, 0xab, 0x6a, 0x6c, 0x98, - 0x03, 0xd8, 0xe8, 0xb7, 0x3a, 0x76, 0x5b, 0xe9, 0x52, 0xc1, 0xb6, 0xa1, 0x1e, 0x42, 0x45, 0xa3, - 0x8a, 0x42, 0x62, 0x7c, 0x51, 0x54, 0x2d, 0x80, 0xaf, 0x13, 0x4e, 0x2d, 0x50, 0x3e, 0x92, 0x2b, - 0x3c, 0xa3, 0x2a, 0x53, 0x36, 0xf1, 0xc9, 0xca, 0x51, 0xd8, 0x41, 0xdb, 0xe6, 0xa8, 0x6d, 0xdb, - 0xa2, 0x29, 0x5a, 0xe3, 0xbf, 0xf3, 0x30, 0x1d, 0x9b, 0xe3, 0x55, 0x1c, 0x0e, 0x73, 0x00, 0x22, - 0x63, 0x10, 0x65, 0xf5, 0x27, 0xc4, 0x8a, 0xf0, 0x11, 0x2a, 0x1b, 0xc9, 0x62, 0x92, 0x28, 0xc5, - 0x57, 0xcc, 0x4c, 0xf1, 0xdd, 0x82, 0x2a, 0x35, 0x9f, 0x7e, 0xda, 0x67, 0xde, 0xbe, 0x4c, 0x7b, - 0x61, 0x5e, 0xcb, 0x33, 0x9f, 0x6e, 0xff, 0x90, 0x03, 0x69, 0x84, 0x26, 0x46, 0xd4, 0xfc, 0xa0, - 0x64, 0x72, 0x44, 0xf3, 0x43, 0xd8, 0xf2, 0x60, 0xfc, 0x61, 0x01, 0xa6, 0x96, 0xcd, 0xc0, 0x6c, - 0x99, 0x7e, 0xdc, 0x32, 0xf0, 0x21, 0x4c, 0x86, 0x30, 0x6e, 0x1e, 0x3b, 0x7a, 0x00, 0x7d, 0x66, - 0x38, 0xd0, 0xc1, 0x6a, 0x6d, 0xfb, 0x02, 0x4a, 0xd3, 0x64, 0xe4, 0x57, 0x62, 0x69, 0xd1, 0xc3, - 0xd8, 0x42, 0xbc, 0x09, 0xac, 0xd6, 0x76, 0x4f, 0x82, 0xe9, 0x08, 0x21, 0xb9, 0x0d, 0xf5, 0x10, - 0xf6, 0x88, 0xae, 0xca, 0xef, 0xc7, 0x49, 0x5b, 0xad, 0xed, 0xbe, 0x67, 0x53, 0x15, 0x4d, 0xe6, - 0x60, 0x3c, 0xfc, 0x57, 0xc9, 0x01, 0x62, 0x5d, 0xc5, 0x6a, 0x89, 0xb7, 0xe7, 0x09, 0x02, 0x95, - 0x01, 0x77, 0x48, 0x39, 0xc1, 0x80, 0xaf, 0xc7, 0x13, 0x04, 0xc6, 0x4f, 0x8b, 0x30, 0x13, 0x7f, - 0xe0, 0xa9, 0x87, 0x7c, 0x35, 0xfb, 0x33, 0xce, 0xb6, 0x55, 0x5e, 0xa0, 0xea, 0xd8, 0x80, 0x6a, - 0x68, 0x0a, 0x59, 0x26, 0x89, 0xae, 0x8a, 0xe9, 0xe5, 0x9b, 0x56, 0x7d, 0x88, 0x37, 0xbe, 0x2c, - 0x8c, 0xd8, 0x53, 0x6c, 0x94, 0x13, 0x69, 0x4f, 0x55, 0x23, 0xa5, 0x97, 0xd3, 0x08, 0x99, 0x87, - 0x89, 0xf0, 0x6f, 0xe1, 0x51, 0xca, 0x4a, 0x5b, 0x65, 0x4b, 0x3a, 0x94, 0x24, 0x89, 0xf1, 0x7b, - 0x05, 0x20, 0x29, 0x2d, 0x9e, 0xd8, 0xc7, 0x31, 0xaf, 0x40, 0x87, 0xc6, 0x5f, 0xe5, 0x61, 0x7a, - 0xa4, 0x5f, 0x8b, 0xbc, 0x0f, 0x20, 0x20, 0x4a, 0xef, 0x15, 0xf6, 0x5c, 0xc4, 0x3d, 0x5c, 0xc2, - 0x47, 0x29, 0x64, 0x64, 0x0e, 0xaa, 0xe2, 0xbf, 0xe8, 0x57, 0x23, 0xd2, 0x2c, 0xfd, 0xbe, 0x6d, - 0xd1, 0x88, 0x28, 0x1e, 0x05, 0x7f, 0x35, 0xa4, 0x98, 0xc9, 0x12, 0xec, 0xf7, 0xa2, 0x51, 0x38, - 0x99, 0xf1, 0x65, 0x1e, 0xc6, 0xa3, 0x09, 0x2f, 0x5a, 0xc7, 0x65, 0xba, 0x8a, 0x6c, 0x7d, 0x2b, - 0x3e, 0xaf, 0xf5, 0x2d, 0xe5, 0x10, 0x64, 0xaf, 0xdb, 0x3f, 0xe6, 0x61, 0x32, 0xa2, 0x3d, 0xc6, - 0xb6, 0xa7, 0x23, 0x7f, 0xc8, 0x4f, 0x2e, 0x40, 0x79, 0xdd, 0x61, 0xeb, 0x8f, 0xc9, 0x5d, 0xa5, - 0xc7, 0x52, 0xce, 0x7f, 0x5a, 0x9d, 0x07, 0x22, 0x9a, 0x39, 0xaa, 0x74, 0x62, 0x2e, 0xa8, 0xbd, - 0x70, 0x72, 0xee, 0x44, 0xe5, 0x11, 0x98, 0x66, 0x8e, 0xaa, 0x3d, 0x73, 0x0b, 0x6a, 0xb3, 0x98, - 0x9c, 0x77, 0x82, 0x4b, 0x60, 0x42, 0x2e, 0xa9, 0xdd, 0xb5, 0xac, 0xde, 0xac, 0xf4, 0x8b, 0xb2, - 0x51, 0x8a, 0x66, 0x8e, 0x66, 0xf7, 0x74, 0x25, 0x7e, 0x1b, 0x40, 0x1e, 0x29, 0x33, 0xa9, 0x0d, - 0x8c, 0xb8, 0x66, 0x8e, 0x26, 0x7f, 0x47, 0xe0, 0x5e, 0xe2, 0x61, 0xb7, 0x3c, 0x47, 0xce, 0xa6, - 0x58, 0x39, 0xaa, 0x99, 0xa3, 0xa9, 0x27, 0xe0, 0x89, 0x57, 0xc6, 0xf2, 0x24, 0x49, 0x0f, 0x8a, - 0x38, 0x65, 0x50, 0xf1, 0x22, 0xf9, 0xd7, 0x52, 0x4f, 0x72, 0x65, 0x49, 0xfd, 0x5c, 0x8a, 0x59, - 0x20, 0x9b, 0x39, 0x9a, 0x7a, 0xc0, 0x3b, 0x1b, 0x3e, 0x3e, 0x95, 0x5d, 0x49, 0x67, 0x94, 0x4c, - 0x87, 0xfd, 0x39, 0xd7, 0x52, 0xf8, 0x38, 0x75, 0x41, 0x7d, 0x74, 0x28, 0x9f, 0x87, 0x91, 0xd4, - 0x28, 0x2b, 0x8e, 0xc5, 0xad, 0xa3, 0xf8, 0xdf, 0x8f, 0xd3, 0x6f, 0x7d, 0xe4, 0xa3, 0xaf, 0xf3, - 0x29, 0x4e, 0x89, 0x6d, 0xe6, 0x68, 0xfa, 0x6d, 0xd0, 0xbd, 0xc4, 0x3b, 0x13, 0x19, 0x5d, 0xa6, - 0xb5, 0xca, 0x51, 0x8a, 0x56, 0xf1, 0x45, 0xca, 0xc7, 0xe9, 0x87, 0x0f, 0xda, 0x44, 0xe6, 0xd0, - 0x12, 0xab, 0x0c, 0x1d, 0x3e, 0x94, 0xb8, 0x97, 0x68, 0xad, 0xd7, 0xce, 0x64, 0x0f, 0x6d, 0x06, - 0xa6, 0x3a, 0xb4, 0x68, 0xc2, 0x4f, 0x34, 0x79, 0x6b, 0x93, 0x99, 0x06, 0x45, 0x9c, 0x62, 0x50, - 0xd1, 0x10, 0x7e, 0x2f, 0xd1, 0xcb, 0xa5, 0x4d, 0x25, 0x07, 0x55, 0x50, 0x7c, 0x50, 0xb5, 0xeb, - 0x6b, 0x41, 0x6d, 0x71, 0xd2, 0xa6, 0x93, 0x06, 0x8a, 0x31, 0xdc, 0x40, 0x4a, 0x2b, 0x94, 0x8e, - 0xed, 0x13, 0x1a, 0x41, 0xf2, 0x7a, 0x34, 0xc3, 0xa5, 0x8d, 0x66, 0x8e, 0x62, 0x63, 0x85, 0x21, - 0x1a, 0x73, 0xb4, 0xb3, 0x48, 0x31, 0x1e, 0x52, 0x70, 0x58, 0x33, 0x47, 0x45, 0xd3, 0xce, 0x5d, - 0xa5, 0x76, 0xaf, 0xcd, 0x24, 0x5d, 0x44, 0x84, 0xe0, 0x2e, 0x22, 0xae, 0xf0, 0xdf, 0x1f, 0xad, - 0x6f, 0x6b, 0xe7, 0x92, 0x67, 0x5d, 0x1a, 0xdf, 0xcc, 0xd1, 0xd1, 0x9a, 0xf8, 0xbd, 0x44, 0xc9, - 0x57, 0x3b, 0x9f, 0x54, 0x97, 0x82, 0xe2, 0xea, 0x52, 0x8b, 0xc3, 0xeb, 0x99, 0x8d, 0x94, 0xda, - 0x05, 0x14, 0xf0, 0x56, 0x24, 0x60, 0x94, 0xa4, 0x99, 0xa3, 0x99, 0x2d, 0x98, 0x9f, 0x1d, 0x5c, - 0x78, 0xd5, 0x34, 0x94, 0x7a, 0x4d, 0xd9, 0x5c, 0x99, 0x74, 0xcd, 0x1c, 0x3d, 0xb8, 0x78, 0xbb, - 0xa0, 0xd6, 0x40, 0xb5, 0x8b, 0x49, 0xfb, 0xc6, 0x18, 0x6e, 0x5f, 0xa5, 0x56, 0xba, 0xa0, 0x96, - 0x1c, 0xb5, 0x4b, 0xa3, 0x5c, 0xb1, 0x53, 0x55, 0x4a, 0x93, 0x34, 0xbb, 0xc2, 0xa7, 0xbd, 0x85, - 0xfc, 0x97, 0x43, 0xfe, 0x2c, 0x9a, 0x66, 0x8e, 0x66, 0x57, 0x07, 0x69, 0x76, 0x91, 0x4d, 0xbb, - 0x7c, 0x98, 0xcc, 0x68, 0x76, 0xd9, 0x05, 0x3a, 0xf3, 0x90, 0x3a, 0x97, 0x76, 0x25, 0x99, 0x88, - 0x3a, 0x90, 0xb0, 0x99, 0xa3, 0x87, 0x54, 0xcb, 0x1e, 0x1d, 0x50, 0x74, 0xd2, 0xae, 0x26, 0x7b, - 0x97, 0x32, 0x89, 0x9a, 0x39, 0x7a, 0x40, 0xc9, 0xea, 0xd1, 0x01, 0x95, 0x1f, 0x4d, 0x3f, 0x54, - 0x6c, 0xa4, 0x8f, 0x03, 0xea, 0x46, 0xeb, 0x99, 0xe5, 0x17, 0xed, 0x5a, 0x72, 0x55, 0x67, 0x90, - 0xf0, 0x55, 0x9d, 0x55, 0xb8, 0x59, 0xcf, 0xac, 0x7f, 0x68, 0xd7, 0x0f, 0x11, 0x18, 0xcd, 0x31, - 0xb3, 0x72, 0xb2, 0x9e, 0x59, 0x80, 0xd0, 0x8c, 0xa4, 0xc0, 0x0c, 0x12, 0x2e, 0x30, 0xab, 0x74, - 0xb1, 0x9e, 0x59, 0x01, 0xd0, 0x6e, 0x1c, 0x22, 0x30, 0x9e, 0x61, 0x56, 0xed, 0xe0, 0x5e, 0x22, - 0x05, 0xaf, 0x7d, 0x2b, 0xe9, 0x52, 0x14, 0x14, 0x77, 0x29, 0x6a, 0xb2, 0x7e, 0x69, 0x24, 0x6b, - 0xa9, 0xbd, 0x9d, 0x0c, 0x00, 0x52, 0xe8, 0x66, 0x8e, 0x8e, 0xe4, 0x39, 0x97, 0x46, 0x12, 0x6f, - 0xda, 0xcd, 0x83, 0x84, 0x20, 0x3a, 0x29, 0x44, 0xa4, 0xea, 0x56, 0x33, 0xd2, 0x45, 0xda, 0x3b, - 0xc9, 0x9b, 0xe0, 0x08, 0x41, 0x33, 0x47, 0x33, 0x92, 0x4c, 0x34, 0x3b, 0xdb, 0xa0, 0xcd, 0x26, - 0xb7, 0x6d, 0x16, 0x0d, 0xdf, 0xb6, 0x99, 0x99, 0x8a, 0xb5, 0xac, 0x58, 0x4d, 0xbb, 0x95, 0xbc, - 0xb3, 0x8d, 0x52, 0xf0, 0x3b, 0x5b, 0x46, 0x8c, 0x47, 0xb3, 0xe3, 0x67, 0xed, 0x97, 0x0e, 0x9d, - 0x21, 0xd2, 0x64, 0xcc, 0x50, 0xc4, 0xde, 0xf1, 0xb5, 0xea, 0x51, 0xaf, 0xe3, 0x9a, 0x96, 0xf6, - 0x6e, 0xe6, 0xb5, 0x4a, 0x20, 0x95, 0x6b, 0x95, 0x00, 0xf0, 0x0b, 0x80, 0x1a, 0xcb, 0x68, 0xb7, - 0x93, 0x17, 0x00, 0x15, 0xc7, 0x2f, 0x00, 0x89, 0xb8, 0x67, 0x69, 0x24, 0x82, 0xd0, 0xde, 0x4b, - 0x2e, 0x80, 0x14, 0x9a, 0x2f, 0x80, 0x14, 0xa8, 0x31, 0x06, 0xe5, 0x15, 0x4e, 0x6c, 0xfc, 0x49, - 0x1e, 0xc6, 0x37, 0x03, 0x8f, 0x99, 0x5d, 0x99, 0xb2, 0xb8, 0x04, 0x55, 0x31, 0xc9, 0xf0, 0x87, - 0x0d, 0x69, 0xf4, 0x3f, 0xb9, 0x09, 0x67, 0xd6, 0x4c, 0x3f, 0x40, 0x4e, 0xe5, 0x67, 0x6a, 0x68, - 0x0a, 0x4a, 0xd6, 0x04, 0x9d, 0xe0, 0xc3, 0x9f, 0x0b, 0x28, 0x3e, 0xf7, 0x6d, 0x4e, 0x95, 0x87, - 0x19, 0xf8, 0x20, 0x27, 0xc5, 0x6b, 0x0c, 0xf3, 0x30, 0xa2, 0xbe, 0x97, 0x8f, 0x98, 0xd6, 0x47, - 0x7e, 0xcc, 0x51, 0x06, 0x20, 0xdf, 0x30, 0x0a, 0x1f, 0xf9, 0x29, 0xc8, 0x1b, 0x50, 0x7c, 0xb4, - 0xba, 0xac, 0x3e, 0xff, 0x49, 0xfe, 0xbe, 0x25, 0xc7, 0x92, 0x77, 0xa2, 0xdb, 0xf1, 0x23, 0xba, - 0x26, 0xf3, 0x15, 0xf8, 0xbc, 0xbf, 0xef, 0x75, 0xa8, 0x82, 0x6a, 0x4c, 0x7d, 0xf5, 0x9f, 0x57, - 0x73, 0x5f, 0x7d, 0x7d, 0x35, 0xff, 0xb3, 0xaf, 0xaf, 0xe6, 0xff, 0xe3, 0xeb, 0xab, 0xf9, 0x56, - 0x05, 0x95, 0xf5, 0xfe, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x8a, 0x47, 0xe5, 0x25, 0xfc, 0x53, - 0x00, 0x00, +func init() { proto.RegisterFile("events.proto", fileDescriptor_events_183547552ed1ab9b) } + +var fileDescriptor_events_183547552ed1ab9b = []byte{ + // 4108 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3c, 0x4d, 0x6f, 0x1c, 0x47, + 0x76, 0xf3, 0xcd, 0x99, 0x37, 0x94, 0x44, 0x96, 0x28, 0xa9, 0x25, 0xcb, 0x6a, 0xa9, 0x65, 0xcb, + 0x54, 0x2c, 0x8b, 0x11, 0xcd, 0xb5, 0x36, 0x9b, 0x04, 0x36, 0x87, 0xa4, 0x76, 0x18, 0x53, 0x22, + 0x5d, 0xa4, 0x76, 0xf7, 0xb2, 0x1e, 0xf4, 0x4c, 0x97, 0xc8, 0x5e, 0xcd, 0x74, 0xcf, 0x76, 0xf7, + 0x50, 0xa2, 0x4f, 0xf9, 0xb8, 0xec, 0xc1, 0x01, 0x82, 0xcd, 0x29, 0xc8, 0x21, 0x01, 0x82, 0x1c, + 0x12, 0x04, 0x49, 0x90, 0x43, 0x90, 0xbb, 0xb3, 0x81, 0x81, 0x60, 0x93, 0xc5, 0xe6, 0x9c, 0x49, + 0x62, 0x20, 0x97, 0x01, 0xf2, 0x07, 0x82, 0x00, 0x59, 0xd4, 0xab, 0xea, 0xee, 0xea, 0x9e, 0x26, + 0x65, 0x89, 0x5a, 0x10, 0x94, 0x78, 0x23, 0xdf, 0x57, 0x75, 0xbd, 0x57, 0xf5, 0xaa, 0xde, 0x47, + 0x0d, 0x4c, 0xb2, 0x5d, 0xe6, 0x04, 0xfe, 0xed, 0xbe, 0xe7, 0x06, 0x2e, 0xa9, 0x88, 0xff, 0x2e, + 0xcd, 0x6c, 0xbb, 0xdb, 0x2e, 0x82, 0xe6, 0xf8, 0x5f, 0x02, 0x7b, 0x49, 0xdf, 0x76, 0xdd, 0xed, + 0x2e, 0x9b, 0xc3, 0xff, 0xda, 0x83, 0x47, 0x73, 0x81, 0xdd, 0x63, 0x7e, 0x60, 0xf6, 0xfa, 0x92, + 0xe0, 0x72, 0x9a, 0xc0, 0x0f, 0xbc, 0x41, 0x27, 0x10, 0x58, 0xe3, 0x47, 0x05, 0xa8, 0xde, 0x67, + 0x81, 0x69, 0x99, 0x81, 0x49, 0x2e, 0x43, 0x79, 0xd5, 0xb1, 0xd8, 0x53, 0x2d, 0x7f, 0x35, 0x3f, + 0x5b, 0x6c, 0x54, 0x46, 0x43, 0xbd, 0xc0, 0x6c, 0x2a, 0x80, 0xe4, 0x4d, 0x28, 0x6d, 0xed, 0xf5, + 0x99, 0x56, 0xb8, 0x9a, 0x9f, 0xad, 0x35, 0x6a, 0xa3, 0xa1, 0x5e, 0xc6, 0x2f, 0xa3, 0x08, 0x26, + 0xd7, 0xa0, 0xb0, 0xba, 0xac, 0x15, 0x11, 0x39, 0x3d, 0x1a, 0xea, 0xa7, 0x06, 0xb6, 0x75, 0xcb, + 0xed, 0xd9, 0x01, 0xeb, 0xf5, 0x83, 0x3d, 0x5a, 0x58, 0x5d, 0x26, 0x37, 0xa0, 0xb4, 0xe4, 0x5a, + 0x4c, 0x2b, 0x21, 0x11, 0x19, 0x0d, 0xf5, 0xd3, 0x1d, 0xd7, 0x62, 0x0a, 0x15, 0xe2, 0xc9, 0x47, + 0x50, 0xda, 0xb2, 0x7b, 0x4c, 0x2b, 0x5f, 0xcd, 0xcf, 0xd6, 0xe7, 0x2f, 0xdd, 0x16, 0x33, 0xb8, + 0x1d, 0xce, 0xe0, 0xf6, 0x56, 0x38, 0xc5, 0xc6, 0xd4, 0x97, 0x43, 0x3d, 0x37, 0x1a, 0xea, 0x25, + 0x3e, 0xeb, 0x3f, 0xf8, 0x0f, 0x3d, 0x4f, 0x91, 0x93, 0xcc, 0x43, 0x7d, 0xa9, 0x3b, 0xf0, 0x03, + 0xe6, 0x3d, 0x30, 0x7b, 0x4c, 0xab, 0xe0, 0x80, 0x53, 0xa3, 0xa1, 0x3e, 0xd9, 0x11, 0xe0, 0x96, + 0x63, 0xf6, 0x18, 0x55, 0x89, 0x8c, 0x1f, 0xc0, 0x99, 0x4d, 0xe6, 0xfb, 0xb6, 0xeb, 0x44, 0x0a, + 0x79, 0x1b, 0x6a, 0x12, 0xb4, 0xba, 0x8c, 0x4a, 0xa9, 0x35, 0x26, 0x46, 0x43, 0xbd, 0xe8, 0xdb, + 0x16, 0x8d, 0x31, 0xe4, 0x57, 0x61, 0xe2, 0xbb, 0x76, 0xb0, 0x73, 0xff, 0xde, 0xa2, 0x54, 0xce, + 0xf9, 0xd1, 0x50, 0x27, 0x4f, 0xec, 0x60, 0xa7, 0xd5, 0x7b, 0x64, 0x2a, 0xd3, 0x0b, 0xc9, 0x8c, + 0xef, 0xc2, 0xe4, 0x43, 0x9f, 0x79, 0x8a, 0xe6, 0x4b, 0xfc, 0x7f, 0x39, 0x46, 0x95, 0xcf, 0x68, + 0xe0, 0x33, 0x8f, 0x22, 0x94, 0xdc, 0x84, 0xf2, 0x9a, 0xbb, 0x6d, 0x3b, 0x52, 0xfa, 0xd9, 0xd1, + 0x50, 0x3f, 0xd3, 0xe5, 0x00, 0x45, 0xb4, 0xa0, 0x30, 0xfe, 0xb6, 0x08, 0xa7, 0x37, 0x99, 0xb7, + 0xab, 0xc8, 0x5e, 0xe4, 0xf3, 0xe2, 0x10, 0x3e, 0x4b, 0xbf, 0x6f, 0x76, 0x98, 0x1c, 0xe6, 0xc2, + 0x68, 0xa8, 0x9f, 0x75, 0x42, 0xa0, 0x22, 0x2b, 0x4d, 0x4f, 0x6e, 0x42, 0x55, 0x80, 0x56, 0x97, + 0xe5, 0x37, 0x9c, 0x1a, 0x0d, 0xf5, 0x9a, 0x8f, 0xb0, 0x96, 0x6d, 0xd1, 0x08, 0x4d, 0x56, 0xc2, + 0xf1, 0x9b, 0xae, 0x1f, 0x70, 0xe1, 0x72, 0x49, 0xbc, 0x39, 0x1a, 0xea, 0x17, 0x25, 0xc3, 0x8e, + 0x44, 0x29, 0x43, 0xa6, 0x98, 0xc8, 0xaf, 0x01, 0x08, 0xc8, 0xa2, 0x65, 0x79, 0x72, 0xc1, 0x5c, + 0x1c, 0x0d, 0xf5, 0x73, 0x52, 0x84, 0x69, 0x59, 0x9e, 0xc2, 0xae, 0x10, 0x93, 0x1e, 0x4c, 0x8a, + 0xff, 0xd6, 0xcc, 0x36, 0xeb, 0xfa, 0x5a, 0xf9, 0x6a, 0x71, 0xb6, 0x3e, 0x3f, 0x7b, 0x5b, 0x6e, + 0xaa, 0xa4, 0x76, 0x6e, 0xab, 0xa4, 0x2b, 0x4e, 0xe0, 0xed, 0x35, 0x74, 0xb9, 0xa6, 0x2e, 0xc8, + 0xa1, 0xba, 0x88, 0x53, 0x06, 0x4b, 0x88, 0xbf, 0xf4, 0x21, 0x4c, 0x8f, 0xc9, 0x20, 0x53, 0x50, + 0x7c, 0xcc, 0xf6, 0x84, 0x9e, 0x29, 0xff, 0x93, 0xcc, 0x40, 0x79, 0xd7, 0xec, 0x0e, 0xe4, 0xf6, + 0xa1, 0xe2, 0x9f, 0x6f, 0x15, 0xbe, 0x99, 0x37, 0xfe, 0x21, 0x0f, 0x64, 0xc9, 0x75, 0x1c, 0xd6, + 0x09, 0xd4, 0xb5, 0xf7, 0x01, 0xd4, 0xd6, 0xdc, 0x8e, 0xd9, 0x45, 0x05, 0x08, 0x83, 0x69, 0xa3, + 0xa1, 0x3e, 0xc3, 0x67, 0x7e, 0xbb, 0xcb, 0x31, 0xca, 0x27, 0xc5, 0xa4, 0x5c, 0x73, 0x94, 0xf5, + 0xdc, 0x80, 0x21, 0x63, 0x21, 0xd6, 0x1c, 0x32, 0x7a, 0x88, 0x52, 0x35, 0x17, 0x13, 0x93, 0x39, + 0xa8, 0x6e, 0xf0, 0x3d, 0xd6, 0x71, 0xbb, 0xd2, 0x6a, 0xb8, 0xd4, 0x70, 0xdf, 0x29, 0x2c, 0x11, + 0x91, 0xf1, 0xbb, 0x05, 0xb8, 0xf8, 0xf1, 0xa0, 0xcd, 0x3c, 0x87, 0x05, 0xcc, 0x97, 0x9b, 0x29, + 0x9a, 0xc1, 0x03, 0x98, 0x1e, 0x43, 0xca, 0x99, 0x5c, 0x1d, 0x0d, 0xf5, 0xcb, 0x8f, 0x23, 0x64, + 0x4b, 0xee, 0x4a, 0x65, 0x90, 0x71, 0x56, 0xd2, 0x84, 0x33, 0x31, 0x90, 0x6f, 0x0c, 0x5f, 0x2b, + 0x5c, 0x2d, 0xce, 0xd6, 0x1a, 0x57, 0x46, 0x43, 0xfd, 0x92, 0x22, 0x8d, 0x6f, 0x1d, 0xd5, 0x60, + 0x69, 0x36, 0xf2, 0x31, 0x4c, 0xc5, 0xa0, 0x6f, 0x7b, 0xee, 0xa0, 0xef, 0x6b, 0x45, 0x14, 0xa5, + 0x8f, 0x86, 0xfa, 0x1b, 0x8a, 0xa8, 0x6d, 0x44, 0x2a, 0xb2, 0xc6, 0x18, 0x8d, 0xff, 0x2e, 0xc2, + 0xb9, 0x18, 0xb8, 0xe1, 0x5a, 0x91, 0x02, 0xd6, 0x55, 0x05, 0x6c, 0xb8, 0x16, 0xfa, 0x22, 0xa1, + 0x80, 0x6b, 0xa3, 0xa1, 0xfe, 0xa6, 0x32, 0x4e, 0xdf, 0xb5, 0x5a, 0xa9, 0x2d, 0x31, 0xce, 0x4b, + 0x3e, 0x85, 0xf3, 0x63, 0x40, 0xb1, 0xa3, 0x85, 0x9d, 0x6f, 0x8c, 0x86, 0xba, 0x91, 0x21, 0x35, + 0xbd, 0xc1, 0xf7, 0x91, 0x42, 0x4c, 0xb8, 0xa0, 0xa8, 0xdd, 0x75, 0x02, 0xd3, 0x76, 0xa4, 0x0b, + 0x15, 0xeb, 0xe1, 0x9d, 0xd1, 0x50, 0xbf, 0xae, 0xda, 0x2d, 0xa4, 0x49, 0x7f, 0xfc, 0x7e, 0x72, + 0x88, 0x05, 0x5a, 0x06, 0x6a, 0xb5, 0x67, 0x6e, 0x87, 0xe7, 0xc2, 0xec, 0x68, 0xa8, 0xbf, 0x95, + 0x39, 0x86, 0xcd, 0xa9, 0x94, 0x41, 0xf6, 0x95, 0x44, 0x28, 0x90, 0x18, 0xf7, 0xc0, 0xb5, 0x18, + 0xce, 0xa1, 0x8c, 0xf2, 0x8d, 0xd1, 0x50, 0xbf, 0xa2, 0xc8, 0x77, 0x5c, 0x8b, 0xa5, 0x3f, 0x3f, + 0x83, 0xdb, 0xf8, 0xbf, 0x12, 0x77, 0x2c, 0xe8, 0xf3, 0x37, 0x03, 0xd3, 0x0b, 0xc8, 0xb7, 0xe2, + 0xa3, 0x13, 0xad, 0x5a, 0x9f, 0x9f, 0x0a, 0x9d, 0x4c, 0x08, 0x6f, 0x4c, 0x72, 0x67, 0xf2, 0xb3, + 0xa1, 0x9e, 0x1f, 0x0d, 0xf5, 0x1c, 0xad, 0x2a, 0xbb, 0x5b, 0x38, 0xfc, 0x02, 0xf2, 0xcd, 0x84, + 0x7c, 0xea, 0xa1, 0x90, 0xe2, 0x15, 0x47, 0xc1, 0x87, 0x30, 0x21, 0xbf, 0x01, 0x2d, 0x52, 0x9f, + 0xbf, 0x10, 0xfb, 0xb5, 0xc4, 0xd9, 0x95, 0xe2, 0x0e, 0xb9, 0xc8, 0x6f, 0x40, 0x45, 0xb8, 0x2b, + 0xd4, 0x76, 0x7d, 0xfe, 0x7c, 0xb6, 0x5f, 0x4c, 0xb1, 0x4b, 0x1e, 0xd2, 0x04, 0x88, 0x5d, 0x55, + 0x74, 0x3e, 0x4b, 0x09, 0xe3, 0x4e, 0x2c, 0x25, 0x45, 0xe1, 0x25, 0x1f, 0xc0, 0xe4, 0x16, 0xf3, + 0x7a, 0xb6, 0x63, 0x76, 0x37, 0xed, 0xcf, 0xc2, 0x23, 0x1a, 0xef, 0x04, 0xbe, 0xfd, 0x99, 0x6a, + 0x8b, 0x04, 0x1d, 0xf9, 0x7e, 0x96, 0x53, 0x99, 0xc0, 0x0f, 0xb9, 0x16, 0x7e, 0xc8, 0xbe, 0x2e, + 0x29, 0xf5, 0x3d, 0x19, 0x3e, 0xe6, 0x13, 0x38, 0x95, 0xd8, 0x1b, 0x5a, 0x15, 0x45, 0xbf, 0x39, + 0x2e, 0x5a, 0xd9, 0xe8, 0x29, 0xb1, 0x49, 0x09, 0xfc, 0x44, 0x5c, 0x75, 0xec, 0xc0, 0x36, 0xbb, + 0x4b, 0x6e, 0xaf, 0x67, 0x3a, 0x96, 0x56, 0x43, 0x57, 0x83, 0x27, 0xa2, 0x2d, 0x30, 0xad, 0x8e, + 0x40, 0xa9, 0x27, 0x62, 0x92, 0xc9, 0xf8, 0x8b, 0x22, 0xd4, 0xa5, 0x11, 0x7f, 0xcb, 0xb5, 0x9d, + 0x93, 0xd5, 0x77, 0x98, 0xd5, 0x97, 0xb9, 0x8a, 0x2a, 0x2f, 0x6b, 0x15, 0x19, 0x9f, 0x17, 0x22, + 0x57, 0xb1, 0xe1, 0xd9, 0xce, 0xe1, 0x5c, 0xc5, 0x0d, 0x80, 0xa5, 0x9d, 0x81, 0xf3, 0x58, 0x5c, + 0xcd, 0x0b, 0xf1, 0xd5, 0xbc, 0x63, 0x53, 0x05, 0xc3, 0xef, 0xe7, 0xcb, 0x5c, 0x3e, 0xb7, 0xcc, + 0x64, 0xa3, 0xf6, 0xa5, 0x90, 0x94, 0x7f, 0x8f, 0x22, 0x98, 0xe8, 0x50, 0x6e, 0xec, 0x05, 0xcc, + 0x47, 0xcd, 0x17, 0xc5, 0xfd, 0xbd, 0xcd, 0x01, 0x54, 0xc0, 0xc9, 0x02, 0x4c, 0x2f, 0xb3, 0xae, + 0xb9, 0x77, 0xdf, 0xee, 0x76, 0x6d, 0x9f, 0x75, 0x5c, 0xc7, 0xf2, 0x51, 0xc9, 0x72, 0xb8, 0x9e, + 0x4f, 0xc7, 0x09, 0x88, 0x01, 0x95, 0xf5, 0x47, 0x8f, 0x7c, 0x16, 0xa0, 0xfa, 0x8a, 0x0d, 0x18, + 0x0d, 0xf5, 0x8a, 0x8b, 0x10, 0x2a, 0x31, 0xc6, 0xcf, 0x0b, 0x70, 0x4a, 0xaa, 0x83, 0xb2, 0x1f, + 0xb0, 0xce, 0xd1, 0xb8, 0xce, 0x78, 0xed, 0x15, 0x0f, 0xbd, 0xf6, 0x4a, 0x87, 0x58, 0x7b, 0x06, + 0x54, 0x28, 0x33, 0x7d, 0xb9, 0x82, 0x6b, 0x42, 0x63, 0x1e, 0x42, 0xa8, 0xc4, 0x90, 0x6b, 0x30, + 0x71, 0xdf, 0x7c, 0x6a, 0xf7, 0x06, 0x3d, 0xa9, 0x56, 0x0c, 0x3b, 0x7a, 0xe6, 0x53, 0x1a, 0xc2, + 0x8d, 0xbf, 0x29, 0x71, 0x39, 0xdc, 0x57, 0x1e, 0x4f, 0x57, 0xf0, 0xf2, 0x14, 0x1a, 0x1b, 0xb6, + 0xfc, 0x02, 0x86, 0x7d, 0x6d, 0x0e, 0x22, 0xe3, 0x2f, 0x27, 0x78, 0x50, 0x85, 0xda, 0x5f, 0x71, + 0xac, 0x93, 0x55, 0x73, 0x98, 0x55, 0xb3, 0x0c, 0xd3, 0x2b, 0xce, 0x8e, 0xe9, 0x74, 0x98, 0x45, + 0x59, 0xc7, 0xf5, 0x2c, 0xdb, 0xd9, 0xc6, 0xa5, 0x53, 0x15, 0xc1, 0x3f, 0x93, 0xc8, 0x96, 0x17, + 0x62, 0xe9, 0x38, 0x03, 0xb9, 0x03, 0xf5, 0x55, 0x27, 0x60, 0x9e, 0xd9, 0x09, 0xec, 0x5d, 0x86, + 0xab, 0xa7, 0xda, 0x38, 0x33, 0x1a, 0xea, 0x75, 0x3b, 0x06, 0x53, 0x95, 0x86, 0x2c, 0xc0, 0xe4, + 0x86, 0xe9, 0x05, 0x76, 0xc7, 0xee, 0x9b, 0x4e, 0xe0, 0x6b, 0x55, 0xbc, 0x4b, 0x60, 0x6a, 0xa3, + 0xaf, 0xc0, 0x69, 0x82, 0x8a, 0x7c, 0x1f, 0x6a, 0x78, 0x67, 0xc5, 0xb4, 0x4a, 0xed, 0x99, 0x69, + 0x95, 0xeb, 0x71, 0x08, 0x8c, 0x6a, 0x6f, 0xf9, 0x9c, 0x39, 0xde, 0x0a, 0x98, 0x69, 0x89, 0x25, + 0x92, 0xef, 0xc1, 0xc4, 0x8a, 0x63, 0xa1, 0x70, 0x78, 0xa6, 0x70, 0x43, 0x0a, 0x3f, 0x1f, 0x0b, + 0x77, 0xfb, 0x29, 0xd9, 0xa1, 0xb8, 0xec, 0x5d, 0x56, 0xff, 0xe5, 0xed, 0xb2, 0xc9, 0x5f, 0xc2, + 0x75, 0xef, 0xd4, 0x8b, 0x5c, 0xf7, 0x3e, 0x83, 0x7a, 0x63, 0xe3, 0x5e, 0xb4, 0xe1, 0x2e, 0x42, + 0x71, 0x43, 0xe6, 0xa0, 0x4a, 0xe2, 0x30, 0xe8, 0xdb, 0x16, 0xe5, 0x30, 0x72, 0x13, 0xaa, 0x4b, + 0x18, 0xa6, 0xca, 0xe4, 0x4c, 0x49, 0x24, 0x67, 0x3a, 0x08, 0xc3, 0xe4, 0x4c, 0x88, 0x26, 0x6f, + 0xc3, 0xc4, 0x86, 0xe7, 0x6e, 0x7b, 0x66, 0x4f, 0xc6, 0x73, 0xf5, 0xd1, 0x50, 0x9f, 0xe8, 0x0b, + 0x10, 0x0d, 0x71, 0xc6, 0x1f, 0xe6, 0xa1, 0xb2, 0x19, 0x98, 0xc1, 0xc0, 0xe7, 0x1c, 0x9b, 0x83, + 0x4e, 0x87, 0xf9, 0x3e, 0x8e, 0x5d, 0x15, 0x1c, 0xbe, 0x00, 0xd1, 0x10, 0x47, 0x6e, 0x42, 0x79, + 0xc5, 0xf3, 0x5c, 0x4f, 0xcd, 0x50, 0x31, 0x0e, 0x50, 0x33, 0x54, 0x48, 0x41, 0xee, 0x42, 0x5d, + 0xb8, 0x09, 0xdf, 0xe7, 0x31, 0x9f, 0xf8, 0x8e, 0x73, 0xa3, 0xa1, 0x3e, 0xdd, 0x13, 0x20, 0x85, + 0x45, 0xa5, 0x34, 0xbe, 0xc0, 0xd4, 0x16, 0x2e, 0x19, 0xa9, 0xa4, 0xd7, 0xf1, 0x0e, 0xfc, 0x3e, + 0x14, 0x1b, 0x1b, 0xf7, 0xa4, 0xcf, 0x3a, 0x1b, 0xb2, 0x2a, 0x4b, 0x25, 0xc5, 0xc7, 0xa9, 0xc9, + 0x65, 0x28, 0x6d, 0xf0, 0xe5, 0x53, 0xc1, 0xe5, 0x81, 0xe9, 0xc5, 0x3e, 0x5f, 0x3f, 0x08, 0x45, + 0xac, 0x19, 0xec, 0xa0, 0xfb, 0x91, 0xc9, 0xc7, 0xbe, 0x19, 0xec, 0x50, 0x84, 0x72, 0xec, 0xa2, + 0xb7, 0xbd, 0x2b, 0x1d, 0x0d, 0x62, 0x4d, 0x6f, 0x7b, 0x97, 0x22, 0x94, 0xcc, 0x01, 0x50, 0x16, + 0x0c, 0x3c, 0x07, 0x13, 0xbb, 0xdc, 0xb3, 0x94, 0x85, 0x03, 0xf3, 0x10, 0xda, 0xea, 0xb8, 0x16, + 0xa3, 0x0a, 0x89, 0xf1, 0xe7, 0x71, 0x18, 0xb3, 0x6c, 0xfb, 0x8f, 0x4f, 0x4c, 0xf8, 0x1c, 0x26, + 0xe4, 0x46, 0xaa, 0x64, 0x1a, 0x49, 0x87, 0xf2, 0xbd, 0xae, 0xb9, 0xed, 0xa3, 0x0d, 0xcb, 0xe2, + 0x72, 0xff, 0x88, 0x03, 0xa8, 0x80, 0xa7, 0xec, 0x54, 0x7d, 0xb6, 0x9d, 0xfe, 0x3d, 0xde, 0x6d, + 0x0f, 0x58, 0xf0, 0xc4, 0xf5, 0x4e, 0x4c, 0xf5, 0x75, 0x4d, 0x75, 0x03, 0x26, 0x36, 0xbd, 0x0e, + 0xa6, 0x5f, 0x85, 0xb5, 0x26, 0x47, 0x43, 0xbd, 0xea, 0x7b, 0x1d, 0xcc, 0x5a, 0xd3, 0x10, 0xc9, + 0xe9, 0x96, 0xfd, 0x00, 0xe9, 0x26, 0x62, 0x3a, 0xcb, 0x0f, 0x24, 0x9d, 0x44, 0x4a, 0xba, 0x0d, + 0xd7, 0x0b, 0xa4, 0xe1, 0x22, 0xba, 0xbe, 0xeb, 0x05, 0x34, 0x44, 0x92, 0x77, 0x01, 0xb6, 0x96, + 0x36, 0xbe, 0xc3, 0x3c, 0x54, 0x97, 0xd8, 0x8b, 0xe8, 0xae, 0x77, 0x05, 0x88, 0x2a, 0x68, 0xe3, + 0xaf, 0x94, 0x7d, 0xc8, 0x0d, 0x74, 0x92, 0x4e, 0x38, 0xc4, 0x5d, 0x72, 0x1e, 0xa6, 0x30, 0x86, + 0xde, 0xf2, 0x4c, 0xc7, 0xef, 0xd9, 0x41, 0xc0, 0x2c, 0xe9, 0x6b, 0x31, 0x72, 0x0e, 0x9e, 0xd2, + 0x31, 0x3c, 0xb9, 0x05, 0xa7, 0x10, 0x46, 0x59, 0x87, 0xd9, 0xbb, 0xcc, 0xc2, 0x35, 0x20, 0x19, + 0xbc, 0xa7, 0x34, 0x89, 0x34, 0xfe, 0x39, 0xce, 0x28, 0xac, 0x31, 0x73, 0x97, 0x9d, 0xd8, 0xeb, + 0x10, 0xf6, 0x32, 0xfe, 0xac, 0x08, 0x35, 0x3e, 0x23, 0xac, 0x99, 0x1d, 0x89, 0x2a, 0x17, 0xc2, + 0x1b, 0x96, 0xd4, 0xe4, 0xe9, 0x48, 0x13, 0x08, 0x1d, 0xd3, 0x80, 0xb8, 0x8d, 0xdd, 0x82, 0xca, + 0x7d, 0x16, 0xec, 0xb8, 0x96, 0x4c, 0x95, 0xcf, 0x8c, 0x86, 0xfa, 0x54, 0x0f, 0x21, 0xca, 0xad, + 0x49, 0xd2, 0x90, 0xc7, 0x40, 0x56, 0x2d, 0xe6, 0x04, 0x76, 0xb0, 0xb7, 0x18, 0x04, 0x9e, 0xdd, + 0x1e, 0x04, 0xcc, 0x97, 0x7a, 0xbb, 0x30, 0x76, 0x41, 0xdf, 0xc4, 0xb2, 0x30, 0x66, 0xc7, 0x67, + 0xcc, 0x88, 0x3c, 0x16, 0xfb, 0xbf, 0x43, 0xbd, 0x22, 0x68, 0x68, 0x86, 0x58, 0xf2, 0x09, 0xd4, + 0xee, 0xdf, 0x5b, 0x5c, 0x66, 0xbb, 0x76, 0x87, 0xc9, 0x4c, 0xda, 0xc5, 0x48, 0x8b, 0x21, 0x22, + 0x52, 0x09, 0x56, 0xb2, 0x7a, 0x8f, 0xcc, 0x96, 0x85, 0x70, 0xb5, 0x92, 0x15, 0x11, 0x1b, 0x5f, + 0xe5, 0x61, 0x8a, 0x32, 0xdf, 0x1d, 0x78, 0x31, 0x27, 0xb9, 0x01, 0x25, 0xa5, 0x8c, 0x82, 0x61, + 0x7a, 0x2a, 0x77, 0x8f, 0x78, 0xb2, 0x0a, 0x13, 0x2b, 0x4f, 0xfb, 0xb6, 0xc7, 0x7c, 0x69, 0x9b, + 0x83, 0x42, 0x92, 0xb3, 0x32, 0x24, 0x99, 0x60, 0x82, 0x45, 0xc6, 0x20, 0xe2, 0x1f, 0xf2, 0x01, + 0xd4, 0x1e, 0xf6, 0x2d, 0x33, 0x60, 0x56, 0x63, 0x4f, 0xde, 0x57, 0xf1, 0xfb, 0x07, 0x02, 0xd8, + 0x6a, 0xef, 0xa9, 0xdf, 0x1f, 0x91, 0x92, 0xeb, 0x50, 0xdc, 0xda, 0x5a, 0x93, 0xa6, 0xc2, 0x92, + 0x78, 0x10, 0xa8, 0x45, 0x3b, 0x8e, 0x35, 0x7e, 0x5c, 0x00, 0xe0, 0x2b, 0x62, 0xc9, 0x63, 0x66, + 0x70, 0x34, 0xdb, 0xba, 0x01, 0xd5, 0x50, 0xcd, 0x72, 0x35, 0x6a, 0x21, 0x6f, 0x5a, 0xfd, 0xe9, + 0xb1, 0x43, 0x3c, 0xbf, 0x80, 0x50, 0xb7, 0x8b, 0xd9, 0xc5, 0x62, 0xd8, 0x1d, 0xe0, 0x71, 0x00, + 0x15, 0x70, 0xf2, 0x2e, 0xd4, 0xe4, 0x06, 0x74, 0x3d, 0x99, 0xf8, 0x12, 0x61, 0x4a, 0x08, 0xa4, + 0x31, 0xde, 0xf8, 0xc7, 0xbc, 0x50, 0xca, 0x32, 0xeb, 0xb2, 0xe3, 0xab, 0x14, 0xe3, 0x47, 0x79, + 0x20, 0x5c, 0xd8, 0x86, 0xe9, 0xfb, 0x4f, 0x5c, 0xcf, 0x5a, 0xda, 0x31, 0x9d, 0xed, 0x23, 0x99, + 0x8e, 0xf1, 0xe3, 0x12, 0x9c, 0x5d, 0x14, 0x41, 0x1b, 0xfb, 0xe1, 0x80, 0xf9, 0xc1, 0x31, 0x5f, + 0x6f, 0x37, 0x93, 0xeb, 0x0d, 0x03, 0x4e, 0x5c, 0x6f, 0x6a, 0xc0, 0x29, 0x56, 0xde, 0x5b, 0x50, + 0x93, 0x73, 0x5e, 0x5d, 0x96, 0x2b, 0x0f, 0x0f, 0x59, 0xdb, 0xa2, 0x31, 0x82, 0xbc, 0x07, 0x93, + 0xf2, 0x1f, 0xee, 0x6b, 0xc3, 0x34, 0x20, 0xae, 0x63, 0x9f, 0x03, 0x68, 0x02, 0x4d, 0xbe, 0x01, + 0x35, 0xbe, 0x38, 0xb7, 0x4d, 0xbe, 0x9c, 0x27, 0xe2, 0x76, 0x0a, 0x2b, 0x04, 0xaa, 0x2e, 0x21, + 0xa2, 0xe4, 0x0e, 0x5c, 0xe6, 0x7e, 0xab, 0xb1, 0x03, 0x17, 0xb9, 0x5f, 0xd5, 0x81, 0xcb, 0x2c, + 0xf0, 0xa7, 0x50, 0x5f, 0x74, 0x1c, 0x37, 0x30, 0xf9, 0xa1, 0xe5, 0xcb, 0xbc, 0xcd, 0xbe, 0x9e, + 0xfb, 0x3a, 0x16, 0xf9, 0x63, 0xfa, 0x4c, 0xd7, 0xad, 0x0a, 0x34, 0xfe, 0xa4, 0x00, 0x75, 0x7e, + 0x73, 0xbc, 0xe7, 0x7a, 0x4f, 0x4c, 0xef, 0x68, 0xc2, 0xe9, 0xe4, 0xa1, 0x5e, 0x3c, 0xc4, 0x25, + 0x2c, 0x3e, 0x52, 0x4b, 0xcf, 0x71, 0xa4, 0xf2, 0xf0, 0x96, 0xdf, 0xc0, 0xcb, 0x71, 0x5c, 0x85, + 0xb7, 0x6f, 0x84, 0x1a, 0xbf, 0x5d, 0x00, 0xf8, 0xde, 0x9d, 0x3b, 0xaf, 0xb1, 0x82, 0x8c, 0x3f, + 0xce, 0xc3, 0x19, 0x99, 0x6f, 0x51, 0xfa, 0xa2, 0x26, 0xc2, 0xe4, 0x56, 0x3e, 0xce, 0x23, 0xc9, + 0xa4, 0x16, 0x0d, 0x71, 0x64, 0x1e, 0xaa, 0x2b, 0x4f, 0xed, 0x00, 0x43, 0x4e, 0xa5, 0x31, 0x8a, + 0x49, 0x98, 0xda, 0x52, 0x12, 0xd2, 0x91, 0xf7, 0xc2, 0x4c, 0x52, 0x31, 0xde, 0x54, 0x9c, 0x61, + 0x25, 0x33, 0x9b, 0x64, 0xfc, 0x7d, 0x09, 0x4a, 0x2b, 0x4f, 0x59, 0xe7, 0x98, 0x9b, 0x46, 0xb9, + 0x59, 0x97, 0x0e, 0x79, 0xb3, 0x7e, 0x91, 0x6c, 0xf6, 0x87, 0xb1, 0x3d, 0x2b, 0xc9, 0xe1, 0x53, + 0x96, 0x4f, 0x0f, 0x1f, 0x5a, 0xfa, 0xf8, 0x15, 0x43, 0x7e, 0x52, 0x84, 0xe2, 0xe6, 0xd2, 0xc6, + 0xc9, 0xba, 0x39, 0xd2, 0x75, 0x73, 0x70, 0xea, 0xd1, 0x80, 0xca, 0xa2, 0xd0, 0x51, 0x35, 0xae, + 0x94, 0x9a, 0x08, 0xa1, 0x12, 0x63, 0x7c, 0x5e, 0x80, 0xda, 0xe6, 0xa0, 0xed, 0xef, 0xf9, 0x01, + 0xeb, 0x1d, 0x73, 0x6b, 0x5e, 0x96, 0xb1, 0x4d, 0x29, 0xd6, 0x06, 0xb6, 0xa9, 0x8a, 0x88, 0xe6, + 0x7a, 0xe8, 0x19, 0x95, 0xdb, 0x73, 0xe4, 0x19, 0x43, 0x7f, 0xf8, 0x77, 0x05, 0x98, 0x5a, 0xea, + 0xda, 0xcc, 0x09, 0x96, 0x6d, 0x5f, 0xde, 0xad, 0x8f, 0xb9, 0x56, 0x0e, 0x97, 0x34, 0xf8, 0x1a, + 0xd5, 0x76, 0xe3, 0x77, 0x0a, 0x50, 0x5f, 0x1c, 0x04, 0x3b, 0x8b, 0x01, 0x1e, 0x2e, 0xaf, 0xe5, + 0x31, 0xff, 0xf3, 0x3c, 0x68, 0x94, 0xf9, 0x2c, 0x08, 0x83, 0x95, 0x2d, 0xf7, 0x31, 0x73, 0x5e, + 0x42, 0x94, 0xa0, 0xde, 0xf6, 0x0b, 0x2f, 0x78, 0xdb, 0x0f, 0x95, 0x5a, 0x7c, 0xce, 0xa8, 0x87, + 0xc7, 0x91, 0x3c, 0x08, 0x78, 0x45, 0xa6, 0xf1, 0x12, 0xc2, 0xe1, 0xa3, 0x9c, 0xc6, 0xbf, 0xe4, + 0x61, 0x66, 0xcb, 0xe3, 0x27, 0xba, 0x25, 0x0f, 0xf6, 0x63, 0x6e, 0x97, 0xf1, 0x09, 0x1d, 0x73, + 0x0b, 0xfd, 0x5b, 0x1e, 0x2e, 0x26, 0x27, 0xf4, 0x2a, 0x78, 0x81, 0x7f, 0xcd, 0xc3, 0xb9, 0x6f, + 0xdb, 0xc1, 0xce, 0xa0, 0x1d, 0x65, 0x98, 0x5e, 0xbd, 0x19, 0x1d, 0xf3, 0x95, 0xf7, 0xd3, 0x3c, + 0x9c, 0x5d, 0x5f, 0x5d, 0x5e, 0x7a, 0x55, 0x2c, 0x34, 0x36, 0x9f, 0x57, 0xc0, 0x3e, 0x9b, 0x8b, + 0xf7, 0xd7, 0x5e, 0x25, 0xfb, 0x24, 0xe6, 0x73, 0xcc, 0xed, 0xf3, 0x7b, 0x15, 0xa8, 0xf3, 0x00, + 0x57, 0x26, 0x29, 0x5f, 0xeb, 0x2b, 0xff, 0x3c, 0xd4, 0xa5, 0x1a, 0x30, 0xb6, 0x2c, 0xc7, 0x8f, + 0xff, 0x3c, 0x01, 0x6e, 0x61, 0x8c, 0xa9, 0x12, 0xf1, 0xd0, 0xeb, 0x3b, 0xcc, 0x6b, 0xab, 0xed, + 0x15, 0xbb, 0xcc, 0x6b, 0x53, 0x84, 0x92, 0xb5, 0xb8, 0x10, 0xb5, 0xb8, 0xb1, 0x8a, 0xef, 0x7e, + 0x64, 0xc8, 0x8a, 0x0f, 0x99, 0x3c, 0x89, 0x6b, 0x99, 0x7d, 0x5b, 0xbc, 0x18, 0x52, 0x1f, 0x0c, + 0xa5, 0x39, 0xc9, 0x03, 0x98, 0x0e, 0x61, 0xf1, 0x03, 0x9e, 0x6a, 0x86, 0xb8, 0xac, 0xa7, 0x3b, + 0xe3, 0xac, 0xe4, 0x43, 0x98, 0x0c, 0x81, 0x1f, 0xdb, 0xf8, 0xbc, 0x80, 0x8b, 0x7a, 0x63, 0x34, + 0xd4, 0x2f, 0x44, 0xa2, 0x1e, 0xdb, 0x89, 0x6e, 0xb3, 0x04, 0x83, 0x2a, 0x00, 0xe3, 0x4f, 0xc8, + 0x10, 0x90, 0x2a, 0xb2, 0x25, 0x18, 0xc8, 0x37, 0x50, 0x40, 0xdf, 0x75, 0x7c, 0x86, 0xc9, 0xbe, + 0x3a, 0xf6, 0x1e, 0x60, 0xc9, 0xcb, 0x93, 0x70, 0xd1, 0x61, 0x92, 0x20, 0x23, 0xeb, 0x00, 0x71, + 0x52, 0x46, 0xb6, 0xde, 0x3d, 0x77, 0xba, 0x48, 0x11, 0x61, 0xfc, 0x7f, 0x01, 0xce, 0x2c, 0xf6, + 0xfb, 0x27, 0xaf, 0x74, 0x5e, 0x56, 0x63, 0xc3, 0x1c, 0xc0, 0xc6, 0xa0, 0xdd, 0xb5, 0x3b, 0x4a, + 0x97, 0x0a, 0xb6, 0x0d, 0xf5, 0x11, 0x2a, 0x1a, 0x55, 0x14, 0x12, 0xe3, 0xf3, 0xa2, 0x6a, 0x01, + 0x7c, 0x9d, 0x70, 0x62, 0x81, 0xf2, 0xa1, 0x5c, 0xe1, 0x69, 0x55, 0x99, 0xb2, 0x89, 0x4f, 0x56, + 0x8e, 0xc2, 0x0e, 0xda, 0x0e, 0x47, 0xb5, 0x6c, 0x8b, 0xa6, 0x68, 0x8d, 0xff, 0xc9, 0xc3, 0x74, + 0x6c, 0x8e, 0x97, 0x71, 0x38, 0xcc, 0x01, 0x88, 0x8c, 0x41, 0x94, 0xd5, 0x3f, 0x25, 0x56, 0x84, + 0x8f, 0x50, 0xd9, 0x48, 0x16, 0x93, 0x44, 0x29, 0xbe, 0x62, 0x66, 0x8a, 0xef, 0x26, 0x54, 0xa9, + 0xf9, 0xe4, 0x93, 0x01, 0xf3, 0xf6, 0x64, 0xda, 0x0b, 0xf3, 0x5a, 0x9e, 0xf9, 0xa4, 0xf5, 0x43, + 0x0e, 0xa4, 0x11, 0x9a, 0x18, 0x51, 0xf3, 0x83, 0x92, 0xc9, 0x11, 0xcd, 0x0f, 0x61, 0xcb, 0x83, + 0xf1, 0x47, 0x05, 0x98, 0x5a, 0x36, 0x03, 0xb3, 0x6d, 0xfa, 0x71, 0xcb, 0xc0, 0x37, 0xe1, 0x4c, + 0x08, 0xe3, 0xe6, 0xb1, 0xa3, 0x07, 0xd0, 0xa7, 0x47, 0x43, 0x1d, 0xac, 0x76, 0xcb, 0x17, 0x50, + 0x9a, 0x26, 0x23, 0xbf, 0x1e, 0x4b, 0x8b, 0x1e, 0xc6, 0x16, 0xe2, 0x4d, 0x60, 0xb5, 0x5b, 0x7d, + 0x09, 0xa6, 0x63, 0x84, 0xe4, 0x16, 0xd4, 0x43, 0xd8, 0x43, 0xba, 0x2a, 0xe7, 0x8f, 0x1f, 0x6d, + 0xb5, 0x5b, 0x03, 0xcf, 0xa6, 0x2a, 0x9a, 0xcc, 0xc1, 0x64, 0xf8, 0xaf, 0x92, 0x03, 0xc4, 0xba, + 0x8a, 0xd5, 0x16, 0xaf, 0xd5, 0x13, 0x04, 0x2a, 0x03, 0xee, 0x90, 0x72, 0x82, 0x01, 0x5f, 0x8f, + 0x27, 0x08, 0x8c, 0x9f, 0x16, 0x61, 0x26, 0x9e, 0xe0, 0x89, 0x87, 0x7c, 0x39, 0xfb, 0x33, 0xce, + 0xb6, 0x55, 0x9e, 0xa3, 0xea, 0xd8, 0x80, 0x6a, 0x68, 0x0a, 0x59, 0x26, 0x89, 0xae, 0x8a, 0xe9, + 0xe5, 0x9b, 0x56, 0x7d, 0x88, 0x37, 0xbe, 0x28, 0x8c, 0xd9, 0x53, 0x6c, 0x94, 0x63, 0x69, 0x4f, + 0x55, 0x23, 0xa5, 0x17, 0xd3, 0x08, 0x99, 0x87, 0x53, 0xe1, 0xdf, 0xc2, 0xa3, 0x94, 0x95, 0xb6, + 0xca, 0xb6, 0x74, 0x28, 0x49, 0x12, 0xe3, 0xf7, 0x0b, 0x40, 0x52, 0x5a, 0x3c, 0xb6, 0x8f, 0x63, + 0x5e, 0x82, 0x0e, 0x8d, 0xbf, 0xce, 0xc3, 0xf4, 0x58, 0xbf, 0x16, 0x79, 0x1f, 0x40, 0x40, 0x94, + 0xde, 0x2b, 0xec, 0xb9, 0x88, 0x7b, 0xb8, 0x84, 0x8f, 0x52, 0xc8, 0xc8, 0x1c, 0x54, 0xc5, 0x7f, + 0xd1, 0xaf, 0x46, 0xa4, 0x59, 0x06, 0x03, 0xdb, 0xa2, 0x11, 0x51, 0x3c, 0x0a, 0xfe, 0xce, 0x48, + 0x31, 0x93, 0x25, 0xd8, 0xeb, 0x47, 0xa3, 0x70, 0x32, 0xe3, 0x8b, 0x3c, 0x4c, 0x46, 0x1f, 0xbc, + 0x68, 0x1d, 0x95, 0xe9, 0x2a, 0xb2, 0xf5, 0xad, 0xf8, 0xac, 0xd6, 0xb7, 0x94, 0x43, 0x90, 0xbd, + 0x6e, 0xff, 0x94, 0x87, 0x33, 0x11, 0xed, 0x11, 0xb6, 0x3d, 0x1d, 0x7a, 0x22, 0x3f, 0xb9, 0x00, + 0xe5, 0x75, 0x87, 0xad, 0x3f, 0x22, 0x77, 0x94, 0x1e, 0x4b, 0xf9, 0xfd, 0xd3, 0xea, 0x77, 0x20, + 0xa2, 0x99, 0xa3, 0x4a, 0x27, 0xe6, 0x82, 0xda, 0x0b, 0x27, 0xbf, 0x9d, 0xa8, 0x3c, 0x02, 0xd3, + 0xcc, 0x51, 0xb5, 0x67, 0x6e, 0x41, 0x6d, 0x16, 0x93, 0xdf, 0x9d, 0xe0, 0x12, 0x98, 0x90, 0x4b, + 0x6a, 0x77, 0x2d, 0xab, 0x37, 0x2b, 0xfd, 0xa2, 0x6c, 0x9c, 0xa2, 0x99, 0xa3, 0xd9, 0x3d, 0x5d, + 0x89, 0xdf, 0x06, 0x90, 0x47, 0xca, 0x4c, 0x6a, 0x03, 0x23, 0xae, 0x99, 0xa3, 0xc9, 0xdf, 0x11, + 0xb8, 0x9b, 0x78, 0xd8, 0x2d, 0xcf, 0x91, 0xb3, 0x29, 0x56, 0x8e, 0x6a, 0xe6, 0x68, 0xea, 0x09, + 0x78, 0xe2, 0x95, 0xb1, 0x3c, 0x49, 0xd2, 0x83, 0x22, 0x4e, 0x19, 0x54, 0xbc, 0x48, 0xfe, 0xcd, + 0xd4, 0x93, 0x5c, 0x59, 0x52, 0x3f, 0x97, 0x62, 0x16, 0xc8, 0x66, 0x8e, 0xa6, 0x1e, 0xf0, 0xce, + 0x86, 0x8f, 0x4f, 0x65, 0x57, 0xd2, 0x69, 0x25, 0xd3, 0x61, 0x7f, 0xc6, 0xb5, 0x14, 0x3e, 0x4e, + 0x5d, 0x50, 0x1f, 0x1d, 0xca, 0xe7, 0x61, 0x24, 0x35, 0xca, 0x8a, 0x63, 0x71, 0xeb, 0x28, 0xfe, + 0xf7, 0xa3, 0xf4, 0x5b, 0x1f, 0xf9, 0xe8, 0xeb, 0x7c, 0x8a, 0x53, 0x62, 0x9b, 0x39, 0x9a, 0x7e, + 0x1b, 0x74, 0x37, 0xf1, 0xce, 0x44, 0x46, 0x97, 0x69, 0xad, 0x72, 0x94, 0xa2, 0x55, 0x7c, 0x91, + 0xf2, 0x51, 0xfa, 0xe1, 0x83, 0x76, 0x2a, 0x73, 0x68, 0x89, 0x55, 0x86, 0x0e, 0x1f, 0x4a, 0xdc, + 0x4d, 0xb4, 0xd6, 0x6b, 0xa7, 0xb3, 0x87, 0x36, 0x03, 0x53, 0x1d, 0x5a, 0x34, 0xe1, 0x27, 0x9a, + 0xbc, 0xb5, 0x33, 0x99, 0x06, 0x45, 0x9c, 0x62, 0x50, 0xd1, 0x10, 0x7e, 0x37, 0xd1, 0xcb, 0xa5, + 0x4d, 0x25, 0x07, 0x55, 0x50, 0x7c, 0x50, 0xb5, 0xeb, 0x6b, 0x41, 0x6d, 0x71, 0xd2, 0xa6, 0x93, + 0x06, 0x8a, 0x31, 0xdc, 0x40, 0x4a, 0x2b, 0x94, 0x8e, 0xed, 0x13, 0x1a, 0x41, 0xf2, 0x7a, 0xf4, + 0x85, 0x4b, 0x1b, 0xcd, 0x1c, 0xc5, 0xc6, 0x0a, 0x43, 0x34, 0xe6, 0x68, 0x67, 0x91, 0x62, 0x32, + 0xa4, 0xe0, 0xb0, 0x66, 0x8e, 0x8a, 0xa6, 0x9d, 0x3b, 0x4a, 0xed, 0x5e, 0x9b, 0x49, 0xba, 0x88, + 0x08, 0xc1, 0x5d, 0x44, 0x5c, 0xe1, 0xbf, 0x37, 0x5e, 0xdf, 0xd6, 0xce, 0x25, 0xcf, 0xba, 0x34, + 0xbe, 0x99, 0xa3, 0xe3, 0x35, 0xf1, 0xbb, 0x89, 0x92, 0xaf, 0x76, 0x3e, 0xa9, 0x2e, 0x05, 0xc5, + 0xd5, 0xa5, 0x16, 0x87, 0xd7, 0x33, 0x1b, 0x29, 0xb5, 0x0b, 0x28, 0xe0, 0x8d, 0x48, 0xc0, 0x38, + 0x49, 0x33, 0x47, 0x33, 0x5b, 0x30, 0x3f, 0xdd, 0xbf, 0xf0, 0xaa, 0x69, 0x28, 0xf5, 0xaa, 0xb2, + 0xb9, 0x32, 0xe9, 0x9a, 0x39, 0xba, 0x7f, 0xf1, 0x76, 0x41, 0xad, 0x81, 0x6a, 0x17, 0x93, 0xf6, + 0x8d, 0x31, 0xdc, 0xbe, 0x4a, 0xad, 0x74, 0x41, 0x2d, 0x39, 0x6a, 0x97, 0xc6, 0xb9, 0x62, 0xa7, + 0xaa, 0x94, 0x26, 0x69, 0x76, 0x85, 0x4f, 0x7b, 0x03, 0xf9, 0x2f, 0x87, 0xfc, 0x59, 0x34, 0xcd, + 0x1c, 0xcd, 0xae, 0x0e, 0xd2, 0xec, 0x22, 0x9b, 0x76, 0xf9, 0x20, 0x99, 0xd1, 0xd7, 0x65, 0x17, + 0xe8, 0xcc, 0x03, 0xea, 0x5c, 0xda, 0x9b, 0xc9, 0x44, 0xd4, 0xbe, 0x84, 0xcd, 0x1c, 0x3d, 0xa0, + 0x5a, 0xf6, 0x70, 0x9f, 0xa2, 0x93, 0x76, 0x25, 0xd9, 0xbb, 0x94, 0x49, 0xd4, 0xcc, 0xd1, 0x7d, + 0x4a, 0x56, 0x0f, 0xf7, 0xa9, 0xfc, 0x68, 0xfa, 0x81, 0x62, 0x23, 0x7d, 0xec, 0x53, 0x37, 0x5a, + 0xcf, 0x2c, 0xbf, 0x68, 0x57, 0x93, 0xab, 0x3a, 0x83, 0x84, 0xaf, 0xea, 0xac, 0xc2, 0xcd, 0x7a, + 0x66, 0xfd, 0x43, 0xbb, 0x76, 0x80, 0xc0, 0xe8, 0x1b, 0x33, 0x2b, 0x27, 0xeb, 0x99, 0x05, 0x08, + 0xcd, 0x48, 0x0a, 0xcc, 0x20, 0xe1, 0x02, 0xb3, 0x4a, 0x17, 0xeb, 0x99, 0x15, 0x00, 0xed, 0xfa, + 0x01, 0x02, 0xe3, 0x2f, 0xcc, 0xaa, 0x1d, 0xdc, 0x4d, 0xa4, 0xe0, 0xb5, 0xb7, 0x92, 0x2e, 0x45, + 0x41, 0x71, 0x97, 0xa2, 0x26, 0xeb, 0x97, 0xc6, 0xb2, 0x96, 0xda, 0xdb, 0xc9, 0x00, 0x20, 0x85, + 0x6e, 0xe6, 0xe8, 0x58, 0x9e, 0x73, 0x69, 0x2c, 0xf1, 0xa6, 0xdd, 0xd8, 0x4f, 0x08, 0xa2, 0x93, + 0x42, 0x44, 0xaa, 0x6e, 0x35, 0x23, 0x5d, 0xa4, 0xbd, 0x93, 0xbc, 0x09, 0x8e, 0x11, 0x34, 0x73, + 0x34, 0x23, 0xc9, 0x44, 0xb3, 0xb3, 0x0d, 0xda, 0x6c, 0x72, 0xdb, 0x66, 0xd1, 0xf0, 0x6d, 0x9b, + 0x99, 0xa9, 0x58, 0xcb, 0x8a, 0xd5, 0xb4, 0x9b, 0xc9, 0x3b, 0xdb, 0x38, 0x05, 0xbf, 0xb3, 0x65, + 0xc4, 0x78, 0x34, 0x3b, 0x7e, 0xd6, 0x7e, 0xe5, 0xc0, 0x2f, 0x44, 0x9a, 0x8c, 0x2f, 0x14, 0xb1, + 0x77, 0x7c, 0xad, 0x7a, 0xd8, 0xef, 0xba, 0xa6, 0xa5, 0xbd, 0x9b, 0x79, 0xad, 0x12, 0x48, 0xe5, + 0x5a, 0x25, 0x00, 0xfc, 0x02, 0xa0, 0xc6, 0x32, 0xda, 0xad, 0xe4, 0x05, 0x40, 0xc5, 0xf1, 0x0b, + 0x40, 0x22, 0xee, 0x59, 0x1a, 0x8b, 0x20, 0xb4, 0xf7, 0x92, 0x0b, 0x20, 0x85, 0xe6, 0x0b, 0x20, + 0x05, 0x6a, 0x4c, 0x40, 0x79, 0x85, 0x13, 0x1b, 0x7f, 0x9a, 0x87, 0xc9, 0xcd, 0xc0, 0x63, 0x66, + 0x4f, 0xa6, 0x2c, 0x2e, 0x41, 0x55, 0x7c, 0x64, 0xf8, 0x53, 0x88, 0x34, 0xfa, 0x9f, 0xdc, 0x80, + 0xd3, 0x6b, 0xa6, 0x1f, 0x20, 0xa7, 0xf2, 0x33, 0x35, 0x34, 0x05, 0x25, 0x6b, 0x82, 0x4e, 0xf0, + 0xe1, 0xcf, 0x05, 0x14, 0x9f, 0xf9, 0x36, 0xa7, 0xca, 0xc3, 0x0c, 0x7c, 0x90, 0x93, 0xe2, 0x35, + 0x46, 0x79, 0x18, 0x53, 0xdf, 0x8b, 0x47, 0x4c, 0xeb, 0x63, 0x3f, 0xff, 0x28, 0x03, 0x90, 0xaf, + 0x19, 0x85, 0x8f, 0xfd, 0x78, 0xe4, 0x75, 0x28, 0x3e, 0x5c, 0x5d, 0x56, 0x9f, 0xff, 0x24, 0x7f, + 0x11, 0x93, 0x63, 0xc9, 0x3b, 0xd1, 0xed, 0xf8, 0x21, 0x5d, 0x93, 0xf9, 0x0a, 0x7c, 0xde, 0x3f, + 0xf0, 0xba, 0x54, 0x41, 0x35, 0xa6, 0xbe, 0xfc, 0xaf, 0x2b, 0xb9, 0x2f, 0xbf, 0xba, 0x92, 0xff, + 0xd9, 0x57, 0x57, 0xf2, 0xff, 0xf9, 0xd5, 0x95, 0x7c, 0xbb, 0x82, 0xca, 0x7a, 0xff, 0x17, 0x01, + 0x00, 0x00, 0xff, 0xff, 0xf7, 0xd0, 0x29, 0x5d, 0x2e, 0x54, 0x00, 0x00, } diff --git a/api/types/events/events.proto b/api/types/events/events.proto index fac686fdf120b..975c9dd9daf84 100644 --- a/api/types/events/events.proto +++ b/api/types/events/events.proto @@ -35,6 +35,8 @@ message Metadata { message SessionMetadata { // SessionID is a unique UUID of the session. string SessionID = 1 [ (gogoproto.jsontag) = "sid" ]; + // WithMFA is a UUID of an MFA device used to start this session. + string WithMFA = 2 [ (gogoproto.jsontag) = "with_mfa,omitempty" ]; } // UserMetadata is a common user event metadata diff --git a/lib/auth/auth.go b/lib/auth/auth.go index 48f790f8c6f1c..bc9663a7acc22 100644 --- a/lib/auth/auth.go +++ b/lib/auth/auth.go @@ -478,16 +478,18 @@ type certRequest struct { // dbName is the optional database name which, if provided, will be used // as a default database. dbName string - // mfaVerified is set when this certRequest was created immediately after - // an MFA check. - mfaVerified bool + // mfaVerified is the UUID of an MFA device when this certRequest was + // created immediately after an MFA check. + mfaVerified string // clientIP is an IP of the client requesting the certificate. clientIP string } type certRequestOption func(*certRequest) -func certRequestMFAVerified(r *certRequest) { r.mfaVerified = true } +func certRequestMFAVerified(mfaID string) certRequestOption { + return func(r *certRequest) { r.mfaVerified = mfaID } +} func certRequestClientIP(ip string) certRequestOption { return func(r *certRequest) { r.clientIP = ip } } @@ -2026,21 +2028,19 @@ func (a *Server) mfaAuthChallenge(ctx context.Context, user string, u2fStorage u return challenge, nil } -func (a *Server) validateMFAAuthResponse(ctx context.Context, user string, resp *proto.MFAAuthenticateResponse, u2fStorage u2f.AuthenticationStorage) error { - var err error +func (a *Server) validateMFAAuthResponse(ctx context.Context, user string, resp *proto.MFAAuthenticateResponse, u2fStorage u2f.AuthenticationStorage) (*types.MFADevice, error) { switch res := resp.Response.(type) { case *proto.MFAAuthenticateResponse_TOTP: - _, err = a.checkOTP(user, res.TOTP.Code) + return a.checkOTP(user, res.TOTP.Code) case *proto.MFAAuthenticateResponse_U2F: - _, err = a.checkU2F(ctx, user, u2f.AuthenticateChallengeResponse{ + return a.checkU2F(ctx, user, u2f.AuthenticateChallengeResponse{ KeyHandle: res.U2F.KeyHandle, ClientData: res.U2F.ClientData, SignatureData: res.U2F.Signature, }, u2fStorage) default: - err = trace.BadParameter("unknown or missing MFAAuthenticateResponse type %T", resp.Response) + return nil, trace.BadParameter("unknown or missing MFAAuthenticateResponse type %T", resp.Response) } - return trace.Wrap(err) } func (a *Server) checkU2F(ctx context.Context, user string, res u2f.AuthenticateChallengeResponse, u2fStorage u2f.AuthenticationStorage) (*types.MFADevice, error) { diff --git a/lib/auth/auth_test.go b/lib/auth/auth_test.go index 28d1c0ec7b0fd..4de01cc652e1d 100644 --- a/lib/auth/auth_test.go +++ b/lib/auth/auth_test.go @@ -45,6 +45,7 @@ import ( "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" "github.com/gravitational/teleport/lib/services/suite" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -225,9 +226,8 @@ func (s *AuthSuite) TestAuthenticateSSHUser(c *C) { // Verify the public key and principals in SSH cert. inSSHPub, _, _, _, err := ssh.ParseAuthorizedKey(pub) c.Assert(err, IsNil) - gotSSHCertPub, _, _, _, err := ssh.ParseAuthorizedKey(resp.Cert) + gotSSHCert, err := sshutils.ParseCertificate(resp.Cert) c.Assert(err, IsNil) - gotSSHCert := gotSSHCertPub.(*ssh.Certificate) c.Assert(gotSSHCert.Key, DeepEquals, inSSHPub) c.Assert(gotSSHCert.ValidPrincipals, DeepEquals, []string{user}) // Verify the public key and Subject in TLS cert. @@ -567,9 +567,8 @@ func (s *AuthSuite) TestTokensCRUD(c *C) { c.Assert(err, IsNil) // along the way, make sure that additional principals work - key, _, _, _, err := ssh.ParseAuthorizedKey(keys.Cert) + hostCert, err := sshutils.ParseCertificate(keys.Cert) c.Assert(err, IsNil) - hostCert := key.(*ssh.Certificate) comment := Commentf("can't find example.com in %v", hostCert.ValidPrincipals) c.Assert(utils.SliceContainsStr(hostCert.ValidPrincipals, "example.com"), Equals, true, comment) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index e9f3715f7179c..11ff9efa0b22c 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -2512,7 +2512,7 @@ func (a *ServerWithRoles) UpsertKubeService(ctx context.Context, s services.Serv } for _, kube := range s.GetKubernetesClusters() { - if err := a.context.Checker.CheckAccessToKubernetes(s.GetNamespace(), kube, a.context.Identity.GetIdentity().MFAVerified); err != nil { + if err := a.context.Checker.CheckAccessToKubernetes(s.GetNamespace(), kube, a.context.Identity.GetIdentity().MFAVerified != ""); err != nil { return utils.OpaqueAccessDenied(err) } } diff --git a/lib/auth/grpcserver.go b/lib/auth/grpcserver.go index 46428a7251c15..4ac9e8ebca005 100644 --- a/lib/auth/grpcserver.go +++ b/lib/auth/grpcserver.go @@ -1363,7 +1363,7 @@ func addMFADeviceAuthChallenge(gctx *grpcContext, stream proto.AuthService_AddMF } // Only validate if there was a challenge. if authChallenge.TOTP != nil || len(authChallenge.U2F) > 0 { - if err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage); err != nil { + if _, err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage); err != nil { return trace.Wrap(err) } } @@ -1581,7 +1581,7 @@ func deleteMFADeviceAuthChallenge(gctx *grpcContext, stream proto.AuthService_De if authResp == nil { return trace.BadParameter("expected MFAAuthenticateResponse, got %T", req) } - if err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage); err != nil { + if _, err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage); err != nil { return trace.Wrap(err) } return nil @@ -1649,12 +1649,13 @@ func (g *GRPCServer) GenerateUserSingleUseCerts(stream proto.AuthService_Generat // 2. send MFAChallenge // 3. receive and validate MFAResponse - if err := userSingleUseCertsAuthChallenge(actx, stream); err != nil { + mfaDev, err := userSingleUseCertsAuthChallenge(actx, stream) + if err != nil { return trail.ToGRPC(err) } // Generate the cert. - respCert, err := userSingleUseCertsGenerate(stream.Context(), actx, *initReq) + respCert, err := userSingleUseCertsGenerate(stream.Context(), actx, *initReq, mfaDev) if err != nil { return trail.ToGRPC(err) } @@ -1694,40 +1695,41 @@ func validateUserSingleUseCertRequest(req *proto.UserCertsRequest, clock clockwo return nil } -func userSingleUseCertsAuthChallenge(gctx *grpcContext, stream proto.AuthService_GenerateUserSingleUseCertsServer) error { +func userSingleUseCertsAuthChallenge(gctx *grpcContext, stream proto.AuthService_GenerateUserSingleUseCertsServer) (*types.MFADevice, error) { ctx := stream.Context() auth := gctx.authServer user := gctx.User.GetName() u2fStorage, err := u2f.InMemoryAuthenticationStorage(auth.Identity) if err != nil { - return trace.Wrap(err) + return nil, trace.Wrap(err) } authChallenge, err := auth.mfaAuthChallenge(ctx, user, u2fStorage) if err != nil { - return trace.Wrap(err) + return nil, trace.Wrap(err) } if err := stream.Send(&proto.UserSingleUseCertsResponse{ Response: &proto.UserSingleUseCertsResponse_MFAChallenge{MFAChallenge: authChallenge}, }); err != nil { - return trace.Wrap(err) + return nil, trace.Wrap(err) } req, err := stream.Recv() if err != nil { - return trace.Wrap(err) + return nil, trace.Wrap(err) } authResp := req.GetMFAResponse() if authResp == nil { - return trace.BadParameter("expected MFAAuthenticateResponse, got %T", req.Request) + return nil, trace.BadParameter("expected MFAAuthenticateResponse, got %T", req.Request) } - if err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage); err != nil { - return trace.Wrap(err) + mfaDev, err := auth.validateMFAAuthResponse(ctx, user, authResp, u2fStorage) + if err != nil { + return nil, trace.Wrap(err) } - return nil + return mfaDev, nil } -func userSingleUseCertsGenerate(ctx context.Context, actx *grpcContext, req proto.UserCertsRequest) (*proto.SingleUseUserCert, error) { +func userSingleUseCertsGenerate(ctx context.Context, actx *grpcContext, req proto.UserCertsRequest, mfaDev *types.MFADevice) (*proto.SingleUseUserCert, error) { // Get the client IP. clientPeer, ok := peer.FromContext(ctx) if !ok { @@ -1739,7 +1741,7 @@ func userSingleUseCertsGenerate(ctx context.Context, actx *grpcContext, req prot } // Generate the cert. - certs, err := actx.generateUserCerts(ctx, req, certRequestMFAVerified, certRequestClientIP(clientIP)) + certs, err := actx.generateUserCerts(ctx, req, certRequestMFAVerified(mfaDev.Id), certRequestClientIP(clientIP)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index 880377118a612..adf4df262a6fb 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -31,7 +31,6 @@ import ( "github.com/pquerna/otp" "github.com/pquerna/otp/totp" "github.com/stretchr/testify/require" - "golang.org/x/crypto/ssh" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/client/proto" @@ -40,6 +39,7 @@ import ( "github.com/gravitational/teleport/lib/auth/mocku2f" "github.com/gravitational/teleport/lib/auth/u2f" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" ) @@ -619,6 +619,12 @@ func TestGenerateUserSingleUseCert(t *testing.T) { return wantDev }, }) + // Fetch MFA device ID. + devs, err := srv.Auth().GetMFADevices(ctx, user.GetName()) + require.NoError(t, err) + require.Len(t, devs, 1) + u2fDevID := devs[0].Id + u2fChallengeHandler := func(t *testing.T, req *proto.MFAAuthenticateChallenge) *proto.MFAAuthenticateResponse { require.Len(t, req.U2F, 1) chal := req.U2F[0] @@ -660,12 +666,10 @@ func TestGenerateUserSingleUseCert(t *testing.T) { crt := c.GetSSH() require.NotEmpty(t, crt) - key, _, _, _, err := ssh.ParseAuthorizedKey(crt) + cert, err := sshutils.ParseCertificate(crt) require.NoError(t, err) - cert, ok := key.(*ssh.Certificate) - require.True(t, ok) - require.Contains(t, cert.Extensions, teleport.CertExtensionMFAVerified) + require.Equal(t, cert.Extensions[teleport.CertExtensionMFAVerified], u2fDevID) require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionClientIP]).IsLoopback()) require.Equal(t, cert.ValidBefore, uint64(clock.Now().Add(teleport.UserSingleUseCertTTL).Unix())) }, @@ -694,7 +698,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) { identity, err := tlsca.FromSubject(cert.Subject, cert.NotAfter) require.NoError(t, err) - require.True(t, identity.MFAVerified) + require.Equal(t, identity.MFAVerified, u2fDevID) require.True(t, net.ParseIP(identity.ClientIP).IsLoopback()) require.Equal(t, identity.Usage, []string{teleport.UsageKubeOnly}) require.Equal(t, identity.KubernetesCluster, "kube-a") @@ -726,7 +730,7 @@ func TestGenerateUserSingleUseCert(t *testing.T) { identity, err := tlsca.FromSubject(cert.Subject, cert.NotAfter) require.NoError(t, err) - require.True(t, identity.MFAVerified) + require.Equal(t, identity.MFAVerified, u2fDevID) require.True(t, net.ParseIP(identity.ClientIP).IsLoopback()) require.Equal(t, identity.Usage, []string{teleport.UsageDatabaseOnly}) require.Equal(t, identity.RouteToDatabase.ServiceName, "db-a") @@ -765,12 +769,10 @@ func TestGenerateUserSingleUseCert(t *testing.T) { crt := c.GetSSH() require.NotEmpty(t, crt) - key, _, _, _, err := ssh.ParseAuthorizedKey(crt) + cert, err := sshutils.ParseCertificate(crt) require.NoError(t, err) - cert, ok := key.(*ssh.Certificate) - require.True(t, ok) - require.Contains(t, cert.Extensions, teleport.CertExtensionMFAVerified) + require.Equal(t, cert.Extensions[teleport.CertExtensionMFAVerified], u2fDevID) require.True(t, net.ParseIP(cert.Extensions[teleport.CertExtensionClientIP]).IsLoopback()) require.Equal(t, cert.ValidBefore, uint64(clock.Now().Add(teleport.UserSingleUseCertTTL).Unix())) }, diff --git a/lib/auth/init.go b/lib/auth/init.go index c529769f91273..22cb523d814a5 100644 --- a/lib/auth/init.go +++ b/lib/auth/init.go @@ -1016,16 +1016,11 @@ func ReadSSHIdentityFromKeyPair(keyBytes, certBytes []byte) (*Identity, error) { return nil, trace.BadParameter("Cert: missing parameter") } - pubKey, _, _, _, err := ssh.ParseAuthorizedKey(certBytes) + cert, err := sshutils.ParseCertificate(certBytes) if err != nil { return nil, trace.BadParameter("failed to parse server certificate: %v", err) } - cert, ok := pubKey.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("expected ssh.Certificate, got %v", pubKey) - } - signer, err := ssh.ParsePrivateKey(keyBytes) if err != nil { return nil, trace.BadParameter("failed to parse private key: %v", err) diff --git a/lib/auth/init_test.go b/lib/auth/init_test.go index 2f7861fdb921d..973e28c08ea6b 100644 --- a/lib/auth/init_test.go +++ b/lib/auth/init_test.go @@ -90,10 +90,8 @@ func TestReadIdentity(t *testing.T) { TTL: ttl, }) require.NoError(t, err) - pk, _, _, _, err := ssh.ParseAuthorizedKey(bytes) + copy, err := sshutils.ParseCertificate(bytes) require.NoError(t, err) - copy, ok := pk.(*ssh.Certificate) - require.True(t, ok) require.Equal(t, uint64(expiryDate.Unix()), copy.ValidBefore) } diff --git a/lib/auth/native/native.go b/lib/auth/native/native.go index db5613a5d6908..71d11dc79f958 100644 --- a/lib/auth/native/native.go +++ b/lib/auth/native/native.go @@ -277,8 +277,8 @@ func (k *Keygen) GenerateUserCertWithoutValidation(c services.UserCertParams) ([ if c.PermitPortForwarding { cert.Permissions.Extensions[teleport.CertExtensionPermitPortForwarding] = "" } - if c.MFAVerified { - cert.Permissions.Extensions[teleport.CertExtensionMFAVerified] = "" + if c.MFAVerified != "" { + cert.Permissions.Extensions[teleport.CertExtensionMFAVerified] = c.MFAVerified } if c.ClientIP != "" { cert.Permissions.Extensions[teleport.CertExtensionClientIP] = c.ClientIP diff --git a/lib/auth/native/native_test.go b/lib/auth/native/native_test.go index f04ec767df5c1..c35e10a89a691 100644 --- a/lib/auth/native/native_test.go +++ b/lib/auth/native/native_test.go @@ -22,12 +22,11 @@ import ( "testing" "time" - "golang.org/x/crypto/ssh" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/lib/auth/test" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/services" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/utils" "github.com/jonboulle/clockwork" @@ -182,12 +181,9 @@ func (s *NativeSuite) TestBuildPrincipals(c *check.C) { }) c.Assert(err, check.IsNil) - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(hostCertificateBytes) + hostCertificate, err := sshutils.ParseCertificate(hostCertificateBytes) c.Assert(err, check.IsNil) - hostCertificate, ok := publicKey.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) - c.Assert(hostCertificate.ValidPrincipals, check.DeepEquals, tt.outValidPrincipals) } } @@ -232,15 +228,12 @@ func (s *NativeSuite) TestUserCertCompatibility(c *check.C) { }) c.Assert(err, check.IsNil, comment) - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(userCertificateBytes) + userCertificate, err := sshutils.ParseCertificate(userCertificateBytes) c.Assert(err, check.IsNil, comment) - - userCertificate, ok := publicKey.(*ssh.Certificate) - c.Assert(ok, check.Equals, true, comment) // Check that the signature algorithm is correct. c.Assert(userCertificate.Signature.Format, check.Equals, defaults.CASignatureAlgorithm) // check if we added the roles extension - _, ok = userCertificate.Extensions[teleport.CertExtensionTeleportRoles] + _, ok := userCertificate.Extensions[teleport.CertExtensionTeleportRoles] c.Assert(ok, check.Equals, tt.outHasRoles, comment) } } diff --git a/lib/auth/test/suite.go b/lib/auth/test/suite.go index b54e141f8b6c1..f13a63ce56b93 100644 --- a/lib/auth/test/suite.go +++ b/lib/auth/test/suite.go @@ -24,6 +24,7 @@ import ( "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/sshca" + "github.com/gravitational/teleport/lib/sshutils" "golang.org/x/crypto/ssh" @@ -75,12 +76,9 @@ func (s *AuthSuite) GenerateHostCert(c *check.C) { }) c.Assert(err, check.IsNil) - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(cert) + certificate, err := sshutils.ParseCertificate(cert) c.Assert(err, check.IsNil) - certificate, ok := publicKey.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) - // Check the valid time is not more than 1 minute before the current time. validAfter := time.Unix(int64(certificate.ValidAfter), 0) c.Assert(validAfter.Unix(), check.Equals, s.Clock.Now().UTC().Add(-1*time.Minute).Unix()) @@ -107,12 +105,9 @@ func (s *AuthSuite) GenerateUserCert(c *check.C) { }) c.Assert(err, check.IsNil) - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(cert) + certificate, err := sshutils.ParseCertificate(cert) c.Assert(err, check.IsNil) - certificate, ok := publicKey.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) - // Check the valid time is not more than 1 minute before the current time. validAfter := time.Unix(int64(certificate.ValidAfter), 0) c.Assert(validAfter.Unix(), check.Equals, s.Clock.Now().UTC().Add(-1*time.Minute).Unix()) @@ -177,10 +172,8 @@ func (s *AuthSuite) GenerateUserCert(c *check.C) { Roles: inRoles, }) c.Assert(err, check.IsNil) - parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(cert) + parsedCert, err := sshutils.ParseCertificate(cert) c.Assert(err, check.IsNil) - parsedCert, ok := parsedKey.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) outRoles, err := services.UnmarshalCertRoles(parsedCert.Extensions[teleport.CertExtensionTeleportRoles]) c.Assert(err, check.IsNil) c.Assert(outRoles, check.DeepEquals, inRoles) diff --git a/lib/auth/tls_test.go b/lib/auth/tls_test.go index 17353038015de..d1ca77736dca8 100644 --- a/lib/auth/tls_test.go +++ b/lib/auth/tls_test.go @@ -49,6 +49,7 @@ import ( "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/suite" "github.com/gravitational/teleport/lib/session" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -1502,12 +1503,9 @@ func (s *TLSSuite) TestWebSessionWithApprovedAccessRequest(c *check.C) { sess, err := web.ExtendWebSession(user, ws.GetName(), accessReq.GetMetadata().Name) c.Assert(err, check.IsNil) - pub, _, _, _, err := ssh.ParseAuthorizedKey(sess.GetPub()) + sshcert, err := sshutils.ParseCertificate(sess.GetPub()) c.Assert(err, check.IsNil) - sshcert, ok := pub.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) - // Roles extracted from cert should contain the initial role and the role assigned with access request. roles, _, err := services.ExtractFromCertificate(clt, sshcert) c.Assert(err, check.IsNil) @@ -1670,12 +1668,8 @@ func (s *TLSSuite) TestAccessRequest(c *check.C) { // certLogins extracts the logins from an ssh certificate certLogins := func(sshCert []byte) []string { - key, _, _, _, err := ssh.ParseAuthorizedKey(sshCert) + cert, err := sshutils.ParseCertificate(sshCert) c.Assert(err, check.IsNil) - - cert, ok := key.(*ssh.Certificate) - c.Assert(ok, check.Equals, true) - return cert.ValidPrincipals } @@ -1840,9 +1834,8 @@ func TestGenerateCerts(t *testing.T) { }) require.NoError(t, err) - key, _, _, _, err := ssh.ParseAuthorizedKey(certs.Cert) + hostCert, err := sshutils.ParseCertificate(certs.Cert) require.NoError(t, err) - hostCert := key.(*ssh.Certificate) require.Contains(t, hostCert.ValidPrincipals, "example.com") // sign server public keys for node @@ -1861,9 +1854,8 @@ func TestGenerateCerts(t *testing.T) { }) require.NoError(t, err) - key, _, _, _, err = ssh.ParseAuthorizedKey(certs.Cert) + hostCert, err = sshutils.ParseCertificate(certs.Cert) require.NoError(t, err) - hostCert = key.(*ssh.Certificate) require.Contains(t, hostCert.ValidPrincipals, "example.com") // attempt to elevate privileges by getting admin role in the certificate @@ -1937,9 +1929,8 @@ func TestGenerateCerts(t *testing.T) { require.NoError(t, err) parseCert := func(sshCert []byte) (*ssh.Certificate, time.Duration) { - parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(sshCert) + parsedCert, err := sshutils.ParseCertificate(sshCert) require.NoError(t, err) - parsedCert, _ := parsedKey.(*ssh.Certificate) validBefore := time.Unix(int64(parsedCert.ValidBefore), 0) return parsedCert, time.Until(validBefore) } @@ -2185,9 +2176,8 @@ func (s *TLSSuite) TestCertificateFormat(c *check.C) { }) c.Assert(err, check.IsNil) - parsedKey, _, _, _, err := ssh.ParseAuthorizedKey(re.Cert) + parsedCert, err := sshutils.ParseCertificate(re.Cert) c.Assert(err, check.IsNil) - parsedCert, _ := parsedKey.(*ssh.Certificate) _, ok := parsedCert.Extensions[teleport.CertExtensionTeleportRoles] c.Assert(ok, check.Equals, tt.outCertContainsRole) diff --git a/lib/client/api.go b/lib/client/api.go index b3dc0a81893a3..0f6258edf40a1 100644 --- a/lib/client/api.go +++ b/lib/client/api.go @@ -55,6 +55,7 @@ import ( "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/session" "github.com/gravitational/teleport/lib/shell" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/sshutils/scp" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -459,14 +460,10 @@ func readProfile(profileDir string, profileName string) (*ProfileStatus, error) if err != nil { return nil, trace.Wrap(err) } - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(key.Cert) + sshCert, err := sshutils.ParseCertificate(key.Cert) if err != nil { return nil, trace.Wrap(err) } - sshCert, ok := publicKey.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("no certificate found") - } // Extract from the certificate how much longer it will be valid for. validUntil := time.Unix(int64(sshCert.ValidBefore), 0) diff --git a/lib/client/interfaces.go b/lib/client/interfaces.go index 8f3d5573f21d8..6fb135acacc63 100644 --- a/lib/client/interfaces.go +++ b/lib/client/interfaces.go @@ -329,16 +329,7 @@ func (k *Key) AsAuthMethod() (ssh.AuthMethod, error) { // SSHCert returns parsed SSH certificate func (k *Key) SSHCert() (*ssh.Certificate, error) { - key, _, _, _, err := ssh.ParseAuthorizedKey(k.Cert) - if err != nil { - return nil, trace.Wrap(err) - } - - cert, ok := key.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("found key, not certificate") - } - return cert, nil + return sshutils.ParseCertificate(k.Cert) } // CheckCert makes sure the SSH certificate is valid. diff --git a/lib/kube/proxy/forwarder.go b/lib/kube/proxy/forwarder.go index 5b9fe1f1bce33..112ab7d2211b7 100644 --- a/lib/kube/proxy/forwarder.go +++ b/lib/kube/proxy/forwarder.go @@ -594,7 +594,7 @@ func (f *Forwarder) authorize(ctx context.Context, actx *authContext) error { if ks.Name != actx.kubeCluster { continue } - if err := actx.Checker.CheckAccessToKubernetes(s.GetNamespace(), ks, actx.Identity.GetIdentity().MFAVerified); err != nil { + if err := actx.Checker.CheckAccessToKubernetes(s.GetNamespace(), ks, actx.Identity.GetIdentity().MFAVerified != ""); err != nil { return clusterNotFound } return nil @@ -722,6 +722,7 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ }, SessionMetadata: events.SessionMetadata{ SessionID: string(sessionID), + WithMFA: ctx.Identity.GetIdentity().MFAVerified, }, UserMetadata: events.UserMetadata{ User: ctx.User.GetName(), @@ -763,6 +764,7 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ }, SessionMetadata: events.SessionMetadata{ SessionID: string(sessionID), + WithMFA: ctx.Identity.GetIdentity().MFAVerified, }, UserMetadata: events.UserMetadata{ User: ctx.User.GetName(), @@ -845,6 +847,7 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ }, SessionMetadata: events.SessionMetadata{ SessionID: string(sessionID), + WithMFA: ctx.Identity.GetIdentity().MFAVerified, }, UserMetadata: events.UserMetadata{ User: ctx.User.GetName(), @@ -875,6 +878,7 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ }, SessionMetadata: events.SessionMetadata{ SessionID: string(sessionID), + WithMFA: ctx.Identity.GetIdentity().MFAVerified, }, UserMetadata: events.UserMetadata{ User: ctx.User.GetName(), @@ -910,6 +914,7 @@ func (f *Forwarder) exec(ctx *authContext, w http.ResponseWriter, req *http.Requ }, SessionMetadata: events.SessionMetadata{ SessionID: string(sessionID), + WithMFA: ctx.Identity.GetIdentity().MFAVerified, }, UserMetadata: events.UserMetadata{ User: ctx.User.GetName(), diff --git a/lib/reversetunnel/cache.go b/lib/reversetunnel/cache.go index 1492af8285178..61b5029325d95 100644 --- a/lib/reversetunnel/cache.go +++ b/lib/reversetunnel/cache.go @@ -27,6 +27,7 @@ import ( "github.com/gravitational/teleport/lib/auth" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/sshca" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/trace" "github.com/gravitational/ttlmap" @@ -154,14 +155,10 @@ func (c *certificateCache) generateHostCert(principals []string) (ssh.Signer, er if err != nil { return nil, trace.Wrap(err) } - publicKey, _, _, _, err := ssh.ParseAuthorizedKey(certBytes) + cert, err := sshutils.ParseCertificate(certBytes) if err != nil { return nil, err } - cert, ok := publicKey.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("not a certificate") - } // return a ssh.Signer s, err := ssh.NewCertSigner(cert, privateKey) diff --git a/lib/services/authority.go b/lib/services/authority.go index aa8d662b9e259..6eb09cbeb30b7 100644 --- a/lib/services/authority.go +++ b/lib/services/authority.go @@ -265,9 +265,9 @@ type UserCertParams struct { // ActiveRequests tracks privilege escalation requests applied during // certificate construction. ActiveRequests RequestIDs - // MFAVerified is set when these cert parameters were provided by the auth - // server immediately after an MFA check. - MFAVerified bool + // MFAVerified is the UUID of an MFA device when this Identity was + // confirmed immediately after an MFA check. + MFAVerified string // ClientIP is an IP of the client to embed in the certificate. ClientIP string } diff --git a/lib/services/role_test.go b/lib/services/role_test.go index c2e3ac2afb0ff..f6f0b6ebe66fa 100644 --- a/lib/services/role_test.go +++ b/lib/services/role_test.go @@ -24,13 +24,12 @@ import ( "testing" "time" - "golang.org/x/crypto/ssh" - "github.com/gravitational/teleport" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/wrappers" "github.com/gravitational/teleport/lib/defaults" "github.com/gravitational/teleport/lib/fixtures" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -1990,10 +1989,8 @@ func TestExtractFrom(t *testing.T) { }) // Create a SSH certificate. - pubkey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(fixtures.UserCertificateStandard)) + cert, err := sshutils.ParseCertificate([]byte(fixtures.UserCertificateStandard)) require.NoError(t, err) - cert, ok := pubkey.(*ssh.Certificate) - require.True(t, ok) // Create a TLS identity. identity := &tlsca.Identity{ @@ -2052,10 +2049,8 @@ func TestExtractFromLegacy(t *testing.T) { }) // Create a SSH certificate in the legacy format. - pubkey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(fixtures.UserCertificateLegacy)) + cert, err := sshutils.ParseCertificate([]byte(fixtures.UserCertificateLegacy)) require.NoError(t, err) - cert, ok := pubkey.(*ssh.Certificate) - require.True(t, ok) // Create a TLS identity with only roles. identity := &tlsca.Identity{ diff --git a/lib/srv/app/server.go b/lib/srv/app/server.go index 7be9a1761f7d8..a852f52bcc77c 100644 --- a/lib/srv/app/server.go +++ b/lib/srv/app/server.go @@ -374,7 +374,7 @@ func (s *Server) authorize(ctx context.Context, r *http.Request) (*tlsca.Identit if err != nil { return nil, nil, trace.Wrap(err) } - err = authContext.Checker.CheckAccessToApp(defaults.Namespace, app, identity.MFAVerified) + err = authContext.Checker.CheckAccessToApp(defaults.Namespace, app, identity.MFAVerified != "") if err != nil { return nil, nil, utils.OpaqueAccessDenied(err) } diff --git a/lib/srv/app/session.go b/lib/srv/app/session.go index ceb245d1097d1..070bf82b544af 100644 --- a/lib/srv/app/session.go +++ b/lib/srv/app/session.go @@ -142,6 +142,7 @@ func (s *Server) newStreamWriter(identity *tlsca.Identity) (events.StreamWriter, }, SessionMetadata: events.SessionMetadata{ SessionID: identity.RouteToApp.SessionID, + WithMFA: identity.MFAVerified, }, UserMetadata: events.UserMetadata{ User: identity.Username, diff --git a/lib/srv/authhandlers.go b/lib/srv/authhandlers.go index fa4f2139a9057..2584db6be7022 100644 --- a/lib/srv/authhandlers.go +++ b/lib/srv/authhandlers.go @@ -68,7 +68,6 @@ type AuthHandlers struct { func (h *AuthHandlers) CreateIdentityContext(sconn *ssh.ServerConn) (IdentityContext, error) { identity := IdentityContext{ TeleportUser: sconn.Permissions.Extensions[utils.CertTeleportUser], - Certificate: []byte(sconn.Permissions.Extensions[utils.CertTeleportUserCertificate]), Login: sconn.User(), } @@ -77,10 +76,12 @@ func (h *AuthHandlers) CreateIdentityContext(sconn *ssh.ServerConn) (IdentityCon return IdentityContext{}, trace.Wrap(err) } - certificate, err := identity.GetCertificate() + certRaw := []byte(sconn.Permissions.Extensions[utils.CertTeleportUserCertificate]) + certificate, err := sshutils.ParseCertificate(certRaw) if err != nil { return IdentityContext{}, trace.Wrap(err) } + identity.Certificate = certificate identity.RouteToCluster = certificate.Extensions[teleport.CertExtensionTeleportRouteToCluster] if certificate.ValidBefore != 0 { identity.CertValidBefore = time.Unix(int64(certificate.ValidBefore), 0) diff --git a/lib/srv/ctx.go b/lib/srv/ctx.go index d01651c7c6eaf..852bee3e05c11 100644 --- a/lib/srv/ctx.go +++ b/lib/srv/ctx.go @@ -137,7 +137,7 @@ type IdentityContext struct { // Certificate is the SSH user certificate bytes marshalled in the OpenSSH // authorized_keys format. - Certificate []byte + Certificate *ssh.Certificate // CertAuthority is the Certificate Authority that signed the Certificate. CertAuthority services.CertAuthority @@ -154,21 +154,6 @@ type IdentityContext struct { RouteToCluster string } -// GetCertificate parses the SSH certificate bytes and returns a *ssh.Certificate. -func (c IdentityContext) GetCertificate() (*ssh.Certificate, error) { - k, _, _, _, err := ssh.ParseAuthorizedKey(c.Certificate) - if err != nil { - return nil, trace.Wrap(err) - } - - cert, ok := k.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("not a certificate") - } - - return cert, nil -} - // ServerContext holds session specific context, such as SSH auth agents, PTYs, // and other resources. SessionContext also holds a ServerContext which can be // used to access resources on the underlying server. SessionContext can also @@ -579,6 +564,10 @@ func (c *ServerContext) reportStats(conn utils.Stater) { ServerID: c.GetServer().HostUUID(), ServerNamespace: c.GetServer().GetNamespace(), }, + SessionMetadata: events.SessionMetadata{ + SessionID: string(c.SessionID()), + WithMFA: c.Identity.Certificate.Extensions[teleport.CertExtensionMFAVerified], + }, UserMetadata: events.UserMetadata{ User: c.Identity.TeleportUser, Login: c.Identity.Login, @@ -592,10 +581,6 @@ func (c *ServerContext) reportStats(conn utils.Stater) { if !c.srv.UseTunnel() { sessionDataEvent.ConnectionMetadata.LocalAddr = c.ServerConn.LocalAddr().String() } - sessionID := string(c.SessionID()) - if sessionID != "" { - sessionDataEvent.SessionMetadata.SessionID = sessionID - } if err := c.GetServer().EmitAuditEvent(c.GetServer().Context(), sessionDataEvent); err != nil { c.WithError(err).Warn("Failed to emit session data event.") } diff --git a/lib/srv/db/common/audit.go b/lib/srv/db/common/audit.go index 8849673744013..8a5cb89c8780c 100644 --- a/lib/srv/db/common/audit.go +++ b/lib/srv/db/common/audit.go @@ -73,6 +73,7 @@ func (a *Audit) OnSessionStart(ctx context.Context, session Session, sessionErr }, SessionMetadata: events.SessionMetadata{ SessionID: session.ID, + WithMFA: session.Identity.MFAVerified, }, Status: events.Status{ Success: true, @@ -115,6 +116,7 @@ func (a *Audit) OnSessionEnd(ctx context.Context, session Session) error { }, SessionMetadata: events.SessionMetadata{ SessionID: session.ID, + WithMFA: session.Identity.MFAVerified, }, DatabaseMetadata: events.DatabaseMetadata{ DatabaseService: session.Server.GetName(), @@ -143,6 +145,7 @@ func (a *Audit) OnQuery(ctx context.Context, session Session, query string) erro }, SessionMetadata: events.SessionMetadata{ SessionID: session.ID, + WithMFA: session.Identity.MFAVerified, }, DatabaseMetadata: events.DatabaseMetadata{ DatabaseService: session.Server.GetName(), diff --git a/lib/srv/db/mysql/engine.go b/lib/srv/db/mysql/engine.go index 4c69203a1e09a..e0cabed680fb5 100644 --- a/lib/srv/db/mysql/engine.go +++ b/lib/srv/db/mysql/engine.go @@ -129,7 +129,7 @@ func (e *Engine) checkAccess(sessionCtx *common.Session) error { // on queries, we might be able to restrict db_names as well e.g. by // detecting full-qualified table names like db.table, until then the // proper way is to use MySQL grants system. - err := sessionCtx.Checker.CheckAccessToDatabase(sessionCtx.Server, sessionCtx.Identity.MFAVerified, + err := sessionCtx.Checker.CheckAccessToDatabase(sessionCtx.Server, sessionCtx.Identity.MFAVerified != "", &services.DatabaseLabelsMatcher{Labels: sessionCtx.Server.GetAllLabels()}, &services.DatabaseUserMatcher{User: sessionCtx.DatabaseUser}) if err != nil { diff --git a/lib/srv/db/postgres/engine.go b/lib/srv/db/postgres/engine.go index 918afbe775a03..1df230b820e48 100644 --- a/lib/srv/db/postgres/engine.go +++ b/lib/srv/db/postgres/engine.go @@ -178,7 +178,7 @@ func (e *Engine) handleStartup(client *pgproto3.Backend, sessionCtx *common.Sess } func (e *Engine) checkAccess(sessionCtx *common.Session) error { - err := sessionCtx.Checker.CheckAccessToDatabase(sessionCtx.Server, sessionCtx.Identity.MFAVerified, + err := sessionCtx.Checker.CheckAccessToDatabase(sessionCtx.Server, sessionCtx.Identity.MFAVerified != "", &services.DatabaseLabelsMatcher{Labels: sessionCtx.Server.GetAllLabels()}, &services.DatabaseUserMatcher{User: sessionCtx.DatabaseUser}, &services.DatabaseNameMatcher{Name: sessionCtx.DatabaseName}) diff --git a/lib/srv/exec.go b/lib/srv/exec.go index a822b0293bf7c..6e898c4d158d5 100644 --- a/lib/srv/exec.go +++ b/lib/srv/exec.go @@ -366,10 +366,9 @@ func emitExecAuditEvent(ctx *ServerContext, cmd string, execErr error) { ServerNamespace: ctx.srv.GetNamespace(), } - var sessionMeta events.SessionMetadata - sessionID := string(ctx.SessionID()) - if sessionID != "" { - sessionMeta.SessionID = sessionID + sessionMeta := events.SessionMetadata{ + SessionID: string(ctx.SessionID()), + WithMFA: ctx.Identity.Certificate.Extensions[teleport.CertExtensionMFAVerified], } userMeta := events.UserMetadata{ diff --git a/lib/srv/exec_test.go b/lib/srv/exec_test.go index deb5d4b6e52a7..8435a2ecfad92 100644 --- a/lib/srv/exec_test.go +++ b/lib/srv/exec_test.go @@ -41,6 +41,7 @@ import ( "github.com/gravitational/teleport/lib/backend/lite" "github.com/gravitational/teleport/lib/bpf" "github.com/gravitational/teleport/lib/events" + "github.com/gravitational/teleport/lib/fixtures" "github.com/gravitational/teleport/lib/pam" "github.com/gravitational/teleport/lib/services" rsession "github.com/gravitational/teleport/lib/session" @@ -82,7 +83,8 @@ func TestMain(m *testing.M) { } func (s *ExecSuite) SetUpSuite(c *check.C) { - bk, err := lite.NewWithConfig(context.TODO(), lite.Config{Path: c.MkDir()}) + ctx := context.TODO() + bk, err := lite.NewWithConfig(ctx, lite.Config{Path: c.MkDir()}) c.Assert(err, check.IsNil) clusterName, err := services.NewClusterName(services.ClusterNameSpecV2{ @@ -113,23 +115,29 @@ func (s *ExecSuite) SetUpSuite(c *check.C) { c.Assert(err, check.IsNil) s.usr, _ = user.Current() + cert, err := sshutils.ParseCertificate([]byte(fixtures.UserCertificateStandard)) + c.Assert(err, check.IsNil) s.ctx = &ServerContext{ - ConnectionContext: &sshutils.ConnectionContext{}, - IsTestStub: true, - ClusterName: "localhost", + ConnectionContext: &sshutils.ConnectionContext{ + ServerConn: &ssh.ServerConn{Conn: s}, + }, + IsTestStub: true, + ClusterName: "localhost", srv: &fakeServer{ accessPoint: s.a, auditLog: &fakeLog{}, id: "00000000-0000-0000-0000-000000000000", }, - } - s.ctx.Identity.Login = s.usr.Username - s.ctx.session = &session{id: "xxx", term: &fakeTerminal{f: f}} - s.ctx.Identity.TeleportUser = "galt" - s.ctx.ServerConn = &ssh.ServerConn{Conn: s} - s.ctx.ExecRequest = &localExec{Ctx: s.ctx} - s.ctx.request = &ssh.Request{ - Type: sshutils.ExecRequest, + Identity: IdentityContext{ + Login: s.usr.Username, + TeleportUser: "galt", + Certificate: cert, + }, + session: &session{id: "xxx", term: &fakeTerminal{f: f}}, + ExecRequest: &localExec{Ctx: s.ctx}, + request: &ssh.Request{ + Type: sshutils.ExecRequest, + }, } term, err := newLocalTerminal(s.ctx) diff --git a/lib/sshutils/parse.go b/lib/sshutils/parse.go new file mode 100644 index 0000000000000..c2e02e02e896d --- /dev/null +++ b/lib/sshutils/parse.go @@ -0,0 +1,36 @@ +/* +Copyright 2021 Gravitational, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package sshutils + +import ( + "github.com/gravitational/trace" + "golang.org/x/crypto/ssh" +) + +// ParseCertificate parses an SSH certificate from the authorized_keys format. +func ParseCertificate(buf []byte) (*ssh.Certificate, error) { + k, _, _, _, err := ssh.ParseAuthorizedKey(buf) + if err != nil { + return nil, trace.Wrap(err) + } + + cert, ok := k.(*ssh.Certificate) + if !ok { + return nil, trace.BadParameter("not an SSH certificate") + } + + return cert, nil +} diff --git a/lib/sshutils/signer.go b/lib/sshutils/signer.go index e1f9a98035c6a..630f5d2da5432 100644 --- a/lib/sshutils/signer.go +++ b/lib/sshutils/signer.go @@ -79,16 +79,11 @@ func NewSigner(keyBytes, certBytes []byte) (ssh.Signer, error) { return nil, trace.Wrap(err, "failed to parse SSH private key") } - pubkey, _, _, _, err := ssh.ParseAuthorizedKey(certBytes) + cert, err := ParseCertificate(certBytes) if err != nil { return nil, trace.Wrap(err, "failed to parse SSH certificate") } - cert, ok := pubkey.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("expected SSH certificate, got %T ", pubkey) - } - return ssh.NewCertSigner(cert, keySigner) } diff --git a/lib/tlsca/ca.go b/lib/tlsca/ca.go index db3033c905717..5a7f322548642 100644 --- a/lib/tlsca/ca.go +++ b/lib/tlsca/ca.go @@ -114,9 +114,9 @@ type Identity struct { DatabaseNames []string // DatabaseUsers is a list of allowed database users. DatabaseUsers []string - // MFAVerified is set when this Identity was confirmed immediately after an - // MFA check. - MFAVerified bool + // MFAVerified is the UUID of an MFA device when this Identity was + // confirmed immediately after an MFA check. + MFAVerified string // ClientIP is an observed IP of the client that this Identity represents. ClientIP string } @@ -332,11 +332,11 @@ func (id *Identity) Subject() (pkix.Name, error) { Value: id.TeleportCluster, }) } - if id.MFAVerified { + if id.MFAVerified != "" { subject.ExtraNames = append(subject.ExtraNames, pkix.AttributeTypeAndValue{ Type: MFAVerifiedASN1ExtensionOID, - Value: "true", + Value: id.MFAVerified, }) } if id.ClientIP != "" { @@ -456,7 +456,7 @@ func FromSubject(subject pkix.Name, expires time.Time) (*Identity, error) { case attr.Type.Equal(MFAVerifiedASN1ExtensionOID): val, ok := attr.Value.(string) if ok { - id.MFAVerified = val == "true" + id.MFAVerified = val } case attr.Type.Equal(ClientIPASN1ExtensionOID): val, ok := attr.Value.(string) diff --git a/lib/web/apps.go b/lib/web/apps.go index 3e9c7b5e01f63..5e79d0292bccc 100644 --- a/lib/web/apps.go +++ b/lib/web/apps.go @@ -151,6 +151,7 @@ func (h *Handler) createAppSession(w http.ResponseWriter, r *http.Request, p htt }, SessionMetadata: events.SessionMetadata{ SessionID: identity.RouteToApp.SessionID, + WithMFA: identity.MFAVerified, }, UserMetadata: events.UserMetadata{ User: ws.GetUser(), diff --git a/lib/web/sessions.go b/lib/web/sessions.go index 5676bc9f52294..32aa8ce69bd9c 100644 --- a/lib/web/sessions.go +++ b/lib/web/sessions.go @@ -40,6 +40,7 @@ import ( "github.com/gravitational/teleport/lib/reversetunnel" "github.com/gravitational/teleport/lib/services" "github.com/gravitational/teleport/lib/services/local" + "github.com/gravitational/teleport/lib/sshutils" "github.com/gravitational/teleport/lib/tlsca" "github.com/gravitational/teleport/lib/utils" @@ -288,15 +289,7 @@ func (c *SessionContext) GetAgent() (agent.Agent, *ssh.Certificate, error) { // GetSSHCertificate returns the *ssh.Certificate associated with this session. func (c *SessionContext) GetSSHCertificate() (*ssh.Certificate, error) { - pub, _, _, _, err := ssh.ParseAuthorizedKey(c.session.GetPub()) - if err != nil { - return nil, trace.Wrap(err) - } - sshCert, ok := pub.(*ssh.Certificate) - if !ok { - return nil, trace.BadParameter("expected certificate, got %T", pub) - } - return sshCert, nil + return sshutils.ParseCertificate(c.session.GetPub()) } // GetX509Certificate returns the *x509.Certificate associated with this session.