|
- // Copyright 2011 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- package ssh
-
- import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
- "math/big"
- "reflect"
- "strconv"
- "strings"
- )
-
- // These are SSH message type numbers. They are scattered around several
- // documents but many were taken from [SSH-PARAMETERS].
- const (
- msgIgnore = 2
- msgUnimplemented = 3
- msgDebug = 4
- msgNewKeys = 21
- )
-
- // SSH messages:
- //
- // These structures mirror the wire format of the corresponding SSH messages.
- // They are marshaled using reflection with the marshal and unmarshal functions
- // in this file. The only wrinkle is that a final member of type []byte with a
- // ssh tag of "rest" receives the remainder of a packet when unmarshaling.
-
- // See RFC 4253, section 11.1.
- const msgDisconnect = 1
-
- // disconnectMsg is the message that signals a disconnect. It is also
- // the error type returned from mux.Wait()
- type disconnectMsg struct {
- Reason uint32 `sshtype:"1"`
- Message string
- Language string
- }
-
- func (d *disconnectMsg) Error() string {
- return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
- }
-
- // See RFC 4253, section 7.1.
- const msgKexInit = 20
-
- type kexInitMsg struct {
- Cookie [16]byte `sshtype:"20"`
- KexAlgos []string
- ServerHostKeyAlgos []string
- CiphersClientServer []string
- CiphersServerClient []string
- MACsClientServer []string
- MACsServerClient []string
- CompressionClientServer []string
- CompressionServerClient []string
- LanguagesClientServer []string
- LanguagesServerClient []string
- FirstKexFollows bool
- Reserved uint32
- }
-
- // See RFC 4253, section 8.
-
- // Diffie-Helman
- const msgKexDHInit = 30
-
- type kexDHInitMsg struct {
- X *big.Int `sshtype:"30"`
- }
-
- const msgKexECDHInit = 30
-
- type kexECDHInitMsg struct {
- ClientPubKey []byte `sshtype:"30"`
- }
-
- const msgKexECDHReply = 31
-
- type kexECDHReplyMsg struct {
- HostKey []byte `sshtype:"31"`
- EphemeralPubKey []byte
- Signature []byte
- }
-
- const msgKexDHReply = 31
-
- type kexDHReplyMsg struct {
- HostKey []byte `sshtype:"31"`
- Y *big.Int
- Signature []byte
- }
-
- // See RFC 4419, section 5.
- const msgKexDHGexGroup = 31
-
- type kexDHGexGroupMsg struct {
- P *big.Int `sshtype:"31"`
- G *big.Int
- }
-
- const msgKexDHGexInit = 32
-
- type kexDHGexInitMsg struct {
- X *big.Int `sshtype:"32"`
- }
-
- const msgKexDHGexReply = 33
-
- type kexDHGexReplyMsg struct {
- HostKey []byte `sshtype:"33"`
- Y *big.Int
- Signature []byte
- }
-
- const msgKexDHGexRequest = 34
-
- type kexDHGexRequestMsg struct {
- MinBits uint32 `sshtype:"34"`
- PreferedBits uint32
- MaxBits uint32
- }
-
- // See RFC 4253, section 10.
- const msgServiceRequest = 5
-
- type serviceRequestMsg struct {
- Service string `sshtype:"5"`
- }
-
- // See RFC 4253, section 10.
- const msgServiceAccept = 6
-
- type serviceAcceptMsg struct {
- Service string `sshtype:"6"`
- }
-
- // See RFC 4252, section 5.
- const msgUserAuthRequest = 50
-
- type userAuthRequestMsg struct {
- User string `sshtype:"50"`
- Service string
- Method string
- Payload []byte `ssh:"rest"`
- }
-
- // Used for debug printouts of packets.
- type userAuthSuccessMsg struct {
- }
-
- // See RFC 4252, section 5.1
- const msgUserAuthFailure = 51
-
- type userAuthFailureMsg struct {
- Methods []string `sshtype:"51"`
- PartialSuccess bool
- }
-
- // See RFC 4252, section 5.1
- const msgUserAuthSuccess = 52
-
- // See RFC 4252, section 5.4
- const msgUserAuthBanner = 53
-
- type userAuthBannerMsg struct {
- Message string `sshtype:"53"`
- // unused, but required to allow message parsing
- Language string
- }
-
- // See RFC 4256, section 3.2
- const msgUserAuthInfoRequest = 60
- const msgUserAuthInfoResponse = 61
-
- type userAuthInfoRequestMsg struct {
- User string `sshtype:"60"`
- Instruction string
- DeprecatedLanguage string
- NumPrompts uint32
- Prompts []byte `ssh:"rest"`
- }
-
- // See RFC 4254, section 5.1.
- const msgChannelOpen = 90
-
- type channelOpenMsg struct {
- ChanType string `sshtype:"90"`
- PeersID uint32
- PeersWindow uint32
- MaxPacketSize uint32
- TypeSpecificData []byte `ssh:"rest"`
- }
-
- const msgChannelExtendedData = 95
- const msgChannelData = 94
-
- // Used for debug print outs of packets.
- type channelDataMsg struct {
- PeersID uint32 `sshtype:"94"`
- Length uint32
- Rest []byte `ssh:"rest"`
- }
-
- // See RFC 4254, section 5.1.
- const msgChannelOpenConfirm = 91
-
- type channelOpenConfirmMsg struct {
- PeersID uint32 `sshtype:"91"`
- MyID uint32
- MyWindow uint32
- MaxPacketSize uint32
- TypeSpecificData []byte `ssh:"rest"`
- }
-
- // See RFC 4254, section 5.1.
- const msgChannelOpenFailure = 92
-
- type channelOpenFailureMsg struct {
- PeersID uint32 `sshtype:"92"`
- Reason RejectionReason
- Message string
- Language string
- }
-
- const msgChannelRequest = 98
-
- type channelRequestMsg struct {
- PeersID uint32 `sshtype:"98"`
- Request string
- WantReply bool
- RequestSpecificData []byte `ssh:"rest"`
- }
-
- // See RFC 4254, section 5.4.
- const msgChannelSuccess = 99
-
- type channelRequestSuccessMsg struct {
- PeersID uint32 `sshtype:"99"`
- }
-
- // See RFC 4254, section 5.4.
- const msgChannelFailure = 100
-
- type channelRequestFailureMsg struct {
- PeersID uint32 `sshtype:"100"`
- }
-
- // See RFC 4254, section 5.3
- const msgChannelClose = 97
-
- type channelCloseMsg struct {
- PeersID uint32 `sshtype:"97"`
- }
-
- // See RFC 4254, section 5.3
- const msgChannelEOF = 96
-
- type channelEOFMsg struct {
- PeersID uint32 `sshtype:"96"`
- }
-
- // See RFC 4254, section 4
- const msgGlobalRequest = 80
-
- type globalRequestMsg struct {
- Type string `sshtype:"80"`
- WantReply bool
- Data []byte `ssh:"rest"`
- }
-
- // See RFC 4254, section 4
- const msgRequestSuccess = 81
-
- type globalRequestSuccessMsg struct {
- Data []byte `ssh:"rest" sshtype:"81"`
- }
-
- // See RFC 4254, section 4
- const msgRequestFailure = 82
-
- type globalRequestFailureMsg struct {
- Data []byte `ssh:"rest" sshtype:"82"`
- }
-
- // See RFC 4254, section 5.2
- const msgChannelWindowAdjust = 93
-
- type windowAdjustMsg struct {
- PeersID uint32 `sshtype:"93"`
- AdditionalBytes uint32
- }
-
- // See RFC 4252, section 7
- const msgUserAuthPubKeyOk = 60
-
- type userAuthPubKeyOkMsg struct {
- Algo string `sshtype:"60"`
- PubKey []byte
- }
-
- // See RFC 4462, section 3
- const msgUserAuthGSSAPIResponse = 60
-
- type userAuthGSSAPIResponse struct {
- SupportMech []byte `sshtype:"60"`
- }
-
- const msgUserAuthGSSAPIToken = 61
-
- type userAuthGSSAPIToken struct {
- Token []byte `sshtype:"61"`
- }
-
- const msgUserAuthGSSAPIMIC = 66
-
- type userAuthGSSAPIMIC struct {
- MIC []byte `sshtype:"66"`
- }
-
- // See RFC 4462, section 3.9
- const msgUserAuthGSSAPIErrTok = 64
-
- type userAuthGSSAPIErrTok struct {
- ErrorToken []byte `sshtype:"64"`
- }
-
- // See RFC 4462, section 3.8
- const msgUserAuthGSSAPIError = 65
-
- type userAuthGSSAPIError struct {
- MajorStatus uint32 `sshtype:"65"`
- MinorStatus uint32
- Message string
- LanguageTag string
- }
-
- // typeTags returns the possible type bytes for the given reflect.Type, which
- // should be a struct. The possible values are separated by a '|' character.
- func typeTags(structType reflect.Type) (tags []byte) {
- tagStr := structType.Field(0).Tag.Get("sshtype")
-
- for _, tag := range strings.Split(tagStr, "|") {
- i, err := strconv.Atoi(tag)
- if err == nil {
- tags = append(tags, byte(i))
- }
- }
-
- return tags
- }
-
- func fieldError(t reflect.Type, field int, problem string) error {
- if problem != "" {
- problem = ": " + problem
- }
- return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
- }
-
- var errShortRead = errors.New("ssh: short read")
-
- // Unmarshal parses data in SSH wire format into a structure. The out
- // argument should be a pointer to struct. If the first member of the
- // struct has the "sshtype" tag set to a '|'-separated set of numbers
- // in decimal, the packet must start with one of those numbers. In
- // case of error, Unmarshal returns a ParseError or
- // UnexpectedMessageError.
- func Unmarshal(data []byte, out interface{}) error {
- v := reflect.ValueOf(out).Elem()
- structType := v.Type()
- expectedTypes := typeTags(structType)
-
- var expectedType byte
- if len(expectedTypes) > 0 {
- expectedType = expectedTypes[0]
- }
-
- if len(data) == 0 {
- return parseError(expectedType)
- }
-
- if len(expectedTypes) > 0 {
- goodType := false
- for _, e := range expectedTypes {
- if e > 0 && data[0] == e {
- goodType = true
- break
- }
- }
- if !goodType {
- return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
- }
- data = data[1:]
- }
-
- var ok bool
- for i := 0; i < v.NumField(); i++ {
- field := v.Field(i)
- t := field.Type()
- switch t.Kind() {
- case reflect.Bool:
- if len(data) < 1 {
- return errShortRead
- }
- field.SetBool(data[0] != 0)
- data = data[1:]
- case reflect.Array:
- if t.Elem().Kind() != reflect.Uint8 {
- return fieldError(structType, i, "array of unsupported type")
- }
- if len(data) < t.Len() {
- return errShortRead
- }
- for j, n := 0, t.Len(); j < n; j++ {
- field.Index(j).Set(reflect.ValueOf(data[j]))
- }
- data = data[t.Len():]
- case reflect.Uint64:
- var u64 uint64
- if u64, data, ok = parseUint64(data); !ok {
- return errShortRead
- }
- field.SetUint(u64)
- case reflect.Uint32:
- var u32 uint32
- if u32, data, ok = parseUint32(data); !ok {
- return errShortRead
- }
- field.SetUint(uint64(u32))
- case reflect.Uint8:
- if len(data) < 1 {
- return errShortRead
- }
- field.SetUint(uint64(data[0]))
- data = data[1:]
- case reflect.String:
- var s []byte
- if s, data, ok = parseString(data); !ok {
- return fieldError(structType, i, "")
- }
- field.SetString(string(s))
- case reflect.Slice:
- switch t.Elem().Kind() {
- case reflect.Uint8:
- if structType.Field(i).Tag.Get("ssh") == "rest" {
- field.Set(reflect.ValueOf(data))
- data = nil
- } else {
- var s []byte
- if s, data, ok = parseString(data); !ok {
- return errShortRead
- }
- field.Set(reflect.ValueOf(s))
- }
- case reflect.String:
- var nl []string
- if nl, data, ok = parseNameList(data); !ok {
- return errShortRead
- }
- field.Set(reflect.ValueOf(nl))
- default:
- return fieldError(structType, i, "slice of unsupported type")
- }
- case reflect.Ptr:
- if t == bigIntType {
- var n *big.Int
- if n, data, ok = parseInt(data); !ok {
- return errShortRead
- }
- field.Set(reflect.ValueOf(n))
- } else {
- return fieldError(structType, i, "pointer to unsupported type")
- }
- default:
- return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
- }
- }
-
- if len(data) != 0 {
- return parseError(expectedType)
- }
-
- return nil
- }
-
- // Marshal serializes the message in msg to SSH wire format. The msg
- // argument should be a struct or pointer to struct. If the first
- // member has the "sshtype" tag set to a number in decimal, that
- // number is prepended to the result. If the last of member has the
- // "ssh" tag set to "rest", its contents are appended to the output.
- func Marshal(msg interface{}) []byte {
- out := make([]byte, 0, 64)
- return marshalStruct(out, msg)
- }
-
- func marshalStruct(out []byte, msg interface{}) []byte {
- v := reflect.Indirect(reflect.ValueOf(msg))
- msgTypes := typeTags(v.Type())
- if len(msgTypes) > 0 {
- out = append(out, msgTypes[0])
- }
-
- for i, n := 0, v.NumField(); i < n; i++ {
- field := v.Field(i)
- switch t := field.Type(); t.Kind() {
- case reflect.Bool:
- var v uint8
- if field.Bool() {
- v = 1
- }
- out = append(out, v)
- case reflect.Array:
- if t.Elem().Kind() != reflect.Uint8 {
- panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
- }
- for j, l := 0, t.Len(); j < l; j++ {
- out = append(out, uint8(field.Index(j).Uint()))
- }
- case reflect.Uint32:
- out = appendU32(out, uint32(field.Uint()))
- case reflect.Uint64:
- out = appendU64(out, uint64(field.Uint()))
- case reflect.Uint8:
- out = append(out, uint8(field.Uint()))
- case reflect.String:
- s := field.String()
- out = appendInt(out, len(s))
- out = append(out, s...)
- case reflect.Slice:
- switch t.Elem().Kind() {
- case reflect.Uint8:
- if v.Type().Field(i).Tag.Get("ssh") != "rest" {
- out = appendInt(out, field.Len())
- }
- out = append(out, field.Bytes()...)
- case reflect.String:
- offset := len(out)
- out = appendU32(out, 0)
- if n := field.Len(); n > 0 {
- for j := 0; j < n; j++ {
- f := field.Index(j)
- if j != 0 {
- out = append(out, ',')
- }
- out = append(out, f.String()...)
- }
- // overwrite length value
- binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
- }
- default:
- panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
- }
- case reflect.Ptr:
- if t == bigIntType {
- var n *big.Int
- nValue := reflect.ValueOf(&n)
- nValue.Elem().Set(field)
- needed := intLength(n)
- oldLength := len(out)
-
- if cap(out)-len(out) < needed {
- newOut := make([]byte, len(out), 2*(len(out)+needed))
- copy(newOut, out)
- out = newOut
- }
- out = out[:oldLength+needed]
- marshalInt(out[oldLength:], n)
- } else {
- panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
- }
- }
- }
-
- return out
- }
-
- var bigOne = big.NewInt(1)
-
- func parseString(in []byte) (out, rest []byte, ok bool) {
- if len(in) < 4 {
- return
- }
- length := binary.BigEndian.Uint32(in)
- in = in[4:]
- if uint32(len(in)) < length {
- return
- }
- out = in[:length]
- rest = in[length:]
- ok = true
- return
- }
-
- var (
- comma = []byte{','}
- emptyNameList = []string{}
- )
-
- func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
- contents, rest, ok := parseString(in)
- if !ok {
- return
- }
- if len(contents) == 0 {
- out = emptyNameList
- return
- }
- parts := bytes.Split(contents, comma)
- out = make([]string, len(parts))
- for i, part := range parts {
- out[i] = string(part)
- }
- return
- }
-
- func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
- contents, rest, ok := parseString(in)
- if !ok {
- return
- }
- out = new(big.Int)
-
- if len(contents) > 0 && contents[0]&0x80 == 0x80 {
- // This is a negative number
- notBytes := make([]byte, len(contents))
- for i := range notBytes {
- notBytes[i] = ^contents[i]
- }
- out.SetBytes(notBytes)
- out.Add(out, bigOne)
- out.Neg(out)
- } else {
- // Positive number
- out.SetBytes(contents)
- }
- ok = true
- return
- }
-
- func parseUint32(in []byte) (uint32, []byte, bool) {
- if len(in) < 4 {
- return 0, nil, false
- }
- return binary.BigEndian.Uint32(in), in[4:], true
- }
-
- func parseUint64(in []byte) (uint64, []byte, bool) {
- if len(in) < 8 {
- return 0, nil, false
- }
- return binary.BigEndian.Uint64(in), in[8:], true
- }
-
- func intLength(n *big.Int) int {
- length := 4 /* length bytes */
- if n.Sign() < 0 {
- nMinus1 := new(big.Int).Neg(n)
- nMinus1.Sub(nMinus1, bigOne)
- bitLen := nMinus1.BitLen()
- if bitLen%8 == 0 {
- // The number will need 0xff padding
- length++
- }
- length += (bitLen + 7) / 8
- } else if n.Sign() == 0 {
- // A zero is the zero length string
- } else {
- bitLen := n.BitLen()
- if bitLen%8 == 0 {
- // The number will need 0x00 padding
- length++
- }
- length += (bitLen + 7) / 8
- }
-
- return length
- }
-
- func marshalUint32(to []byte, n uint32) []byte {
- binary.BigEndian.PutUint32(to, n)
- return to[4:]
- }
-
- func marshalUint64(to []byte, n uint64) []byte {
- binary.BigEndian.PutUint64(to, n)
- return to[8:]
- }
-
- func marshalInt(to []byte, n *big.Int) []byte {
- lengthBytes := to
- to = to[4:]
- length := 0
-
- if n.Sign() < 0 {
- // A negative number has to be converted to two's-complement
- // form. So we'll subtract 1 and invert. If the
- // most-significant-bit isn't set then we'll need to pad the
- // beginning with 0xff in order to keep the number negative.
- nMinus1 := new(big.Int).Neg(n)
- nMinus1.Sub(nMinus1, bigOne)
- bytes := nMinus1.Bytes()
- for i := range bytes {
- bytes[i] ^= 0xff
- }
- if len(bytes) == 0 || bytes[0]&0x80 == 0 {
- to[0] = 0xff
- to = to[1:]
- length++
- }
- nBytes := copy(to, bytes)
- to = to[nBytes:]
- length += nBytes
- } else if n.Sign() == 0 {
- // A zero is the zero length string
- } else {
- bytes := n.Bytes()
- if len(bytes) > 0 && bytes[0]&0x80 != 0 {
- // We'll have to pad this with a 0x00 in order to
- // stop it looking like a negative number.
- to[0] = 0
- to = to[1:]
- length++
- }
- nBytes := copy(to, bytes)
- to = to[nBytes:]
- length += nBytes
- }
-
- lengthBytes[0] = byte(length >> 24)
- lengthBytes[1] = byte(length >> 16)
- lengthBytes[2] = byte(length >> 8)
- lengthBytes[3] = byte(length)
- return to
- }
-
- func writeInt(w io.Writer, n *big.Int) {
- length := intLength(n)
- buf := make([]byte, length)
- marshalInt(buf, n)
- w.Write(buf)
- }
-
- func writeString(w io.Writer, s []byte) {
- var lengthBytes [4]byte
- lengthBytes[0] = byte(len(s) >> 24)
- lengthBytes[1] = byte(len(s) >> 16)
- lengthBytes[2] = byte(len(s) >> 8)
- lengthBytes[3] = byte(len(s))
- w.Write(lengthBytes[:])
- w.Write(s)
- }
-
- func stringLength(n int) int {
- return 4 + n
- }
-
- func marshalString(to []byte, s []byte) []byte {
- to[0] = byte(len(s) >> 24)
- to[1] = byte(len(s) >> 16)
- to[2] = byte(len(s) >> 8)
- to[3] = byte(len(s))
- to = to[4:]
- copy(to, s)
- return to[len(s):]
- }
-
- var bigIntType = reflect.TypeOf((*big.Int)(nil))
-
- // Decode a packet into its corresponding message.
- func decode(packet []byte) (interface{}, error) {
- var msg interface{}
- switch packet[0] {
- case msgDisconnect:
- msg = new(disconnectMsg)
- case msgServiceRequest:
- msg = new(serviceRequestMsg)
- case msgServiceAccept:
- msg = new(serviceAcceptMsg)
- case msgKexInit:
- msg = new(kexInitMsg)
- case msgKexDHInit:
- msg = new(kexDHInitMsg)
- case msgKexDHReply:
- msg = new(kexDHReplyMsg)
- case msgUserAuthRequest:
- msg = new(userAuthRequestMsg)
- case msgUserAuthSuccess:
- return new(userAuthSuccessMsg), nil
- case msgUserAuthFailure:
- msg = new(userAuthFailureMsg)
- case msgUserAuthPubKeyOk:
- msg = new(userAuthPubKeyOkMsg)
- case msgGlobalRequest:
- msg = new(globalRequestMsg)
- case msgRequestSuccess:
- msg = new(globalRequestSuccessMsg)
- case msgRequestFailure:
- msg = new(globalRequestFailureMsg)
- case msgChannelOpen:
- msg = new(channelOpenMsg)
- case msgChannelData:
- msg = new(channelDataMsg)
- case msgChannelOpenConfirm:
- msg = new(channelOpenConfirmMsg)
- case msgChannelOpenFailure:
- msg = new(channelOpenFailureMsg)
- case msgChannelWindowAdjust:
- msg = new(windowAdjustMsg)
- case msgChannelEOF:
- msg = new(channelEOFMsg)
- case msgChannelClose:
- msg = new(channelCloseMsg)
- case msgChannelRequest:
- msg = new(channelRequestMsg)
- case msgChannelSuccess:
- msg = new(channelRequestSuccessMsg)
- case msgChannelFailure:
- msg = new(channelRequestFailureMsg)
- case msgUserAuthGSSAPIToken:
- msg = new(userAuthGSSAPIToken)
- case msgUserAuthGSSAPIMIC:
- msg = new(userAuthGSSAPIMIC)
- case msgUserAuthGSSAPIErrTok:
- msg = new(userAuthGSSAPIErrTok)
- case msgUserAuthGSSAPIError:
- msg = new(userAuthGSSAPIError)
- default:
- return nil, unexpectedMessageError(0, packet[0])
- }
- if err := Unmarshal(packet, msg); err != nil {
- return nil, err
- }
- return msg, nil
- }
-
- var packetTypeNames = map[byte]string{
- msgDisconnect: "disconnectMsg",
- msgServiceRequest: "serviceRequestMsg",
- msgServiceAccept: "serviceAcceptMsg",
- msgKexInit: "kexInitMsg",
- msgKexDHInit: "kexDHInitMsg",
- msgKexDHReply: "kexDHReplyMsg",
- msgUserAuthRequest: "userAuthRequestMsg",
- msgUserAuthSuccess: "userAuthSuccessMsg",
- msgUserAuthFailure: "userAuthFailureMsg",
- msgUserAuthPubKeyOk: "userAuthPubKeyOkMsg",
- msgGlobalRequest: "globalRequestMsg",
- msgRequestSuccess: "globalRequestSuccessMsg",
- msgRequestFailure: "globalRequestFailureMsg",
- msgChannelOpen: "channelOpenMsg",
- msgChannelData: "channelDataMsg",
- msgChannelOpenConfirm: "channelOpenConfirmMsg",
- msgChannelOpenFailure: "channelOpenFailureMsg",
- msgChannelWindowAdjust: "windowAdjustMsg",
- msgChannelEOF: "channelEOFMsg",
- msgChannelClose: "channelCloseMsg",
- msgChannelRequest: "channelRequestMsg",
- msgChannelSuccess: "channelRequestSuccessMsg",
- msgChannelFailure: "channelRequestFailureMsg",
- }
|